Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Sweta-Kumari-Sharma committed Dec 19, 2024
1 parent 653fd0e commit b196599
Showing 1 changed file with 124 additions and 3 deletions.
127 changes: 124 additions & 3 deletions crates/router/src/connector/bankofamerica/transformers.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<String>,
version: String,
data: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum PaymentInformation {
Expand All @@ -204,6 +226,7 @@ pub enum PaymentInformation {
ApplePay(Box<ApplePayPaymentInformation>),
ApplePayToken(Box<ApplePayTokenPaymentInformation>),
MandatePayment(Box<MandatePaymentInformation>),
SamsungPay(Box<SamsungPayPaymentInformation>),
}

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -237,7 +260,10 @@ pub struct TokenizedCard {
#[serde(rename_all = "camelCase")]
pub struct FluidData {
value: Secret<String>,
#[serde(skip_serializing_if = "Option::is_none")]
descriptor: Option<String>,
}
pub const FLUID_DATA_DESCRIPTOR_FOR_SAMSUNG_PAY: &str = "FID=COMMON.SAMSUNG.INAPP.PAYMENT";

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -559,13 +585,15 @@ fn get_boa_card_type(card_network: common_enums::CardNetwork) -> Option<&'static
pub enum PaymentSolution {
ApplePay,
GooglePay,
SamsungPay,
}

impl From<PaymentSolution> for String {
fn from(solution: PaymentSolution) -> Self {
let payment_solution = match solution {
PaymentSolution::ApplePay => "001",
PaymentSolution::GooglePay => "012",
PaymentSolution::SamsungPay => "008",
};
payment_solution.to_string()
}
Expand All @@ -575,6 +603,8 @@ impl From<PaymentSolution> for String {
pub enum TransactionType {
#[serde(rename = "1")]
ApplePay,
#[serde(rename = "1")]
SamsungPay,
}

impl
Expand Down Expand Up @@ -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(_)
Expand All @@ -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(_)
Expand Down Expand Up @@ -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<SamsungPayFluidDataValue, error_stack::Report<errors::ConnectorError>> {
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<domain::SamsungPayWalletData>,
)> for BankOfAmericaPaymentsRequest
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
(item, samsung_pay_data): (
&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>,
Box<domain::SamsungPayWalletData>,
),
) -> Result<Self, Self::Error> {
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::<MerchantDefinedInformation>::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<PaymentSolution>, Option<String>)> for ProcessingInformation {
type Error = error_stack::Report<errors::ConnectorError>;
Expand Down Expand Up @@ -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,
Expand All @@ -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,
},
}))
}
Expand Down

0 comments on commit b196599

Please sign in to comment.