refactor(FRM): refactor frm configs (#4581)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
chikke srujan
2024-05-17 15:53:13 +05:30
committed by GitHub
parent a62f69d447
commit 853f3b4854
32 changed files with 137 additions and 148 deletions

View File

@@ -729,8 +729,11 @@ 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<common_enums::PaymentMethod>,
///payment method types(credit, debit) that can be used in the payment
pub payment_method_types: Vec<FrmPaymentMethodType>,
///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<Vec<FrmPaymentMethodType>>,
///frm flow type to be used, can be pre/post
#[schema(value_type = Option<FrmPreferredFlowTypes>)]
pub flow: Option<api_enums::FrmPreferredFlowTypes>,
}
///Details of FrmPaymentMethodType are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table
@@ -743,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<Vec<common_enums::CardNetwork>>,
///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

View File

@@ -464,7 +464,8 @@ pub struct PaymentsRequest {
pub session_expiry: Option<u32>,
/// additional data related to some frm connectors
pub frm_metadata: Option<serde_json::Value>,
#[schema(value_type = Option<Object>, example = r#"{ "coverage_request" : "fraud", "fulfillment_method" : "delivery" }"#)]
pub frm_metadata: Option<pii::SecretSerdeValue>,
/// Whether to perform external authentication (if applicable)
#[schema(example = true)]
@@ -3410,6 +3411,10 @@ pub struct PaymentsResponse {
#[schema(example = "2022-09-10T10:11:12Z")]
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub updated: Option<PrimitiveDateTime>,
/// 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<Object>, example = r#"{ "fulfillment_method" : "deliver", "coverage_request" : "fraud" }"#)]
pub frm_metadata: Option<pii::SecretSerdeValue>,
}
#[derive(Setter, Clone, Default, Debug, PartialEq, serde::Serialize, ToSchema)]

View File

@@ -58,6 +58,7 @@ pub struct PaymentIntent {
pub session_expiry: Option<PrimitiveDateTime>,
pub fingerprint_id: Option<String>,
pub request_external_three_ds_authentication: Option<bool>,
pub frm_metadata: Option<pii::SecretSerdeValue>,
}
#[derive(
@@ -111,6 +112,7 @@ pub struct PaymentIntentNew {
pub session_expiry: Option<PrimitiveDateTime>,
pub fingerprint_id: Option<String>,
pub request_external_three_ds_authentication: Option<bool>,
pub frm_metadata: Option<pii::SecretSerdeValue>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -167,6 +169,7 @@ pub enum PaymentIntentUpdate {
session_expiry: Option<PrimitiveDateTime>,
fingerprint_id: Option<String>,
request_external_three_ds_authentication: Option<bool>,
frm_metadata: Option<pii::SecretSerdeValue>,
},
PaymentAttemptAndAttemptCountUpdate {
active_attempt_id: String,
@@ -236,6 +239,7 @@ pub struct PaymentIntentUpdateInternal {
pub session_expiry: Option<PrimitiveDateTime>,
pub fingerprint_id: Option<String>,
pub request_external_three_ds_authentication: Option<bool>,
pub frm_metadata: Option<pii::SecretSerdeValue>,
}
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<PaymentIntentUpdate> 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<PaymentIntentUpdate> 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_metadata": null
}"#;
let deserialized_payment_intent =
serde_json::from_str::<super::PaymentIntent>(serialized_payment_intent);

View File

@@ -846,6 +846,7 @@ diesel::table! {
#[max_length = 64]
fingerprint_id -> Nullable<Varchar>,
request_external_three_ds_authentication -> Nullable<Bool>,
frm_metadata -> Nullable<Jsonb>,
}
}

View File

@@ -60,4 +60,5 @@ pub struct PaymentIntent {
#[serde(with = "common_utils::custom_serde::iso8601::option")]
pub session_expiry: Option<PrimitiveDateTime>,
pub request_external_three_ds_authentication: Option<bool>,
pub frm_metadata: Option<pii::SecretSerdeValue>,
}

View File

@@ -81,6 +81,7 @@ pub struct PaymentIntentNew {
pub description: Option<String>,
pub return_url: Option<String>,
pub metadata: Option<pii::SecretSerdeValue>,
pub frm_metadata: Option<pii::SecretSerdeValue>,
pub connector_id: Option<String>,
pub shipping_address_id: Option<String>,
pub billing_address_id: Option<String>,
@@ -164,6 +165,7 @@ pub enum PaymentIntentUpdate {
statement_descriptor_suffix: Option<String>,
order_details: Option<Vec<pii::SecretSerdeValue>>,
metadata: Option<pii::SecretSerdeValue>,
frm_metadata: Option<pii::SecretSerdeValue>,
payment_confirm_source: Option<storage_enums::PaymentSource>,
updated_by: String,
fingerprint_id: Option<String>,
@@ -237,6 +239,7 @@ pub struct PaymentIntentUpdateInternal {
pub fingerprint_id: Option<String>,
pub session_expiry: Option<PrimitiveDateTime>,
pub request_external_three_ds_authentication: Option<bool>,
pub frm_metadata: Option<pii::SecretSerdeValue>,
}
impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
@@ -263,6 +266,7 @@ impl From<PaymentIntentUpdate> 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<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
fingerprint_id,
session_expiry,
request_external_three_ds_authentication,
frm_metadata,
..Default::default()
},
PaymentIntentUpdate::MetadataUpdate {

View File

@@ -57,7 +57,7 @@ pub struct RouterData<Flow, Request, Response> {
/// Contains apple pay flow type simplified or manual
pub apple_pay_flow: Option<common_enums::enums::ApplePayFlow>,
pub frm_metadata: Option<serde_json::Value>,
pub frm_metadata: Option<common_utils::pii::SecretSerdeValue>,
pub dispute_id: Option<String>,
pub refund_id: Option<String>,

View File

@@ -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()?;

View File

@@ -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,
@@ -185,15 +182,14 @@ 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::<Result<Vec<_>, _>>()?;
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::<Vec<_>>()
.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>(
"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::<Vec<_>>();
filtered_pm_config_by_pmt
})
.collect::<Vec<_>>()
.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,18 +255,19 @@ where
frm_enabled_pm: filtered_payment_methods
.first()
.and_then(|pm| pm.payment_method),
frm_enabled_pm_type: filtered_payment_method_types
// 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(|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
.first()
.map(|pmt| pmt.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: {:?} {:?} {:?} {:?}",
@@ -411,13 +343,13 @@ where
let payment_to_frm_data = PaymentToFrmData {
amount: payment_data.amount,
payment_intent: payment_data.payment_intent,
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(),
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<F> =
@@ -495,12 +427,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: {:?} {:?}",
@@ -511,6 +438,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())
@@ -571,11 +501,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);
}

View File

@@ -25,7 +25,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,
@@ -186,7 +186,7 @@ impl<F: Send + Clone> Domain<F> for FraudCheckPost {
req_state: ReqState,
frm_data: &mut FrmData,
merchant_account: &domain::MerchantAccount,
frm_configs: FrmConfigsObject,
_frm_configs: FrmConfigsObject,
frm_suggestion: &mut Option<FrmSuggestion>,
key_store: domain::MerchantKeyStore,
payment_data: &mut payments::PaymentData<F>,
@@ -194,7 +194,6 @@ impl<F: Send + Clone> Domain<F> for FraudCheckPost {
_should_continue_capture: &mut bool,
) -> RouterResult<Option<FrmData>> {
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
@@ -242,9 +241,10 @@ impl<F: Send + Clone> Domain<F> 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!(
@@ -477,25 +477,34 @@ impl<F: Clone + Send> UpdateTracker<FrmData, F> 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,
@@ -508,7 +517,7 @@ impl<F: Clone + Send> UpdateTracker<FrmData, F> 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,

View File

@@ -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<Vec<api_models::payments::OrderDetailsWithAmount>>,
pub refund: Option<RefundResponse>,
pub frm_metadata: Option<serde_json::Value>,
pub frm_metadata: Option<SecretSerdeValue>,
}
#[derive(Debug)]
@@ -80,15 +80,13 @@ pub struct PaymentToFrmData {
pub address: PaymentAddress,
pub connector_details: ConnectorDetailsCore,
pub order_details: Option<Vec<api_models::payments::OrderDetailsWithAmount>>,
pub frm_metadata: Option<serde_json::Value>,
pub frm_metadata: Option<SecretSerdeValue>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrmConfigsObject {
pub frm_enabled_pm: Option<PaymentMethod>,
pub frm_enabled_pm_type: Option<PaymentMethodType>,
pub frm_enabled_gateway: Option<api_models::enums::Connector>,
pub frm_action: api_enums::FrmAction,
pub frm_preferred_flow_type: api_enums::FrmPreferredFlowTypes,
}

View File

@@ -2450,7 +2450,6 @@ where
pub incremental_authorization_details: Option<IncrementalAuthorizationDetails>,
pub authorizations: Vec<diesel_models::authorization::Authorization>,
pub authentication: Option<storage::Authentication>,
pub frm_metadata: Option<serde_json::Value>,
pub recurring_details: Option<RecurringDetails>,
pub poll_config: Option<router_types::PollConfig>,
}

View File

@@ -2965,6 +2965,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());
@@ -3023,6 +3024,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())
@@ -3080,6 +3082,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())

View File

@@ -172,7 +172,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCaptureRequest>
payment_link_data: None,
incremental_authorization_details: None,
authorizations: vec![],
frm_metadata: None,
authentication: None,
recurring_details: None,
poll_config: None,

View File

@@ -185,7 +185,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
payment_link_data: None,
incremental_authorization_details: None,
authorizations: vec![],
frm_metadata: None,
authentication: None,
recurring_details: None,
poll_config: None,

View File

@@ -228,7 +228,6 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
payment_link_data: None,
incremental_authorization_details: None,
authorizations: vec![],
frm_metadata: None,
authentication: None,
recurring_details: None,
poll_config: None,

View File

@@ -303,7 +303,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
incremental_authorization_details: None,
authorizations: vec![],
authentication: None,
frm_metadata: None,
recurring_details,
poll_config: None,
};

