From 8dd380aa042f11b82a3f95bd8d774f2bb8c2219e Mon Sep 17 00:00:00 2001 From: DEEPANSHU BANSAL <41580413+deepanshu-iiitu@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:01:07 +0530 Subject: [PATCH] feat(connector): [BANKOFAMERICA] Implement Google Pay (#2940) --- .../connector/bankofamerica/transformers.rs | 256 ++++++++++++++---- 1 file changed, 210 insertions(+), 46 deletions(-) diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index 7456895c8a49..39d221e74ba7 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -1,4 +1,5 @@ use api_models::payments; +use base64::Engine; use common_utils::pii; use masking::Secret; use serde::{Deserialize, Serialize}; @@ -87,6 +88,7 @@ pub struct BankOfAmericaPaymentsRequest { #[serde(rename_all = "camelCase")] pub struct ProcessingInformation { capture: bool, + payment_solution: Option, } #[derive(Debug, Serialize)] @@ -97,10 +99,24 @@ pub struct CaptureOptions { } #[derive(Debug, Serialize)] -pub struct PaymentInformation { +#[serde(rename_all = "camelCase")] +pub struct CardPaymentInformation { card: Card, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GooglePayPaymentInformation { + fluid_data: FluidData, +} + +#[derive(Debug, Serialize)] +#[serde(untagged)] +pub enum PaymentInformation { + Cards(CardPaymentInformation), + GooglePay(GooglePayPaymentInformation), +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Card { @@ -112,6 +128,12 @@ pub struct Card { card_type: Option, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FluidData { + value: Secret, +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct OrderInformationWithBill { @@ -177,12 +199,165 @@ impl From for String { } } +#[derive(Debug, Serialize)] +pub enum PaymentSolution { + ApplePay, + GooglePay, +} + +impl From for String { + fn from(solution: PaymentSolution) -> Self { + let payment_solution = match solution { + PaymentSolution::ApplePay => "001", + PaymentSolution::GooglePay => "012", + }; + payment_solution.to_string() + } +} + +impl + From<( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + BillTo, + )> for OrderInformationWithBill +{ + fn from( + (item, bill_to): ( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + BillTo, + ), + ) -> Self { + Self { + amount_details: Amount { + total_amount: item.amount.to_owned(), + currency: item.router_data.request.currency, + }, + bill_to, + } + } +} + +impl + From<( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + Option, + )> for ProcessingInformation +{ + fn from( + (item, solution): ( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + Option, + ), + ) -> Self { + Self { + capture: matches!( + item.router_data.request.capture_method, + Some(enums::CaptureMethod::Automatic) | None + ), + payment_solution: solution.map(String::from), + } + } +} + +impl From<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> + for ClientReferenceInformation +{ + fn from(item: &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>) -> Self { + Self { + code: Some(item.router_data.connector_request_reference_id.clone()), + } + } +} + #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ClientReferenceInformation { code: Option, } +impl + TryFrom<( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + payments::Card, + )> for BankOfAmericaPaymentsRequest +{ + type Error = error_stack::Report; + fn try_from( + (item, ccard): ( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + payments::Card, + ), + ) -> 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 card_issuer = ccard.get_card_issuer(); + let card_type = match card_issuer { + Ok(issuer) => Some(String::from(issuer)), + Err(_) => None, + }; + + let payment_information = PaymentInformation::Cards(CardPaymentInformation { + card: Card { + number: ccard.card_number, + expiration_month: ccard.card_exp_month, + expiration_year: ccard.card_exp_year, + security_code: ccard.card_cvc, + card_type, + }, + }); + + let processing_information = ProcessingInformation::from((item, None)); + let client_reference_information = ClientReferenceInformation::from(item); + + Ok(Self { + processing_information, + payment_information, + order_information, + client_reference_information, + }) + } +} + +impl + TryFrom<( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + payments::GooglePayWalletData, + )> for BankOfAmericaPaymentsRequest +{ + type Error = error_stack::Report; + fn try_from( + (item, google_pay_data): ( + &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, + payments::GooglePayWalletData, + ), + ) -> 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 payment_information = PaymentInformation::GooglePay(GooglePayPaymentInformation { + fluid_data: FluidData { + value: Secret::from( + consts::BASE64_ENGINE.encode(google_pay_data.tokenization_data.token), + ), + }, + }); + + let processing_information = + ProcessingInformation::from((item, Some(PaymentSolution::GooglePay))); + let client_reference_information = ClientReferenceInformation::from(item); + + Ok(Self { + processing_information, + payment_information, + order_information, + client_reference_information, + }) + } +} + impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> for BankOfAmericaPaymentsRequest { @@ -191,52 +366,41 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> item: &BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { match item.router_data.request.payment_method_data.clone() { - api::PaymentMethodData::Card(ccard) => { - let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; - - let order_information = OrderInformationWithBill { - amount_details: Amount { - total_amount: item.amount.to_owned(), - currency: item.router_data.request.currency, - }, - bill_to, - }; - let card_issuer = ccard.get_card_issuer(); - let card_type = match card_issuer { - Ok(issuer) => Some(String::from(issuer)), - Err(_) => None, - }; - let payment_information = PaymentInformation { - card: Card { - number: ccard.card_number, - expiration_month: ccard.card_exp_month, - expiration_year: ccard.card_exp_year, - security_code: ccard.card_cvc, - card_type, - }, - }; - - let processing_information = ProcessingInformation { - capture: matches!( - item.router_data.request.capture_method, - Some(enums::CaptureMethod::Automatic) | None - ), - }; - - let client_reference_information = ClientReferenceInformation { - code: Some(item.router_data.connector_request_reference_id.clone()), - }; - - Ok(Self { - processing_information, - payment_information, - order_information, - client_reference_information, - }) - } + payments::PaymentMethodData::Card(ccard) => Self::try_from((item, ccard)), + payments::PaymentMethodData::Wallet(wallet_data) => match wallet_data { + payments::WalletData::GooglePay(google_pay_data) => { + Self::try_from((item, google_pay_data)) + } + payments::WalletData::AliPayQr(_) + | payments::WalletData::AliPayRedirect(_) + | payments::WalletData::AliPayHkRedirect(_) + | payments::WalletData::MomoRedirect(_) + | payments::WalletData::KakaoPayRedirect(_) + | payments::WalletData::GoPayRedirect(_) + | payments::WalletData::GcashRedirect(_) + | payments::WalletData::ApplePay(_) + | payments::WalletData::ApplePayRedirect(_) + | payments::WalletData::ApplePayThirdPartySdk(_) + | payments::WalletData::DanaRedirect {} + | payments::WalletData::GooglePayRedirect(_) + | payments::WalletData::GooglePayThirdPartySdk(_) + | payments::WalletData::MbWayRedirect(_) + | payments::WalletData::MobilePayRedirect(_) + | payments::WalletData::PaypalRedirect(_) + | payments::WalletData::PaypalSdk(_) + | payments::WalletData::SamsungPay(_) + | payments::WalletData::TwintRedirect {} + | payments::WalletData::VippsRedirect {} + | payments::WalletData::TouchNGoRedirect(_) + | payments::WalletData::WeChatPayRedirect(_) + | payments::WalletData::WeChatPayQr(_) + | payments::WalletData::CashappQr(_) + | payments::WalletData::SwishQr(_) => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("Bank of America"), + ) + .into()), + }, payments::PaymentMethodData::CardRedirect(_) - | payments::PaymentMethodData::Wallet(_) | payments::PaymentMethodData::PayLater(_) | payments::PaymentMethodData::BankRedirect(_) | payments::PaymentMethodData::BankDebit(_)