From f1466b953bcb06035aefed48dc10a7e8536661fc Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Tue, 12 Dec 2023 15:47:49 +0530 Subject: [PATCH 1/9] feat(pm_auth): Support different pm types in PM auth --- crates/api_models/src/payment_methods.rs | 6 ++ .../src/connector/plaid/transformers.rs | 59 ++++++++++- crates/pm_auth/src/types.rs | 27 ++++- .../router/src/core/payment_methods/cards.rs | 29 +++--- crates/router/src/core/pm_auth.rs | 99 +++++++++++++------ .../src/types/storage/payment_method.rs | 2 +- 6 files changed, 177 insertions(+), 45 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 85b0adefca5..366a827615c 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -176,6 +176,12 @@ pub struct PaymentMethodDataBankCreds { pub connector_details: Vec, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct BankAccountTokenData { + pub payment_method_type: api_enums::PaymentMethodType, + pub connector_details: BankAccountConnectorDetails, +} + #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub struct BankAccountConnectorDetails { pub connector: String, diff --git a/crates/pm_auth/src/connector/plaid/transformers.rs b/crates/pm_auth/src/connector/plaid/transformers.rs index 5e1ad67aead..8d5554c343a 100644 --- a/crates/pm_auth/src/connector/plaid/transformers.rs +++ b/crates/pm_auth/src/connector/plaid/transformers.rs @@ -246,10 +246,15 @@ impl (None, None) }; + let account_details = + types::PaymentMethodTypeDetails::ACH(types::BankAccountDetailsACH { + account_number: Secret::new(ach.account), + routing_number: Secret::new(ach.routing), + }); + let bank_details_new = types::BankAccountDetails { account_name: acc_name, - account_number: ach.account, - routing_number: ach.routing, + account_details, payment_method_type: PaymentMethodType::Ach, account_id: ach.account_id, account_type: acc_type, @@ -258,6 +263,56 @@ impl bank_account_vec.push(bank_details_new); }); + account_numbers.bacs.into_iter().for_each(|bacs| { + let (acc_type, acc_name) = + if let Some((_type, name)) = id_to_suptype.get(&bacs.account_id) { + (_type.to_owned(), Some(name.clone())) + } else { + (None, None) + }; + + let account_details = + types::PaymentMethodTypeDetails::BACS(types::BankAccountDetailsBACS { + account_number: Secret::new(bacs.account), + sort_code: Secret::new(bacs.sort_code), + }); + + let bank_details_new = types::BankAccountDetails { + account_name: acc_name, + account_details, + payment_method_type: PaymentMethodType::Bacs, + account_id: bacs.account_id, + account_type: acc_type, + }; + + bank_account_vec.push(bank_details_new); + }); + + account_numbers.international.into_iter().for_each(|sepa| { + let (acc_type, acc_name) = + if let Some((_type, name)) = id_to_suptype.get(&sepa.account_id) { + (_type.to_owned(), Some(name.clone())) + } else { + (None, None) + }; + + let account_details = + types::PaymentMethodTypeDetails::SEPA(types::BankAccountDetailsSEPA { + iban: Secret::new(sepa.iban), + bic: Secret::new(sepa.bic), + }); + + let bank_details_new = types::BankAccountDetails { + account_name: acc_name, + account_details, + payment_method_type: PaymentMethodType::Sepa, + account_id: sepa.account_id, + account_type: acc_type, + }; + + bank_account_vec.push(bank_details_new); + }); + Ok(Self { response: Ok(types::BankAccountCredentialsResponse { credentials: bank_account_vec, diff --git a/crates/pm_auth/src/types.rs b/crates/pm_auth/src/types.rs index 6f5875247f1..49c53563fcc 100644 --- a/crates/pm_auth/src/types.rs +++ b/crates/pm_auth/src/types.rs @@ -72,13 +72,36 @@ pub struct BankAccountCredentialsResponse { #[derive(Debug, Clone)] pub struct BankAccountDetails { pub account_name: Option, - pub account_number: String, - pub routing_number: String, + pub account_details: PaymentMethodTypeDetails, pub payment_method_type: PaymentMethodType, pub account_id: String, pub account_type: Option, } +#[derive(Debug, Clone)] +pub enum PaymentMethodTypeDetails { + ACH(BankAccountDetailsACH), + BACS(BankAccountDetailsBACS), + SEPA(BankAccountDetailsSEPA), +} +#[derive(Debug, Clone)] +pub struct BankAccountDetailsACH { + pub account_number: Secret, + pub routing_number: Secret, +} + +#[derive(Debug, Clone)] +pub struct BankAccountDetailsBACS { + pub account_number: Secret, + pub sort_code: Secret, +} + +#[derive(Debug, Clone)] +pub struct BankAccountDetailsSEPA { + pub iban: Secret, + pub bic: Secret, +} + pub type BankDetailsRouterData = PaymentAuthRouterData< BankAccountCredentials, BankAccountCredentialsRequest, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index aaecd86627c..4c00957daf0 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -7,7 +7,7 @@ use api_models::{ admin::{self, PaymentMethodsEnabled}, enums::{self as api_enums}, payment_methods::{ - BankAccountConnectorDetails, CardDetailsPaymentMethod, CardNetworkTypes, MaskedBankDetails, + BankAccountTokenData, CardDetailsPaymentMethod, CardNetworkTypes, MaskedBankDetails, PaymentExperienceTypes, PaymentMethodsData, RequestPaymentMethodTypes, RequiredFieldInfo, ResponsePaymentMethodIntermediate, ResponsePaymentMethodTypes, ResponsePaymentMethodsEnabled, @@ -2415,14 +2415,14 @@ pub async fn list_customer_payment_method( enums::PaymentMethod::BankDebit => { // Retrieve the pm_auth connector details so that it can be tokenized - let bank_account_connector_details = get_bank_account_connector_details(&pm, key) + let bank_account_token_data = get_bank_account_connector_details(&pm, key) .await .unwrap_or_else(|err| { logger::error!(error=?err); None }); - if let Some(connector_details) = bank_account_connector_details { - let token_data = PaymentTokenData::AuthBankDebit(connector_details); + if let Some(data) = bank_account_token_data { + let token_data = PaymentTokenData::AuthBankDebit(data); (None, None, token_data) } else { continue; @@ -2652,7 +2652,7 @@ async fn get_masked_bank_details( async fn get_bank_account_connector_details( pm: &payment_method::PaymentMethod, key: &[u8], -) -> errors::RouterResult> { +) -> errors::RouterResult> { let payment_method_data = decrypt::(pm.payment_method_data.clone(), key) .await @@ -2681,12 +2681,19 @@ async fn get_bank_account_connector_details( .connector_details .first() .ok_or(errors::ApiErrorResponse::InternalServerError)?; - Ok(Some(BankAccountConnectorDetails { - connector: connector_details.connector.clone(), - account_id: connector_details.account_id.clone(), - mca_id: connector_details.mca_id.clone(), - access_token: connector_details.access_token.clone(), - })) + + let pm_type = pm + .payment_method_type + .ok_or(errors::ApiErrorResponse::InternalServerError) + .into_report() + .attach_printable("PaymentMethodType not found")?; + + let token_data = BankAccountTokenData { + payment_method_type: pm_type, + connector_details: connector_details.clone(), + }; + + Ok(Some(token_data)) } }, None => Ok(None), diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 821f049d8cf..530d802a08d 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -359,7 +359,24 @@ async fn store_bank_details_in_payment_methods( let mut new_entries: Vec = Vec::new(); for creds in bank_account_details_resp.credentials { - let hash_string = format!("{}-{}", creds.account_number, creds.routing_number); + let (account_number, hash_string) = match creds.account_details { + pm_auth_types::PaymentMethodTypeDetails::ACH(ach) => ( + ach.account_number.clone(), + format!( + "{}-{}", + ach.account_number.peek(), + ach.routing_number.peek() + ), + ), + pm_auth_types::PaymentMethodTypeDetails::BACS(bacs) => ( + bacs.account_number.clone(), + format!("{}-{}", bacs.account_number.peek(), bacs.sort_code.peek()), + ), + pm_auth_types::PaymentMethodTypeDetails::SEPA(sepa) => { + (sepa.iban.clone(), sepa.iban.expose()) + } + }; + let generated_hash = hex::encode( HmacSha256::sign_message(&HmacSha256, pm_auth_key.as_bytes(), hash_string.as_bytes()) .change_context(ApiErrorResponse::InternalServerError) @@ -368,8 +385,8 @@ async fn store_bank_details_in_payment_methods( let contains_account = hash_to_payment_method.get(&generated_hash); let mut pmd = payment_methods::PaymentMethodDataBankCreds { - mask: creds - .account_number + mask: account_number + .peek() .chars() .rev() .take(4) @@ -595,7 +612,9 @@ async fn get_selected_config_from_redis( "Vec", ) .await - .change_context(errors::ApiErrorResponse::InternalServerError) + .change_context(errors::ApiErrorResponse::GenericNotFoundError { + message: "payment method auth connector name not found".to_string(), + }) .attach_printable("Failed to get payment method auth choices from redis")?; let selected_config = pm_auth_configs @@ -605,7 +624,7 @@ async fn get_selected_config_from_redis( && conf.payment_method_type == payload.payment_method_type }) .ok_or(ApiErrorResponse::GenericNotFoundError { - message: "connector name not found".to_string(), + message: "payment method auth connector name not found".to_string(), }) .into_report()? .clone(); @@ -616,13 +635,13 @@ async fn get_selected_config_from_redis( pub async fn retrieve_payment_method_from_auth_service( state: &AppState, key_store: &domain::MerchantKeyStore, - auth_token: &payment_methods::BankAccountConnectorDetails, + auth_token: &payment_methods::BankAccountTokenData, payment_intent: &PaymentIntent, ) -> RouterResult> { let db = state.store.as_ref(); let connector = pm_auth_types::api::PaymentAuthConnectorData::get_connector_by_name( - auth_token.connector.as_str(), + auth_token.connector_details.connector.as_str(), )?; let merchant_account = db @@ -633,12 +652,12 @@ pub async fn retrieve_payment_method_from_auth_service( let mca = db .find_by_merchant_connector_account_merchant_id_merchant_connector_id( &payment_intent.merchant_id, - &auth_token.mca_id, + &auth_token.connector_details.mca_id, key_store, ) .await .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound { - id: auth_token.mca_id.clone(), + id: auth_token.connector_details.mca_id.clone(), }) .attach_printable( "error while fetching merchant_connector_account from merchant_id and connector name", @@ -646,24 +665,24 @@ pub async fn retrieve_payment_method_from_auth_service( let auth_type = pm_auth_helpers::get_connector_auth_type(mca)?; - let BankAccountAccessCreds::AccessToken(access_token) = &auth_token.access_token; + let BankAccountAccessCreds::AccessToken(access_token) = + &auth_token.connector_details.access_token; let bank_account_creds = get_bank_account_creds( connector, &merchant_account, - &auth_token.connector, + &auth_token.connector_details.connector, access_token, auth_type, state, - Some(auth_token.account_id.clone()), + Some(auth_token.connector_details.account_id.clone()), ) .await?; - logger::debug!("bank_creds: {:?}", bank_account_creds); - let bank_account = bank_account_creds .credentials - .first() + .iter() + .find(|acc| acc.payment_method_type == auth_token.payment_method_type) .ok_or(errors::ApiErrorResponse::InternalServerError) .into_report() .attach_printable("Bank account details not found")?; @@ -710,20 +729,42 @@ pub async fn retrieve_payment_method_from_auth_service( last_name, } }); - let payment_method_data = PaymentMethodData::BankDebit(BankDebitData::AchBankDebit { - billing_details: BankDebitBilling { - name: name.unwrap_or_default(), - email: common_utils::pii::Email::from(masking::Secret::new("".to_string())), - address: address_details, - }, - account_number: masking::Secret::new(bank_account.account_number.clone()), - routing_number: masking::Secret::new(bank_account.routing_number.clone()), - card_holder_name: None, - bank_account_holder_name: None, - bank_name: None, - bank_type, - bank_holder_type: None, - }); + + let billing_details = BankDebitBilling { + name: name.unwrap_or_default(), + email: common_utils::pii::Email::from(masking::Secret::new("".to_string())), + address: address_details, + }; + + let payment_method_data = match &bank_account.account_details { + pm_auth_types::PaymentMethodTypeDetails::ACH(ach) => { + PaymentMethodData::BankDebit(BankDebitData::AchBankDebit { + billing_details, + account_number: ach.account_number.clone(), + routing_number: ach.routing_number.clone(), + card_holder_name: None, + bank_account_holder_name: None, + bank_name: None, + bank_type, + bank_holder_type: None, + }) + } + pm_auth_types::PaymentMethodTypeDetails::BACS(bacs) => { + PaymentMethodData::BankDebit(BankDebitData::BacsBankDebit { + billing_details, + account_number: bacs.account_number.clone(), + sort_code: bacs.sort_code.clone(), + bank_account_holder_name: None, + }) + } + pm_auth_types::PaymentMethodTypeDetails::SEPA(sepa) => { + PaymentMethodData::BankDebit(BankDebitData::SepaBankDebit { + billing_details, + iban: sepa.iban.clone(), + bank_account_holder_name: None, + }) + } + }; Ok(Some((payment_method_data, enums::PaymentMethod::BankDebit))) } diff --git a/crates/router/src/types/storage/payment_method.rs b/crates/router/src/types/storage/payment_method.rs index 096303446dc..d4137407e03 100644 --- a/crates/router/src/types/storage/payment_method.rs +++ b/crates/router/src/types/storage/payment_method.rs @@ -30,7 +30,7 @@ pub enum PaymentTokenData { TemporaryGeneric(GenericTokenData), Permanent(CardTokenData), PermanentCard(CardTokenData), - AuthBankDebit(payment_methods::BankAccountConnectorDetails), + AuthBankDebit(payment_methods::BankAccountTokenData), } impl PaymentTokenData { From 1117c9a36a5354dd69091e7f3a5038221d0f992e Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Mon, 8 Jan 2024 13:37:19 +0530 Subject: [PATCH 2/9] fix(pm_auth): Fixed spelling --- crates/pm_auth/src/connector/plaid/transformers.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/pm_auth/src/connector/plaid/transformers.rs b/crates/pm_auth/src/connector/plaid/transformers.rs index 8d5554c343a..e43fd6c6950 100644 --- a/crates/pm_auth/src/connector/plaid/transformers.rs +++ b/crates/pm_auth/src/connector/plaid/transformers.rs @@ -232,15 +232,15 @@ impl ) -> Result { let (account_numbers, accounts_info) = (item.response.numbers, item.response.accounts); let mut bank_account_vec = Vec::new(); - let mut id_to_suptype = HashMap::new(); + let mut id_to_subtype = HashMap::new(); accounts_info.into_iter().for_each(|acc| { - id_to_suptype.insert(acc.account_id, (acc.subtype, acc.name)); + id_to_subtype.insert(acc.account_id, (acc.subtype, acc.name)); }); account_numbers.ach.into_iter().for_each(|ach| { let (acc_type, acc_name) = - if let Some((_type, name)) = id_to_suptype.get(&ach.account_id) { + if let Some((_type, name)) = id_to_subtype.get(&ach.account_id) { (_type.to_owned(), Some(name.clone())) } else { (None, None) @@ -265,7 +265,7 @@ impl account_numbers.bacs.into_iter().for_each(|bacs| { let (acc_type, acc_name) = - if let Some((_type, name)) = id_to_suptype.get(&bacs.account_id) { + if let Some((_type, name)) = id_to_subtype.get(&bacs.account_id) { (_type.to_owned(), Some(name.clone())) } else { (None, None) @@ -290,7 +290,7 @@ impl account_numbers.international.into_iter().for_each(|sepa| { let (acc_type, acc_name) = - if let Some((_type, name)) = id_to_suptype.get(&sepa.account_id) { + if let Some((_type, name)) = id_to_subtype.get(&sepa.account_id) { (_type.to_owned(), Some(name.clone())) } else { (None, None) From 5a80c9208ba5d055c9605a014b90a6b70a809374 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 18 Jan 2024 17:05:04 +0530 Subject: [PATCH 3/9] fix(pm_auth): Fixed clippy errors --- crates/router/src/core/pm_auth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 0ccf5751cb5..64466ea7000 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -740,7 +740,7 @@ pub async fn retrieve_payment_method_from_auth_service( let billing_details = BankDebitBilling { name: name.unwrap_or_default(), - email: email, + email, address: address_details, }; From ed813a8bbebc157524bf4f2c6f9aa2b671e3467f Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 18 Jan 2024 19:23:28 +0530 Subject: [PATCH 4/9] fix(pm_auth): Resolved comments --- crates/pm_auth/src/connector/plaid/transformers.rs | 6 +++--- crates/pm_auth/src/types.rs | 12 ++++++------ crates/router/src/core/pm_auth.rs | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/pm_auth/src/connector/plaid/transformers.rs b/crates/pm_auth/src/connector/plaid/transformers.rs index e43fd6c6950..eda56e382c6 100644 --- a/crates/pm_auth/src/connector/plaid/transformers.rs +++ b/crates/pm_auth/src/connector/plaid/transformers.rs @@ -247,7 +247,7 @@ impl }; let account_details = - types::PaymentMethodTypeDetails::ACH(types::BankAccountDetailsACH { + types::PaymentMethodTypeDetails::Ach(types::BankAccountDetailsAch { account_number: Secret::new(ach.account), routing_number: Secret::new(ach.routing), }); @@ -272,7 +272,7 @@ impl }; let account_details = - types::PaymentMethodTypeDetails::BACS(types::BankAccountDetailsBACS { + types::PaymentMethodTypeDetails::Bacs(types::BankAccountDetailsBacs { account_number: Secret::new(bacs.account), sort_code: Secret::new(bacs.sort_code), }); @@ -297,7 +297,7 @@ impl }; let account_details = - types::PaymentMethodTypeDetails::SEPA(types::BankAccountDetailsSEPA { + types::PaymentMethodTypeDetails::Sepa(types::BankAccountDetailsSepa { iban: Secret::new(sepa.iban), bic: Secret::new(sepa.bic), }); diff --git a/crates/pm_auth/src/types.rs b/crates/pm_auth/src/types.rs index 49c53563fcc..e9fc6663742 100644 --- a/crates/pm_auth/src/types.rs +++ b/crates/pm_auth/src/types.rs @@ -80,24 +80,24 @@ pub struct BankAccountDetails { #[derive(Debug, Clone)] pub enum PaymentMethodTypeDetails { - ACH(BankAccountDetailsACH), - BACS(BankAccountDetailsBACS), - SEPA(BankAccountDetailsSEPA), + Ach(BankAccountDetailsAch), + Bacs(BankAccountDetailsBacs), + Sepa(BankAccountDetailsSepa), } #[derive(Debug, Clone)] -pub struct BankAccountDetailsACH { +pub struct BankAccountDetailsAch { pub account_number: Secret, pub routing_number: Secret, } #[derive(Debug, Clone)] -pub struct BankAccountDetailsBACS { +pub struct BankAccountDetailsBacs { pub account_number: Secret, pub sort_code: Secret, } #[derive(Debug, Clone)] -pub struct BankAccountDetailsSEPA { +pub struct BankAccountDetailsSepa { pub iban: Secret, pub bic: Secret, } diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 64466ea7000..ed2a51c62fb 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -361,7 +361,7 @@ async fn store_bank_details_in_payment_methods( for creds in bank_account_details_resp.credentials { let (account_number, hash_string) = match creds.account_details { - pm_auth_types::PaymentMethodTypeDetails::ACH(ach) => ( + pm_auth_types::PaymentMethodTypeDetails::Ach(ach) => ( ach.account_number.clone(), format!( "{}-{}", @@ -369,11 +369,11 @@ async fn store_bank_details_in_payment_methods( ach.routing_number.peek() ), ), - pm_auth_types::PaymentMethodTypeDetails::BACS(bacs) => ( + pm_auth_types::PaymentMethodTypeDetails::Bacs(bacs) => ( bacs.account_number.clone(), format!("{}-{}", bacs.account_number.peek(), bacs.sort_code.peek()), ), - pm_auth_types::PaymentMethodTypeDetails::SEPA(sepa) => { + pm_auth_types::PaymentMethodTypeDetails::Sepa(sepa) => { (sepa.iban.clone(), sepa.iban.expose()) } }; @@ -745,7 +745,7 @@ pub async fn retrieve_payment_method_from_auth_service( }; let payment_method_data = match &bank_account.account_details { - pm_auth_types::PaymentMethodTypeDetails::ACH(ach) => { + pm_auth_types::PaymentMethodTypeDetails::Ach(ach) => { PaymentMethodData::BankDebit(BankDebitData::AchBankDebit { billing_details, account_number: ach.account_number.clone(), @@ -757,7 +757,7 @@ pub async fn retrieve_payment_method_from_auth_service( bank_holder_type: None, }) } - pm_auth_types::PaymentMethodTypeDetails::BACS(bacs) => { + pm_auth_types::PaymentMethodTypeDetails::Bacs(bacs) => { PaymentMethodData::BankDebit(BankDebitData::BacsBankDebit { billing_details, account_number: bacs.account_number.clone(), @@ -765,7 +765,7 @@ pub async fn retrieve_payment_method_from_auth_service( bank_account_holder_name: None, }) } - pm_auth_types::PaymentMethodTypeDetails::SEPA(sepa) => { + pm_auth_types::PaymentMethodTypeDetails::Sepa(sepa) => { PaymentMethodData::BankDebit(BankDebitData::SepaBankDebit { billing_details, iban: sepa.iban.clone(), From 2f6f8ee2a25db8802c43ccb8be2bc0da2844d9ac Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Wed, 24 Jan 2024 20:13:16 +0530 Subject: [PATCH 5/9] refactor(pm_auth): Added payment_method in bank token data --- crates/api_models/src/payment_methods.rs | 1 + crates/pm_auth/src/connector/plaid/transformers.rs | 5 ++++- crates/pm_auth/src/types.rs | 3 ++- crates/router/src/core/payment_methods/cards.rs | 1 + crates/router/src/core/pm_auth.rs | 5 ++++- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 3904823e030..c9c7630eaa9 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -192,6 +192,7 @@ pub struct PaymentMethodDataBankCreds { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct BankAccountTokenData { pub payment_method_type: api_enums::PaymentMethodType, + pub payment_method: api_enums::PaymentMethod, pub connector_details: BankAccountConnectorDetails, } diff --git a/crates/pm_auth/src/connector/plaid/transformers.rs b/crates/pm_auth/src/connector/plaid/transformers.rs index eda56e382c6..51b90a1f286 100644 --- a/crates/pm_auth/src/connector/plaid/transformers.rs +++ b/crates/pm_auth/src/connector/plaid/transformers.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use common_enums::PaymentMethodType; +use common_enums::{PaymentMethod, PaymentMethodType}; use masking::Secret; use serde::{Deserialize, Serialize}; @@ -256,6 +256,7 @@ impl account_name: acc_name, account_details, payment_method_type: PaymentMethodType::Ach, + payment_method: PaymentMethod::BankDebit, account_id: ach.account_id, account_type: acc_type, }; @@ -281,6 +282,7 @@ impl account_name: acc_name, account_details, payment_method_type: PaymentMethodType::Bacs, + payment_method: PaymentMethod::BankDebit, account_id: bacs.account_id, account_type: acc_type, }; @@ -306,6 +308,7 @@ impl account_name: acc_name, account_details, payment_method_type: PaymentMethodType::Sepa, + payment_method: PaymentMethod::BankDebit, account_id: sepa.account_id, account_type: acc_type, }; diff --git a/crates/pm_auth/src/types.rs b/crates/pm_auth/src/types.rs index e9fc6663742..a2bbc59eff6 100644 --- a/crates/pm_auth/src/types.rs +++ b/crates/pm_auth/src/types.rs @@ -3,7 +3,7 @@ pub mod api; use std::marker::PhantomData; use api::auth_service::{BankAccountCredentials, ExchangeToken, LinkToken}; -use common_enums::PaymentMethodType; +use common_enums::{PaymentMethod, PaymentMethodType}; use masking::Secret; #[derive(Debug, Clone)] pub struct PaymentAuthRouterData { @@ -74,6 +74,7 @@ pub struct BankAccountDetails { pub account_name: Option, pub account_details: PaymentMethodTypeDetails, pub payment_method_type: PaymentMethodType, + pub payment_method: PaymentMethod, pub account_id: String, pub account_type: Option, } diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 3ffe8fc455e..311ce850381 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2840,6 +2840,7 @@ async fn get_bank_account_connector_details( let token_data = BankAccountTokenData { payment_method_type: pm_type, + payment_method: pm.payment_method, connector_details: connector_details.clone(), }; diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index ed2a51c62fb..b41db4554d2 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -684,7 +684,10 @@ pub async fn retrieve_payment_method_from_auth_service( let bank_account = bank_account_creds .credentials .iter() - .find(|acc| acc.payment_method_type == auth_token.payment_method_type) + .find(|acc| { + acc.payment_method_type == auth_token.payment_method_type + && acc.payment_method == auth_token.payment_method + }) .ok_or(errors::ApiErrorResponse::InternalServerError) .into_report() .attach_printable("Bank account details not found")?; From 3b907ac137b013322d6f9ca5f7ad74d5886b331d Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 8 Feb 2024 17:12:10 +0530 Subject: [PATCH 6/9] fix(pm_auth): Resolved comments --- crates/router/src/core/payment_methods/cards.rs | 3 +-- crates/router/src/core/pm_auth.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 311ce850381..986b877f689 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2834,8 +2834,7 @@ async fn get_bank_account_connector_details( let pm_type = pm .payment_method_type - .ok_or(errors::ApiErrorResponse::InternalServerError) - .into_report() + .get_required_value("payment_method_type") .attach_printable("PaymentMethodType not found")?; let token_data = BankAccountTokenData { diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index b41db4554d2..93c3542c98c 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -711,7 +711,12 @@ pub async fn retrieve_payment_method_from_auth_service( let name = address .as_ref() - .and_then(|addr| addr.first_name.clone().map(|name| name.into_inner())); + .and_then(|addr| addr.first_name.clone().map(|name| name.into_inner())) + .ok_or(errors::ApiErrorResponse::GenericNotFoundError { + message: "billing_first_name not found".to_string(), + }) + .into_report() + .attach_printable("billing_first_name not found")?; let address_details = address.clone().map(|addr| { let line1 = addr.line1.map(|line1| line1.into_inner()); @@ -742,7 +747,7 @@ pub async fn retrieve_payment_method_from_auth_service( .get_required_value("email")?; let billing_details = BankDebitBilling { - name: name.unwrap_or_default(), + name, email, address: address_details, }; From 82c60181761191769eb4d4fa964f267d6b53b42b Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Fri, 9 Feb 2024 13:16:45 +0530 Subject: [PATCH 7/9] refactor(pm_auth): Added billing name in required fields --- crates/router/src/configs/defaults.rs | 30 ++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index 42839bf3513..4c4df599b1f 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -5677,7 +5677,15 @@ impl Default for super::settings::RequiredFields { RequiredFieldFinal { mandate: HashMap::new(), non_mandate: HashMap::new(), - common: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + )]), })] )} ), @@ -5690,7 +5698,15 @@ impl Default for super::settings::RequiredFields { RequiredFieldFinal { mandate: HashMap::new(), non_mandate: HashMap::new(), - common: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + )]), } ), ]), @@ -5705,7 +5721,15 @@ impl Default for super::settings::RequiredFields { RequiredFieldFinal { mandate: HashMap::new(), non_mandate: HashMap::new(), - common: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + )]), } ), ]), From 7d0c81d9f2820b4ca98a87c2f9e75e9d443aa1ca Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 14 Mar 2024 16:05:36 +0530 Subject: [PATCH 8/9] fix(pm_auth): Resolved comments --- crates/api_models/src/payment_methods.rs | 4 +- .../src/connector/plaid/transformers.rs | 26 ++++++++----- crates/pm_auth/src/types.rs | 6 +-- crates/router/src/core/pm_auth.rs | 38 ++++++++++++------- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 92f0aba2174..9873f62bfe1 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -232,14 +232,14 @@ pub struct BankAccountTokenData { #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub struct BankAccountConnectorDetails { pub connector: String, - pub account_id: String, + pub account_id: masking::Secret, pub mca_id: String, pub access_token: BankAccountAccessCreds, } #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub enum BankAccountAccessCreds { - AccessToken(String), + AccessToken(masking::Secret), } #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] pub struct CardDetailFromLocker { diff --git a/crates/pm_auth/src/connector/plaid/transformers.rs b/crates/pm_auth/src/connector/plaid/transformers.rs index 51b90a1f286..f163875958e 100644 --- a/crates/pm_auth/src/connector/plaid/transformers.rs +++ b/crates/pm_auth/src/connector/plaid/transformers.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use common_enums::{PaymentMethod, PaymentMethodType}; -use masking::Secret; +use masking::{PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use crate::{core::errors, types}; @@ -200,13 +200,19 @@ pub struct PlaidBankAccountCredentialsBacs { impl TryFrom<&types::BankDetailsRouterData> for PlaidBankAccountCredentialsRequest { type Error = error_stack::Report; fn try_from(item: &types::BankDetailsRouterData) -> Result { + let options = item.request.optional_ids.as_ref().map(|bank_account_ids| { + let ids = bank_account_ids + .ids + .iter() + .map(|id| id.peek().to_string()) + .collect::>(); + + BankAccountCredentialsOptions { account_ids: ids } + }); + Ok(Self { - access_token: item.request.access_token.clone(), - options: item.request.optional_ids.as_ref().map(|bank_account_ids| { - BankAccountCredentialsOptions { - account_ids: bank_account_ids.ids.clone(), - } - }), + access_token: item.request.access_token.peek().to_string(), + options, }) } } @@ -257,7 +263,7 @@ impl account_details, payment_method_type: PaymentMethodType::Ach, payment_method: PaymentMethod::BankDebit, - account_id: ach.account_id, + account_id: ach.account_id.into(), account_type: acc_type, }; @@ -283,7 +289,7 @@ impl account_details, payment_method_type: PaymentMethodType::Bacs, payment_method: PaymentMethod::BankDebit, - account_id: bacs.account_id, + account_id: bacs.account_id.into(), account_type: acc_type, }; @@ -309,7 +315,7 @@ impl account_details, payment_method_type: PaymentMethodType::Sepa, payment_method: PaymentMethod::BankDebit, - account_id: sepa.account_id, + account_id: sepa.account_id.into(), account_type: acc_type, }; diff --git a/crates/pm_auth/src/types.rs b/crates/pm_auth/src/types.rs index a2bbc59eff6..51fd796072b 100644 --- a/crates/pm_auth/src/types.rs +++ b/crates/pm_auth/src/types.rs @@ -55,13 +55,13 @@ pub type ExchangeTokenRouterData = #[derive(Debug, Clone)] pub struct BankAccountCredentialsRequest { - pub access_token: String, + pub access_token: Secret, pub optional_ids: Option, } #[derive(Debug, Clone)] pub struct BankAccountOptionalIDs { - pub ids: Vec, + pub ids: Vec>, } #[derive(Debug, Clone)] @@ -75,7 +75,7 @@ pub struct BankAccountDetails { pub account_details: PaymentMethodTypeDetails, pub payment_method_type: PaymentMethodType, pub payment_method: PaymentMethod, - pub account_id: String, + pub account_id: Secret, pub account_type: Option, } diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index fc08a0e706a..f83a115905c 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -5,6 +5,7 @@ use api_models::{ payment_methods::{self, BankAccountAccessCreds}, payments::{AddressDetails, BankDebitBilling, BankDebitData, PaymentMethodData}, }; +use common_enums::PaymentMethodType; use hex; pub mod helpers; pub mod transformers; @@ -18,7 +19,7 @@ use common_utils::{ use data_models::payments::PaymentIntent; use error_stack::{IntoReport, ResultExt}; use helpers::PaymentAuthConnectorDataExt; -use masking::{ExposeInterface, PeekInterface}; +use masking::{ExposeInterface, PeekInterface, Secret}; use pm_auth::{ connector::plaid::transformers::PlaidAuthType, types::{ @@ -273,7 +274,7 @@ async fn store_bank_details_in_payment_methods( merchant_account: domain::MerchantAccount, state: AppState, bank_account_details_resp: pm_auth_types::BankAccountCredentialsResponse, - connector_details: (&str, String), + connector_details: (&str, Secret), mca_id: String, ) -> RouterResult<()> { let key = key_store.key.get_inner().peek(); @@ -361,18 +362,29 @@ async fn store_bank_details_in_payment_methods( pm_auth_types::PaymentMethodTypeDetails::Ach(ach) => ( ach.account_number.clone(), format!( - "{}-{}", + "{}-{}-{}", ach.account_number.peek(), - ach.routing_number.peek() + ach.routing_number.peek(), + PaymentMethodType::Ach.to_string(), ), ), pm_auth_types::PaymentMethodTypeDetails::Bacs(bacs) => ( bacs.account_number.clone(), - format!("{}-{}", bacs.account_number.peek(), bacs.sort_code.peek()), + format!( + "{}-{}-{}", + bacs.account_number.peek(), + bacs.sort_code.peek(), + PaymentMethodType::Bacs.to_string() + ), + ), + pm_auth_types::PaymentMethodTypeDetails::Sepa(sepa) => ( + sepa.iban.clone(), + format!( + "{}-{}", + sepa.iban.expose(), + PaymentMethodType::Sepa.to_string() + ), ), - pm_auth_types::PaymentMethodTypeDetails::Sepa(sepa) => { - (sepa.iban.clone(), sepa.iban.expose()) - } }; let generated_hash = hex::encode( @@ -489,10 +501,10 @@ pub async fn get_bank_account_creds( connector: PaymentAuthConnectorData, merchant_account: &domain::MerchantAccount, connector_name: &str, - access_token: &str, + access_token: &Secret, auth_type: pm_auth_types::ConnectorAuthType, state: &AppState, - bank_account_id: Option, + bank_account_id: Option>, ) -> RouterResult { let connector_integration_bank_details: BoxedConnectorIntegration< '_, @@ -506,7 +518,7 @@ pub async fn get_bank_account_creds( merchant_id: Some(merchant_account.merchant_id.clone()), connector: Some(connector_name.to_string()), request: pm_auth_types::BankAccountCredentialsRequest { - access_token: access_token.to_string(), + access_token: access_token.clone(), optional_ids: bank_account_id .map(|id| pm_auth_types::BankAccountOptionalIDs { ids: vec![id] }), }, @@ -547,7 +559,7 @@ async fn get_access_token_from_exchange_api( payload: &api_models::pm_auth::ExchangeTokenCreateRequest, auth_type: &pm_auth_types::ConnectorAuthType, state: &AppState, -) -> RouterResult { +) -> RouterResult> { let connector_integration: BoxedConnectorIntegration< '_, ExchangeToken, @@ -590,7 +602,7 @@ async fn get_access_token_from_exchange_api( })?; let access_token = exchange_token_resp.access_token; - Ok(access_token) + Ok(Secret::new(access_token)) } async fn get_selected_config_from_redis( From 7ea9b14057ade1b5f3195760ce00ad226c9da308 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 14 Mar 2024 16:34:19 +0530 Subject: [PATCH 9/9] fix(pm_auth): Fixed clippy errors --- crates/router/src/core/pm_auth.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 4b949db084b..20db03a26a6 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -365,7 +365,7 @@ async fn store_bank_details_in_payment_methods( "{}-{}-{}", ach.account_number.peek(), ach.routing_number.peek(), - PaymentMethodType::Ach.to_string(), + PaymentMethodType::Ach, ), ), pm_auth_types::PaymentMethodTypeDetails::Bacs(bacs) => ( @@ -374,16 +374,12 @@ async fn store_bank_details_in_payment_methods( "{}-{}-{}", bacs.account_number.peek(), bacs.sort_code.peek(), - PaymentMethodType::Bacs.to_string() + PaymentMethodType::Bacs ), ), pm_auth_types::PaymentMethodTypeDetails::Sepa(sepa) => ( sepa.iban.clone(), - format!( - "{}-{}", - sepa.iban.expose(), - PaymentMethodType::Sepa.to_string() - ), + format!("{}-{}", sepa.iban.expose(), PaymentMethodType::Sepa), ), };