mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 09:38:33 +08:00
feat(payment_methods): add support to migrate existing customer PMs from processor to hyperswitch (#5306)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -7,13 +7,14 @@ use common_utils::{
|
||||
id_type, link_utils, pii,
|
||||
types::{MinorUnit, Percentage, Surcharge},
|
||||
};
|
||||
use masking::PeekInterface;
|
||||
use serde::de;
|
||||
use utoipa::{schema, ToSchema};
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
use crate::payouts;
|
||||
use crate::{
|
||||
admin, enums as api_enums,
|
||||
admin, customers, enums as api_enums,
|
||||
payments::{self, BankCodeResponse},
|
||||
};
|
||||
|
||||
@ -1335,3 +1336,177 @@ pub struct TokenizedBankRedirectValue1 {
|
||||
pub struct TokenizedBankRedirectValue2 {
|
||||
pub customer_id: Option<id_type::CustomerId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
|
||||
pub struct PaymentMethodRecord {
|
||||
pub customer_id: id_type::CustomerId,
|
||||
pub name: Option<masking::Secret<String>>,
|
||||
pub email: Option<pii::Email>,
|
||||
pub phone: Option<masking::Secret<String>>,
|
||||
pub phone_country_code: Option<String>,
|
||||
pub merchant_id: String,
|
||||
pub payment_method: Option<api_enums::PaymentMethod>,
|
||||
pub payment_method_type: Option<api_enums::PaymentMethodType>,
|
||||
pub nick_name: masking::Secret<String>,
|
||||
pub payment_instrument_id: masking::Secret<String>,
|
||||
pub card_number_masked: masking::Secret<String>,
|
||||
pub card_expiry_month: masking::Secret<String>,
|
||||
pub card_expiry_year: masking::Secret<String>,
|
||||
pub card_scheme: Option<String>,
|
||||
pub original_transaction_id: String,
|
||||
pub billing_address_zip: masking::Secret<String>,
|
||||
pub billing_address_state: masking::Secret<String>,
|
||||
pub billing_address_first_name: masking::Secret<String>,
|
||||
pub billing_address_last_name: masking::Secret<String>,
|
||||
pub billing_address_city: String,
|
||||
pub billing_address_country: Option<api_enums::CountryAlpha2>,
|
||||
pub billing_address_line1: masking::Secret<String>,
|
||||
pub billing_address_line2: Option<masking::Secret<String>>,
|
||||
pub billing_address_line3: Option<masking::Secret<String>>,
|
||||
pub raw_card_number: Option<masking::Secret<String>>,
|
||||
pub merchant_connector_id: String,
|
||||
pub original_transaction_amount: Option<i64>,
|
||||
pub original_transaction_currency: Option<common_enums::Currency>,
|
||||
pub line_number: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, serde::Serialize)]
|
||||
pub struct PaymentMethodMigrationResponse {
|
||||
pub line_number: Option<i64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub payment_method_id: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub payment_method: Option<api_enums::PaymentMethod>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub payment_method_type: Option<api_enums::PaymentMethodType>,
|
||||
pub customer_id: Option<id_type::CustomerId>,
|
||||
pub migration_status: MigrationStatus,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub migration_error: Option<String>,
|
||||
pub card_number_masked: Option<masking::Secret<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, serde::Serialize)]
|
||||
pub enum MigrationStatus {
|
||||
Success,
|
||||
#[default]
|
||||
Failed,
|
||||
}
|
||||
|
||||
type PaymentMethodMigrationResponseType =
|
||||
(Result<PaymentMethodResponse, String>, PaymentMethodRecord);
|
||||
impl From<PaymentMethodMigrationResponseType> for PaymentMethodMigrationResponse {
|
||||
fn from((response, record): PaymentMethodMigrationResponseType) -> Self {
|
||||
match response {
|
||||
Ok(res) => Self {
|
||||
payment_method_id: Some(res.payment_method_id),
|
||||
payment_method: res.payment_method,
|
||||
payment_method_type: res.payment_method_type,
|
||||
customer_id: res.customer_id,
|
||||
migration_status: MigrationStatus::Success,
|
||||
migration_error: None,
|
||||
card_number_masked: Some(record.card_number_masked),
|
||||
line_number: record.line_number,
|
||||
},
|
||||
Err(e) => Self {
|
||||
customer_id: Some(record.customer_id),
|
||||
migration_status: MigrationStatus::Failed,
|
||||
migration_error: Some(e),
|
||||
card_number_masked: Some(record.card_number_masked),
|
||||
line_number: record.line_number,
|
||||
..Self::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PaymentMethodRecord> for PaymentMethodMigrate {
|
||||
fn from(record: PaymentMethodRecord) -> Self {
|
||||
let mut mandate_reference = HashMap::new();
|
||||
mandate_reference.insert(
|
||||
record.merchant_connector_id,
|
||||
PaymentsMandateReferenceRecord {
|
||||
connector_mandate_id: record.payment_instrument_id.peek().to_string(),
|
||||
payment_method_type: record.payment_method_type,
|
||||
original_payment_authorized_amount: record
|
||||
.original_transaction_amount
|
||||
.or(Some(1000)),
|
||||
original_payment_authorized_currency: record
|
||||
.original_transaction_currency
|
||||
.or(Some(common_enums::Currency::USD)),
|
||||
},
|
||||
);
|
||||
Self {
|
||||
merchant_id: record.merchant_id,
|
||||
customer_id: Some(record.customer_id),
|
||||
card: Some(MigrateCardDetail {
|
||||
card_number: record.raw_card_number.unwrap_or(record.card_number_masked),
|
||||
card_exp_month: record.card_expiry_month,
|
||||
card_exp_year: record.card_expiry_year,
|
||||
card_holder_name: record.name,
|
||||
card_network: None,
|
||||
card_type: None,
|
||||
card_issuer: None,
|
||||
card_issuing_country: None,
|
||||
nick_name: Some(record.nick_name),
|
||||
}),
|
||||
payment_method: record.payment_method,
|
||||
payment_method_type: record.payment_method_type,
|
||||
payment_method_issuer: None,
|
||||
billing: Some(payments::Address {
|
||||
address: Some(payments::AddressDetails {
|
||||
city: Some(record.billing_address_city),
|
||||
country: record.billing_address_country,
|
||||
line1: Some(record.billing_address_line1),
|
||||
line2: record.billing_address_line2,
|
||||
state: Some(record.billing_address_state),
|
||||
line3: record.billing_address_line3,
|
||||
zip: Some(record.billing_address_zip),
|
||||
first_name: Some(record.billing_address_first_name),
|
||||
last_name: Some(record.billing_address_last_name),
|
||||
}),
|
||||
phone: Some(payments::PhoneDetails {
|
||||
number: record.phone,
|
||||
country_code: record.phone_country_code,
|
||||
}),
|
||||
email: record.email,
|
||||
}),
|
||||
connector_mandate_details: Some(PaymentsMandateReference(mandate_reference)),
|
||||
metadata: None,
|
||||
payment_method_issuer_code: None,
|
||||
card_network: None,
|
||||
#[cfg(feature = "payouts")]
|
||||
bank_transfer: None,
|
||||
#[cfg(feature = "payouts")]
|
||||
wallet: None,
|
||||
payment_method_data: None,
|
||||
network_transaction_id: record.original_transaction_id.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PaymentMethodRecord> for customers::CustomerRequest {
|
||||
fn from(record: PaymentMethodRecord) -> Self {
|
||||
Self {
|
||||
customer_id: Some(record.customer_id),
|
||||
merchant_id: record.merchant_id,
|
||||
name: record.name,
|
||||
email: record.email,
|
||||
phone: record.phone,
|
||||
description: None,
|
||||
phone_country_code: record.phone_country_code,
|
||||
address: Some(payments::AddressDetails {
|
||||
city: Some(record.billing_address_city),
|
||||
country: record.billing_address_country,
|
||||
line1: Some(record.billing_address_line1),
|
||||
line2: record.billing_address_line2,
|
||||
state: Some(record.billing_address_state),
|
||||
line3: record.billing_address_line3,
|
||||
zip: Some(record.billing_address_zip),
|
||||
first_name: Some(record.billing_address_first_name),
|
||||
last_name: Some(record.billing_address_last_name),
|
||||
}),
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user