View File

@@ -393,6 +393,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
.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| {
@@ -632,7 +633,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
payment_link_data: None,
incremental_authorization_details: None,
authorizations: vec![],
frm_metadata: request.frm_metadata.clone(),
authentication: None,
recurring_details,
poll_config: None,
@@ -1062,6 +1062,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
.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()
@@ -1155,6 +1156,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
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;
@@ -1184,6 +1186,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
fingerprint_id: None,
session_expiry,
request_external_three_ds_authentication: None,
frm_metadata: m_frm_metadata,
},
storage_scheme,
)

View File

@@ -446,7 +446,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
incremental_authorization_details: None,
authorizations: vec![],
authentication: None,
frm_metadata: request.frm_metadata.clone(),
recurring_details,
poll_config: None,
};
@@ -1038,6 +1037,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(),
})
}

View File

@@ -170,7 +170,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, PaymentsCancelRequest> for P
incremental_authorization_details: None,
authorizations: vec![],
authentication: None,
frm_metadata: None,
recurring_details: None,
poll_config: None,
};

View File

@@ -197,7 +197,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
incremental_authorization_details: None,
authorizations: vec![],
authentication: None,
frm_metadata: None,
recurring_details: None,
poll_config: None,
};

View File

@@ -182,7 +182,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
incremental_authorization_details: None,
authorizations: vec![],
authentication: None,
frm_metadata: None,
recurring_details: None,
poll_config: None,
};

