From e4a8fc4293ce56dc14a37616f6ec90ec5d16369b Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Wed, 8 May 2024 13:32:54 +0530 Subject: [PATCH 01/16] refactor frm configs --- crates/api_models/src/admin.rs | 17 --- crates/openapi/src/openapi.rs | 1 - crates/router/src/core/fraud_check.rs | 102 ++---------------- .../fraud_check/operation/fraud_check_post.rs | 12 +-- crates/router/src/core/fraud_check/types.rs | 2 - 5 files changed, 14 insertions(+), 120 deletions(-) diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index bf4eeb79fef1..01e2a61b7d4c 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -729,26 +729,9 @@ pub struct FrmPaymentMethod { ///payment methods(card, wallet, etc) that can be used in the payment #[schema(value_type = PaymentMethod,example = "card")] pub payment_method: Option, - ///payment method types(credit, debit) that can be used in the payment - pub payment_method_types: Vec, -} - -///Details of FrmPaymentMethodType are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table -#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] -#[serde(deny_unknown_fields)] -pub struct FrmPaymentMethodType { - ///payment method types(credit, debit) that can be used in the payment - #[schema(value_type = PaymentMethodType)] - pub payment_method_type: Option, - ///card networks(like visa mastercard) types that can be used in the payment - #[schema(value_type = CardNetwork)] - pub card_networks: Option>, ///frm flow type to be used...can be pre/post #[schema(value_type = FrmPreferredFlowTypes)] pub flow: api_enums::FrmPreferredFlowTypes, - ///action that the frm would take, in case fraud is detected - #[schema(value_type = FrmAction)] - pub action: api_enums::FrmAction, } /// Details of all the payment methods enabled for the connector for the given merchant account #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 7abbc3b77e42..f47f2a2554fe 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -252,7 +252,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::admin::PrimaryBusinessDetails, api_models::admin::FrmConfigs, api_models::admin::FrmPaymentMethod, - api_models::admin::FrmPaymentMethodType, api_models::admin::PaymentMethodsEnabled, api_models::admin::MerchantConnectorDetailsWrap, api_models::admin::MerchantConnectorDetails, diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index e26d5d0b4612..46aa09ac090b 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use api_models::{admin::FrmConfigs, enums as api_enums, payments::AdditionalPaymentData}; +use api_models::{admin::FrmConfigs, enums as api_enums}; use common_enums::CaptureMethod; use error_stack::ResultExt; use masking::{ExposeInterface, PeekInterface}; @@ -20,10 +20,7 @@ use super::errors::{ConnectorErrorExt, RouterResponse}; use crate::{ core::{ errors::{self, RouterResult}, - payments::{ - self, flows::ConstructFlowSpecificData, helpers::get_additional_payment_data, - operations::BoxedOperation, - }, + payments::{self, flows::ConstructFlowSpecificData, operations::BoxedOperation}, utils as core_utils, }, db::StorageInterface, @@ -193,7 +190,6 @@ where let mut is_frm_connector_enabled = false; let mut is_frm_pm_enabled = false; - let mut is_frm_pmt_enabled = false; let filtered_frm_config = frm_configs_struct .iter() .filter(|frm_config| { @@ -243,76 +239,11 @@ where }) .collect::>() .concat(); - - let additional_payment_data = match &payment_data.payment_method_data { - Some(pmd) => { - let additional_payment_data = - get_additional_payment_data(pmd, db, &profile_id).await; - Some(additional_payment_data) - } - None => payment_data - .payment_attempt - .payment_method_data - .as_ref() - .map(|pm_data| { - pm_data.clone().parse_value::( - "AdditionalPaymentData", - ) - }) - .transpose() - .unwrap_or_default(), // Making this default in case of error as we don't want to fail payment for frm errors - }; - let filtered_payment_method_types = filtered_payment_methods - .iter() - .map(|frm_pm_config| { - let filtered_pm_config_by_pmt = frm_pm_config - .payment_method_types - .iter() - .filter(|frm_pm_config_by_pmt| { - match ( - &payment_data - .clone() - .payment_attempt - .payment_method_type, - frm_pm_config_by_pmt.payment_method_type, - ) { - (Some(curr), Some(conf)) - if curr.to_string() == conf.to_string() => - { - is_frm_pmt_enabled = true; - true - } - (None, Some(conf)) => match additional_payment_data - .clone() - { - Some(AdditionalPaymentData::Card(card)) => { - let card_type = card - .card_type - .unwrap_or_else(|| "debit".to_string()); - let is_enabled = card_type.to_lowercase() - == conf.to_string().to_lowercase(); - if is_enabled { - is_frm_pmt_enabled = true; - } - is_enabled - } - _ => false, - }, - _ => false, - } - }) - .collect::>(); - filtered_pm_config_by_pmt - }) - .collect::>() - .concat(); - let is_frm_enabled = - is_frm_connector_enabled && is_frm_pm_enabled && is_frm_pmt_enabled; + let is_frm_enabled = is_frm_connector_enabled && is_frm_pm_enabled; logger::debug!( - "is_frm_connector_enabled {:?}, is_frm_pm_enabled: {:?},is_frm_pmt_enabled : {:?}, is_frm_enabled :{:?}", + "is_frm_connector_enabled {:?}, is_frm_pm_enabled: {:?}, is_frm_enabled :{:?}", is_frm_connector_enabled, is_frm_pm_enabled, - is_frm_pmt_enabled, is_frm_enabled ); // filtered_frm_config... @@ -324,17 +255,9 @@ where frm_enabled_pm: filtered_payment_methods .first() .and_then(|pm| pm.payment_method), - frm_enabled_pm_type: filtered_payment_method_types - .first() - .and_then(|pmt| pmt.payment_method_type), - frm_action: filtered_payment_method_types - // .clone() - .first() - .map(|pmt| pmt.action.clone()) - .unwrap_or(api_enums::FrmAction::ManualReview), - frm_preferred_flow_type: filtered_payment_method_types + frm_preferred_flow_type: filtered_payment_methods .first() - .map(|pmt| pmt.flow.clone()) + .map(|pm| pm.flow.clone()) .unwrap_or(api_enums::FrmPreferredFlowTypes::Pre), }; logger::debug!( @@ -495,12 +418,7 @@ where payment_data.frm_message = Some(frm_fraud_check.clone()); if matches!(frm_fraud_check.frm_status, FraudCheckStatus::Fraud) { *should_continue_transaction = false; - if matches!(frm_configs.frm_action, api_enums::FrmAction::CancelTxn) { - frm_info.suggested_action = Some(FrmSuggestion::FrmCancelTransaction); - } else if matches!(frm_configs.frm_action, api_enums::FrmAction::ManualReview) { - *should_continue_capture = false; - frm_info.suggested_action = Some(FrmSuggestion::FrmManualReview); - } + frm_info.suggested_action = Some(FrmSuggestion::FrmCancelTransaction); } logger::debug!( "frm_updated_data: {:?} {:?}", @@ -571,11 +489,7 @@ where let mut frm_suggestion = None; payment_data.frm_message = Some(frm_fraud_check.clone()); if matches!(frm_fraud_check.frm_status, FraudCheckStatus::Fraud) { - if matches!(frm_configs.frm_action, api_enums::FrmAction::CancelTxn) { - frm_info.suggested_action = Some(FrmSuggestion::FrmCancelTransaction); - } else if matches!(frm_configs.frm_action, api_enums::FrmAction::ManualReview) { - frm_info.suggested_action = Some(FrmSuggestion::FrmManualReview); - } + frm_info.suggested_action = Some(FrmSuggestion::FrmCancelTransaction); } else if matches!(frm_fraud_check.frm_status, FraudCheckStatus::ManualReview) { frm_info.suggested_action = Some(FrmSuggestion::FrmManualReview); } diff --git a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs index 49862495f3e3..5bada7e83ce7 100644 --- a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs +++ b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs @@ -26,7 +26,7 @@ use crate::{ services::{self, api}, types::{ api::{ - enums::{AttemptStatus, FrmAction, IntentStatus}, + enums::{AttemptStatus, IntentStatus}, fraud_check as frm_api, payments as payment_types, Capture, Void, }, domain, @@ -187,7 +187,7 @@ impl Domain for FraudCheckPost { req_state: ReqState, frm_data: &mut FrmData, merchant_account: &domain::MerchantAccount, - frm_configs: FrmConfigsObject, + _frm_configs: FrmConfigsObject, frm_suggestion: &mut Option, key_store: domain::MerchantKeyStore, payment_data: &mut payments::PaymentData, @@ -195,7 +195,6 @@ impl Domain for FraudCheckPost { _should_continue_capture: &mut bool, ) -> RouterResult> { if matches!(frm_data.fraud_check.frm_status, FraudCheckStatus::Fraud) - && matches!(frm_configs.frm_action, FrmAction::CancelTxn) && matches!( frm_data.fraud_check.last_step, FraudCheckLastStep::CheckoutOrSale @@ -244,9 +243,10 @@ impl Domain for FraudCheckPost { ) .await?; frm_data.fraud_check.last_step = FraudCheckLastStep::TransactionOrRecordRefund; - } else if matches!(frm_data.fraud_check.frm_status, FraudCheckStatus::Fraud) - && matches!(frm_configs.frm_action, FrmAction::ManualReview) - { + } else if matches!( + frm_data.fraud_check.frm_status, + FraudCheckStatus::ManualReview + ) { *frm_suggestion = Some(FrmSuggestion::FrmManualReview); } else if matches!(frm_data.fraud_check.frm_status, FraudCheckStatus::Legit) && matches!( diff --git a/crates/router/src/core/fraud_check/types.rs b/crates/router/src/core/fraud_check/types.rs index 5acd722077fb..9cd3a9d93ebc 100644 --- a/crates/router/src/core/fraud_check/types.rs +++ b/crates/router/src/core/fraud_check/types.rs @@ -86,9 +86,7 @@ pub struct PaymentToFrmData { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FrmConfigsObject { pub frm_enabled_pm: Option, - pub frm_enabled_pm_type: Option, pub frm_enabled_gateway: Option, - pub frm_action: api_enums::FrmAction, pub frm_preferred_flow_type: api_enums::FrmPreferredFlowTypes, } From f059940847628df60b9b411afe6bc134f7566ea8 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 8 May 2024 08:18:25 +0000 Subject: [PATCH 02/16] docs(openapi): re-generate OpenAPI specification --- openapi/openapi_spec.json | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 391a9176698e..9a05f201bd33 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -9153,43 +9153,14 @@ "description": "Details of FrmPaymentMethod are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", "required": [ "payment_method", - "payment_method_types" + "flow" ], "properties": { "payment_method": { "$ref": "#/components/schemas/PaymentMethod" }, - "payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FrmPaymentMethodType" - }, - "description": "payment method types(credit, debit) that can be used in the payment" - } - }, - "additionalProperties": false - }, - "FrmPaymentMethodType": { - "type": "object", - "description": "Details of FrmPaymentMethodType are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", - "required": [ - "payment_method_type", - "card_networks", - "flow", - "action" - ], - "properties": { - "payment_method_type": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "card_networks": { - "$ref": "#/components/schemas/CardNetwork" - }, "flow": { "$ref": "#/components/schemas/FrmPreferredFlowTypes" - }, - "action": { - "$ref": "#/components/schemas/FrmAction" } }, "additionalProperties": false From 11779d3afc2ef73240b4b273b4cab32d386527d4 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Thu, 9 May 2024 14:47:58 +0530 Subject: [PATCH 03/16] handle error message only in case of fraud payment --- crates/router/src/core/fraud_check.rs | 6 +-- .../fraud_check/operation/fraud_check_post.rs | 37 ++++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index 46aa09ac090b..ba1cd6603ef4 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -182,9 +182,9 @@ where .expose() .parse_value("FrmConfigs") .change_context(errors::ApiErrorResponse::InvalidDataFormat { - field_name: "frm_configs".to_string(), - expected_format: r#"[{ "gateway": "stripe", "payment_methods": [{ "payment_method": "card","payment_method_types": [{"payment_method_type": "credit","card_networks": ["Visa"],"flow": "pre","action": "cancel_txn"}]}]}]"#.to_string(), - }) + field_name: "frm_configs".to_string(), + expected_format: r#"[{ "gateway": "stripe", "payment_methods": [{ "payment_method": "card","flow": "post"}]}]"#.to_string(), + }) }) .collect::, _>>()?; diff --git a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs index 5bada7e83ce7..6b7a80684984 100644 --- a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs +++ b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs @@ -480,25 +480,34 @@ impl UpdateTracker for FraudCheckPost { }; if let Some(frm_suggestion) = frm_suggestion { - let (payment_attempt_status, payment_intent_status) = match frm_suggestion { - FrmSuggestion::FrmCancelTransaction => { - (AttemptStatus::Failure, IntentStatus::Failed) - } - FrmSuggestion::FrmManualReview => ( - AttemptStatus::Unresolved, - IntentStatus::RequiresMerchantAction, - ), - FrmSuggestion::FrmAuthorizeTransaction => { - (AttemptStatus::Authorized, IntentStatus::RequiresCapture) - } - }; + let (payment_attempt_status, payment_intent_status, merchant_decision, error_message) = + match frm_suggestion { + FrmSuggestion::FrmCancelTransaction => ( + AttemptStatus::Failure, + IntentStatus::Failed, + Some(MerchantDecision::Rejected.to_string()), + Some(Some(CANCEL_INITIATED.to_string())), + ), + FrmSuggestion::FrmManualReview => ( + AttemptStatus::Unresolved, + IntentStatus::RequiresMerchantAction, + None, + None, + ), + FrmSuggestion::FrmAuthorizeTransaction => ( + AttemptStatus::Authorized, + IntentStatus::RequiresCapture, + None, + None, + ), + }; payment_data.payment_attempt = db .update_payment_attempt_with_attempt_id( payment_data.payment_attempt.clone(), PaymentAttemptUpdate::RejectUpdate { status: payment_attempt_status, error_code: Some(Some(frm_data.fraud_check.frm_status.to_string())), - error_message: Some(Some(CANCEL_INITIATED.to_string())), + error_message, updated_by: frm_data.merchant_account.storage_scheme.to_string(), }, frm_data.merchant_account.storage_scheme, @@ -511,7 +520,7 @@ impl UpdateTracker for FraudCheckPost { payment_data.payment_intent.clone(), PaymentIntentUpdate::RejectUpdate { status: payment_intent_status, - merchant_decision: Some(MerchantDecision::Rejected.to_string()), + merchant_decision, updated_by: frm_data.merchant_account.storage_scheme.to_string(), }, frm_data.merchant_account.storage_scheme, From c4d7e1b7c1c85d783532c30e519d5f119a62eebe Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Fri, 10 May 2024 11:29:17 +0530 Subject: [PATCH 04/16] add check for authentication failure from frm processor --- crates/router/src/core/fraud_check.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index ba1cd6603ef4..bce2dacaf4e9 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -429,6 +429,9 @@ where } else if matches!( frm_configs.frm_preferred_flow_type, api_enums::FrmPreferredFlowTypes::Post + ) && !matches!( + frm_data.fraud_check.frm_status, + FraudCheckStatus::TransactionFailure // Incase of TransactionFailure frm status(No frm decision is taken by frm processor), if capture method is automatic we should not change it to manual. ) { *should_continue_capture = false; Some(frm_data.to_owned()) From 3c1710f90fcc6db103234aae784c64321aab33e1 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Fri, 10 May 2024 15:35:37 +0530 Subject: [PATCH 05/16] populate frm_metadata in payments response --- crates/api_models/src/payments.rs | 7 ++++++- crates/diesel_models/src/payment_intent.rs | 12 +++++++++++- crates/diesel_models/src/schema.rs | 1 + crates/hyperswitch_domain_models/src/payments.rs | 1 + .../src/payments/payment_intent.rs | 5 +++++ .../src/connector/signifyd/transformers/api.rs | 4 +++- crates/router/src/core/fraud_check/types.rs | 6 +++--- crates/router/src/core/payments.rs | 2 +- .../src/core/payments/operations/payment_confirm.rs | 4 ++++ .../src/core/payments/operations/payment_create.rs | 1 + .../src/core/payments/operations/payment_update.rs | 3 +++ crates/router/src/core/payments/transformers.rs | 1 + crates/router/src/types.rs | 2 +- crates/router/src/utils/user/sample_data.rs | 1 + crates/storage_impl/src/mock_db/payment_intent.rs | 1 + crates/storage_impl/src/payments/payment_intent.rs | 7 +++++++ .../down.sql | 2 ++ .../up.sql | 2 ++ 18 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql create mode 100644 migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 2dc578ef75ed..927878360827 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -459,7 +459,8 @@ pub struct PaymentsRequest { pub session_expiry: Option, /// additional data related to some frm connectors - pub frm_metadata: Option, + #[schema(value_type = Option, example = r#"{ "coverage_request" : "fraud", "fulfillment_method" : "delivery" }"#)] + pub frm_metadata: Option, /// Whether to perform external authentication (if applicable) #[schema(example = true)] @@ -3383,6 +3384,10 @@ pub struct PaymentsResponse { #[schema(example = "2022-09-10T10:11:12Z")] #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub updated: Option, + + /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM. + #[schema(value_type = Option, example = r#"{ "fulfillment_method" : "deliver", "coverage_request" : "fraud" }"#)] + pub frm_metadata: Option, } #[derive(Setter, Clone, Default, Debug, PartialEq, serde::Serialize, ToSchema)] diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index ee6e3960b735..db84c817a061 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -58,6 +58,7 @@ pub struct PaymentIntent { pub session_expiry: Option, pub fingerprint_id: Option, pub request_external_three_ds_authentication: Option, + pub frm_metadata: Option, } #[derive( @@ -111,6 +112,7 @@ pub struct PaymentIntentNew { pub session_expiry: Option, pub fingerprint_id: Option, pub request_external_three_ds_authentication: Option, + pub frm_metadata: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -167,6 +169,7 @@ pub enum PaymentIntentUpdate { session_expiry: Option, fingerprint_id: Option, request_external_three_ds_authentication: Option, + frm_metadata: Option, }, PaymentAttemptAndAttemptCountUpdate { active_attempt_id: String, @@ -236,6 +239,7 @@ pub struct PaymentIntentUpdateInternal { pub session_expiry: Option, pub fingerprint_id: Option, pub request_external_three_ds_authentication: Option, + pub frm_metadata: Option, } impl PaymentIntentUpdate { @@ -271,6 +275,7 @@ impl PaymentIntentUpdate { session_expiry, fingerprint_id, request_external_three_ds_authentication, + frm_metadata, } = self.into(); PaymentIntent { amount: amount.unwrap_or(source.amount), @@ -308,6 +313,8 @@ impl PaymentIntentUpdate { session_expiry: session_expiry.or(source.session_expiry), request_external_three_ds_authentication: request_external_three_ds_authentication .or(source.request_external_three_ds_authentication), + + frm_metadata: frm_metadata.or(source.frm_metadata), ..source } } @@ -337,6 +344,7 @@ impl From for PaymentIntentUpdateInternal { session_expiry, fingerprint_id, request_external_three_ds_authentication, + frm_metadata, } => Self { amount: Some(amount), currency: Some(currency), @@ -359,6 +367,7 @@ impl From for PaymentIntentUpdateInternal { session_expiry, fingerprint_id, request_external_three_ds_authentication, + frm_metadata, ..Default::default() }, PaymentIntentUpdate::MetadataUpdate { @@ -542,7 +551,8 @@ mod tests { "incremental_authorization_allowed": null, "authorization_count": null, "session_expiry": null, - "fingerprint_id": null + "fingerprint_id": null, + "frm_metada": null }"#; let deserialized_payment_intent = serde_json::from_str::(serialized_payment_intent); diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index a81c240e8b0f..340e79dcf942 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -845,6 +845,7 @@ diesel::table! { #[max_length = 64] fingerprint_id -> Nullable, request_external_three_ds_authentication -> Nullable, + frm_metadata -> Nullable, } } diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 8a7dfad5fcbe..cea948d4f999 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -60,4 +60,5 @@ pub struct PaymentIntent { #[serde(with = "common_utils::custom_serde::iso8601::option")] pub session_expiry: Option, pub request_external_three_ds_authentication: Option, + pub frm_metadata: Option, } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index a5e631b5ac33..84dc56403c6f 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -81,6 +81,7 @@ pub struct PaymentIntentNew { pub description: Option, pub return_url: Option, pub metadata: Option, + pub frm_metadata: Option, pub connector_id: Option, pub shipping_address_id: Option, pub billing_address_id: Option, @@ -164,6 +165,7 @@ pub enum PaymentIntentUpdate { statement_descriptor_suffix: Option, order_details: Option>, metadata: Option, + frm_metadata: Option, payment_confirm_source: Option, updated_by: String, fingerprint_id: Option, @@ -237,6 +239,7 @@ pub struct PaymentIntentUpdateInternal { pub fingerprint_id: Option, pub session_expiry: Option, pub request_external_three_ds_authentication: Option, + pub frm_metadata: Option, } impl From for PaymentIntentUpdateInternal { @@ -263,6 +266,7 @@ impl From for PaymentIntentUpdateInternal { fingerprint_id, session_expiry, request_external_three_ds_authentication, + frm_metadata, } => Self { amount: Some(amount), currency: Some(currency), @@ -285,6 +289,7 @@ impl From for PaymentIntentUpdateInternal { fingerprint_id, session_expiry, request_external_three_ds_authentication, + frm_metadata, ..Default::default() }, PaymentIntentUpdate::MetadataUpdate { diff --git a/crates/router/src/connector/signifyd/transformers/api.rs b/crates/router/src/connector/signifyd/transformers/api.rs index b56c7f7011ef..2f742b71570a 100644 --- a/crates/router/src/connector/signifyd/transformers/api.rs +++ b/crates/router/src/connector/signifyd/transformers/api.rs @@ -162,7 +162,9 @@ impl TryFrom<&frm_types::FrmSaleRouterData> for SignifydPaymentsSaleRequest { field_name: "frm_metadata", })? .parse_value("Signifyd Frm Metadata") - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + .change_context(errors::ConnectorError::InvalidDataFormat { + field_name: "frm_metadata", + })?; let ship_address = item.get_shipping_address()?; let billing_address = item.get_billing()?; let street_addr = ship_address.get_line1()?; diff --git a/crates/router/src/core/fraud_check/types.rs b/crates/router/src/core/fraud_check/types.rs index 9cd3a9d93ebc..d2a9b9204573 100644 --- a/crates/router/src/core/fraud_check/types.rs +++ b/crates/router/src/core/fraud_check/types.rs @@ -5,7 +5,7 @@ use api_models::{ refunds::RefundResponse, }; use common_enums::FrmSuggestion; -use common_utils::pii::Email; +use common_utils::pii::{Email, SecretSerdeValue}; use hyperswitch_domain_models::payments::{payment_attempt::PaymentAttempt, PaymentIntent}; use masking::Serialize; use serde::Deserialize; @@ -56,7 +56,7 @@ pub struct FrmData { pub connector_details: ConnectorDetailsCore, pub order_details: Option>, pub refund: Option, - pub frm_metadata: Option, + pub frm_metadata: Option, } #[derive(Debug)] @@ -80,7 +80,7 @@ pub struct PaymentToFrmData { pub address: PaymentAddress, pub connector_details: ConnectorDetailsCore, pub order_details: Option>, - pub frm_metadata: Option, + pub frm_metadata: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 578b8d803021..da66efe46e5d 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2541,7 +2541,7 @@ where pub incremental_authorization_details: Option, pub authorizations: Vec, pub authentication: Option, - pub frm_metadata: Option, + pub frm_metadata: Option, pub recurring_details: Option, pub poll_config: Option, } diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index e77ffa611e04..64c2154f624f 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -396,6 +396,7 @@ impl .attach_printable("Error converting feature_metadata to Value")? .or(payment_intent.feature_metadata); payment_intent.metadata = request.metadata.clone().or(payment_intent.metadata); + payment_intent.frm_metadata = request.frm_metadata.clone().or(payment_intent.frm_metadata); payment_intent.request_incremental_authorization = request .request_incremental_authorization .map(|request_incremental_authorization| { @@ -1072,6 +1073,7 @@ impl .take(); let order_details = payment_data.payment_intent.order_details.clone(); let metadata = payment_data.payment_intent.metadata.clone(); + let frm_metadata = payment_data.payment_intent.frm_metadata.clone(); let authorized_amount = payment_data .surcharge_details .as_ref() @@ -1165,6 +1167,7 @@ impl let m_statement_descriptor_suffix = statement_descriptor_suffix.clone(); let m_order_details = order_details.clone(); let m_metadata = metadata.clone(); + let m_frm_metadata = frm_metadata.clone(); let m_db = state.clone().store; let m_storage_scheme = storage_scheme.to_string(); let session_expiry = m_payment_data_payment_intent.session_expiry; @@ -1194,6 +1197,7 @@ impl fingerprint_id: None, session_expiry, request_external_three_ds_authentication: None, + frm_metadata: m_frm_metadata, }, storage_scheme, ) diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index e90617f5382f..6da36332bb16 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -1047,6 +1047,7 @@ impl PaymentCreate { session_expiry: Some(session_expiry), request_external_three_ds_authentication: request .request_external_three_ds_authentication, + frm_metadata: request.frm_metadata.clone(), }) } diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index c7479672c754..4b342f4933a0 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -255,6 +255,7 @@ impl .attach_printable("Error converting feature_metadata to Value")? .or(payment_intent.feature_metadata); payment_intent.metadata = request.metadata.clone().or(payment_intent.metadata); + payment_intent.frm_metadata = request.frm_metadata.clone().or(payment_intent.frm_metadata); Self::populate_payment_intent_with_request(&mut payment_intent, request); let token = token.or_else(|| payment_attempt.payment_token.clone()); @@ -693,6 +694,7 @@ impl .clone(); let order_details = payment_data.payment_intent.order_details.clone(); let metadata = payment_data.payment_intent.metadata.clone(); + let frm_metadata = payment_data.payment_intent.frm_metadata.clone(); let session_expiry = payment_data.payment_intent.session_expiry; payment_data.payment_intent = state @@ -722,6 +724,7 @@ impl request_external_three_ds_authentication: payment_data .payment_intent .request_external_three_ds_authentication, + frm_metadata, }, storage_scheme, ) diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 2b7ba070d2c4..455fbb04b792 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -776,6 +776,7 @@ where .set_customer(customer_details_response.clone()) .set_browser_info(payment_attempt.browser_info) .set_updated(Some(payment_intent.modified_at)) + .set_frm_metadata(payment_intent.frm_metadata) .to_owned(), headers, )) diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index bffa3eaf8f8a..10d5eac9ca55 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -320,7 +320,7 @@ pub struct RouterData { /// Contains apple pay flow type simplified or manual pub apple_pay_flow: Option, - pub frm_metadata: Option, + pub frm_metadata: Option, pub dispute_id: Option, pub refund_id: Option, diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index 2216cb105548..8cf5caf5f1eb 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -218,6 +218,7 @@ pub async fn generate_sample_data( fingerprint_id: None, session_expiry: Some(session_expiry), request_external_three_ds_authentication: None, + frm_metadata: Default::default(), }; let payment_attempt = PaymentAttemptBatchNew { attempt_id: attempt_id.clone(), diff --git a/crates/storage_impl/src/mock_db/payment_intent.rs b/crates/storage_impl/src/mock_db/payment_intent.rs index 1dfb7ac9d91e..8ad010be1330 100644 --- a/crates/storage_impl/src/mock_db/payment_intent.rs +++ b/crates/storage_impl/src/mock_db/payment_intent.rs @@ -108,6 +108,7 @@ impl PaymentIntentInterface for MockDb { fingerprint_id: new.fingerprint_id, session_expiry: new.session_expiry, request_external_three_ds_authentication: new.request_external_three_ds_authentication, + frm_metadata: new.frm_metadata, }; payment_intents.push(payment_intent.clone()); Ok(payment_intent) diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index 2cbcbaaf01e6..c7592e48211c 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -83,6 +83,7 @@ impl PaymentIntentInterface for KVRouterStore { description: new.description.clone(), return_url: new.return_url.clone(), metadata: new.metadata.clone(), + frm_metadata: new.frm_metadata.clone(), connector_id: new.connector_id.clone(), shipping_address_id: new.shipping_address_id.clone(), billing_address_id: new.billing_address_id.clone(), @@ -806,6 +807,7 @@ impl DataModelExt for PaymentIntentNew { description: self.description, return_url: self.return_url, metadata: self.metadata, + frm_metadata: self.frm_metadata, connector_id: self.connector_id, shipping_address_id: self.shipping_address_id, billing_address_id: self.billing_address_id, @@ -852,6 +854,7 @@ impl DataModelExt for PaymentIntentNew { description: storage_model.description, return_url: storage_model.return_url, metadata: storage_model.metadata, + frm_metadata: storage_model.frm_metadata, connector_id: storage_model.connector_id, shipping_address_id: storage_model.shipping_address_id, billing_address_id: storage_model.billing_address_id, @@ -935,6 +938,7 @@ impl DataModelExt for PaymentIntent { fingerprint_id: self.fingerprint_id, session_expiry: self.session_expiry, request_external_three_ds_authentication: self.request_external_three_ds_authentication, + frm_metadata: self.frm_metadata, } } @@ -983,6 +987,7 @@ impl DataModelExt for PaymentIntent { session_expiry: storage_model.session_expiry, request_external_three_ds_authentication: storage_model .request_external_three_ds_authentication, + frm_metadata: storage_model.frm_metadata, } } } @@ -1070,6 +1075,7 @@ impl DataModelExt for PaymentIntentUpdate { fingerprint_id, session_expiry, request_external_three_ds_authentication, + frm_metadata, } => DieselPaymentIntentUpdate::Update { amount, currency, @@ -1091,6 +1097,7 @@ impl DataModelExt for PaymentIntentUpdate { fingerprint_id, session_expiry, request_external_three_ds_authentication, + frm_metadata, }, Self::PaymentAttemptAndAttemptCountUpdate { active_attempt_id, diff --git a/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql new file mode 100644 index 000000000000..9a42f82d7466 --- /dev/null +++ b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE payment_intent DROP COLUMN frm_metadata; \ No newline at end of file diff --git a/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql new file mode 100644 index 000000000000..852357873bb6 --- /dev/null +++ b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE payment_intent ADD COLUMN frm_metadata JSONB DEFAULT NULL; \ No newline at end of file From 219170dfe4bc13c9995926ae054f6677367fb2d6 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 10:08:07 +0000 Subject: [PATCH 06/16] docs(openapi): re-generate OpenAPI specification --- openapi/openapi_spec.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 5073d4949539..44a81d01e297 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -13673,6 +13673,7 @@ "minimum": 0 }, "frm_metadata": { + "type": "object", "description": "additional data related to some frm connectors", "nullable": true }, @@ -14073,6 +14074,7 @@ "minimum": 0 }, "frm_metadata": { + "type": "object", "description": "additional data related to some frm connectors", "nullable": true }, @@ -14575,6 +14577,7 @@ "minimum": 0 }, "frm_metadata": { + "type": "object", "description": "additional data related to some frm connectors", "nullable": true }, @@ -15112,6 +15115,11 @@ "description": "Date time at which payment was updated", "example": "2022-09-10T10:11:12Z", "nullable": true + }, + "frm_metadata": { + "type": "object", + "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM.", + "nullable": true } } }, @@ -15607,6 +15615,7 @@ "minimum": 0 }, "frm_metadata": { + "type": "object", "description": "additional data related to some frm connectors", "nullable": true }, From 86c45a85c852e2df0c4346c2c0513ec6c36933f9 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Fri, 10 May 2024 16:48:48 +0530 Subject: [PATCH 07/16] remove frm_metadata from payment_data --- crates/router/src/core/fraud_check.rs | 4 ++-- crates/router/src/core/payments.rs | 1 - crates/router/src/core/payments/helpers.rs | 3 +++ crates/router/src/core/payments/operations/payment_approve.rs | 1 - crates/router/src/core/payments/operations/payment_cancel.rs | 1 - crates/router/src/core/payments/operations/payment_capture.rs | 1 - .../core/payments/operations/payment_complete_authorize.rs | 1 - crates/router/src/core/payments/operations/payment_confirm.rs | 1 - crates/router/src/core/payments/operations/payment_create.rs | 1 - crates/router/src/core/payments/operations/payment_reject.rs | 1 - crates/router/src/core/payments/operations/payment_session.rs | 1 - crates/router/src/core/payments/operations/payment_start.rs | 1 - crates/router/src/core/payments/operations/payment_status.rs | 1 - crates/router/src/core/payments/operations/payment_update.rs | 1 - .../payments/operations/payments_incremental_authorization.rs | 1 - 15 files changed, 5 insertions(+), 15 deletions(-) diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index bce2dacaf4e9..2f869b86ced5 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -334,13 +334,13 @@ where let payment_to_frm_data = PaymentToFrmData { amount: payment_data.amount, - payment_intent: payment_data.payment_intent, + payment_intent: payment_data.payment_intent.clone(), payment_attempt: payment_data.payment_attempt, merchant_account: merchant_account.to_owned(), address: payment_data.address.clone(), connector_details: frm_connector_details.clone(), order_details, - frm_metadata: payment_data.frm_metadata.clone(), + frm_metadata: payment_data.payment_intent.frm_metadata, }; let fraud_check_operation: operation::BoxedFraudCheckOperation = diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index da66efe46e5d..a709535af952 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2541,7 +2541,6 @@ where pub incremental_authorization_details: Option, pub authorizations: Vec, pub authentication: Option, - pub frm_metadata: Option, pub recurring_details: Option, pub poll_config: Option, } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index cd61de6a9336..9ac0c31cbe4b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2947,6 +2947,7 @@ mod tests { .saturating_add(time::Duration::seconds(consts::DEFAULT_SESSION_EXPIRY)), ), request_external_three_ds_authentication: None, + frm_metadata: None, }; let req_cs = Some("1".to_string()); assert!(authenticate_client_secret(req_cs.as_ref(), &payment_intent).is_ok()); @@ -3005,6 +3006,7 @@ mod tests { .saturating_add(time::Duration::seconds(consts::DEFAULT_SESSION_EXPIRY)), ), request_external_three_ds_authentication: None, + frm_metadata: None, }; let req_cs = Some("1".to_string()); assert!(authenticate_client_secret(req_cs.as_ref(), &payment_intent,).is_err()) @@ -3062,6 +3064,7 @@ mod tests { .saturating_add(time::Duration::seconds(consts::DEFAULT_SESSION_EXPIRY)), ), request_external_three_ds_authentication: None, + frm_metadata: None, }; let req_cs = Some("1".to_string()); assert!(authenticate_client_secret(req_cs.as_ref(), &payment_intent).is_err()) diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index bc60d8a35815..e8a3cabcb04c 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -173,7 +173,6 @@ impl payment_link_data: None, incremental_authorization_details: None, authorizations: vec![], - frm_metadata: None, authentication: None, recurring_details: None, poll_config: None, diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index 2d05fa215207..a1f790ada73c 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -188,7 +188,6 @@ impl payment_link_data: None, incremental_authorization_details: None, authorizations: vec![], - frm_metadata: None, authentication: None, recurring_details: None, poll_config: None, diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index 71549a17c2a8..188c49b86b00 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -229,7 +229,6 @@ impl payment_link_data: None, incremental_authorization_details: None, authorizations: vec![], - frm_metadata: None, authentication: None, recurring_details: None, poll_config: 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 f1cb0fa92ef4..ee4ba50cd404 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -306,7 +306,6 @@ impl incremental_authorization_details: None, authorizations: vec![], authentication: None, - frm_metadata: None, recurring_details, poll_config: None, }; diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 64c2154f624f..56d4b9d9d8b0 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -636,7 +636,6 @@ impl payment_link_data: None, incremental_authorization_details: None, authorizations: vec![], - frm_metadata: request.frm_metadata.clone(), authentication: None, recurring_details, poll_config: None, diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 6da36332bb16..ee094ed2c56b 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -449,7 +449,6 @@ impl incremental_authorization_details: None, authorizations: vec![], authentication: None, - frm_metadata: request.frm_metadata.clone(), recurring_details, poll_config: None, }; diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index 8ba627dc560d..8fd31df12ead 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -173,7 +173,6 @@ impl incremental_authorization_details: None, authorizations: vec![], authentication: None, - frm_metadata: None, recurring_details: None, poll_config: None, }; diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 485e25c2c9c5..e752c683c99d 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -198,7 +198,6 @@ impl incremental_authorization_details: None, authorizations: vec![], authentication: None, - frm_metadata: None, recurring_details: None, poll_config: None, }; diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 01ab85863540..52d729e5045e 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -185,7 +185,6 @@ impl incremental_authorization_details: None, authorizations: vec![], authentication: None, - frm_metadata: None, recurring_details: None, poll_config: None, }; diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 85e7fa2bf515..ec761d07b694 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -489,7 +489,6 @@ async fn get_tracker_for_sync< incremental_authorization_details: None, authorizations, authentication, - frm_metadata: None, recurring_details: None, poll_config: None, }; diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 4b342f4933a0..c8d1156eb097 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -453,7 +453,6 @@ impl incremental_authorization_details: None, authorizations: vec![], authentication: None, - frm_metadata: request.frm_metadata.clone(), recurring_details, poll_config: None, }; 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 c28e6b35d507..ccbbe9c12aeb 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -153,7 +153,6 @@ impl }), authorizations: vec![], authentication: None, - frm_metadata: None, recurring_details: None, poll_config: None, }; From e4d12b6e11acc24b8c9a357080f15c5912338192 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Fri, 10 May 2024 17:21:26 +0530 Subject: [PATCH 08/16] spell check fix --- crates/diesel_models/src/payment_intent.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index db84c817a061..d65fa6868b98 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -552,7 +552,7 @@ mod tests { "authorization_count": null, "session_expiry": null, "fingerprint_id": null, - "frm_metada": null + "frm_metadata": null }"#; let deserialized_payment_intent = serde_json::from_str::(serialized_payment_intent); From bc88654af60a3a184e55158b71c98af83c71cb17 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Thu, 16 May 2024 17:14:29 +0530 Subject: [PATCH 09/16] provide backward compatibility --- crates/api_models/src/admin.rs | 21 +++++++++++++++++++++ crates/router/src/core/fraud_check.rs | 13 +++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 7a73073189ac..d62edec6418e 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -729,9 +729,30 @@ pub struct FrmPaymentMethod { ///payment methods(card, wallet, etc) that can be used in the payment #[schema(value_type = PaymentMethod,example = "card")] pub payment_method: Option, + ///payment method types(credit, debit) that can be used in the payment + ///This field is deprecated, It is not removed to provide backward compatibility. + pub payment_method_types: Option>, + ///frm flow type to be used...can be pre/post + #[schema(value_type = FrmPreferredFlowTypes)] + pub flow: Option, +} + +///Details of FrmPaymentMethodType are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(deny_unknown_fields)] +pub struct FrmPaymentMethodType { + ///payment method types(credit, debit) that can be used in the payment + #[schema(value_type = PaymentMethodType)] + pub payment_method_type: Option, + ///card networks(like visa mastercard) types that can be used in the payment + #[schema(value_type = CardNetwork)] + pub card_networks: Option>, ///frm flow type to be used...can be pre/post #[schema(value_type = FrmPreferredFlowTypes)] pub flow: api_enums::FrmPreferredFlowTypes, + ///action that the frm would take, in case fraud is detected + #[schema(value_type = FrmAction)] + pub action: api_enums::FrmAction, } /// Details of all the payment methods enabled for the connector for the given merchant account #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index 65c7aa58ad47..36f01540e680 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -255,10 +255,19 @@ where frm_enabled_pm: filtered_payment_methods .first() .and_then(|pm| pm.payment_method), + // flow type should be consumed from payment_method.flow. To provide backward compatibility if we don't find it, we consume it from payment_method.payment_method_types[0].flow_type . frm_preferred_flow_type: filtered_payment_methods .first() - .map(|pm| pm.flow.clone()) - .unwrap_or(api_enums::FrmPreferredFlowTypes::Pre), + .and_then(|pm| pm.flow.clone()) + .or(filtered_payment_methods.first().and_then(|pm| { + pm.payment_method_types.as_ref().and_then(|pmt| { + pmt.first().map(|pmts| pmts.flow.clone()) + }) + })) + .ok_or(errors::ApiErrorResponse::InvalidDataFormat { + field_name: "frm_configs".to_string(), + expected_format: r#"[{ "gateway": "stripe", "payment_methods": [{ "payment_method": "card","flow": "post"}]}]"#.to_string(), + })?, }; logger::debug!( "frm_routing_configs: {:?} {:?} {:?} {:?}", From b51c5a4e2a8f94debaee6f8ff355fa8eede2baef Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Thu, 16 May 2024 17:21:43 +0530 Subject: [PATCH 10/16] use to_owned instead of clone --- crates/router/src/core/fraud_check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index 36f01540e680..d68a0ebc6583 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -343,7 +343,7 @@ where let payment_to_frm_data = PaymentToFrmData { amount: payment_data.amount, - payment_intent: payment_data.payment_intent.clone(), + payment_intent: payment_data.payment_intent.to_owned(), payment_attempt: payment_data.payment_attempt, merchant_account: merchant_account.to_owned(), address: payment_data.address.clone(), From 669e30a8e1a7beadf1ed59524757c4f2ea3ec3b4 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Thu, 16 May 2024 18:16:10 +0530 Subject: [PATCH 11/16] provide comments --- crates/api_models/src/admin.rs | 2 +- crates/router/src/core/fraud_check.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index d62edec6418e..15fb24fd4baf 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -730,7 +730,7 @@ pub struct FrmPaymentMethod { #[schema(value_type = PaymentMethod,example = "card")] pub payment_method: Option, ///payment method types(credit, debit) that can be used in the payment - ///This field is deprecated, It is not removed to provide backward compatibility. + ///This field is deprecated. It has not been removed to provide backward compatibility. pub payment_method_types: Option>, ///frm flow type to be used...can be pre/post #[schema(value_type = FrmPreferredFlowTypes)] diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index d68a0ebc6583..b5427d489c22 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -255,7 +255,7 @@ where frm_enabled_pm: filtered_payment_methods .first() .and_then(|pm| pm.payment_method), - // flow type should be consumed from payment_method.flow. To provide backward compatibility if we don't find it, we consume it from payment_method.payment_method_types[0].flow_type . + // flow type should be consumed from payment_method.flow. To provide backward compatibility, if we don't find it there, we consume it from payment_method.payment_method_types[0].flow_type. frm_preferred_flow_type: filtered_payment_methods .first() .and_then(|pm| pm.flow.clone()) From ab278a4927487ddcd92414d7bf8497543a7d0a5d Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Thu, 16 May 2024 18:28:42 +0530 Subject: [PATCH 12/16] add openapi_spec --- openapi/openapi_spec.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index fdb855db9870..b9449b7e7175 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -9311,6 +9311,14 @@ "payment_method": { "$ref": "#/components/schemas/PaymentMethod" }, + "payment_method_types": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FrmPaymentMethodType" + }, + "description": "payment method types(credit, debit) that can be used in the payment\nThis field is deprecated. It has not been removed to provide backward compatibility.", + "nullable": true + }, "flow": { "$ref": "#/components/schemas/FrmPreferredFlowTypes" } From 036ce1eafa7770472fb37582c980acb0ebb49a0e Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Thu, 16 May 2024 18:39:27 +0530 Subject: [PATCH 13/16] add open api spec --- crates/api_models/src/admin.rs | 4 ++-- openapi/openapi_spec.json | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 15fb24fd4baf..2cbe3682380a 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -729,8 +729,8 @@ pub struct FrmPaymentMethod { ///payment methods(card, wallet, etc) that can be used in the payment #[schema(value_type = PaymentMethod,example = "card")] pub payment_method: Option, - ///payment method types(credit, debit) that can be used in the payment - ///This field is deprecated. It has not been removed to provide backward compatibility. + ///payment method types(credit, debit) that can be used in the payment. This field is deprecated. It has not been removed to provide backward compatibility. + #[schema(value_type = FrmPaymentMethodType)] pub payment_method_types: Option>, ///frm flow type to be used...can be pre/post #[schema(value_type = FrmPreferredFlowTypes)] diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index b9449b7e7175..8da50ad3b01e 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -9305,6 +9305,7 @@ "description": "Details of FrmPaymentMethod are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", "required": [ "payment_method", + "payment_method_types", "flow" ], "properties": { @@ -9312,12 +9313,7 @@ "$ref": "#/components/schemas/PaymentMethod" }, "payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FrmPaymentMethodType" - }, - "description": "payment method types(credit, debit) that can be used in the payment\nThis field is deprecated. It has not been removed to provide backward compatibility.", - "nullable": true + "$ref": "#/components/schemas/FrmPaymentMethodType" }, "flow": { "$ref": "#/components/schemas/FrmPreferredFlowTypes" From cb02c1b66950a7deff8041959283d8c3a0208b6c Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Thu, 16 May 2024 18:47:36 +0530 Subject: [PATCH 14/16] add openapi_spec --- crates/api_models/src/admin.rs | 1 - crates/openapi/src/openapi.rs | 1 + openapi/openapi_spec.json | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 2cbe3682380a..83aa46388811 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -730,7 +730,6 @@ pub struct FrmPaymentMethod { #[schema(value_type = PaymentMethod,example = "card")] pub payment_method: Option, ///payment method types(credit, debit) that can be used in the payment. This field is deprecated. It has not been removed to provide backward compatibility. - #[schema(value_type = FrmPaymentMethodType)] pub payment_method_types: Option>, ///frm flow type to be used...can be pre/post #[schema(value_type = FrmPreferredFlowTypes)] diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 4b3f00b26e8a..5f5597387b1e 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -252,6 +252,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::admin::PrimaryBusinessDetails, api_models::admin::FrmConfigs, api_models::admin::FrmPaymentMethod, + api_models::admin::FrmPaymentMethodType, api_models::admin::PaymentMethodsEnabled, api_models::admin::MerchantConnectorDetailsWrap, api_models::admin::MerchantConnectorDetails, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 8da50ad3b01e..44eea1069623 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -9305,7 +9305,6 @@ "description": "Details of FrmPaymentMethod are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", "required": [ "payment_method", - "payment_method_types", "flow" ], "properties": { @@ -9313,10 +9312,40 @@ "$ref": "#/components/schemas/PaymentMethod" }, "payment_method_types": { - "$ref": "#/components/schemas/FrmPaymentMethodType" + "type": "array", + "items": { + "$ref": "#/components/schemas/FrmPaymentMethodType" + }, + "description": "payment method types(credit, debit) that can be used in the payment. This field is deprecated. It has not been removed to provide backward compatibility.", + "nullable": true + }, + "flow": { + "$ref": "#/components/schemas/FrmPreferredFlowTypes" + } + }, + "additionalProperties": false + }, + "FrmPaymentMethodType": { + "type": "object", + "description": "Details of FrmPaymentMethodType are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", + "required": [ + "payment_method_type", + "card_networks", + "flow", + "action" + ], + "properties": { + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethodType" + }, + "card_networks": { + "$ref": "#/components/schemas/CardNetwork" }, "flow": { "$ref": "#/components/schemas/FrmPreferredFlowTypes" + }, + "action": { + "$ref": "#/components/schemas/FrmAction" } }, "additionalProperties": false From f073443b129566ce0941f8e0c0d8775f325f9e96 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Fri, 17 May 2024 09:51:03 +0530 Subject: [PATCH 15/16] resolve comments --- crates/api_models/src/admin.rs | 6 +++--- .../down.sql | 2 +- .../up.sql | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 83aa46388811..2e288140a9f2 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -731,8 +731,8 @@ pub struct FrmPaymentMethod { pub payment_method: Option, ///payment method types(credit, debit) that can be used in the payment. This field is deprecated. It has not been removed to provide backward compatibility. pub payment_method_types: Option>, - ///frm flow type to be used...can be pre/post - #[schema(value_type = FrmPreferredFlowTypes)] + ///frm flow type to be used, can be pre/post + #[schema(value_type = Option)] pub flow: Option, } @@ -746,7 +746,7 @@ pub struct FrmPaymentMethodType { ///card networks(like visa mastercard) types that can be used in the payment #[schema(value_type = CardNetwork)] pub card_networks: Option>, - ///frm flow type to be used...can be pre/post + ///frm flow type to be used, can be pre/post #[schema(value_type = FrmPreferredFlowTypes)] pub flow: api_enums::FrmPreferredFlowTypes, ///action that the frm would take, in case fraud is detected diff --git a/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql index 9a42f82d7466..17c9260fe30e 100644 --- a/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql +++ b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/down.sql @@ -1,2 +1,2 @@ -- This file should undo anything in `up.sql` -ALTER TABLE payment_intent DROP COLUMN frm_metadata; \ No newline at end of file +ALTER TABLE payment_intent DROP COLUMN IF EXISTS frm_metadata; \ No newline at end of file diff --git a/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql index 852357873bb6..6918adb82a8c 100644 --- a/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql +++ b/migrations/2024-05-10-074332_add_frm_metadata_to_payment_intent/up.sql @@ -1,2 +1,2 @@ -- Your SQL goes here -ALTER TABLE payment_intent ADD COLUMN frm_metadata JSONB DEFAULT NULL; \ No newline at end of file +ALTER TABLE payment_intent ADD COLUMN IF NOT EXISTS frm_metadata JSONB DEFAULT NULL; \ No newline at end of file From 712ec21e4170be41dbd67bd447f2b3ab08cf8d68 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 04:23:21 +0000 Subject: [PATCH 16/16] docs(openapi): re-generate OpenAPI specification --- openapi/openapi_spec.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 44eea1069623..631d61592d5d 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -9304,8 +9304,7 @@ "type": "object", "description": "Details of FrmPaymentMethod are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", "required": [ - "payment_method", - "flow" + "payment_method" ], "properties": { "payment_method": { @@ -9320,7 +9319,12 @@ "nullable": true }, "flow": { - "$ref": "#/components/schemas/FrmPreferredFlowTypes" + "allOf": [ + { + "$ref": "#/components/schemas/FrmPreferredFlowTypes" + } + ], + "nullable": true } }, "additionalProperties": false