From bdb04adceead48faebfd13b21359b5762a826a3e Mon Sep 17 00:00:00 2001 From: Kashif Date: Thu, 18 Sep 2025 18:57:23 +0530 Subject: [PATCH] fix(payouts): populate additional payout method data during recurring payouts (#9426) --- .../src/payment_method_data.rs | 28 +++++++++++++++++++ crates/router/src/core/payouts.rs | 10 ++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 43af1bfa85..59202837dc 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -15,6 +15,7 @@ use common_utils::{ new_type::{ MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, MaskedUpiVpaId, }, + payout_method_utils, pii::{self, Email}, }; use masking::{PeekInterface, Secret}; @@ -2299,6 +2300,33 @@ impl PaymentMethodsData { pub fn get_co_badged_card_data(&self) -> Option { todo!() } + + #[cfg(feature = "v1")] + pub fn get_additional_payout_method_data( + &self, + ) -> Option { + match self { + Self::Card(card_details) => { + router_env::logger::info!("Populating AdditionalPayoutMethodData from Card payment method data for recurring payout"); + Some(payout_method_utils::AdditionalPayoutMethodData::Card( + Box::new(payout_method_utils::CardAdditionalData { + card_issuer: card_details.card_issuer.clone(), + card_network: card_details.card_network.clone(), + bank_code: None, + card_type: card_details.card_type.clone(), + card_issuing_country: card_details.issuer_country.clone(), + last4: card_details.last4_digits.clone(), + card_isin: card_details.card_isin.clone(), + card_extended_bin: None, + card_exp_month: card_details.expiry_month.clone(), + card_exp_year: card_details.expiry_year.clone(), + card_holder_name: card_details.card_holder_name.clone(), + }), + )) + } + Self::BankDetails(_) | Self::WalletDetails(_) | Self::NetworkToken(_) => None, + } + } } #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 491957045c..e0bb73fd29 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -2782,7 +2782,15 @@ pub async fn payout_create_db_entries( helpers::get_additional_payout_data(&payout_method_data, &*state.store, profile_id) .await }) - .await; + .await + // If no payout method data in request but we have a stored payment method, populate from it + .or_else(|| { + payment_method.as_ref().and_then(|payment_method| { + payment_method + .get_payment_methods_data() + .and_then(|pmd| pmd.get_additional_payout_method_data()) + }) + }); let payout_attempt_req = storage::PayoutAttemptNew { payout_attempt_id: payout_attempt_id.to_string(),