mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 12:06:56 +08:00
fix(router): store customer_acceptance in payment_attempt, use it in confirm flow for delayed authorizations like external 3ds flow (#5308)
This commit is contained in:
committed by
GitHub
parent
61b3aef661
commit
0f70473a3a
@ -1,3 +1,4 @@
|
||||
use common_utils::pii;
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
@ -72,6 +73,7 @@ pub struct PaymentAttempt {
|
||||
pub charge_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
pub customer_acceptance: Option<pii::SecretSerdeValue>,
|
||||
}
|
||||
|
||||
impl PaymentAttempt {
|
||||
@ -155,6 +157,7 @@ pub struct PaymentAttemptNew {
|
||||
pub charge_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
pub customer_acceptance: Option<pii::SecretSerdeValue>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptNew {
|
||||
@ -240,6 +243,7 @@ pub enum PaymentAttemptUpdate {
|
||||
payment_method_billing_address_id: Option<String>,
|
||||
client_source: Option<String>,
|
||||
client_version: Option<String>,
|
||||
customer_acceptance: Option<pii::SecretSerdeValue>,
|
||||
},
|
||||
VoidUpdate {
|
||||
status: storage_enums::AttemptStatus,
|
||||
@ -410,6 +414,7 @@ pub struct PaymentAttemptUpdateInternal {
|
||||
charge_id: Option<String>,
|
||||
client_source: Option<String>,
|
||||
client_version: Option<String>,
|
||||
customer_acceptance: Option<pii::SecretSerdeValue>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptUpdateInternal {
|
||||
@ -478,6 +483,7 @@ impl PaymentAttemptUpdate {
|
||||
charge_id,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance,
|
||||
} = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source);
|
||||
PaymentAttempt {
|
||||
amount: amount.unwrap_or(source.amount),
|
||||
@ -529,6 +535,7 @@ impl PaymentAttemptUpdate {
|
||||
charge_id: charge_id.or(source.charge_id),
|
||||
client_source: client_source.or(source.client_source),
|
||||
client_version: client_version.or(source.client_version),
|
||||
customer_acceptance: customer_acceptance.or(source.customer_acceptance),
|
||||
..source
|
||||
}
|
||||
}
|
||||
@ -617,6 +624,7 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
|
||||
payment_method_id,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance,
|
||||
} => Self {
|
||||
amount: Some(amount),
|
||||
currency: Some(currency),
|
||||
@ -648,6 +656,7 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
|
||||
capture_method,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance,
|
||||
..Default::default()
|
||||
},
|
||||
PaymentAttemptUpdate::VoidUpdate {
|
||||
|
||||
@ -820,6 +820,7 @@ diesel::table! {
|
||||
client_source -> Nullable<Varchar>,
|
||||
#[max_length = 64]
|
||||
client_version -> Nullable<Varchar>,
|
||||
customer_acceptance -> Nullable<Jsonb>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -76,6 +76,7 @@ pub struct PaymentAttemptBatchNew {
|
||||
pub charge_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
pub customer_acceptance: Option<common_utils::pii::SecretSerdeValue>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -139,6 +140,7 @@ impl PaymentAttemptBatchNew {
|
||||
charge_id: self.charge_id,
|
||||
client_source: self.client_source,
|
||||
client_version: self.client_version,
|
||||
customer_acceptance: self.customer_acceptance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ pub struct MandateData {
|
||||
pub mandate_type: Option<MandateDataType>,
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Debug, Clone, serde::Deserialize)]
|
||||
#[derive(Default, Eq, PartialEq, Debug, Clone, serde::Deserialize, serde::Serialize)]
|
||||
pub struct CustomerAcceptance {
|
||||
/// Type of acceptance provided by the
|
||||
pub acceptance_type: AcceptanceType,
|
||||
@ -54,7 +54,7 @@ pub struct CustomerAcceptance {
|
||||
pub online: Option<OnlineMandate>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, serde::Deserialize)]
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AcceptanceType {
|
||||
Online,
|
||||
@ -62,7 +62,7 @@ pub enum AcceptanceType {
|
||||
Offline,
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Debug, Clone, serde::Deserialize)]
|
||||
#[derive(Default, Eq, PartialEq, Debug, Clone, serde::Deserialize, serde::Serialize)]
|
||||
pub struct OnlineMandate {
|
||||
/// Ip address of the customer machine from which the mandate was created
|
||||
#[serde(skip_deserializing)]
|
||||
|
||||
@ -2,6 +2,7 @@ use api_models::enums::Connector;
|
||||
use common_enums as storage_enums;
|
||||
use common_utils::{
|
||||
errors::{CustomResult, ValidationError},
|
||||
pii,
|
||||
types::MinorUnit,
|
||||
};
|
||||
use error_stack::ResultExt;
|
||||
@ -175,6 +176,7 @@ pub struct PaymentAttempt {
|
||||
pub charge_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
pub customer_acceptance: Option<pii::SecretSerdeValue>,
|
||||
}
|
||||
|
||||
impl PaymentAttempt {
|
||||
@ -264,6 +266,7 @@ pub struct PaymentAttemptNew {
|
||||
pub charge_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
pub customer_acceptance: Option<pii::SecretSerdeValue>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptNew {
|
||||
@ -346,6 +349,7 @@ pub enum PaymentAttemptUpdate {
|
||||
payment_method_id: Option<String>,
|
||||
client_source: Option<String>,
|
||||
client_version: Option<String>,
|
||||
customer_acceptance: Option<pii::SecretSerdeValue>,
|
||||
},
|
||||
RejectUpdate {
|
||||
status: storage_enums::AttemptStatus,
|
||||
|
||||
@ -3712,6 +3712,7 @@ impl AttemptType {
|
||||
charge_id: None,
|
||||
client_source: old_payment_attempt.client_source,
|
||||
client_version: old_payment_attempt.client_version,
|
||||
customer_acceptance: old_payment_attempt.customer_acceptance,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -341,7 +341,17 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "browser_info",
|
||||
})?;
|
||||
let customer_acceptance = request.customer_acceptance.clone().map(From::from);
|
||||
let customer_acceptance = request.customer_acceptance.clone().or(payment_attempt
|
||||
.customer_acceptance
|
||||
.clone()
|
||||
.map(|customer_acceptance| {
|
||||
customer_acceptance
|
||||
.expose()
|
||||
.parse_value("CustomerAcceptance")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed while deserializing customer_acceptance")
|
||||
})
|
||||
.transpose()?);
|
||||
|
||||
let recurring_details = request.recurring_details.clone();
|
||||
|
||||
@ -360,6 +370,16 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
|
||||
payment_attempt.capture_method = request.capture_method.or(payment_attempt.capture_method);
|
||||
|
||||
payment_attempt.customer_acceptance = request
|
||||
.customer_acceptance
|
||||
.clone()
|
||||
.map(|customer_acceptance| customer_acceptance.encode_to_value())
|
||||
.transpose()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed while encoding customer_acceptance to value")?
|
||||
.map(masking::Secret::new)
|
||||
.or(payment_attempt.customer_acceptance);
|
||||
|
||||
currency = payment_attempt.currency.get_required_value("currency")?;
|
||||
amount = payment_attempt.get_total_amount().into();
|
||||
|
||||
@ -616,7 +636,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
mandate_id: None,
|
||||
mandate_connector,
|
||||
setup_mandate,
|
||||
customer_acceptance,
|
||||
customer_acceptance: customer_acceptance.map(From::from),
|
||||
token,
|
||||
address: PaymentAddress::new(
|
||||
shipping_address.as_ref().map(From::from),
|
||||
@ -1211,6 +1231,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
|
||||
payment_method_id: m_payment_method_id,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance: payment_data.payment_attempt.customer_acceptance,
|
||||
},
|
||||
storage_scheme,
|
||||
)
|
||||
|
||||
@ -281,6 +281,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
&payment_method_info,
|
||||
merchant_key_store,
|
||||
profile_id,
|
||||
&customer_acceptance,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -796,6 +797,7 @@ impl PaymentCreate {
|
||||
payment_method_info: &Option<PaymentMethod>,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
profile_id: String,
|
||||
customer_acceptance: &Option<payments::CustomerAcceptance>,
|
||||
) -> RouterResult<(
|
||||
storage::PaymentAttemptNew,
|
||||
Option<api_models::payments::AdditionalPaymentData>,
|
||||
@ -966,6 +968,13 @@ impl PaymentCreate {
|
||||
charge_id: None,
|
||||
client_source: None,
|
||||
client_version: None,
|
||||
customer_acceptance: customer_acceptance
|
||||
.clone()
|
||||
.map(|customer_acceptance| customer_acceptance.encode_to_value())
|
||||
.transpose()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to serialize customer_acceptance")?
|
||||
.map(Secret::new),
|
||||
},
|
||||
additional_pm_data,
|
||||
))
|
||||
|
||||
@ -157,6 +157,7 @@ impl PaymentAttemptInterface for MockDb {
|
||||
charge_id: payment_attempt.charge_id,
|
||||
client_source: payment_attempt.client_source,
|
||||
client_version: payment_attempt.client_version,
|
||||
customer_acceptance: payment_attempt.customer_acceptance,
|
||||
};
|
||||
payment_attempts.push(payment_attempt.clone());
|
||||
Ok(payment_attempt)
|
||||
|
||||
@ -418,6 +418,7 @@ impl<T: DatabaseStore> PaymentAttemptInterface for KVRouterStore<T> {
|
||||
charge_id: payment_attempt.charge_id.clone(),
|
||||
client_source: payment_attempt.client_source.clone(),
|
||||
client_version: payment_attempt.client_version.clone(),
|
||||
customer_acceptance: payment_attempt.customer_acceptance.clone(),
|
||||
};
|
||||
|
||||
let field = format!("pa_{}", created_attempt.attempt_id);
|
||||
@ -1202,6 +1203,7 @@ impl DataModelExt for PaymentAttempt {
|
||||
charge_id: self.charge_id,
|
||||
client_source: self.client_source,
|
||||
client_version: self.client_version,
|
||||
customer_acceptance: self.customer_acceptance,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1268,6 +1270,7 @@ impl DataModelExt for PaymentAttempt {
|
||||
charge_id: storage_model.charge_id,
|
||||
client_source: storage_model.client_source,
|
||||
client_version: storage_model.client_version,
|
||||
customer_acceptance: storage_model.customer_acceptance,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1339,6 +1342,7 @@ impl DataModelExt for PaymentAttemptNew {
|
||||
charge_id: self.charge_id,
|
||||
client_source: self.client_source,
|
||||
client_version: self.client_version,
|
||||
customer_acceptance: self.customer_acceptance,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1404,6 +1408,7 @@ impl DataModelExt for PaymentAttemptNew {
|
||||
charge_id: storage_model.charge_id,
|
||||
client_source: storage_model.client_source,
|
||||
client_version: storage_model.client_version,
|
||||
customer_acceptance: storage_model.customer_acceptance,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1528,6 +1533,7 @@ impl DataModelExt for PaymentAttemptUpdate {
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance,
|
||||
} => DieselPaymentAttemptUpdate::ConfirmUpdate {
|
||||
amount: amount.get_amount_as_i64(),
|
||||
currency,
|
||||
@ -1560,6 +1566,7 @@ impl DataModelExt for PaymentAttemptUpdate {
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance,
|
||||
},
|
||||
Self::VoidUpdate {
|
||||
status,
|
||||
@ -1863,6 +1870,7 @@ impl DataModelExt for PaymentAttemptUpdate {
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance,
|
||||
} => Self::ConfirmUpdate {
|
||||
amount: MinorUnit::new(amount),
|
||||
currency,
|
||||
@ -1893,6 +1901,7 @@ impl DataModelExt for PaymentAttemptUpdate {
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
customer_acceptance,
|
||||
},
|
||||
DieselPaymentAttemptUpdate::VoidUpdate {
|
||||
status,
|
||||
|
||||
@ -0,0 +1 @@
|
||||
ALTER TABLE payment_attempt DROP COLUMN IF EXISTS customer_acceptance;
|
||||
@ -0,0 +1,2 @@
|
||||
-- Your SQL goes here
|
||||
ALTER TABLE payment_attempt ADD COLUMN IF NOT EXISTS customer_acceptance JSONB DEFAULT NULL;
|
||||
Reference in New Issue
Block a user