From d9033de5580c663ccd53e0b9ac1ece3661017f92 Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Thu, 7 Mar 2024 18:04:47 +0530 Subject: [PATCH 1/8] feat(router): add routing support for token-based mit payments --- crates/api_models/src/payments.rs | 4 +- .../src/connector/dlocal/transformers.rs | 2 +- crates/router/src/core/mandate.rs | 82 +++---- crates/router/src/core/payments.rs | 204 +++++++++++++----- crates/router/src/core/payments/helpers.rs | 136 ++++++------ .../payments/operations/payment_approve.rs | 2 + .../payments/operations/payment_cancel.rs | 2 + .../payments/operations/payment_capture.rs | 2 + .../operations/payment_complete_authorize.rs | 8 + .../payments/operations/payment_confirm.rs | 19 ++ .../payments/operations/payment_create.rs | 14 +- .../payments/operations/payment_reject.rs | 2 + .../payments/operations/payment_response.rs | 4 +- .../payments/operations/payment_session.rs | 2 + .../core/payments/operations/payment_start.rs | 11 + .../payments/operations/payment_status.rs | 4 +- .../payments/operations/payment_update.rs | 14 +- .../payments_incremental_authorization.rs | 2 + crates/router/src/core/payments/retry.rs | 2 +- .../router/src/core/payments/transformers.rs | 4 +- crates/router/src/core/payouts/helpers.rs | 2 +- crates/router/src/core/routing.rs | 3 +- .../src/types/storage/payment_method.rs | 2 +- 23 files changed, 352 insertions(+), 175 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 86b09f2fa5a6..e1475b63e425 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -738,7 +738,7 @@ pub enum MandateTransactionType { #[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] pub struct MandateIds { - pub mandate_id: String, + pub mandate_id: Option, pub mandate_reference_id: Option, } @@ -765,7 +765,7 @@ pub struct UpdateHistory { impl MandateIds { pub fn new(mandate_id: String) -> Self { Self { - mandate_id, + mandate_id: Some(mandate_id), mandate_reference_id: None, } } diff --git a/crates/router/src/connector/dlocal/transformers.rs b/crates/router/src/connector/dlocal/transformers.rs index 5eb682d4cfa4..c1b8731ee893 100644 --- a/crates/router/src/connector/dlocal/transformers.rs +++ b/crates/router/src/connector/dlocal/transformers.rs @@ -139,7 +139,7 @@ impl TryFrom<&DlocalRouterData<&types::PaymentsAuthorizeRouterData>> for DlocalP .request .mandate_id .as_ref() - .map(|ids| ids.mandate_id.clone()), + .and_then(|ids| ids.mandate_id.clone()), // [#595[FEATURE] Pass Mandate history information in payment flows/request] installments: item .router_data diff --git a/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs index d07a8814c888..2838edfbf91d 100644 --- a/crates/router/src/core/mandate.rs +++ b/crates/router/src/core/mandate.rs @@ -326,48 +326,52 @@ where Err(_) => {} Ok(_) => match resp.request.get_mandate_id() { Some(mandate_id) => { - let mandate_id = &mandate_id.mandate_id; - let mandate = state - .store - .find_mandate_by_merchant_id_mandate_id(resp.merchant_id.as_ref(), mandate_id) - .await - .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?; - let mandate = match mandate.mandate_type { - storage_enums::MandateType::SingleUse => state + if let Some(ref mandate_id) = mandate_id.mandate_id { + let mandate = state .store - .update_mandate_by_merchant_id_mandate_id( - &resp.merchant_id, + .find_mandate_by_merchant_id_mandate_id( + resp.merchant_id.as_ref(), mandate_id, - storage::MandateUpdate::StatusUpdate { - mandate_status: storage_enums::MandateStatus::Revoked, - }, ) .await - .change_context(errors::ApiErrorResponse::MandateUpdateFailed), - storage_enums::MandateType::MultiUse => state - .store - .update_mandate_by_merchant_id_mandate_id( - &resp.merchant_id, - mandate_id, - storage::MandateUpdate::CaptureAmountUpdate { - amount_captured: Some( - mandate.amount_captured.unwrap_or(0) - + resp.request.get_amount(), - ), - }, - ) - .await - .change_context(errors::ApiErrorResponse::MandateUpdateFailed), - }?; - metrics::SUBSEQUENT_MANDATE_PAYMENT.add( - &metrics::CONTEXT, - 1, - &[metrics::request::add_attributes( - "connector", - mandate.connector, - )], - ); - resp.payment_method_id = Some(mandate.payment_method_id); + .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?; + let mandate = match mandate.mandate_type { + storage_enums::MandateType::SingleUse => state + .store + .update_mandate_by_merchant_id_mandate_id( + &resp.merchant_id, + mandate_id, + storage::MandateUpdate::StatusUpdate { + mandate_status: storage_enums::MandateStatus::Revoked, + }, + ) + .await + .change_context(errors::ApiErrorResponse::MandateUpdateFailed), + storage_enums::MandateType::MultiUse => state + .store + .update_mandate_by_merchant_id_mandate_id( + &resp.merchant_id, + mandate_id, + storage::MandateUpdate::CaptureAmountUpdate { + amount_captured: Some( + mandate.amount_captured.unwrap_or(0) + + resp.request.get_amount(), + ), + }, + ) + .await + .change_context(errors::ApiErrorResponse::MandateUpdateFailed), + }?; + metrics::SUBSEQUENT_MANDATE_PAYMENT.add( + &metrics::CONTEXT, + 1, + &[metrics::request::add_attributes( + "connector", + mandate.connector, + )], + ); + resp.payment_method_id = Some(mandate.payment_method_id); + } } None => { if resp.request.get_setup_mandate_details().is_some() { @@ -409,7 +413,7 @@ where logger::debug!("{:?}", new_mandate_data); resp.request .set_mandate_id(Some(api_models::payments::MandateIds { - mandate_id: new_mandate_data.mandate_id.clone(), + mandate_id: Some(new_mandate_data.mandate_id.clone()), mandate_reference_id: new_mandate_data .connector_mandate_ids .clone() diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 002502e9d9d0..e9f2bc619ae3 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -11,9 +11,14 @@ pub mod tokenization; pub mod transformers; pub mod types; -use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant, vec::IntoIter}; +use std::{ + collections::HashMap, fmt::Debug, marker::PhantomData, ops::Deref, time::Instant, vec::IntoIter, +}; -use api_models::{self, enums, payments::HeaderPayload}; +use api_models::{ + self, enums, + payments::{self as payments_api, HeaderPayload}, +}; use common_utils::{ext_traits::AsyncExt, pii, types::Surcharge}; use data_models::mandates::{CustomerAcceptance, MandateData}; use diesel_models::{ephemeral_key, fraud_check::FraudCheck}; @@ -2053,9 +2058,11 @@ where pub customer_acceptance: Option, pub address: PaymentAddress, pub token: Option, + pub token_data: Option, pub confirm: Option, pub force_sync: Option, pub payment_method_data: Option, + pub payment_method_info: Option, pub refunds: Vec, pub disputes: Vec, pub attempts: Option>, @@ -2642,7 +2649,10 @@ where .as_ref() .zip(payment_data.payment_attempt.payment_method_type.as_ref()) { - if let Some(choice) = pre_routing_results.get(storage_pm_type) { + if let (Some(choice), None) = ( + pre_routing_results.get(storage_pm_type), + &payment_data.token_data, + ) { let connector_data = api::ConnectorData::get_connector_by_name( &state.conf.connectors, &choice.connector.to_string(), @@ -2677,6 +2687,12 @@ where .attach_printable("Failed execution of straight through routing")?; if check_eligibility { + #[cfg(feature = "business_profile_routing")] + let profile_id = payment_data.payment_intent.profile_id.clone(); + + #[cfg(not(feature = "business_profile_routing"))] + let profile_id = None; + connectors = routing::perform_eligibility_analysis_with_fallback( &state.clone(), key_store, @@ -2685,20 +2701,13 @@ where &TransactionData::Payment(payment_data), eligible_connectors, #[cfg(feature = "business_profile_routing")] - payment_data.payment_intent.profile_id.clone(), + profile_id, ) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed eligibility analysis and fallback")?; } - let first_connector_choice = connectors - .first() - .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) - .into_report() - .attach_printable("Empty connector list returned")? - .clone(); - let connector_data = connectors .into_iter() .map(|conn| { @@ -2716,17 +2725,11 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Invalid connector name received")?; - routing_data.routed_through = Some(first_connector_choice.connector.to_string()); - #[cfg(feature = "connector_choice_mca_id")] - { - routing_data.merchant_connector_id = first_connector_choice.merchant_connector_id; - } - #[cfg(not(feature = "connector_choice_mca_id"))] - { - routing_data.business_sub_label = first_connector_choice.sub_label.clone(); - } - routing_data.routing_info.algorithm = Some(routing_algorithm); - return Ok(api::ConnectorCallType::Retryable(connector_data)); + return decide_connector_for_token_based_mit_flow( + payment_data, + routing_data, + connector_data, + ); } if let Some(ref routing_algorithm) = routing_data.routing_info.algorithm { @@ -2738,6 +2741,12 @@ where .attach_printable("Failed execution of straight through routing")?; if check_eligibility { + #[cfg(feature = "business_profile_routing")] + let profile_id = payment_data.payment_intent.profile_id.clone(); + + #[cfg(not(feature = "business_profile_routing"))] + let profile_id = None; + connectors = routing::perform_eligibility_analysis_with_fallback( &state, key_store, @@ -2746,20 +2755,13 @@ where &TransactionData::Payment(payment_data), eligible_connectors, #[cfg(feature = "business_profile_routing")] - payment_data.payment_intent.profile_id.clone(), + profile_id, ) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed eligibility analysis and fallback")?; } - let first_connector_choice = connectors - .first() - .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) - .into_report() - .attach_printable("Empty connector list returned")? - .clone(); - let connector_data = connectors .into_iter() .map(|conn| { @@ -2777,16 +2779,11 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Invalid connector name received")?; - routing_data.routed_through = Some(first_connector_choice.connector.to_string()); - #[cfg(feature = "connector_choice_mca_id")] - { - routing_data.merchant_connector_id = first_connector_choice.merchant_connector_id; - } - #[cfg(not(feature = "connector_choice_mca_id"))] - { - routing_data.business_sub_label = first_connector_choice.sub_label; - } - return Ok(api::ConnectorCallType::Retryable(connector_data)); + return decide_connector_for_token_based_mit_flow( + payment_data, + routing_data, + connector_data, + ); } route_connector_v1( @@ -2794,13 +2791,97 @@ where merchant_account, business_profile, key_store, - &TransactionData::Payment(payment_data), + TransactionData::Payment(payment_data), routing_data, eligible_connectors, ) .await } +pub fn decide_connector_for_token_based_mit_flow( + payment_data: &mut PaymentData, + routing_data: &mut storage::RoutingData, + connectors: Vec, +) -> RouterResult { + if let Some((storage_enums::FutureUsage::OffSession, _)) = payment_data + .payment_intent + .setup_future_usage + .zip(payment_data.token_data.as_ref()) + { + logger::debug!("performing routing for token-based MIT flow"); + + let payment_method_info = payment_data + .payment_method_info + .as_ref() + .get_required_value("payment_method_info")?; + + let connector_mandate_details = payment_method_info + .connector_mandate_details + .clone() + .map(|details| { + details.parse_value::>("connector_mandate_details") + }) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to deserialize connector mandate details")? + .get_required_value("connector_mandate_details") + .change_context(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) + .attach_printable("no eligible connector found for token-based MIT flow since there were no connector mandate details")?; + + let mut connector_choice = None; + for connector_data in connectors { + if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { + if let Some(connector_mandate_id) = + connector_mandate_details.get(merchant_connector_id) + { + connector_choice = Some((connector_data, connector_mandate_id.clone())); + break; + } + } + } + + let (chosen_connector_data, chosen_mandate_id) = connector_choice + .get_required_value("connector_choice") + .change_context(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) + .attach_printable("no eligible connector found for token-based MIT payment")?; + + routing_data.routed_through = Some(chosen_connector_data.connector_name.to_string()); + #[cfg(feature = "connector_choice_mca_id")] + { + routing_data.merchant_connector_id = + chosen_connector_data.merchant_connector_id.clone(); + } + + payment_data.mandate_id = Some(payments_api::MandateIds { + mandate_id: None, + mandate_reference_id: Some(payments_api::MandateReferenceId::ConnectorMandateId( + payments_api::ConnectorMandateReferenceId { + connector_mandate_id: Some(chosen_mandate_id), + payment_method_id: Some(payment_method_info.payment_method_id.clone()), + update_history: None, + }, + )), + }); + + Ok(api::ConnectorCallType::PreDetermined(chosen_connector_data)) + } else { + let first_choice = connectors + .first() + .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) + .into_report() + .attach_printable("no eligible connector found for payment")? + .clone(); + + routing_data.routed_through = Some(first_choice.connector_name.to_string()); + #[cfg(feature = "connector_choice_mca_id")] + { + routing_data.merchant_connector_id = first_choice.merchant_connector_id; + } + + Ok(api::ConnectorCallType::Retryable(connectors)) + } +} + pub fn should_add_task_to_process_tracker(payment_data: &PaymentData) -> bool { let connector = payment_data.payment_attempt.connector.as_deref(); @@ -2930,7 +3011,7 @@ pub async fn route_connector_v1( merchant_account: &domain::MerchantAccount, business_profile: &storage::business_profile::BusinessProfile, key_store: &domain::MerchantKeyStore, - transaction_data: &TransactionData<'_, F>, + transaction_data: TransactionData<'_, F>, routing_data: &mut storage::RoutingData, eligible_connectors: Option>, ) -> RouterResult @@ -2938,7 +3019,7 @@ where F: Send + Clone, { #[allow(unused_variables)] - let (profile_id, routing_algorithm) = match transaction_data { + let (profile_id, routing_algorithm) = match &transaction_data { TransactionData::Payment(payment_data) => { if cfg!(feature = "business_profile_routing") { ( @@ -2973,7 +3054,7 @@ where state, &merchant_account.merchant_id, algorithm_ref, - transaction_data, + &transaction_data, ) .await .change_context(errors::ApiErrorResponse::InternalServerError)?; @@ -2983,7 +3064,7 @@ where key_store, merchant_account.modified_at.assume_utc().unix_timestamp(), connectors, - transaction_data, + &transaction_data, eligible_connectors, #[cfg(feature = "business_profile_routing")] profile_id, @@ -2999,17 +3080,6 @@ where .attach_printable("Empty connector list returned")? .clone(); - routing_data.routed_through = Some(first_connector_choice.connector.to_string()); - - #[cfg(feature = "connector_choice_mca_id")] - { - routing_data.merchant_connector_id = first_connector_choice.merchant_connector_id; - } - #[cfg(not(feature = "connector_choice_mca_id"))] - { - routing_data.business_sub_label = first_connector_choice.sub_label; - } - let connector_data = connectors .into_iter() .map(|conn| { @@ -3027,5 +3097,25 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Invalid connector name received")?; - Ok(ConnectorCallType::Retryable(connector_data)) + match transaction_data { + TransactionData::Payment(payment_data) => { + decide_connector_for_token_based_mit_flow(payment_data, routing_data, connector_data) + } + + #[cfg(feature = "payouts")] + TransactionData::Payout(_) => { + routing_data.routed_through = Some(first_connector_choice.connector.to_string()); + + #[cfg(feature = "connector_choice_mca_id")] + { + routing_data.merchant_connector_id = first_connector_choice.merchant_connector_id; + } + #[cfg(not(feature = "connector_choice_mca_id"))] + { + routing_data.business_sub_label = first_connector_choice.sub_label; + } + + Ok(ConnectorCallType::Retryable(connector_data)) + } + } } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index eb476cfccdd4..ee696f16c7ee 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1590,6 +1590,79 @@ pub async fn retrieve_card_with_permanent_token( Ok(api::PaymentMethodData::Card(api_card)) } +pub async fn retrieve_payment_method_from_db_with_token_data( + state: &AppState, + token_data: &storage::PaymentTokenData, +) -> RouterResult> { + match token_data { + storage::PaymentTokenData::PermanentCard(data) => { + if let Some(ref payment_method_id) = data.payment_method_id { + state + .store + .find_payment_method(payment_method_id) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound) + .attach_printable("error retrieving payment method from DB") + .map(Some) + } else { + Ok(None) + } + } + + _ => Ok(None), + } +} + +pub async fn retrieve_payment_token_data( + state: &AppState, + token: String, + payment_method: Option, +) -> RouterResult { + let redis_conn = state + .store + .get_redis_conn() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to get redis connection")?; + + let key = format!( + "pm_token_{}_{}_hyperswitch", + token, + payment_method.get_required_value("payment_method")? + ); + + let token_data_string = redis_conn + .get_key::>(&key) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to fetch the token from redis")? + .ok_or(error_stack::Report::new( + errors::ApiErrorResponse::UnprocessableEntity { + message: "Token is invalid or expired".to_owned(), + }, + ))?; + + let token_data_result = token_data_string + .clone() + .parse_struct("PaymentTokenData") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to deserialize hyperswitch token data"); + + let token_data = match token_data_result { + Ok(data) => data, + Err(e) => { + // The purpose of this logic is backwards compatibility to support tokens + // in redis that might be following the old format. + if token_data_string.starts_with('{') { + return Err(e); + } else { + storage::PaymentTokenData::temporary_generic(token_data_string) + } + } + }; + + Ok(token_data) +} + pub async fn make_pm_data<'a, F: Clone, R, Ctx: PaymentMethodRetrieve>( operation: BoxedOperation<'a, F, R, Ctx>, state: &'a AppState, @@ -1617,72 +1690,13 @@ pub async fn make_pm_data<'a, F: Clone, R, Ctx: PaymentMethodRetrieve>( } } - let token = payment_data.token.clone(); - - let hyperswitch_token = match payment_data.mandate_id { - Some(_) => token.map(storage::PaymentTokenData::temporary_generic), - None => { - if let Some(token) = token { - let redis_conn = state - .store - .get_redis_conn() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to get redis connection")?; - - let key = format!( - "pm_token_{}_{}_hyperswitch", - token, - payment_data - .payment_attempt - .payment_method - .to_owned() - .get_required_value("payment_method")?, - ); - - let token_data_string = redis_conn - .get_key::>(&key) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to fetch the token from redis")? - .ok_or(error_stack::Report::new( - errors::ApiErrorResponse::UnprocessableEntity { - message: "Token is invalid or expired".to_owned(), - }, - ))?; - - let token_data_result = token_data_string - .clone() - .parse_struct("PaymentTokenData") - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to deserialize hyperswitch token data"); - - let token_data = match token_data_result { - Ok(data) => data, - Err(e) => { - // The purpose of this logic is backwards compatibility to support tokens - // in redis that might be following the old format. - if token_data_string.starts_with('{') { - return Err(e); - } else { - storage::PaymentTokenData::temporary_generic(token_data_string) - } - } - }; - - Some(token_data) - } else { - None - } - } - }; - // TODO: Handle case where payment method and token both are present in request properly. - let payment_method = match (request, hyperswitch_token) { + let payment_method = match (request, payment_data.token_data.as_ref()) { (_, Some(hyperswitch_token)) => { let payment_method_details = Ctx::retrieve_payment_method_with_token( state, merchant_key_store, - &hyperswitch_token, + hyperswitch_token, &payment_data.payment_intent, card_token_data.as_ref(), customer, diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index a38c7bbdd3c0..bb1ff9f2d819 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -149,6 +149,7 @@ impl setup_mandate: None, customer_acceptance: None, token: None, + token_data: None, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -158,6 +159,7 @@ impl }, confirm: None, payment_method_data: None, + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index 1b09e9abce57..a04abfd898ae 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -157,6 +157,7 @@ impl setup_mandate: None, customer_acceptance: None, token: None, + token_data: None, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -166,6 +167,7 @@ impl }, confirm: None, payment_method_data: None, + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index 4a488a07eb3e..033df29a7024 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -202,6 +202,7 @@ impl setup_mandate: None, customer_acceptance: None, token: None, + token_data: None, address: payments::PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -211,6 +212,7 @@ impl }, confirm: None, payment_method_data: None, + payment_method_info: None, refunds: vec![], disputes: vec![], attempts: None, diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index 395f8e59dbc4..f013ce5e6cdb 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -131,6 +131,12 @@ impl } } + let token_data = if let Some(token) = token.clone() { + Some(helpers::retrieve_payment_token_data(state, token, payment_method).await?) + } else { + None + }; + payment_attempt.payment_method = payment_method.or(payment_attempt.payment_method); payment_attempt.browser_info = browser_info; payment_attempt.payment_method_type = @@ -247,6 +253,7 @@ impl setup_mandate, customer_acceptance: None, token, + token_data, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -259,6 +266,7 @@ impl .payment_method_data .as_ref() .map(|pmd| pmd.payment_method_data.clone()), + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 529565c71e86..78aa6fe98337 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -383,6 +383,23 @@ impl &token, )?; + let (token_data, payment_method_info) = if let Some(token) = token.clone() { + let token_data = helpers::retrieve_payment_token_data( + state, + token, + payment_method.or(payment_attempt.payment_method), + ) + .await?; + + let payment_method_info = + helpers::retrieve_payment_method_from_db_with_token_data(state, &token_data) + .await?; + + (Some(token_data), payment_method_info) + } else { + (None, None) + }; + payment_attempt.payment_method = payment_method.or(payment_attempt.payment_method); payment_attempt.browser_info = browser_info; payment_attempt.payment_method_type = @@ -548,6 +565,7 @@ impl setup_mandate, customer_acceptance, token, + token_data, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -557,6 +575,7 @@ impl }, confirm: request.confirm, payment_method_data: payment_method_data_after_card_bin_call, + payment_method_info, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 5ec8bfaf550e..cf97d9236f9f 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -120,6 +120,12 @@ impl ) .await?; + let token_data = if let Some(token) = token.clone() { + Some(helpers::retrieve_payment_token_data(state, token, payment_method).await?) + } else { + None + }; + let customer_details = helpers::get_customer_details_from_request(request); let shipping_address = helpers::create_or_find_address_for_payment_by_request( @@ -302,7 +308,7 @@ impl mandate_obj.connector_mandate_ids, ) { (Some(network_tx_id), _) => Ok(api_models::payments::MandateIds { - mandate_id: mandate_obj.mandate_id, + mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: Some( api_models::payments::MandateReferenceId::NetworkMandateId( network_tx_id, @@ -314,7 +320,7 @@ impl .change_context(errors::ApiErrorResponse::MandateNotFound) .map(|connector_id: api_models::payments::ConnectorMandateReferenceId| { api_models::payments::MandateIds { - mandate_id: mandate_obj.mandate_id, + mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: Some(api_models::payments::MandateReferenceId::ConnectorMandateId( api_models::payments::ConnectorMandateReferenceId{ connector_mandate_id: connector_id.connector_mandate_id, @@ -325,7 +331,7 @@ impl } }), (_, _) => Ok(api_models::payments::MandateIds { - mandate_id: mandate_obj.mandate_id, + mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: None, }), } @@ -390,6 +396,7 @@ impl setup_mandate, customer_acceptance, token, + token_data, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -399,6 +406,7 @@ impl }, confirm: request.confirm, payment_method_data: payment_method_data_after_card_bin_call, + payment_method_info: None, refunds: vec![], disputes: vec![], attempts: None, diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index a1416ea1908b..5ac92eef17ed 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -145,6 +145,7 @@ impl setup_mandate: None, customer_acceptance: None, token: None, + token_data: None, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -154,6 +155,7 @@ impl }, confirm: None, payment_method_data: None, + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 33e8ff26edc0..c5f6c1cbc062 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -652,7 +652,7 @@ async fn payment_response_update_tracker( mandate_id: payment_data .mandate_id .clone() - .map(|mandate| mandate.mandate_id), + .and_then(|mandate| mandate.mandate_id), connector_metadata, payment_token: None, error_code: error_status.clone(), @@ -842,7 +842,7 @@ async fn payment_response_update_tracker( .or(payment_data .mandate_id .clone() - .map(|mandate_ids| mandate_ids.mandate_id)); + .and_then(|mandate_ids| mandate_ids.mandate_id)); let m_router_data_response = router_data.response.clone(); let mandate_update_fut = tokio::spawn( async move { diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index ed3eda8832bd..014e7cbe22fb 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -169,6 +169,7 @@ impl mandate_connector: None, customer_acceptance: None, token: None, + token_data: None, setup_mandate: None, address: payments::PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), @@ -179,6 +180,7 @@ impl }, confirm: None, payment_method_data: None, + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 650fef7e1bf6..bf729283be2f 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -114,6 +114,15 @@ impl ) .await?; + let token_data = if let Some(token) = payment_attempt.payment_token.clone() { + Some( + helpers::retrieve_payment_token_data(state, token, payment_attempt.payment_method) + .await?, + ) + } else { + None + }; + payment_intent.shipping_address_id = shipping_address.clone().map(|i| i.address_id); payment_intent.billing_address_id = billing_address.clone().map(|i| i.address_id); @@ -147,6 +156,7 @@ impl setup_mandate: None, customer_acceptance: None, token: payment_attempt.payment_token.clone(), + token_data, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -157,6 +167,7 @@ impl confirm: Some(payment_attempt.confirm), payment_attempt, payment_method_data: None, + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 70f04ed364d5..3cb9b0f19bec 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -409,13 +409,14 @@ async fn get_tracker_for_sync< .mandate_id .clone() .map(|id| api_models::payments::MandateIds { - mandate_id: id, + mandate_id: Some(id), mandate_reference_id: None, }), mandate_connector: None, setup_mandate: None, customer_acceptance: None, token: None, + token_data: None, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), @@ -425,6 +426,7 @@ async fn get_tracker_for_sync< }, confirm: Some(request.force_sync), payment_method_data: None, + payment_method_info: None, force_sync: Some( request.force_sync && (helpers::check_force_psync_precondition(&payment_attempt.status) diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 81efdbabc4cc..c1e65ff190db 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -254,6 +254,12 @@ impl )?; } + let token_data = if let Some(token) = token.clone() { + Some(helpers::retrieve_payment_token_data(state, token, payment_method).await?) + } else { + None + }; + let mandate_id = request .mandate_id .as_ref() @@ -268,7 +274,7 @@ impl mandate_obj.connector_mandate_ids, ) { (Some(network_tx_id), _) => Ok(api_models::payments::MandateIds { - mandate_id: mandate_obj.mandate_id, + mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: Some( api_models::payments::MandateReferenceId::NetworkMandateId( network_tx_id, @@ -280,14 +286,14 @@ impl .change_context(errors::ApiErrorResponse::MandateNotFound) .map(|connector_id: api_models::payments::ConnectorMandateReferenceId| { api_models::payments::MandateIds { - mandate_id: mandate_obj.mandate_id, + mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: Some(api_models::payments::MandateReferenceId::ConnectorMandateId( api_models::payments::ConnectorMandateReferenceId {connector_mandate_id:connector_id.connector_mandate_id,payment_method_id:connector_id.payment_method_id, update_history: None }, )) } }), (_, _) => Ok(api_models::payments::MandateIds { - mandate_id: mandate_obj.mandate_id, + mandate_id: Some(mandate_obj.mandate_id), mandate_reference_id: None, }), } @@ -383,6 +389,7 @@ impl mandate_id, mandate_connector, token, + token_data, setup_mandate, customer_acceptance, address: PaymentAddress { @@ -395,6 +402,7 @@ impl .payment_method_data .as_ref() .map(|pmd| pmd.payment_method_data.clone()), + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index 96cbf9fb9dbf..c33fe6a29d05 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -122,6 +122,7 @@ impl setup_mandate: None, customer_acceptance: None, token: None, + token_data: None, address: PaymentAddress { billing: None, shipping: None, @@ -129,6 +130,7 @@ impl }, confirm: None, payment_method_data: None, + payment_method_info: None, force_sync: None, refunds: vec![], disputes: vec![], diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 91b6061c1112..2af73f29909a 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -377,7 +377,7 @@ where mandate_id: payment_data .mandate_id .clone() - .map(|mandate| mandate.mandate_id), + .and_then(|mandate| mandate.mandate_id), connector_metadata, payment_token: None, error_code: None, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 8ccab155c690..e01b1ed90498 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -325,7 +325,9 @@ where phone: customer .as_ref() .and_then(|cus| cus.phone.as_ref().map(|s| s.to_owned())), - mandate_id: data.mandate_id.map(|mandate_ids| mandate_ids.mandate_id), + mandate_id: data + .mandate_id + .and_then(|mandate_ids| mandate_ids.mandate_id), payment_method: data.payment_attempt.payment_method, payment_method_data: payment_method_data_response, payment_token: data.token, diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 9fd7458155a0..847c555a86d8 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -600,7 +600,7 @@ pub async fn decide_payout_connector( merchant_account, &payout_data.business_profile, key_store, - &TransactionData::<()>::Payout(payout_data), + TransactionData::<()>::Payout(payout_data), routing_data, eligible_connectors, ) diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index 31a2e05dd797..0d9c7f4f62ce 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -36,12 +36,11 @@ use crate::{core::errors, services::api as service_api, types::storage}; #[cfg(feature = "business_profile_routing")] use crate::{errors, services::api as service_api}; -#[derive(Clone)] pub enum TransactionData<'a, F> where F: Clone, { - Payment(&'a payments::PaymentData), + Payment(&'a mut payments::PaymentData), #[cfg(feature = "payouts")] Payout(&'a payouts::PayoutData), } diff --git a/crates/router/src/types/storage/payment_method.rs b/crates/router/src/types/storage/payment_method.rs index ba6e1b13200b..a8f890a17d8e 100644 --- a/crates/router/src/types/storage/payment_method.rs +++ b/crates/router/src/types/storage/payment_method.rs @@ -29,7 +29,7 @@ pub struct WalletTokenData { pub payment_method_id: String, } -#[derive(Debug, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(tag = "kind", rename_all = "snake_case")] pub enum PaymentTokenData { // The variants 'Temporary' and 'Permanent' are added for backwards compatibility From ffa74ce460fbf0babc908b5ebd979fc2db35e374 Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Fri, 8 Mar 2024 15:58:18 +0530 Subject: [PATCH 2/8] feat(router): set recurring mandate payment data for token-based mit transactions --- config/development.toml | 2 +- crates/router/src/core/payments.rs | 24 ++++++++++----- .../src/core/payments/flows/authorize_flow.rs | 4 +++ .../core/payments/flows/setup_mandate_flow.rs | 6 ++++ .../router/src/core/payments/tokenization.rs | 30 +++++++++++++++++-- .../src/types/storage/payment_method.rs | 29 ++++++++++++++++-- 6 files changed, 81 insertions(+), 14 deletions(-) diff --git a/config/development.toml b/config/development.toml index c7bfefc3435d..408c60912122 100644 --- a/config/development.toml +++ b/config/development.toml @@ -579,4 +579,4 @@ enabled = true file_storage_backend = "file_system" [unmasked_headers] -keys = "user-agent" \ No newline at end of file +keys = "user-agent" diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index e9f2bc619ae3..baac7e82ea52 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -11,9 +11,7 @@ pub mod tokenization; pub mod transformers; pub mod types; -use std::{ - collections::HashMap, fmt::Debug, marker::PhantomData, ops::Deref, time::Instant, vec::IntoIter, -}; +use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant, vec::IntoIter}; use api_models::{ self, enums, @@ -2819,7 +2817,7 @@ pub fn decide_connector_for_token_based_mit_flow( .connector_mandate_details .clone() .map(|details| { - details.parse_value::>("connector_mandate_details") + details.parse_value::("connector_mandate_details") }) .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) @@ -2831,16 +2829,16 @@ pub fn decide_connector_for_token_based_mit_flow( let mut connector_choice = None; for connector_data in connectors { if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { - if let Some(connector_mandate_id) = + if let Some(mandate_reference_record) = connector_mandate_details.get(merchant_connector_id) { - connector_choice = Some((connector_data, connector_mandate_id.clone())); + connector_choice = Some((connector_data, mandate_reference_record.clone())); break; } } } - let (chosen_connector_data, chosen_mandate_id) = connector_choice + let (chosen_connector_data, mandate_reference_record) = connector_choice .get_required_value("connector_choice") .change_context(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) .attach_printable("no eligible connector found for token-based MIT payment")?; @@ -2856,13 +2854,23 @@ pub fn decide_connector_for_token_based_mit_flow( mandate_id: None, mandate_reference_id: Some(payments_api::MandateReferenceId::ConnectorMandateId( payments_api::ConnectorMandateReferenceId { - connector_mandate_id: Some(chosen_mandate_id), + connector_mandate_id: Some( + mandate_reference_record.connector_mandate_id.clone(), + ), payment_method_id: Some(payment_method_info.payment_method_id.clone()), update_history: None, }, )), }); + payment_data.recurring_mandate_payment_data = Some(RecurringMandatePaymentData { + payment_method_type: mandate_reference_record.payment_method_type, + original_payment_authorized_amount: mandate_reference_record + .original_payment_authorized_amount, + original_payment_authorized_currency: mandate_reference_record + .original_payment_authorized_currency, + }); + Ok(api::ConnectorCallType::PreDetermined(chosen_connector_data)) } else { let first_choice = connectors diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index cc2540aa2212..80da4d231e81 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -99,6 +99,8 @@ impl Feature for types::PaymentsAu merchant_account, self.request.payment_method_type, key_store, + Some(resp.request.amount), + Some(resp.request.currency), )) .await?; Ok(mandate::mandate_procedure( @@ -130,6 +132,8 @@ impl Feature for types::PaymentsAu &merchant_account, self.request.payment_method_type, &key_store, + Some(resp.request.amount), + Some(resp.request.currency), )) .await; diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs index 71d439893361..e4a000139de0 100644 --- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs +++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs @@ -107,6 +107,8 @@ impl Feature for types::Setup merchant_account, self.request.payment_method_type, key_store, + resp.request.amount, + Some(resp.request.currency), )) .await?; mandate::mandate_procedure( @@ -241,6 +243,8 @@ impl types::SetupMandateRouterData { merchant_account, payment_method_type, key_store, + resp.request.amount, + Some(resp.request.currency), )) .await?; @@ -324,6 +328,8 @@ impl types::SetupMandateRouterData { merchant_account, self.request.payment_method_type, key_store, + resp.request.amount, + Some(resp.request.currency), )) .await?; let mandate = state diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index c085382232bd..3d2967b09714 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -39,6 +39,8 @@ pub async fn save_payment_method( merchant_account: &domain::MerchantAccount, payment_method_type: Option, key_store: &domain::MerchantKeyStore, + amount: Option, + currency: Option, ) -> RouterResult> where FData: mandate::MandateBehaviour, @@ -93,7 +95,13 @@ where .map(|future_usage| future_usage == storage_enums::FutureUsage::OffSession) .unwrap_or(false) { - add_connector_mandate_details_in_payment_method(responses, connector) + add_connector_mandate_details_in_payment_method( + responses, + payment_method_type, + amount, + currency, + connector, + ) } else { None } @@ -646,8 +654,12 @@ pub async fn add_payment_method_token( fn add_connector_mandate_details_in_payment_method( resp: types::PaymentsResponseData, + payment_method_type: Option, + authorized_amount: Option, + authorized_currency: Option, connector: &api::ConnectorData, ) -> Option { + println!("{resp:?}"); let mut mandate_details = HashMap::new(); let connector_mandate_id = match resp { @@ -663,8 +675,20 @@ fn add_connector_mandate_details_in_payment_method( _ => None, }; - if let Some(mca_id) = connector.merchant_connector_id.clone() { - mandate_details.insert(mca_id, connector_mandate_id); + if let Some((mca_id, connector_mandate_id)) = connector + .merchant_connector_id + .clone() + .zip(connector_mandate_id) + { + mandate_details.insert( + mca_id, + storage::PaymentsMandateReferenceRecord { + connector_mandate_id, + payment_method_type, + original_payment_authorized_amount: authorized_amount, + original_payment_authorized_currency: authorized_currency, + }, + ); Some(storage::PaymentsMandateReference(mandate_details)) } else { None diff --git a/crates/router/src/types/storage/payment_method.rs b/crates/router/src/types/storage/payment_method.rs index a8f890a17d8e..39b40aaff89f 100644 --- a/crates/router/src/types/storage/payment_method.rs +++ b/crates/router/src/types/storage/payment_method.rs @@ -1,4 +1,7 @@ -use std::collections::HashMap; +use std::{ + collections::HashMap, + ops::{Deref, DerefMut}, +}; use api_models::payment_methods; pub use diesel_models::payment_method::{ @@ -65,4 +68,26 @@ impl PaymentTokenData { } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct PaymentsMandateReference(pub HashMap>); +pub struct PaymentsMandateReferenceRecord { + pub connector_mandate_id: String, + pub payment_method_type: Option, + pub original_payment_authorized_amount: Option, + pub original_payment_authorized_currency: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PaymentsMandateReference(pub HashMap); + +impl Deref for PaymentsMandateReference { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for PaymentsMandateReference { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} From e57f8c7c4dd10cfad1c25f739f121a8c7e6a21bf Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Fri, 8 Mar 2024 16:49:48 +0530 Subject: [PATCH 3/8] fix: ci issues --- crates/router/src/core/payments.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index baac7e82ea52..ac10e121af5b 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2689,7 +2689,7 @@ where let profile_id = payment_data.payment_intent.profile_id.clone(); #[cfg(not(feature = "business_profile_routing"))] - let profile_id = None; + let profile_id: Option = None; connectors = routing::perform_eligibility_analysis_with_fallback( &state.clone(), @@ -3081,6 +3081,7 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed eligibility analysis and fallback")?; + #[cfg(feature = "payouts")] let first_connector_choice = connectors .first() .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) From a1d3217976bdc070f7d47deb15417294d686570d Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Fri, 8 Mar 2024 17:07:58 +0530 Subject: [PATCH 4/8] fix(router): remove invalid token data fetch from payments create get trackers operation --- .../router/src/core/payments/operations/payment_create.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index cf97d9236f9f..01fe2df75bd2 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -120,12 +120,6 @@ impl ) .await?; - let token_data = if let Some(token) = token.clone() { - Some(helpers::retrieve_payment_token_data(state, token, payment_method).await?) - } else { - None - }; - let customer_details = helpers::get_customer_details_from_request(request); let shipping_address = helpers::create_or_find_address_for_payment_by_request( @@ -396,7 +390,7 @@ impl setup_mandate, customer_acceptance, token, - token_data, + token_data: None, address: PaymentAddress { shipping: shipping_address.as_ref().map(|a| a.into()), billing: billing_address.as_ref().map(|a| a.into()), From 9ddc21f89c46873bf9e31446c466c153a33c4a91 Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Fri, 8 Mar 2024 17:24:23 +0530 Subject: [PATCH 5/8] fix: ci issues --- crates/router/src/core/payments.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index ac10e121af5b..6b61792a9461 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2743,7 +2743,7 @@ where let profile_id = payment_data.payment_intent.profile_id.clone(); #[cfg(not(feature = "business_profile_routing"))] - let profile_id = None; + let profile_id: Option = None; connectors = routing::perform_eligibility_analysis_with_fallback( &state, From 6e49349e9359cd078c67af2ee8c5b91c72020673 Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Fri, 8 Mar 2024 17:49:36 +0530 Subject: [PATCH 6/8] fix: ci issues --- crates/router/src/core/payments.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 6b61792a9461..29cea4490ba5 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2689,7 +2689,7 @@ where let profile_id = payment_data.payment_intent.profile_id.clone(); #[cfg(not(feature = "business_profile_routing"))] - let profile_id: Option = None; + let _profile_id: Option = None; connectors = routing::perform_eligibility_analysis_with_fallback( &state.clone(), @@ -2743,7 +2743,7 @@ where let profile_id = payment_data.payment_intent.profile_id.clone(); #[cfg(not(feature = "business_profile_routing"))] - let profile_id: Option = None; + let _profile_id: Option = None; connectors = routing::perform_eligibility_analysis_with_fallback( &state, From f90705396902b3cbae177bc3e80f87c26e593406 Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Fri, 8 Mar 2024 19:29:31 +0530 Subject: [PATCH 7/8] refactor(router): add payment method retrieval support for wallet tokens --- crates/router/src/core/payments/helpers.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index ea86304c6ad2..b36ed2d3f18b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1609,7 +1609,18 @@ pub async fn retrieve_payment_method_from_db_with_token_data( } } - _ => Ok(None), + storage::PaymentTokenData::WalletToken(data) => state + .store + .find_payment_method(&data.payment_method_id) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound) + .attach_printable("error retrieveing payment method from DB") + .map(Some), + + storage::PaymentTokenData::Temporary(_) + | storage::PaymentTokenData::TemporaryGeneric(_) + | storage::PaymentTokenData::Permanent(_) + | storage::PaymentTokenData::AuthBankDebit(_) => Ok(None), } } From 15cb72bc58f6aad309279d91cdfa385f5b4a9a8d Mon Sep 17 00:00:00 2001 From: shashank_attarde Date: Mon, 11 Mar 2024 12:17:29 +0530 Subject: [PATCH 8/8] refactor(router): remove redundant println --- crates/router/src/core/payments/tokenization.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 3d2967b09714..57aa37c08c8d 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -659,7 +659,6 @@ fn add_connector_mandate_details_in_payment_method( authorized_currency: Option, connector: &api::ConnectorData, ) -> Option { - println!("{resp:?}"); let mut mandate_details = HashMap::new(); let connector_mandate_id = match resp {