Skip to content

Commit

Permalink
feat(payments): propagate additional payment method data for google p…
Browse files Browse the repository at this point in the history
…ay during MIT (#6644)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
kashif-m and hyperswitch-bot[bot] authored Nov 26, 2024
1 parent e922f96 commit 75fe9c0
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 33 deletions.
33 changes: 33 additions & 0 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,9 @@ pub struct PaymentMethodResponse {
pub enum PaymentMethodsData {
Card(CardDetailsPaymentMethod),
BankDetails(PaymentMethodDataBankCreds),
WalletDetails(PaymentMethodDataWalletInfo),
}

#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct CardDetailsPaymentMethod {
pub last4_digits: Option<String>,
Expand All @@ -847,6 +849,37 @@ pub struct PaymentMethodDataBankCreds {
pub connector_details: Vec<BankAccountConnectorDetails>,
}

#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct PaymentMethodDataWalletInfo {
/// Last 4 digits of the card number
pub last4: String,
/// The information of the payment method
pub card_network: String,
/// The type of payment method
#[serde(rename = "type")]
pub card_type: String,
}

impl From<payments::additional_info::WalletAdditionalDataForCard> for PaymentMethodDataWalletInfo {
fn from(item: payments::additional_info::WalletAdditionalDataForCard) -> Self {
Self {
last4: item.last4,
card_network: item.card_network,
card_type: item.card_type,
}
}
}

impl From<PaymentMethodDataWalletInfo> for payments::additional_info::WalletAdditionalDataForCard {
fn from(item: PaymentMethodDataWalletInfo) -> Self {
Self {
last4: item.last4,
card_network: item.card_network,
card_type: item.card_type,
}
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct BankAccountTokenData {
pub payment_method_type: api_enums::PaymentMethodType,
Expand Down
12 changes: 11 additions & 1 deletion crates/hyperswitch_domain_models/src/payment_method_data.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use api_models::{
mandates,
mandates, payment_methods,
payments::{additional_info as payment_additional_types, ExtendedCardInfo},
};
use common_enums::enums as api_enums;
Expand Down Expand Up @@ -1708,3 +1708,13 @@ impl From<Card> for ExtendedCardInfo {
}
}
}

impl From<GooglePayWalletData> for payment_methods::PaymentMethodDataWalletInfo {
fn from(item: GooglePayWalletData) -> Self {
Self {
last4: item.info.card_details,
card_network: item.info.card_network,
card_type: item.pm_type,
}
}
}
7 changes: 7 additions & 0 deletions crates/router/src/core/payment_methods/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5453,6 +5453,7 @@ pub async fn get_masked_bank_details(
PaymentMethodsData::BankDetails(bank_details) => Ok(Some(MaskedBankDetails {
mask: bank_details.mask,
})),
PaymentMethodsData::WalletDetails(_) => Ok(None),
},
None => Err(report!(errors::ApiErrorResponse::InternalServerError))
.attach_printable("Unable to fetch payment method data"),
Expand Down Expand Up @@ -5492,6 +5493,12 @@ pub async fn get_bank_account_connector_details(
message: "Card is not a valid entity".to_string(),
}
.into()),
PaymentMethodsData::WalletDetails(_) => {
Err(errors::ApiErrorResponse::UnprocessableEntity {
message: "Wallet is not a valid entity".to_string(),
}
.into())
}
PaymentMethodsData::BankDetails(bank_details) => {
let connector_details = bank_details
.connector_details
Expand Down
54 changes: 30 additions & 24 deletions crates/router/src/core/payments/operations/payment_create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,33 +1132,39 @@ impl PaymentCreate {

if additional_pm_data.is_none() {
// If recurring payment is made using payment_method_id, then fetch payment_method_data from retrieved payment_method object
additional_pm_data = payment_method_info
.as_ref()
.and_then(|pm_info| {
pm_info
.payment_method_data
.clone()
.map(|x| x.into_inner().expose())
.and_then(|v| {
serde_json::from_value::<PaymentMethodsData>(v)
.map_err(|err| {
logger::error!(
"Unable to deserialize payment methods data: {:?}",
err
)
additional_pm_data = payment_method_info.as_ref().and_then(|pm_info| {
pm_info
.payment_method_data
.clone()
.map(|x| x.into_inner().expose())
.and_then(|v| {
serde_json::from_value::<PaymentMethodsData>(v)
.map_err(|err| {
logger::error!(
"Unable to deserialize payment methods data: {:?}",
err
)
})
.ok()
})
.and_then(|pmd| match pmd {
PaymentMethodsData::Card(card) => {
Some(api_models::payments::AdditionalPaymentData::Card(Box::new(
api::CardDetailFromLocker::from(card).into(),
)))
}
PaymentMethodsData::WalletDetails(wallet) => match payment_method_type {
Some(enums::PaymentMethodType::GooglePay) => {
Some(api_models::payments::AdditionalPaymentData::Wallet {
apple_pay: None,
google_pay: Some(wallet.into()),
})
.ok()
})
.and_then(|pmd| match pmd {
PaymentMethodsData::Card(crd) => {
Some(api::CardDetailFromLocker::from(crd))
}
_ => None,
})
})
.map(|card| {
api_models::payments::AdditionalPaymentData::Card(Box::new(card.into()))
});
},
_ => None,
})
});
};

let additional_pm_data_value = additional_pm_data
Expand Down
29 changes: 21 additions & 8 deletions crates/router/src/core/payments/tokenization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use std::collections::HashMap;
not(feature = "payment_methods_v2")
))]
use api_models::payment_methods::PaymentMethodsData;
use api_models::payments::ConnectorMandateReferenceId;
use api_models::{
payment_methods::PaymentMethodDataWalletInfo, payments::ConnectorMandateReferenceId,
};
use common_enums::{ConnectorMandateStatus, PaymentMethod};
use common_utils::{
crypto::Encryptable,
Expand Down Expand Up @@ -248,15 +250,26 @@ where
None => None,
};

let pm_card_details = resp.card.as_ref().map(|card| {
PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()))
});
let optional_pm_details = match (
resp.card.as_ref(),
save_payment_method_data.request.get_payment_method_data(),
) {
(Some(card), _) => Some(PaymentMethodsData::Card(
CardDetailsPaymentMethod::from(card.clone()),
)),
(
_,
domain::PaymentMethodData::Wallet(domain::WalletData::GooglePay(googlepay)),
) => Some(PaymentMethodsData::WalletDetails(
PaymentMethodDataWalletInfo::from(googlepay),
)),
_ => None,
};

let key_manager_state = state.into();
let pm_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> =
pm_card_details
.async_map(|pm_card| {
create_encrypted_data(&key_manager_state, key_store, pm_card)
})
optional_pm_details
.async_map(|pm| create_encrypted_data(&key_manager_state, key_store, pm))
.await
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
Expand Down

0 comments on commit 75fe9c0

Please sign in to comment.