Skip to content

Commit

Permalink
feat(router): Add support for network token migration (#6300)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
prasunna09 and hyperswitch-bot[bot] authored Nov 20, 2024
1 parent c04f81e commit 012e352
Show file tree
Hide file tree
Showing 7 changed files with 487 additions and 47 deletions.
25 changes: 24 additions & 1 deletion crates/api_models/src/events/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
ListCountriesCurrenciesResponse, PaymentMethodCollectLinkRenderRequest,
PaymentMethodCollectLinkRequest, PaymentMethodCollectLinkResponse,
PaymentMethodDeleteResponse, PaymentMethodListRequest, PaymentMethodListResponse,
PaymentMethodResponse, PaymentMethodUpdate,
PaymentMethodMigrateResponse, PaymentMethodResponse, PaymentMethodUpdate,
},
payments::{
self, ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints,
Expand Down Expand Up @@ -218,6 +218,29 @@ impl ApiEventMetric for PaymentMethodResponse {
}
}

impl ApiEventMetric for PaymentMethodMigrateResponse {
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.payment_method_response.payment_method_id.clone(),
payment_method: self.payment_method_response.payment_method,
payment_method_type: self.payment_method_response.payment_method_type,
})
}

#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.payment_method_response.payment_method_id.clone(),
payment_method: self.payment_method_response.payment_method_type,
payment_method_type: self.payment_method_response.payment_method_subtype,
})
}
}

impl ApiEventMetric for PaymentMethodUpdate {}

