Skip to content

Commit 8d8ebe9

Browse files
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 899c207 commit 8d8ebe9

File tree

25 files changed

+1355
-238
lines changed

25 files changed

+1355
-238
lines changed

api-reference-v2/openapi_spec.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16999,6 +16999,11 @@
1699916999
"example": "+1",
1700017000
"nullable": true,
1700117001
"maxLength": 255
17002+
},
17003+
"payout_method_id": {
17004+
"type": "string",
17005+
"description": "Identifier for payout method",
17006+
"nullable": true
1700217007
}
1700317008
},
1700417009
"additionalProperties": false
@@ -17238,6 +17243,11 @@
1723817243
"example": "Invalid card details",
1723917244
"nullable": true,
1724017245
"maxLength": 1024
17246+
},
17247+
"payout_method_id": {
17248+
"type": "string",
17249+
"description": "Identifier for payout method",
17250+
"nullable": true
1724117251
}
1724217252
},
1724317253
"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
@@ -243,7 +243,8 @@ pub struct PaymentMethodMigrate {
243243
pub billing: Option<payments::Address>,
244244

245245
/// The connector mandate details of the payment method
246-
pub connector_mandate_details: Option<PaymentsMandateReference>,
246+
#[serde(deserialize_with = "deserialize_connector_mandate_details")]
247+
pub connector_mandate_details: Option<CommonMandateReference>,
247248

248249
// The CIT (customer initiated transaction) transaction id associated with the payment method
249250
pub network_transaction_id: Option<String>,
@@ -267,19 +268,103 @@ pub struct PaymentMethodMigrateResponse {
267268
pub network_transaction_id_migrated: Option<bool>,
268269
}
269270

270-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
271+
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
271272
pub struct PaymentsMandateReference(
272273
pub HashMap<id_type::MerchantConnectorAccountId, PaymentsMandateReferenceRecord>,
273274
);
274275

275-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
276+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
277+
pub struct PayoutsMandateReference(
278+
pub HashMap<id_type::MerchantConnectorAccountId, PayoutsMandateReferenceRecord>,
279+
);
280+
281+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
282+
pub struct PayoutsMandateReferenceRecord {
283+
pub transfer_method_id: Option<String>,
284+
}
285+
286+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
276287
pub struct PaymentsMandateReferenceRecord {
277288
pub connector_mandate_id: String,
278289
pub payment_method_type: Option<common_enums::PaymentMethodType>,
279290
pub original_payment_authorized_amount: Option<i64>,
280291
pub original_payment_authorized_currency: Option<common_enums::Currency>,
281292
}
282293

294+
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
295+
pub struct CommonMandateReference {
296+
pub payments: Option<PaymentsMandateReference>,
297+
pub payouts: Option<PayoutsMandateReference>,
298+
}
299+
300+
impl From<CommonMandateReference> for PaymentsMandateReference {
301+
fn from(common_mandate: CommonMandateReference) -> Self {
302+
common_mandate.payments.unwrap_or_default()
303+
}
304+
}
305+
306+
impl From<PaymentsMandateReference> for CommonMandateReference {
307+
fn from(payments_reference: PaymentsMandateReference) -> Self {
308+
Self {
309+
payments: Some(payments_reference),
310+
payouts: None,
311+
}
312+
}
313+
}
314+
315+
fn deserialize_connector_mandate_details<'de, D>(
316+
deserializer: D,
317+
) -> Result<Option<CommonMandateReference>, D::Error>
318+
where
319+
D: serde::Deserializer<'de>,
320+
{
321+
let value: Option<serde_json::Value> =
322+
<Option<serde_json::Value> as de::Deserialize>::deserialize(deserializer)?;
323+
324+
let payments_data = value
325+
.clone()
326+
.map(|mut mandate_details| {
327+
mandate_details
328+
.as_object_mut()
329+
.map(|obj| obj.remove("payouts"));
330+
331+
serde_json::from_value::<PaymentsMandateReference>(mandate_details)
332+
})
333+
.transpose()
334+
.map_err(|err| {
335+
let err_msg = format!("{err:?}");
336+
de::Error::custom(format_args!(
337+
"Failed to deserialize PaymentsMandateReference `{}`",
338+
err_msg
339+
))
340+
})?;
341+
342+
let payouts_data = value
343+
.clone()
344+
.map(|mandate_details| {
345+
serde_json::from_value::<Option<CommonMandateReference>>(mandate_details).map(
346+
|optional_common_mandate_details| {
347+
optional_common_mandate_details
348+
.and_then(|common_mandate_details| common_mandate_details.payouts)
349+
},
350+
)
351+
})
352+
.transpose()
353+
.map_err(|err| {
354+
let err_msg = format!("{err:?}");
355+
de::Error::custom(format_args!(
356+
"Failed to deserialize CommonMandateReference `{}`",
357+
err_msg
358+
))
359+
})?
360+
.flatten();
361+
362+
Ok(Some(CommonMandateReference {
363+
payments: payments_data,
364+
payouts: payouts_data,
365+
}))
366+
}
367+
283368
#[cfg(all(
284369
any(feature = "v1", feature = "v2"),
285370
not(feature = "payment_methods_v2")
@@ -313,7 +398,12 @@ impl PaymentMethodCreate {
313398
payment_method_issuer_code: payment_method_migrate.payment_method_issuer_code,
314399
metadata: payment_method_migrate.metadata.clone(),
315400
payment_method_data: payment_method_migrate.payment_method_data.clone(),
316-
connector_mandate_details: payment_method_migrate.connector_mandate_details.clone(),
401+
connector_mandate_details: payment_method_migrate
402+
.connector_mandate_details
403+
.clone()
404+
.map(|common_mandate_reference| {
405+
PaymentsMandateReference::from(common_mandate_reference)
406+
}),
317407
client_secret: None,
318408
billing: payment_method_migrate.billing.clone(),
319409
card: card_details,
@@ -2328,7 +2418,11 @@ impl
23282418
}),
23292419
email: record.email,
23302420
}),
2331-
connector_mandate_details,
2421+
connector_mandate_details: connector_mandate_details.map(
2422+
|payments_mandate_reference| {
2423+
CommonMandateReference::from(payments_mandate_reference)
2424+
},
2425+
),
23322426
metadata: None,
23332427
payment_method_issuer_code: None,
23342428
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)