Skip to content

Commit 74f3721

Browse files
fix(core): Add column mandate_data for storing the details of a mandate in PaymentAttempt (#3606)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 3cef73b commit 74f3721

File tree

14 files changed

+91
-144
lines changed

14 files changed

+91
-144
lines changed

crates/data_models/src/mandates.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use time::PrimitiveDateTime;
1313
#[serde(rename_all = "snake_case")]
1414
pub struct MandateDetails {
1515
pub update_mandate_id: Option<String>,
16-
pub mandate_type: Option<MandateDataType>,
1716
}
1817

1918
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
@@ -23,13 +22,6 @@ pub enum MandateDataType {
2322
MultiUse(Option<MandateAmountData>),
2423
}
2524

26-
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
27-
#[serde(rename_all = "snake_case")]
28-
#[serde(untagged)]
29-
pub enum MandateTypeDetails {
30-
MandateType(MandateDataType),
31-
MandateDetails(MandateDetails),
32-
}
3325
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
3426
pub struct MandateAmountData {
3527
pub amount: i64,

crates/data_models/src/payments/payment_attempt.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ use serde::{Deserialize, Serialize};
44
use time::PrimitiveDateTime;
55

66
use super::PaymentIntent;
7-
use crate::{errors, mandates::MandateTypeDetails, ForeignIDRef};
7+
use crate::{
8+
errors,
9+
mandates::{MandateDataType, MandateDetails},
10+
ForeignIDRef,
11+
};
812

913
#[async_trait::async_trait]
1014
pub trait PaymentAttemptInterface {
@@ -143,7 +147,7 @@ pub struct PaymentAttempt {
143147
pub straight_through_algorithm: Option<serde_json::Value>,
144148
pub preprocessing_step_id: Option<String>,
145149
// providing a location to store mandate details intermediately for transaction
146-
pub mandate_details: Option<MandateTypeDetails>,
150+
pub mandate_details: Option<MandateDataType>,
147151
pub error_reason: Option<String>,
148152
pub multiple_capture_count: Option<i16>,
149153
// reference to the payment at connector side
@@ -155,6 +159,7 @@ pub struct PaymentAttempt {
155159
pub merchant_connector_id: Option<String>,
156160
pub unified_code: Option<String>,
157161
pub unified_message: Option<String>,
162+
pub mandate_data: Option<MandateDetails>,
158163
}
159164

160165
impl PaymentAttempt {
@@ -221,7 +226,7 @@ pub struct PaymentAttemptNew {
221226
pub business_sub_label: Option<String>,
222227
pub straight_through_algorithm: Option<serde_json::Value>,
223228
pub preprocessing_step_id: Option<String>,
224-
pub mandate_details: Option<MandateTypeDetails>,
229+
pub mandate_details: Option<MandateDataType>,
225230
pub error_reason: Option<String>,
226231
pub connector_response_reference_id: Option<String>,
227232
pub multiple_capture_count: Option<i16>,
@@ -232,6 +237,7 @@ pub struct PaymentAttemptNew {
232237
pub merchant_connector_id: Option<String>,
233238
pub unified_code: Option<String>,
234239
pub unified_message: Option<String>,
240+
pub mandate_data: Option<MandateDetails>,
235241
}
236242

237243
impl PaymentAttemptNew {

crates/diesel_models/src/enums.rs

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -174,20 +174,8 @@ use diesel::{
174174
#[serde(rename_all = "snake_case")]
175175
pub struct MandateDetails {
176176
pub update_mandate_id: Option<String>,
177-
pub mandate_type: Option<MandateDataType>,
178177
}
179-
180-
#[derive(
181-
serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, FromSqlRow, AsExpression,
182-
)]
183-
#[diesel(sql_type = Jsonb)]
184-
#[serde(rename_all = "snake_case")]
185-
pub enum MandateDataType {
186-
SingleUse(MandateAmountData),
187-
MultiUse(Option<MandateAmountData>),
188-
}
189-
190-
impl<DB: Backend> FromSql<Jsonb, DB> for MandateDataType
178+
impl<DB: Backend> FromSql<Jsonb, DB> for MandateDetails
191179
where
192180
serde_json::Value: FromSql<Jsonb, DB>,
193181
{
@@ -197,7 +185,7 @@ where
197185
}
198186
}
199187

200-
impl ToSql<Jsonb, diesel::pg::Pg> for MandateDataType
188+
impl ToSql<Jsonb, diesel::pg::Pg> for MandateDetails
201189
where
202190
serde_json::Value: ToSql<Jsonb, diesel::pg::Pg>,
203191
{
@@ -210,19 +198,17 @@ where
210198
<serde_json::Value as ToSql<Jsonb, diesel::pg::Pg>>::to_sql(&value, &mut out.reborrow())
211199
}
212200
}
213-
214201
#[derive(
215202
serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, FromSqlRow, AsExpression,
216203
)]
217204
#[diesel(sql_type = Jsonb)]
218-
#[serde(untagged)]
219205
#[serde(rename_all = "snake_case")]
220-
pub enum MandateTypeDetails {
221-
MandateType(MandateDataType),
222-
MandateDetails(MandateDetails),
206+
pub enum MandateDataType {
207+
SingleUse(MandateAmountData),
208+
MultiUse(Option<MandateAmountData>),
223209
}
224210

225-
impl<DB: Backend> FromSql<Jsonb, DB> for MandateTypeDetails
211+
impl<DB: Backend> FromSql<Jsonb, DB> for MandateDataType
226212
where
227213
serde_json::Value: FromSql<Jsonb, DB>,
228214
{
@@ -231,7 +217,8 @@ where
231217
Ok(serde_json::from_value(value)?)
232218
}
233219
}
234-
impl ToSql<Jsonb, diesel::pg::Pg> for MandateTypeDetails
220+
221+
impl ToSql<Jsonb, diesel::pg::Pg> for MandateDataType
235222
where
236223
serde_json::Value: ToSql<Jsonb, diesel::pg::Pg>,
237224
{

crates/diesel_models/src/payment_attempt.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub struct PaymentAttempt {
5151
pub straight_through_algorithm: Option<serde_json::Value>,
5252
pub preprocessing_step_id: Option<String>,
5353
// providing a location to store mandate details intermediately for transaction
54-
pub mandate_details: Option<storage_enums::MandateTypeDetails>,
54+
pub mandate_details: Option<storage_enums::MandateDataType>,
5555
pub error_reason: Option<String>,
5656
pub multiple_capture_count: Option<i16>,
5757
// reference to the payment at connector side
@@ -64,6 +64,7 @@ pub struct PaymentAttempt {
6464
pub unified_code: Option<String>,
6565
pub unified_message: Option<String>,
6666
pub net_amount: Option<i64>,
67+
pub mandate_data: Option<storage_enums::MandateDetails>,
6768
}
6869

6970
impl PaymentAttempt {
@@ -126,7 +127,7 @@ pub struct PaymentAttemptNew {
126127
pub business_sub_label: Option<String>,
127128
pub straight_through_algorithm: Option<serde_json::Value>,
128129
pub preprocessing_step_id: Option<String>,
129-
pub mandate_details: Option<storage_enums::MandateTypeDetails>,
130+
pub mandate_details: Option<storage_enums::MandateDataType>,
130131
pub error_reason: Option<String>,
131132
pub connector_response_reference_id: Option<String>,
132133
pub multiple_capture_count: Option<i16>,
@@ -138,6 +139,7 @@ pub struct PaymentAttemptNew {
138139
pub unified_code: Option<String>,
139140
pub unified_message: Option<String>,
140141
pub net_amount: Option<i64>,
142+
pub mandate_data: Option<storage_enums::MandateDetails>,
141143
}
142144

143145
impl PaymentAttemptNew {

crates/diesel_models/src/schema.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ diesel::table! {
688688
#[max_length = 1024]
689689
unified_message -> Nullable<Varchar>,
690690
net_amount -> Nullable<Int8>,
691+
mandate_data -> Nullable<Jsonb>,
691692
}
692693
}
693694

crates/diesel_models/src/user/sample_data.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ use common_enums::{
55
use serde::{Deserialize, Serialize};
66
use time::PrimitiveDateTime;
77

8-
use crate::{enums::MandateTypeDetails, schema::payment_attempt, PaymentAttemptNew};
8+
use crate::{
9+
enums::{MandateDataType, MandateDetails},
10+
schema::payment_attempt,
11+
PaymentAttemptNew,
12+
};
913

1014
#[derive(
1115
Clone, Debug, Default, diesel::Insertable, router_derive::DebugAsDisplay, Serialize, Deserialize,
@@ -50,7 +54,7 @@ pub struct PaymentAttemptBatchNew {
5054
pub business_sub_label: Option<String>,
5155
pub straight_through_algorithm: Option<serde_json::Value>,
5256
pub preprocessing_step_id: Option<String>,
53-
pub mandate_details: Option<MandateTypeDetails>,
57+
pub mandate_details: Option<MandateDataType>,
5458
pub error_reason: Option<String>,
5559
pub connector_response_reference_id: Option<String>,
5660
pub connector_transaction_id: Option<String>,
@@ -63,6 +67,7 @@ pub struct PaymentAttemptBatchNew {
6367
pub unified_code: Option<String>,
6468
pub unified_message: Option<String>,
6569
pub net_amount: Option<i64>,
70+
pub mandate_data: Option<MandateDetails>,
6671
}
6772

6873
#[allow(dead_code)]
@@ -116,6 +121,7 @@ impl PaymentAttemptBatchNew {
116121
unified_code: self.unified_code,
117122
unified_message: self.unified_message,
118123
net_amount: self.net_amount,
124+
mandate_data: self.mandate_data,
119125
}
120126
}
121127
}

crates/router/src/core/payment_methods/cards.rs

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,17 +2000,8 @@ pub async fn list_payment_methods(
20002000
merchant_name: merchant_account.merchant_name,
20012001
payment_type,
20022002
payment_methods: payment_method_responses,
2003-
mandate_payment: payment_attempt
2004-
.and_then(|inner| inner.mandate_details)
2005-
.and_then(|man_type_details| match man_type_details {
2006-
data_models::mandates::MandateTypeDetails::MandateType(mandate_type) => {
2007-
Some(mandate_type)
2008-
}
2009-
data_models::mandates::MandateTypeDetails::MandateDetails(mandate_details) => {
2010-
mandate_details.mandate_type
2011-
}
2012-
})
2013-
.map(|d| match d {
2003+
mandate_payment: payment_attempt.and_then(|inner| inner.mandate_details).map(
2004+
|d| match d {
20142005
data_models::mandates::MandateDataType::SingleUse(i) => {
20152006
api::MandateType::SingleUse(api::MandateAmountData {
20162007
amount: i.amount,
@@ -2032,7 +2023,8 @@ pub async fn list_payment_methods(
20322023
data_models::mandates::MandateDataType::MultiUse(None) => {
20332024
api::MandateType::MultiUse(None)
20342025
}
2035-
}),
2026+
},
2027+
),
20362028
show_surcharge_breakup_screen: merchant_surcharge_configs
20372029
.show_surcharge_breakup_screen
20382030
.unwrap_or_default(),
@@ -2242,28 +2234,20 @@ pub async fn filter_payment_methods(
22422234
})?;
22432235
let filter7 = payment_attempt
22442236
.and_then(|attempt| attempt.mandate_details.as_ref())
2245-
.map(|mandate_details| {
2246-
let (mandate_type_present, update_mandate_id_present) =
2247-
match mandate_details {
2248-
data_models::mandates::MandateTypeDetails::MandateType(_) => {
2249-
(true, false)
2250-
}
2251-
data_models::mandates::MandateTypeDetails::MandateDetails(
2252-
mand_details,
2253-
) => (
2254-
mand_details.mandate_type.is_some(),
2255-
mand_details.update_mandate_id.is_some(),
2256-
),
2257-
};
2258-
2259-
if mandate_type_present {
2260-
filter_pm_based_on_supported_payments_for_mandate(
2261-
supported_payment_methods_for_mandate,
2262-
&payment_method,
2263-
&payment_method_object.payment_method_type,
2264-
connector_variant,
2265-
)
2266-
} else if update_mandate_id_present {
2237+
.map(|_mandate_details| {
2238+
filter_pm_based_on_supported_payments_for_mandate(
2239+
supported_payment_methods_for_mandate,
2240+
&payment_method,
2241+
&payment_method_object.payment_method_type,
2242+
connector_variant,
2243+
)
2244+
})
2245+
.unwrap_or(true);
2246+
2247+
let filter8 = payment_attempt
2248+
.and_then(|attempt| attempt.mandate_data.as_ref())
2249+
.map(|mandate_detail| {
2250+
if mandate_detail.update_mandate_id.is_some() {
22672251
filter_pm_based_on_update_mandate_support_for_connector(
22682252
supported_payment_methods_for_update_mandate,
22692253
&payment_method,
@@ -2284,7 +2268,15 @@ pub async fn filter_payment_methods(
22842268
payment_method,
22852269
);
22862270

2287-
if filter && filter2 && filter3 && filter4 && filter5 && filter6 && filter7 {
2271+
if filter
2272+
&& filter2
2273+
&& filter3
2274+
&& filter4
2275+
&& filter5
2276+
&& filter6
2277+
&& filter7
2278+
&& filter8
2279+
{
22882280
resp.push(response_pm_type);
22892281
}
22902282
}

crates/router/src/core/payments/helpers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3201,6 +3201,7 @@ impl AttemptType {
32013201
unified_code: None,
32023202
unified_message: None,
32033203
net_amount: old_payment_attempt.amount,
3204+
mandate_data: old_payment_attempt.mandate_data,
32043205
}
32053206
}
32063207

crates/router/src/core/payments/operations/payment_confirm.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -441,28 +441,11 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
441441

442442
// The operation merges mandate data from both request and payment_attempt
443443
setup_mandate = setup_mandate.map(|mut sm| {
444-
sm.mandate_type = payment_attempt
445-
.mandate_details
446-
.clone()
447-
.and_then(|mandate| match mandate {
448-
data_models::mandates::MandateTypeDetails::MandateType(mandate_type) => {
449-
Some(mandate_type)
450-
}
451-
data_models::mandates::MandateTypeDetails::MandateDetails(mandate_details) => {
452-
mandate_details.mandate_type
453-
}
454-
})
455-
.or(sm.mandate_type);
444+
sm.mandate_type = payment_attempt.mandate_details.clone().or(sm.mandate_type);
456445
sm.update_mandate_id = payment_attempt
457-
.mandate_details
446+
.mandate_data
458447
.clone()
459-
.and_then(|mandate| match mandate {
460-
data_models::mandates::MandateTypeDetails::MandateType(_) => None,
461-
data_models::mandates::MandateTypeDetails::MandateDetails(update_id) => {
462-
Some(update_id.update_mandate_id)
463-
}
464-
})
465-
.flatten()
448+
.and_then(|mandate| mandate.update_mandate_id)
466449
.or(sm.update_mandate_id);
467450
sm
468451
});

crates/router/src/core/payments/operations/payment_create.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use api_models::enums::FrmSuggestion;
44
use async_trait::async_trait;
55
use common_utils::ext_traits::{AsyncExt, Encode, ValueExt};
66
use data_models::{
7-
mandates::{MandateData, MandateDetails, MandateTypeDetails},
7+
mandates::{MandateData, MandateDetails},
88
payments::payment_attempt::PaymentAttempt,
99
};
1010
use diesel_models::ephemeral_key;
@@ -733,27 +733,17 @@ impl PaymentCreate {
733733
Err(errors::ApiErrorResponse::InvalidRequestData {message:"Only one field out of 'mandate_type' and 'update_mandate_id' was expected, found both".to_string()})?
734734
}
735735

736-
let mandate_details = if request.mandate_data.is_none() {
737-
None
738-
} else if let Some(update_id) = request
736+
let mandate_data = if let Some(update_id) = request
739737
.mandate_data
740738
.as_ref()
741739
.and_then(|inner| inner.update_mandate_id.clone())
742740
{
743-
let mandate_data = MandateDetails {
741+
let mandate_details = MandateDetails {
744742
update_mandate_id: Some(update_id),
745-
mandate_type: None,
746743
};
747-
Some(MandateTypeDetails::MandateDetails(mandate_data))
744+
Some(mandate_details)
748745
} else {
749-
let mandate_data = MandateDetails {
750-
update_mandate_id: None,
751-
mandate_type: request
752-
.mandate_data
753-
.as_ref()
754-
.and_then(|inner| inner.mandate_type.clone().map(Into::into)),
755-
};
756-
Some(MandateTypeDetails::MandateDetails(mandate_data))
746+
None
757747
};
758748

759749
Ok((
@@ -782,7 +772,11 @@ impl PaymentCreate {
782772
business_sub_label: request.business_sub_label.clone(),
783773
surcharge_amount,
784774
tax_amount,
785-
mandate_details,
775+
mandate_details: request
776+
.mandate_data
777+
.as_ref()
778+
.and_then(|inner| inner.mandate_type.clone().map(Into::into)),
779+
mandate_data,
786780
..storage::PaymentAttemptNew::default()
787781
},
788782
additional_pm_data,

0 commit comments

Comments
 (0)