diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index d3247e24b3db..96e3511eb472 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -4190,6 +4190,93 @@ impl Default for super::settings::RequiredFields { non_mandate: HashMap::new(), common: HashMap::new(), } + ), + ( + enums::Connector::Bankofamerica, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from( + [ + ( + "email".to_string(), + RequiredFieldInfo { + required_field: "email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "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, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ] + ), + common: HashMap::new(), + } ) ]), }, @@ -4292,7 +4379,7 @@ impl Default for super::settings::RequiredFields { ), common: HashMap::new(), } - ), + ) ]), }, ), diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index be25d0e39374..a5ed210845c4 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize}; use crate::{ connector::utils::{ - self, AddressDetailsData, CardData, CardIssuer, PaymentsAuthorizeRequestData, - PaymentsSyncRequestData, RouterData, + self, AddressDetailsData, ApplePayDecrypt, CardData, CardIssuer, + PaymentsAuthorizeRequestData, PaymentsSyncRequestData, RouterData, }, consts, core::errors, @@ -16,6 +16,7 @@ use crate::{ api::{self, enums as api_enums}, storage::enums, transformers::ForeignFrom, + ApplePayPredecryptData, }, }; @@ -110,11 +111,18 @@ pub struct GooglePayPaymentInformation { fluid_data: FluidData, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApplePayPaymentInformation { + tokenized_card: TokenizedCard, +} + #[derive(Debug, Serialize)] #[serde(untagged)] pub enum PaymentInformation { Cards(CardPaymentInformation), GooglePay(GooglePayPaymentInformation), + ApplePay(ApplePayPaymentInformation), } #[derive(Debug, Serialize)] @@ -128,6 +136,16 @@ pub struct Card { card_type: Option, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TokenizedCard { + number: Secret, + expiration_month: Secret, + expiration_year: Secret, + cryptogram: Secret, + transaction_type: TransactionType, +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct FluidData { @@ -215,6 +233,12 @@ impl From for String { } } +#[derive(Debug, Serialize)] +pub enum TransactionType { + #[serde(rename = "1")] + ApplePay, +} + impl From<( &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, @@ -320,6 +344,48 @@ impl } } +impl + TryFrom<( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + Box, + )> for BankOfAmericaPaymentsRequest +{ + type Error = error_stack::Report; + fn try_from( + (item, apple_pay_data): ( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + Box, + ), + ) -> Result { + let email = item.router_data.request.get_email()?; + let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; + let order_information = OrderInformationWithBill::from((item, bill_to)); + let processing_information = + ProcessingInformation::from((item, Some(PaymentSolution::ApplePay))); + let client_reference_information = ClientReferenceInformation::from(item); + + let expiration_month = apple_pay_data.get_expiry_month()?; + let expiration_year = apple_pay_data.get_four_digit_expiry_year()?; + + let payment_information = PaymentInformation::ApplePay(ApplePayPaymentInformation { + tokenized_card: TokenizedCard { + number: apple_pay_data.application_primary_account_number, + cryptogram: apple_pay_data.payment_data.online_payment_cryptogram, + transaction_type: TransactionType::ApplePay, + expiration_year, + expiration_month, + }, + }); + + Ok(Self { + processing_information, + payment_information, + order_information, + client_reference_information, + }) + } +} + impl TryFrom<( &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, @@ -368,6 +434,17 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> match item.router_data.request.payment_method_data.clone() { payments::PaymentMethodData::Card(ccard) => Self::try_from((item, ccard)), payments::PaymentMethodData::Wallet(wallet_data) => match wallet_data { + payments::WalletData::ApplePay(_) => { + let payment_method_token = item.router_data.get_payment_method_token()?; + match payment_method_token { + types::PaymentMethodToken::ApplePayDecrypt(decrypt_data) => { + Self::try_from((item, decrypt_data)) + } + types::PaymentMethodToken::Token(_) => { + Err(errors::ConnectorError::InvalidWalletToken)? + } + } + } payments::WalletData::GooglePay(google_pay_data) => { Self::try_from((item, google_pay_data)) } @@ -378,7 +455,6 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> | payments::WalletData::KakaoPayRedirect(_) | payments::WalletData::GoPayRedirect(_) | payments::WalletData::GcashRedirect(_) - | payments::WalletData::ApplePay(_) | payments::WalletData::ApplePayRedirect(_) | payments::WalletData::ApplePayThirdPartySdk(_) | payments::WalletData::DanaRedirect {} diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 6ad040da2842..1ba541e2eaa3 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -1,12 +1,12 @@ use common_utils::{errors::CustomResult, ext_traits::ByteSliceExt}; use error_stack::{IntoReport, ResultExt}; -use masking::{ExposeInterface, PeekInterface, Secret}; +use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use url::Url; use crate::{ - connector::utils::{self, PaymentsCaptureRequestData, RouterData, WalletData}, + connector::utils::{self, ApplePayDecrypt, PaymentsCaptureRequestData, RouterData, WalletData}, consts, core::errors, services, @@ -303,24 +303,8 @@ impl TryFrom<&CheckoutRouterData<&types::PaymentsAuthorizeRouterData>> for Payme })) } types::PaymentMethodToken::ApplePayDecrypt(decrypt_data) => { - let expiry_year_4_digit = Secret::new(format!( - "20{}", - decrypt_data - .clone() - .application_expiration_date - .peek() - .get(0..2) - .ok_or(errors::ConnectorError::RequestEncodingFailed)? - )); - let exp_month = Secret::new( - decrypt_data - .clone() - .application_expiration_date - .peek() - .get(2..4) - .ok_or(errors::ConnectorError::RequestEncodingFailed)? - .to_owned(), - ); + let exp_month = decrypt_data.get_expiry_month()?; + let expiry_year_4_digit = decrypt_data.get_four_digit_expiry_year()?; Ok(PaymentSource::ApplePayPredecrypt(Box::new( ApplePayPredecrypt { token: decrypt_data.application_primary_account_number, diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 3f0d4f543ba4..5f36b682008a 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -8,7 +8,7 @@ use common_utils::{ }; use data_models::mandates::AcceptanceType; use error_stack::{IntoReport, ResultExt}; -use masking::{ExposeInterface, ExposeOptionInterface, PeekInterface, Secret}; +use masking::{ExposeInterface, ExposeOptionInterface, Secret}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use url::Url; @@ -16,7 +16,9 @@ use uuid::Uuid; use crate::{ collect_missing_value_keys, - connector::utils::{self as connector_util, ApplePay, PaymentsPreProcessingData, RouterData}, + connector::utils::{ + self as connector_util, ApplePay, ApplePayDecrypt, PaymentsPreProcessingData, RouterData, + }, core::errors, services, types::{ @@ -1473,24 +1475,8 @@ impl TryFrom<(&payments::WalletData, Option)> if let Some(types::PaymentMethodToken::ApplePayDecrypt(decrypt_data)) = payment_method_token { - let expiry_year_4_digit = Secret::new(format!( - "20{}", - decrypt_data - .clone() - .application_expiration_date - .peek() - .get(0..2) - .ok_or(errors::ConnectorError::RequestEncodingFailed)? - )); - let exp_month = Secret::new( - decrypt_data - .clone() - .application_expiration_date - .peek() - .get(2..4) - .ok_or(errors::ConnectorError::RequestEncodingFailed)? - .to_owned(), - ); + let expiry_year_4_digit = decrypt_data.get_four_digit_expiry_year()?; + let exp_month = decrypt_data.get_expiry_month()?; Some(Self::Wallet(StripeWallet::ApplePayPredecryptToken( Box::new(StripeApplePayPredecrypt { diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index dfb4036f0252..2d0bb27be47b 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -26,7 +26,7 @@ use crate::{ pii::PeekInterface, types::{ self, api, storage::payment_attempt::PaymentAttemptExt, transformers::ForeignTryFrom, - PaymentsCancelData, ResponseId, + ApplePayPredecryptData, PaymentsCancelData, ResponseId, }, utils::{OptionExt, ValueExt}, }; @@ -848,6 +848,33 @@ impl ApplePay for payments::ApplePayWalletData { } } +pub trait ApplePayDecrypt { + fn get_expiry_month(&self) -> Result, Error>; + fn get_four_digit_expiry_year(&self) -> Result, Error>; +} + +impl ApplePayDecrypt for Box { + fn get_four_digit_expiry_year(&self) -> Result, Error> { + Ok(Secret::new(format!( + "20{}", + self.application_expiration_date + .peek() + .get(0..2) + .ok_or(errors::ConnectorError::RequestEncodingFailed)? + ))) + } + + fn get_expiry_month(&self) -> Result, Error> { + Ok(Secret::new( + self.application_expiration_date + .peek() + .get(2..4) + .ok_or(errors::ConnectorError::RequestEncodingFailed)? + .to_owned(), + )) + } +} + pub trait CryptoData { fn get_pay_currency(&self) -> Result; }