From 465933ba72f9a1aa8f3d5ea12a1f795999bbb17e Mon Sep 17 00:00:00 2001 From: Kashif <46213975+kashif-m@users.noreply.github.com> Date: Fri, 21 Apr 2023 02:52:04 +0530 Subject: [PATCH] feat(router): add support for filtering PaymentMethodTypes at a session (#883) Co-authored-by: Kashif --- crates/api_models/src/payments.rs | 12 +++++++ .../router/src/core/payment_methods/cards.rs | 34 ++++++++++++++++++- crates/router/src/core/payments.rs | 1 + .../payments/operations/payment_create.rs | 8 ++++- .../router/src/core/payments/transformers.rs | 17 ++++++++++ 5 files changed, 70 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index f820c3bfa4..cba73e3f3a 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -212,6 +212,10 @@ pub struct PaymentsRequest { /// Merchant connector details used to make payments. pub merchant_connector_details: Option, + /// Allowed Payment Method Types for a given PaymentIntent + #[schema(value_type = Option>)] + pub allowed_payment_method_types: Option>, + /// Business sub label for the payment pub business_sub_label: Option, } @@ -1058,6 +1062,10 @@ pub struct PaymentsResponse { /// The business_sub_label for this payment pub business_sub_label: Option, + + /// Allowed Payment Method Types for a given PaymentIntent + #[schema(value_type = Option>)] + pub allowed_payment_method_types: Option>, } #[derive(Clone, Debug, serde::Deserialize, ToSchema)] @@ -1318,6 +1326,10 @@ pub struct Metadata { pub data: pii::SecretSerdeValue, /// Payload coming in request as a metadata field pub payload: Option, + + /// Allowed payment method types for a payment intent + #[schema(value_type = Option>)] + pub allowed_payment_method_types: Option>, } #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index bace1619cd..a8f519d097 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -1056,6 +1056,26 @@ async fn filter_payment_methods( let parse_result = serde_json::from_value::(payment_method); if let Ok(payment_methods_enabled) = parse_result { let payment_method = payment_methods_enabled.payment_method; + let allowed_payment_method_types = payment_intent + .map(|payment_intent| + payment_intent + .metadata + .as_ref() + .and_then(|masked_metadata| { + let metadata = masked_metadata.peek().clone(); + let parsed_metadata: Option = + serde_json::from_value(metadata) + .map_err(|error| logger::error!(%error, "Failed to deserialize PaymentIntent metadata")) + .ok(); + parsed_metadata.and_then(|pm| { + logger::info!( + "Only given PaymentMethodTypes will be allowed {:?}", + pm.allowed_payment_method_types + ); + pm.allowed_payment_method_types + }) + })) + .and_then(|a| a); for payment_method_type_info in payment_methods_enabled .payment_method_types .unwrap_or_default() @@ -1115,6 +1135,11 @@ async fn filter_payment_methods( .map(|value| value.foreign_into()), ); + let filter6 = filter_pm_based_on_allowed_types( + allowed_payment_method_types.as_ref(), + &payment_method_object.payment_method_type, + ); + let connector = connector.clone(); let response_pm_type = ResponsePaymentMethodIntermediate::new( @@ -1123,7 +1148,7 @@ async fn filter_payment_methods( payment_method, ); - if filter && filter2 && filter3 && filter4 && filter5 { + if filter && filter2 && filter3 && filter4 && filter5 && filter6 { resp.push(response_pm_type); } } @@ -1358,6 +1383,13 @@ fn filter_amount_based(payment_method: &RequestPaymentMethodTypes, amount: Optio min_check && max_check } +fn filter_pm_based_on_allowed_types( + allowed_types: Option<&Vec>, + payment_method_type: &api_enums::PaymentMethodType, +) -> bool { + allowed_types.map_or(true, |pm| pm.contains(payment_method_type)) +} + fn filter_recurring_based( payment_method: &RequestPaymentMethodTypes, recurring_enabled: Option, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 9cf54c5316..f2a7fdc9b8 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -323,6 +323,7 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize { order_details: None, data: masking::Secret::new("{}".into()), payload: Some(req.json_payload.unwrap_or(serde_json::json!({})).into()), + allowed_payment_method_types: None, }), ..Default::default() }; diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 51a1c135a9..88ba6ffcab 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -485,7 +485,13 @@ impl PaymentCreate { let metadata = request .metadata .as_ref() - .map(Encode::::encode_to_value) + .map(|metadata| { + let transformed_metadata = api_models::payments::Metadata { + allowed_payment_method_types: request.allowed_payment_method_types.clone(), + ..metadata.clone() + }; + Encode::::encode_to_value(&transformed_metadata) + }) .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Encoding Metadata to value failed")?; diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 47fd448ebd..f38e262b8c 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -288,6 +288,19 @@ where connector_name, ) }); + let parsed_metadata: Option = payment_intent + .metadata + .clone() + .map(|metadata_value| { + metadata_value + .parse_value("metadata") + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "metadata", + }) + .attach_printable("unable to parse metadata") + }) + .transpose() + .unwrap_or_default(); services::ApplicationResponse::Json( response .set_payment_id(Some(payment_attempt.payment_id)) @@ -369,6 +382,10 @@ where .set_business_country(payment_intent.business_country) .set_business_label(payment_intent.business_label) .set_business_sub_label(payment_attempt.business_sub_label) + .set_allowed_payment_method_types( + parsed_metadata + .and_then(|metadata| metadata.allowed_payment_method_types), + ) .to_owned(), ) }