mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 12:15:40 +08:00
feat(connector): [AUTHORIZEDOTNET] Support payment_method_id in recurring mandate payment (#4841)
This commit is contained in:
@ -1,16 +1,15 @@
|
|||||||
use common_utils::{
|
use common_utils::{
|
||||||
errors::CustomResult,
|
errors::CustomResult,
|
||||||
ext_traits::{Encode, ValueExt},
|
ext_traits::{Encode, ValueExt},
|
||||||
id_type, pii,
|
|
||||||
};
|
};
|
||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
use masking::{ExposeInterface, PeekInterface, Secret, StrongSecret};
|
use masking::{ExposeInterface, PeekInterface, Secret, StrongSecret};
|
||||||
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
connector::utils::{
|
connector::utils::{
|
||||||
self, missing_field_err, CardData, PaymentsSyncRequestData, RefundsRequestData, RouterData,
|
self, CardData, PaymentsSyncRequestData, RefundsRequestData, RouterData, WalletData,
|
||||||
WalletData,
|
|
||||||
},
|
},
|
||||||
core::errors,
|
core::errors,
|
||||||
services,
|
services,
|
||||||
@ -179,7 +178,7 @@ struct PaymentProfileDetails {
|
|||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CustomerDetails {
|
pub struct CustomerDetails {
|
||||||
id: id_type::CustomerId,
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
@ -273,10 +272,7 @@ pub struct AuthorizedotnetZeroMandateRequest {
|
|||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct Profile {
|
struct Profile {
|
||||||
merchant_customer_id: id_type::CustomerId,
|
description: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
description: Option<String>,
|
|
||||||
email: Option<pii::Email>,
|
|
||||||
payment_profiles: PaymentProfiles,
|
payment_profiles: PaymentProfiles,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,12 +314,8 @@ impl TryFrom<&types::SetupMandateRouterData> for CreateCustomerProfileRequest {
|
|||||||
create_customer_profile_request: AuthorizedotnetZeroMandateRequest {
|
create_customer_profile_request: AuthorizedotnetZeroMandateRequest {
|
||||||
merchant_authentication,
|
merchant_authentication,
|
||||||
profile: Profile {
|
profile: Profile {
|
||||||
merchant_customer_id: item
|
//The payment ID is included in the description because the connector requires unique description when creating a mandate.
|
||||||
.customer_id
|
description: item.payment_id.clone(),
|
||||||
.clone()
|
|
||||||
.ok_or_else(missing_field_err("customer_id"))?,
|
|
||||||
description: item.description.clone(),
|
|
||||||
email: item.request.email.clone(),
|
|
||||||
payment_profiles: PaymentProfiles {
|
payment_profiles: PaymentProfiles {
|
||||||
customer_type: CustomerType::Individual,
|
customer_type: CustomerType::Individual,
|
||||||
payment: PaymentDetails::CreditCard(CreditCardDetails {
|
payment: PaymentDetails::CreditCard(CreditCardDetails {
|
||||||
@ -393,16 +385,18 @@ impl<F, T>
|
|||||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||||
resource_id: types::ResponseId::NoResponseId,
|
resource_id: types::ResponseId::NoResponseId,
|
||||||
redirection_data: None,
|
redirection_data: None,
|
||||||
mandate_reference: item.response.customer_profile_id.map(|mandate_id| {
|
mandate_reference: item.response.customer_profile_id.map(
|
||||||
types::MandateReference {
|
|customer_profile_id| types::MandateReference {
|
||||||
connector_mandate_id: Some(mandate_id),
|
connector_mandate_id: item
|
||||||
payment_method_id: item
|
|
||||||
.response
|
.response
|
||||||
.customer_payment_profile_id_list
|
.customer_payment_profile_id_list
|
||||||
.first()
|
.first()
|
||||||
.cloned(),
|
.map(|payment_profile_id| {
|
||||||
}
|
format!("{customer_profile_id}-{payment_profile_id}")
|
||||||
}),
|
}),
|
||||||
|
payment_method_id: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
connector_metadata: None,
|
connector_metadata: None,
|
||||||
network_txn_id: None,
|
network_txn_id: None,
|
||||||
connector_response_reference_id: None,
|
connector_response_reference_id: None,
|
||||||
@ -635,27 +629,24 @@ impl
|
|||||||
api_models::payments::ConnectorMandateReferenceId,
|
api_models::payments::ConnectorMandateReferenceId,
|
||||||
),
|
),
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
|
let mandate_id = connector_mandate_id
|
||||||
|
.connector_mandate_id
|
||||||
|
.ok_or(errors::ConnectorError::MissingConnectorMandateID)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?,
|
transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?,
|
||||||
amount: item.amount,
|
amount: item.amount,
|
||||||
currency_code: item.router_data.request.currency,
|
currency_code: item.router_data.request.currency,
|
||||||
payment: None,
|
payment: None,
|
||||||
profile: Some(ProfileDetails::CustomerProfileDetails(
|
profile: mandate_id
|
||||||
CustomerProfileDetails {
|
.split_once('-')
|
||||||
customer_profile_id: Secret::from(
|
.map(|(customer_profile_id, payment_profile_id)| {
|
||||||
connector_mandate_id
|
ProfileDetails::CustomerProfileDetails(CustomerProfileDetails {
|
||||||
.connector_mandate_id
|
customer_profile_id: Secret::from(customer_profile_id.to_string()),
|
||||||
.ok_or(errors::ConnectorError::MissingConnectorMandateID)?,
|
payment_profile: PaymentProfileDetails {
|
||||||
),
|
payment_profile_id: Secret::from(payment_profile_id.to_string()),
|
||||||
payment_profile: PaymentProfileDetails {
|
},
|
||||||
payment_profile_id: Secret::from(
|
})
|
||||||
connector_mandate_id
|
}),
|
||||||
.payment_method_id
|
|
||||||
.ok_or(errors::ConnectorError::MissingConnectorMandateID)?,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
order: Order {
|
order: Order {
|
||||||
description: item.router_data.connector_request_reference_id.clone(),
|
description: item.router_data.connector_request_reference_id.clone(),
|
||||||
},
|
},
|
||||||
@ -709,11 +700,13 @@ impl
|
|||||||
create_profile: true,
|
create_profile: true,
|
||||||
})),
|
})),
|
||||||
Some(CustomerDetails {
|
Some(CustomerDetails {
|
||||||
id: item
|
//The payment ID is included in the customer details because the connector requires unique customer information with a length of fewer than 20 characters when creating a mandate.
|
||||||
.router_data
|
//If the length exceeds 20 characters, a random alphanumeric string is used instead.
|
||||||
.customer_id
|
id: if item.router_data.payment_id.len() <= 20 {
|
||||||
.clone()
|
item.router_data.payment_id.clone()
|
||||||
.ok_or_else(missing_field_err("customer_id"))?,
|
} else {
|
||||||
|
Alphanumeric.sample_string(&mut rand::thread_rng(), 20)
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -1087,6 +1080,24 @@ impl<F, T>
|
|||||||
.and_then(|x| x.secure_acceptance_url.to_owned());
|
.and_then(|x| x.secure_acceptance_url.to_owned());
|
||||||
let redirection_data =
|
let redirection_data =
|
||||||
url.map(|url| services::RedirectForm::from((url, services::Method::Get)));
|
url.map(|url| services::RedirectForm::from((url, services::Method::Get)));
|
||||||
|
let mandate_reference = item.response.profile_response.map(|profile_response| {
|
||||||
|
let payment_profile_id = profile_response
|
||||||
|
.customer_payment_profile_id_list
|
||||||
|
.and_then(|customer_payment_profile_id_list| {
|
||||||
|
customer_payment_profile_id_list.first().cloned()
|
||||||
|
});
|
||||||
|
types::MandateReference {
|
||||||
|
connector_mandate_id: profile_response.customer_profile_id.and_then(
|
||||||
|
|customer_profile_id| {
|
||||||
|
payment_profile_id.map(|payment_profile_id| {
|
||||||
|
format!("{customer_profile_id}-{payment_profile_id}")
|
||||||
|
})
|
||||||
|
},
|
||||||
|
),
|
||||||
|
payment_method_id: None,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
status,
|
status,
|
||||||
response: match error {
|
response: match error {
|
||||||
@ -1096,16 +1107,7 @@ impl<F, T>
|
|||||||
transaction_response.transaction_id.clone(),
|
transaction_response.transaction_id.clone(),
|
||||||
),
|
),
|
||||||
redirection_data,
|
redirection_data,
|
||||||
mandate_reference: item.response.profile_response.map(
|
mandate_reference,
|
||||||
|profile_response| types::MandateReference {
|
|
||||||
connector_mandate_id: profile_response.customer_profile_id,
|
|
||||||
payment_method_id: profile_response
|
|
||||||
.customer_payment_profile_id_list
|
|
||||||
.and_then(|customer_payment_profile_id_list| {
|
|
||||||
customer_payment_profile_id_list.first().cloned()
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
connector_metadata: metadata,
|
connector_metadata: metadata,
|
||||||
network_txn_id: transaction_response
|
network_txn_id: transaction_response
|
||||||
.network_trans_id
|
.network_trans_id
|
||||||
|
|||||||
Reference in New Issue
Block a user