fix(router): allow inferring payment method from payment token (#422)

This commit is contained in:
ItsMeShashank
2023-01-19 15:53:16 +05:30
committed by GitHub
parent 749c83a8e6
commit 5924e93413

View File

@ -673,30 +673,37 @@ pub async fn make_pm_data<'a, F: Clone, R>(
state: &'a AppState, state: &'a AppState,
payment_data: &mut PaymentData<F>, payment_data: &mut PaymentData<F>,
) -> RouterResult<(BoxedOperation<'a, F, R>, Option<api::PaymentMethod>)> { ) -> RouterResult<(BoxedOperation<'a, F, R>, Option<api::PaymentMethod>)> {
let payment_method_type = payment_data.payment_attempt.payment_method;
let request = &payment_data.payment_method_data; let request = &payment_data.payment_method_data;
let token = payment_data.token.clone(); let token = payment_data.token.clone();
let card_cvc = payment_data.card_cvc.clone(); let card_cvc = payment_data.card_cvc.clone();
// TODO: Handle case where payment method and token both are present in request properly.
let payment_method = match (request, token) { let payment_method = match (request, token) {
(_, Some(token)) => Ok::<_, error_stack::Report<errors::ApiErrorResponse>>( (_, Some(token)) => {
if payment_method_type == Some(storage_enums::PaymentMethodType::Card) { let (pm, supplementary_data) = vault::Vault::get_payment_method_data_from_locker(
// TODO: Handle token expiry state, &token,
let (pm, supplementary_data) = )
vault::Vault::get_payment_method_data_from_locker(state, &token).await?; .await
utils::when( .attach_printable(
supplementary_data "Payment method for given token not found or there was a problem fetching it",
.customer_id )?;
.ne(&payment_data.payment_intent.customer_id),
|| { utils::when(
Err(errors::ApiErrorResponse::PreconditionFailed { message: "customer associated with payment method and customer passed in payment are not same".into() }) supplementary_data
}, .customer_id
)?; .ne(&payment_data.payment_intent.customer_id),
payment_data.token = Some(token.to_string()); || {
match (pm.clone(), card_cvc) { Err(errors::ApiErrorResponse::PreconditionFailed { message: "customer associated with payment method and customer passed in payment are not same".into() })
(Some(api::PaymentMethod::Card(card)), Some(card_cvc)) => { },
)?;
Ok::<_, error_stack::Report<errors::ApiErrorResponse>>(match pm.clone() {
Some(api::PaymentMethod::Card(card)) => {
payment_data.payment_attempt.payment_method =
Some(storage_enums::PaymentMethodType::Card);
if let Some(cvc) = card_cvc {
let mut updated_card = card; let mut updated_card = card;
updated_card.card_cvc = card_cvc; updated_card.card_cvc = cvc;
let updated_pm = api::PaymentMethod::Card(updated_card); let updated_pm = api::PaymentMethod::Card(updated_card);
vault::Vault::store_payment_method_data_in_locker( vault::Vault::store_payment_method_data_in_locker(
state, state,
@ -706,50 +713,39 @@ pub async fn make_pm_data<'a, F: Clone, R>(
) )
.await?; .await?;
Some(updated_pm) Some(updated_pm)
} else {
pm
} }
(_, _) => pm,
} }
} else if payment_method_type == Some(storage_enums::PaymentMethodType::Wallet) {
let (pm, supplementary_data) =
vault::Vault::get_payment_method_data_from_locker(state, &token).await?;
utils::when( Some(api::PaymentMethod::Wallet(wallet_data)) => {
supplementary_data payment_data.payment_attempt.payment_method =
.customer_id Some(storage_enums::PaymentMethodType::Wallet);
.ne(&payment_data.payment_intent.customer_id), // TODO: Remove redundant update from wallets.
|| { if wallet_data.token.is_some() {
Err(errors::ApiErrorResponse::PreconditionFailed { message: "customer associated with payment method and customer passed in payment are not same".into() }) let updated_pm = api::PaymentMethod::Wallet(wallet_data);
}, vault::Vault::store_payment_method_data_in_locker(
)?; state,
payment_data.token = Some(token.to_string()); Some(token),
match pm.clone() { &updated_pm,
Some(api::PaymentMethod::Wallet(wallet_data)) => { payment_data.payment_intent.customer_id.to_owned(),
if wallet_data.token.is_some() { )
let updated_pm = api::PaymentMethod::Wallet(wallet_data); .await?;
vault::Vault::store_payment_method_data_in_locker( Some(updated_pm)
state, } else {
Some(token), pm
&updated_pm,
payment_data.payment_intent.customer_id.to_owned(),
)
.await?;
Some(updated_pm)
} else {
pm
}
} }
_ => pm,
} }
} else {
utils::when(payment_method_type.is_none(), || { Some(_) => Err(errors::ApiErrorResponse::InternalServerError)
Err(errors::ApiErrorResponse::MissingRequiredField { .into_report()
field_name: "payment_method_type".to_owned(), .attach_printable(
}) "Payment method received from locker is unsupported by locker",
})?; )?,
// [#195]: Implement token flow for other payment methods
None None => None,
}, })
), }
(pm_opt @ Some(pm @ api::PaymentMethod::Card(_)), _) => { (pm_opt @ Some(pm @ api::PaymentMethod::Card(_)), _) => {
let token = vault::Vault::store_payment_method_data_in_locker( let token = vault::Vault::store_payment_method_data_in_locker(
state, state,
@ -840,7 +836,9 @@ pub(crate) fn validate_payment_method_fields_present(
)?; )?;
utils::when( utils::when(
req.payment_method.is_some() && req.payment_method_data.is_none(), req.payment_method.is_some()
&& req.payment_method_data.is_none()
&& req.payment_token.is_none(),
|| { || {
Err(errors::ApiErrorResponse::MissingRequiredField { Err(errors::ApiErrorResponse::MissingRequiredField {
field_name: "payment_method_data".to_string(), field_name: "payment_method_data".to_string(),