Skip to content

Commit 940c020

Browse files
sumanmaji4hyperswitch-bot[bot]
authored andcommitted
refactor(core): add recurring customer support for nomupay payouts. (#6687)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 1a197e7 commit 940c020

File tree

25 files changed

+1355
-237
lines changed

25 files changed

+1355
-237
lines changed

api-reference-v2/openapi_spec.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16136,6 +16136,11 @@
1613616136
"example": "+1",
1613716137
"nullable": true,
1613816138
"maxLength": 255
16139+
},
16140+
"payout_method_id": {
16141+
"type": "string",
16142+
"description": "Identifier for payout method",
16143+
"nullable": true
1613916144
}
1614016145
},
1614116146
"additionalProperties": false
@@ -16375,6 +16380,11 @@
1637516380
"example": "Invalid card details",
1637616381
"nullable": true,
1637716382
"maxLength": 1024
16383+
},
16384+
"payout_method_id": {
16385+
"type": "string",
16386+
"description": "Identifier for payout method",
16387+
"nullable": true
1637816388
}
1637916389
},
1638016390
"additionalProperties": false

api-reference/openapi_spec.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20921,6 +20921,11 @@
2092120921
"example": "+1",
2092220922
"nullable": true,
2092320923
"maxLength": 255
20924+
},
20925+
"payout_method_id": {
20926+
"type": "string",
20927+
"description": "Identifier for payout method",
20928+
"nullable": true
2092420929
}
2092520930
}
2092620931
},
@@ -21219,6 +21224,11 @@
2121921224
"example": "Invalid card details",
2122021225
"nullable": true,
2122121226
"maxLength": 1024
21227+
},
21228+
"payout_method_id": {
21229+
"type": "string",
21230+
"description": "Identifier for payout method",
21231+
"nullable": true
2122221232
}
2122321233
},
2122421234
"additionalProperties": false
@@ -21865,6 +21875,11 @@
2186521875
"example": "+1",
2186621876
"nullable": true,
2186721877
"maxLength": 255
21878+
},
21879+
"payout_method_id": {
21880+
"type": "string",
21881+
"description": "Identifier for payout method",
21882+
"nullable": true
2186821883
}
2186921884
}
2187021885
},
@@ -22077,6 +22092,11 @@
2207722092
"example": "+1",
2207822093
"nullable": true,
2207922094
"maxLength": 255
22095+
},
22096+
"payout_method_id": {
22097+
"type": "string",
22098+
"description": "Identifier for payout method",
22099+
"nullable": true
2208022100
}
2208122101
}
2208222102
},