impl ApiEventMetric for DefaultPaymentMethod {
Expand Down
122 changes: 112 additions & 10 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ pub struct PaymentMethodMigrate {
/// Card Details
pub card: Option<MigrateCardDetail>,

/// Network token details
pub network_token: Option<MigrateNetworkTokenDetail>,

/// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
pub metadata: Option<pii::SecretSerdeValue>,

Expand Down Expand Up @@ -276,6 +279,24 @@ pub struct PaymentMethodMigrate {
pub network_transaction_id: Option<String>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct PaymentMethodMigrateResponse {
//payment method response when payment method entry is created
pub payment_method_response: PaymentMethodResponse,

//card data migration status
pub card_migrated: Option<bool>,

//network token data migration status
pub network_token_migrated: Option<bool>,

//connector mandate details migration status
pub connector_mandate_details_migrated: Option<bool>,

//network transaction id migration status
pub network_transaction_id_migrated: Option<bool>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct PaymentsMandateReference(
pub HashMap<id_type::MerchantConnectorAccountId, PaymentsMandateReferenceRecord>,
Expand Down Expand Up @@ -540,6 +561,53 @@ pub struct MigrateCardDetail {
pub card_type: Option<String>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MigrateNetworkTokenData {
/// Network Token Number
#[schema(value_type = String,example = "4111111145551142")]
pub network_token_number: CardNumber,

/// Network Token Expiry Month
#[schema(value_type = String,example = "10")]
pub network_token_exp_month: masking::Secret<String>,

/// Network Token Expiry Year
#[schema(value_type = String,example = "25")]
pub network_token_exp_year: masking::Secret<String>,

/// Card Holder Name
#[schema(value_type = String,example = "John Doe")]
pub card_holder_name: Option<masking::Secret<String>>,

/// Card Holder's Nick Name
#[schema(value_type = Option<String>,example = "John Doe")]
pub nick_name: Option<masking::Secret<String>>,

/// Card Issuing Country
pub card_issuing_country: Option<String>,

/// Card's Network
#[schema(value_type = Option<CardNetwork>)]
pub card_network: Option<api_enums::CardNetwork>,

/// Issuer Bank for Card
pub card_issuer: Option<String>,

/// Card Type
pub card_type: Option<String>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MigrateNetworkTokenDetail {
/// Network token details
pub network_token_data: MigrateNetworkTokenData,

/// Network token requestor reference id
pub network_token_requestor_ref_id: String,
}

#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
Expand Down Expand Up @@ -2082,6 +2150,10 @@ pub struct PaymentMethodRecord {
pub original_transaction_amount: Option<i64>,
pub original_transaction_currency: Option<common_enums::Currency>,
pub line_number: Option<i64>,
pub network_token_number: Option<CardNumber>,
pub network_token_expiry_month: Option<masking::Secret<String>>,
pub network_token_expiry_year: Option<masking::Secret<String>>,
pub network_token_requestor_ref_id: Option<String>,
}

#[derive(Debug, Default, serde::Serialize)]
Expand All @@ -2098,6 +2170,10 @@ pub struct PaymentMethodMigrationResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub migration_error: Option<String>,
pub card_number_masked: Option<masking::Secret<String>>,
pub card_migrated: Option<bool>,
pub network_token_migrated: Option<bool>,
pub connector_mandate_details_migrated: Option<bool>,
pub network_transaction_id_migrated: Option<bool>,
}

#[derive(Debug, Default, serde::Serialize)]
Expand All @@ -2107,8 +2183,10 @@ pub enum MigrationStatus {
Failed,
}

type PaymentMethodMigrationResponseType =
(Result<PaymentMethodResponse, String>, PaymentMethodRecord);
type PaymentMethodMigrationResponseType = (
Result<PaymentMethodMigrateResponse, String>,
PaymentMethodRecord,
);
#[cfg(all(
any(feature = "v2", feature = "v1"),
not(feature = "payment_methods_v2")
Expand All @@ -2117,14 +2195,18 @@ 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,
payment_method_id: Some(res.payment_method_response.payment_method_id),
payment_method: res.payment_method_response.payment_method,
payment_method_type: res.payment_method_response.payment_method_type,
customer_id: res.payment_method_response.customer_id,
migration_status: MigrationStatus::Success,
migration_error: None,
card_number_masked: Some(record.card_number_masked),
line_number: record.line_number,
card_migrated: res.card_migrated,
network_token_migrated: res.network_token_migrated,
connector_mandate_details_migrated: res.connector_mandate_details_migrated,
network_transaction_id_migrated: res.network_transaction_id_migrated,
},
Err(e) => Self {
customer_id: Some(record.customer_id),
Expand All @@ -2143,14 +2225,18 @@ 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_type,
payment_method_type: res.payment_method_subtype,
customer_id: Some(res.customer_id),
payment_method_id: Some(res.payment_method_response.payment_method_id),
payment_method: res.payment_method_response.payment_method_type,
payment_method_type: res.payment_method_response.payment_method_subtype,
customer_id: Some(res.payment_method_response.customer_id),
migration_status: MigrationStatus::Success,
migration_error: None,
card_number_masked: Some(record.card_number_masked),
line_number: record.line_number,
card_migrated: res.card_migrated,
network_token_migrated: res.network_token_migrated,
connector_mandate_details_migrated: res.connector_mandate_details_migrated,
network_transaction_id_migrated: res.network_transaction_id_migrated,
},
Err(e) => Self {
customer_id: Some(record.customer_id),
Expand Down Expand Up @@ -2213,6 +2299,22 @@ impl
card_issuing_country: None,
nick_name: Some(record.nick_name.clone()),
}),
network_token: Some(MigrateNetworkTokenDetail {
network_token_data: MigrateNetworkTokenData {
network_token_number: record.network_token_number.unwrap_or_default(),
network_token_exp_month: record.network_token_expiry_month.unwrap_or_default(),
network_token_exp_year: record.network_token_expiry_year.unwrap_or_default(),
card_holder_name: record.name,
nick_name: Some(record.nick_name.clone()),
card_issuing_country: None,
card_network: None,
card_issuer: None,
card_type: None,
},
network_token_requestor_ref_id: record
.network_token_requestor_ref_id
.unwrap_or_default(),
}),
payment_method: record.payment_method,
payment_method_type: record.payment_method_type,
payment_method_issuer: None,
Expand Down
26 changes: 26 additions & 0 deletions crates/diesel_models/src/payment_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ pub enum PaymentMethodUpdate {
ConnectorMandateDetailsUpdate {
connector_mandate_details: Option<serde_json::Value>,
},
NetworkTokenDataUpdate {
network_token_requestor_reference_id: Option<String>,
network_token_locker_id: Option<String>,
network_token_payment_method_data: Option<Encryption>,
},
}

#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
Expand Down Expand Up @@ -620,6 +625,27 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_locker_id: None,
network_token_payment_method_data: None,
},
PaymentMethodUpdate::NetworkTokenDataUpdate {
network_token_requestor_reference_id,
network_token_locker_id,
network_token_payment_method_data,
} => Self {
metadata: None,
payment_method_data: None,
last_used_at: None,
status: None,
locker_id: None,
payment_method: None,
connector_mandate_details: None,
updated_by: None,
payment_method_issuer: None,
payment_method_type: None,
last_modified: common_utils::date_time::now(),
network_transaction_id: None,
network_token_requestor_reference_id,
network_token_locker_id,
network_token_payment_method_data,
},
}
}
}
Expand Down
Loading

0 comments on commit 012e352

Please sign in to comment.