From b196599287409f463788a8812d740246f7df7904 Mon Sep 17 00:00:00 2001 From: Sweta-Kumari-Sharma Date: Thu, 19 Dec 2024 13:35:46 +0530 Subject: [PATCH] initial commit --- .../connector/bankofamerica/transformers.rs | 127 +++++++++++++++++- 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index 71cc006700e4..72e9dc42ae08 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -1,5 +1,6 @@ use base64::Engine; -use common_utils::pii; +use common_utils::{ext_traits::OptionExt, pii}; +use error_stack::ResultExt; use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -196,6 +197,27 @@ pub struct ApplePayPaymentInformation { tokenized_card: TokenizedCard, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SamsungPayTokenizedCard { + transaction_type: TransactionType, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SamsungPayPaymentInformation { + fluid_data: FluidData, + tokenized_card: SamsungPayTokenizedCard, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SamsungPayFluidDataValue { + public_key_hash: Secret, + version: String, + data: Secret, +} + #[derive(Debug, Serialize)] #[serde(untagged)] pub enum PaymentInformation { @@ -204,6 +226,7 @@ pub enum PaymentInformation { ApplePay(Box), ApplePayToken(Box), MandatePayment(Box), + SamsungPay(Box), } #[derive(Debug, Serialize)] @@ -237,7 +260,10 @@ pub struct TokenizedCard { #[serde(rename_all = "camelCase")] pub struct FluidData { value: Secret, + #[serde(skip_serializing_if = "Option::is_none")] + descriptor: Option, } +pub const FLUID_DATA_DESCRIPTOR_FOR_SAMSUNG_PAY: &str = "FID=COMMON.SAMSUNG.INAPP.PAYMENT"; #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] @@ -559,6 +585,7 @@ fn get_boa_card_type(card_network: common_enums::CardNetwork) -> Option<&'static pub enum PaymentSolution { ApplePay, GooglePay, + SamsungPay, } impl From for String { @@ -566,6 +593,7 @@ impl From for String { let payment_solution = match solution { PaymentSolution::ApplePay => "001", PaymentSolution::GooglePay => "012", + PaymentSolution::SamsungPay => "008", }; payment_solution.to_string() } @@ -575,6 +603,8 @@ impl From for String { pub enum TransactionType { #[serde(rename = "1")] ApplePay, + #[serde(rename = "1")] + SamsungPay, } impl @@ -1041,7 +1071,9 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> domain::WalletData::GooglePay(google_pay_data) => { Self::try_from((item, google_pay_data)) } - + domain::WalletData::SamsungPay(samsung_pay_data) => { + Self::try_from((item, samsung_pay_data)) + } domain::WalletData::AliPayQr(_) | domain::WalletData::AliPayRedirect(_) | domain::WalletData::AliPayHkRedirect(_) @@ -1059,7 +1091,6 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) | domain::WalletData::Paze(_) - | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} | domain::WalletData::TouchNGoRedirect(_) @@ -2407,6 +2438,94 @@ impl TryFrom<(&types::SetupMandateRouterData, domain::GooglePayWalletData)> } } +fn get_samsung_pay_fluid_data_value( + samsung_pay_token_data: &hyperswitch_domain_models::payment_method_data::SamsungPayTokenData, +) -> Result> { + let samsung_pay_header = + josekit::jwt::decode_header(samsung_pay_token_data.data.clone().peek()) + .change_context(errors::ConnectorError::RequestEncodingFailed) + .attach_printable("Failed to decode samsung pay header")?; + + let samsung_pay_kid_optional = samsung_pay_header.claim("kid").and_then(|kid| kid.as_str()); + + let samsung_pay_fluid_data_value = SamsungPayFluidDataValue { + public_key_hash: Secret::new( + samsung_pay_kid_optional + .get_required_value("samsung pay public_key_hash") + .change_context(errors::ConnectorError::RequestEncodingFailed)? + .to_string(), + ), + version: samsung_pay_token_data.version.clone(), + data: Secret::new(consts::BASE64_ENGINE.encode(samsung_pay_token_data.data.peek())), + }; + + Ok(samsung_pay_fluid_data_value) +} + +impl + TryFrom<( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + Box, + )> for BankOfAmericaPaymentsRequest +{ + type Error = error_stack::Report; + fn try_from( + (item, samsung_pay_data): ( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + Box, + ), + ) -> Result { + let email = item + .router_data + .get_billing_email() + .or(item.router_data.request.get_email())?; + let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?; + let order_information = OrderInformationWithBill::from((item, Some(bill_to))); + + let samsung_pay_fluid_data_value = + get_samsung_pay_fluid_data_value(&samsung_pay_data.payment_credential.token_data)?; + + let samsung_pay_fluid_data_str = serde_json::to_string(&samsung_pay_fluid_data_value) + .change_context(errors::ConnectorError::RequestEncodingFailed) + .attach_printable("Failed to serialize samsung pay fluid data")?; + + let payment_information = + PaymentInformation::SamsungPay(Box::new(SamsungPayPaymentInformation { + fluid_data: FluidData { + value: Secret::new(consts::BASE64_ENGINE.encode(samsung_pay_fluid_data_str)), + descriptor: Some( + consts::BASE64_ENGINE.encode(FLUID_DATA_DESCRIPTOR_FOR_SAMSUNG_PAY), + ), + }, + tokenized_card: SamsungPayTokenizedCard { + transaction_type: TransactionType::SamsungPay, + }, + })); + + let processing_information = ProcessingInformation::try_from(( + item, + Some(PaymentSolution::SamsungPay), + Some(samsung_pay_data.payment_credential.card_brand.to_string()), + ))?; + let client_reference_information = ClientReferenceInformation::from(item); + let merchant_defined_information = item + .router_data + .request + .metadata + .clone() + .map(Vec::::foreign_from); + + Ok(Self { + processing_information, + payment_information, + order_information, + client_reference_information, + consumer_authentication_information: None, + merchant_defined_information, + }) + } +} + // specific for setupMandate flow impl TryFrom<(Option, Option)> for ProcessingInformation { type Error = error_stack::Report; @@ -2493,6 +2612,7 @@ impl From<&domain::ApplePayWalletData> for PaymentInformation { Self::ApplePayToken(Box::new(ApplePayTokenPaymentInformation { fluid_data: FluidData { value: Secret::from(apple_pay_data.payment_data.clone()), + descriptor: None, }, tokenized_card: ApplePayTokenizedCard { transaction_type: TransactionType::ApplePay, @@ -2508,6 +2628,7 @@ impl From<&domain::GooglePayWalletData> for PaymentInformation { value: Secret::from( consts::BASE64_ENGINE.encode(google_pay_data.tokenization_data.token.clone()), ), + descriptor: None, }, })) }