crates/api_models/src/payment_methods.rs

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ pub struct PaymentMethodMigrate {
257257
pub billing: Option<payments::Address>,
258258

259259
/// The connector mandate details of the payment method
260-
pub connector_mandate_details: Option<PaymentsMandateReference>,
260+
#[serde(deserialize_with = "deserialize_connector_mandate_details")]
261+
pub connector_mandate_details: Option<CommonMandateReference>,
261262

262263
// The CIT (customer initiated transaction) transaction id associated with the payment method
263264
pub network_transaction_id: Option<String>,
@@ -281,19 +282,103 @@ pub struct PaymentMethodMigrateResponse {
281282
pub network_transaction_id_migrated: Option<bool>,
282283
}
283284

284-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
285+
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
285286
pub struct PaymentsMandateReference(
286287
pub HashMap<id_type::MerchantConnectorAccountId, PaymentsMandateReferenceRecord>,
287288
);
288289

289-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
290+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
291+
pub struct PayoutsMandateReference(
292+
pub HashMap<id_type::MerchantConnectorAccountId, PayoutsMandateReferenceRecord>,
293+
);
294+
295+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
296+
pub struct PayoutsMandateReferenceRecord {
297+
pub transfer_method_id: Option<String>,
298+
}
299+
300+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
290301
pub struct PaymentsMandateReferenceRecord {
291302
pub connector_mandate_id: String,
292303
pub payment_method_type: Option<common_enums::PaymentMethodType>,
293304
pub original_payment_authorized_amount: Option<i64>,
294305
pub original_payment_authorized_currency: Option<common_enums::Currency>,
295306
}
296307

308+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
309+
pub struct CommonMandateReference {
310+
pub payments: Option<PaymentsMandateReference>,
311+
pub payouts: Option<PayoutsMandateReference>,
312+
}
313+
314+
impl From<CommonMandateReference> for PaymentsMandateReference {
315+
fn from(common_mandate: CommonMandateReference) -> Self {
316+
common_mandate.payments.unwrap_or_default()
317+
}
318+
}
319+
320+
impl From<PaymentsMandateReference> for CommonMandateReference {
321+
fn from(payments_reference: PaymentsMandateReference) -> Self {
322+
Self {
323+
payments: Some(payments_reference),
324+
payouts: None,
325+
}
326+
}
327+
}
328+
329+
fn deserialize_connector_mandate_details<'de, D>(
330+
deserializer: D,
331+
) -> Result<Option<CommonMandateReference>, D::Error>
332+
where
333+
D: serde::Deserializer<'de>,
334+
{
335+
let value: Option<serde_json::Value> =
336+
<Option<serde_json::Value> as de::Deserialize>::deserialize(deserializer)?;
337+
338+
let payments_data = value
339+
.clone()
340+
.map(|mut mandate_details| {
341+
mandate_details
342+
.as_object_mut()
343+
.map(|obj| obj.remove("payouts"));
344+
345+
serde_json::from_value::<PaymentsMandateReference>(mandate_details)
346+
})
347+
.transpose()
348+
.map_err(|err| {
349+
let err_msg = format!("{err:?}");
350+
de::Error::custom(format_args!(
351+
"Failed to deserialize PaymentsMandateReference `{}`",
352+
err_msg
353+
))
354+
})?;
355+
356+
let payouts_data = value
357+
.clone()
358+
.map(|mandate_details| {
359+
serde_json::from_value::<Option<CommonMandateReference>>(mandate_details).map(
360+
|optional_common_mandate_details| {
361+
optional_common_mandate_details
362+
.and_then(|common_mandate_details| common_mandate_details.payouts)
363+
},
364+
)
365+
})
366+
.transpose()
367+
.map_err(|err| {
368+
let err_msg = format!("{err:?}");
369+
de::Error::custom(format_args!(
370+
"Failed to deserialize CommonMandateReference `{}`",
371+
err_msg
372+
))
373+
})?
374+
.flatten();
375+
376+
Ok(Some(CommonMandateReference {
377+
payments: payments_data,
378+
payouts: payouts_data,
379+
}))
380+
}
381+
297382
#[cfg(all(
298383
any(feature = "v1", feature = "v2"),
299384
not(feature = "payment_methods_v2")
@@ -327,7 +412,12 @@ impl PaymentMethodCreate {
327412
payment_method_issuer_code: payment_method_migrate.payment_method_issuer_code,
328413
metadata: payment_method_migrate.metadata.clone(),
329414
payment_method_data: payment_method_migrate.payment_method_data.clone(),
330-
connector_mandate_details: payment_method_migrate.connector_mandate_details.clone(),
415+
connector_mandate_details: payment_method_migrate
416+
.connector_mandate_details
417+
.clone()
418+
.map(|common_mandate_reference| {
419+
PaymentsMandateReference::from(common_mandate_reference)
420+
}),
331421
client_secret: None,
332422
billing: payment_method_migrate.billing.clone(),
333423
card: card_details,
@@ -2335,7 +2425,11 @@ impl
23352425
}),
23362426
email: record.email,
23372427
}),
2338-
connector_mandate_details,
2428+
connector_mandate_details: connector_mandate_details.map(
2429+
|payments_mandate_reference| {
2430+
CommonMandateReference::from(payments_mandate_reference)
2431+
},
2432+
),
23392433
metadata: None,
23402434
payment_method_issuer_code: None,
23412435
card_network: None,

crates/api_models/src/payouts.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ pub struct PayoutCreateRequest {
184184
/// Customer's phone country code. _Deprecated: Use customer object instead._
185185
#[schema(deprecated, max_length = 255, example = "+1")]
186186
pub phone_country_code: Option<String>,
187+
188+
/// Identifier for payout method
189+
pub payout_method_id: Option<String>,
187190
}
188191

189192
impl PayoutCreateRequest {
@@ -568,6 +571,9 @@ pub struct PayoutCreateResponse {
568571
#[remove_in(PayoutCreateResponse)]
569572
#[schema(value_type = Option<String>, max_length = 1024, example = "Invalid card details")]
570573
pub unified_message: Option<UnifiedMessage>,
574+
575+
/// Identifier for payout method
576+
pub payout_method_id: Option<String>,
571577
}
572578

573579
/// The payout method information for response

0 commit comments

Comments
 (0)