View File

@@ -471,7 +471,6 @@ async fn get_tracker_for_sync<
incremental_authorization_details: None,
authorizations,
authentication,
frm_metadata: None,
recurring_details: None,
poll_config: None,
};

View File

@@ -250,6 +250,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
.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());
@@ -451,7 +452,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
incremental_authorization_details: None,
authorizations: vec![],
authentication: None,
frm_metadata: request.frm_metadata.clone(),
recurring_details,
poll_config: None,
};
@@ -690,6 +690,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
.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
@@ -719,6 +720,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
request_external_three_ds_authentication: payment_data
.payment_intent
.request_external_three_ds_authentication,
frm_metadata,
},
storage_scheme,
)

View File

@@ -151,7 +151,6 @@ impl<F: Send + Clone>
}),
authorizations: vec![],
authentication: None,
frm_metadata: None,
recurring_details: None,
poll_config: None,
};

View File

@@ -781,6 +781,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,
))

View File

@@ -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(),

View File

@@ -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)

View File

@@ -83,6 +83,7 @@ impl<T: DatabaseStore> PaymentIntentInterface for KVRouterStore<T> {
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,

View File

@@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
ALTER TABLE payment_intent DROP COLUMN IF EXISTS frm_metadata;

View File

@@ -0,0 +1,2 @@
-- Your SQL goes here
ALTER TABLE payment_intent ADD COLUMN IF NOT EXISTS frm_metadata JSONB DEFAULT NULL;

View File

@@ -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",
"payment_method_types"
"payment_method"
],
"properties": {
"payment_method": {
@@ -9316,7 +9315,16 @@
"items": {
"$ref": "#/components/schemas/FrmPaymentMethodType"
},
"description": "payment method types(credit, debit) that can be used in the payment"
"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": {
"allOf": [
{
"$ref": "#/components/schemas/FrmPreferredFlowTypes"
}
],
"nullable": true
}
},
"additionalProperties": false
@@ -13849,6 +13857,7 @@
"minimum": 0
},
"frm_metadata": {
"type": "object",
"description": "additional data related to some frm connectors",
"nullable": true
},
@@ -14221,6 +14230,7 @@
"minimum": 0
},
"frm_metadata": {
"type": "object",
"description": "additional data related to some frm connectors",
"nullable": true
},
@@ -14727,6 +14737,7 @@
"minimum": 0
},
"frm_metadata": {
"type": "object",
"description": "additional data related to some frm connectors",
"nullable": true
},
@@ -15268,6 +15279,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
}
}
},
@@ -15735,6 +15751,7 @@
"minimum": 0
},
"frm_metadata": {
"type": "object",
"description": "additional data related to some frm connectors",
"nullable": true
},