refactor(core): add recurring customer support for nomupay payouts. (#6687)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Suman Maji
2025-02-05 19:03:11 +05:30
committed by GitHub
parent 899c207d58
commit 8d8ebe9051
25 changed files with 1355 additions and 238 deletions

View File

@ -243,7 +243,8 @@ pub struct PaymentMethodMigrate {
pub billing: Option<payments::Address>,
/// The connector mandate details of the payment method
pub connector_mandate_details: Option<PaymentsMandateReference>,
#[serde(deserialize_with = "deserialize_connector_mandate_details")]
pub connector_mandate_details: Option<CommonMandateReference>,
// The CIT (customer initiated transaction) transaction id associated with the payment method
pub network_transaction_id: Option<String>,
@ -267,12 +268,22 @@ pub struct PaymentMethodMigrateResponse {
pub network_transaction_id_migrated: Option<bool>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct PaymentsMandateReference(
pub HashMap<id_type::MerchantConnectorAccountId, PaymentsMandateReferenceRecord>,
);
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct PayoutsMandateReference(
pub HashMap<id_type::MerchantConnectorAccountId, PayoutsMandateReferenceRecord>,
);
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct PayoutsMandateReferenceRecord {
pub transfer_method_id: Option<String>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct PaymentsMandateReferenceRecord {
pub connector_mandate_id: String,
pub payment_method_type: Option<common_enums::PaymentMethodType>,
@ -280,6 +291,80 @@ pub struct PaymentsMandateReferenceRecord {
pub original_payment_authorized_currency: Option<common_enums::Currency>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct CommonMandateReference {
pub payments: Option<PaymentsMandateReference>,
pub payouts: Option<PayoutsMandateReference>,
}
impl From<CommonMandateReference> for PaymentsMandateReference {
fn from(common_mandate: CommonMandateReference) -> Self {
common_mandate.payments.unwrap_or_default()
}
}
impl From<PaymentsMandateReference> for CommonMandateReference {
fn from(payments_reference: PaymentsMandateReference) -> Self {
Self {
payments: Some(payments_reference),
payouts: None,
}
}
}
fn deserialize_connector_mandate_details<'de, D>(
deserializer: D,
) -> Result<Option<CommonMandateReference>, D::Error>
where
D: serde::Deserializer<'de>,
{
let value: Option<serde_json::Value> =
<Option<serde_json::Value> as de::Deserialize>::deserialize(deserializer)?;
let payments_data = value
.clone()
.map(|mut mandate_details| {
mandate_details
.as_object_mut()
.map(|obj| obj.remove("payouts"));
serde_json::from_value::<PaymentsMandateReference>(mandate_details)
})
.transpose()
.map_err(|err| {
let err_msg = format!("{err:?}");
de::Error::custom(format_args!(
"Failed to deserialize PaymentsMandateReference `{}`",
err_msg
))
})?;
let payouts_data = value
.clone()
.map(|mandate_details| {
serde_json::from_value::<Option<CommonMandateReference>>(mandate_details).map(
|optional_common_mandate_details| {
optional_common_mandate_details
.and_then(|common_mandate_details| common_mandate_details.payouts)
},
)
})
.transpose()
.map_err(|err| {
let err_msg = format!("{err:?}");
de::Error::custom(format_args!(
"Failed to deserialize CommonMandateReference `{}`",
err_msg
))
})?
.flatten();
Ok(Some(CommonMandateReference {
payments: payments_data,
payouts: payouts_data,
}))
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
@ -313,7 +398,12 @@ impl PaymentMethodCreate {
payment_method_issuer_code: payment_method_migrate.payment_method_issuer_code,
metadata: payment_method_migrate.metadata.clone(),
payment_method_data: payment_method_migrate.payment_method_data.clone(),
connector_mandate_details: payment_method_migrate.connector_mandate_details.clone(),
connector_mandate_details: payment_method_migrate
.connector_mandate_details
.clone()
.map(|common_mandate_reference| {
PaymentsMandateReference::from(common_mandate_reference)
}),
client_secret: None,
billing: payment_method_migrate.billing.clone(),
card: card_details,
@ -2328,7 +2418,11 @@ impl
}),
email: record.email,
}),
connector_mandate_details,
connector_mandate_details: connector_mandate_details.map(
|payments_mandate_reference| {
CommonMandateReference::from(payments_mandate_reference)
},
),
metadata: None,
payment_method_issuer_code: None,
card_network: None,

View File

@ -184,6 +184,9 @@ pub struct PayoutCreateRequest {
/// Customer's phone country code. _Deprecated: Use customer object instead._
#[schema(deprecated, max_length = 255, example = "+1")]
pub phone_country_code: Option<String>,
/// Identifier for payout method
pub payout_method_id: Option<String>,
}
impl PayoutCreateRequest {
@ -568,6 +571,9 @@ pub struct PayoutCreateResponse {
#[remove_in(PayoutCreateResponse)]
#[schema(value_type = Option<String>, max_length = 1024, example = "Invalid card details")]
pub unified_message: Option<UnifiedMessage>,
/// Identifier for payout method
pub payout_method_id: Option<String>,
}
/// The payout method information for response