Files
Sarthak Soni c3cc887ea3 feat(payment_methods_v2): Implemented Diesel and Domain models for v2 (#5700)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
2024-09-04 12:30:42 +00:00

381 lines
16 KiB
Rust

use common_utils::{
crypto::OptionalEncryptableValue,
// date_time,
// encryption::Encryption,
errors::{CustomResult, ValidationError},
pii,
type_name,
types::keymanager,
};
use diesel_models::enums as storage_enums;
use error_stack::ResultExt;
use masking::{PeekInterface, Secret};
use time::PrimitiveDateTime;
use crate::type_encryption::{crypto_operation, AsyncLift, CryptoOperation};
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
#[derive(Clone, Debug)]
pub struct PaymentMethod {
pub customer_id: common_utils::id_type::CustomerId,
pub merchant_id: common_utils::id_type::MerchantId,
pub payment_method_id: String,
pub accepted_currency: Option<Vec<storage_enums::Currency>>,
pub scheme: Option<String>,
pub token: Option<String>,
pub cardholder_name: Option<Secret<String>>,
pub issuer_name: Option<String>,
pub issuer_country: Option<String>,
pub payer_country: Option<Vec<String>>,
pub is_stored: Option<bool>,
pub swift_code: Option<String>,
pub direct_debit_token: Option<String>,
pub created_at: PrimitiveDateTime,
pub last_modified: PrimitiveDateTime,
pub payment_method: Option<storage_enums::PaymentMethod>,
pub payment_method_type: Option<storage_enums::PaymentMethodType>,
pub payment_method_issuer: Option<String>,
pub payment_method_issuer_code: Option<storage_enums::PaymentMethodIssuerCode>,
pub metadata: Option<pii::SecretSerdeValue>,
pub payment_method_data: OptionalEncryptableValue,
pub locker_id: Option<String>,
pub last_used_at: PrimitiveDateTime,
pub connector_mandate_details: Option<serde_json::Value>,
pub customer_acceptance: Option<pii::SecretSerdeValue>,
pub status: storage_enums::PaymentMethodStatus,
pub network_transaction_id: Option<String>,
pub client_secret: Option<String>,
pub payment_method_billing_address: OptionalEncryptableValue,
pub updated_by: Option<String>,
pub version: common_enums::ApiVersion,
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Clone, Debug)]
pub struct PaymentMethod {
pub customer_id: common_utils::id_type::CustomerId,
pub merchant_id: common_utils::id_type::MerchantId,
pub created_at: PrimitiveDateTime,
pub last_modified: PrimitiveDateTime,
pub payment_method: Option<storage_enums::PaymentMethod>,
pub payment_method_type: Option<storage_enums::PaymentMethodType>,
pub metadata: Option<pii::SecretSerdeValue>,
pub payment_method_data: OptionalEncryptableValue,
pub locker_id: Option<String>,
pub last_used_at: PrimitiveDateTime,
pub connector_mandate_details: Option<pii::SecretSerdeValue>,
pub customer_acceptance: Option<pii::SecretSerdeValue>,
pub status: storage_enums::PaymentMethodStatus,
pub network_transaction_id: Option<String>,
pub client_secret: Option<String>,
pub payment_method_billing_address: OptionalEncryptableValue,
pub updated_by: Option<String>,
pub locker_fingerprint_id: Option<String>,
pub id: String,
pub version: common_enums::ApiVersion,
}
impl PaymentMethod {
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
pub fn get_id(&self) -> &String {
&self.payment_method_id
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
pub fn get_id(&self) -> &String {
&self.id
}
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
#[async_trait::async_trait]
impl super::behaviour::Conversion for PaymentMethod {
type DstType = diesel_models::payment_method::PaymentMethod;
type NewDstType = diesel_models::payment_method::PaymentMethodNew;
async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
Ok(Self::DstType {
customer_id: self.customer_id,
merchant_id: self.merchant_id,
payment_method_id: self.payment_method_id,
accepted_currency: self.accepted_currency,
scheme: self.scheme,
token: self.token,
cardholder_name: self.cardholder_name,
issuer_name: self.issuer_name,
issuer_country: self.issuer_country,
payer_country: self.payer_country,
is_stored: self.is_stored,
swift_code: self.swift_code,
direct_debit_token: self.direct_debit_token,
created_at: self.created_at,
last_modified: self.last_modified,
payment_method: self.payment_method,
payment_method_type: self.payment_method_type,
payment_method_issuer: self.payment_method_issuer,
payment_method_issuer_code: self.payment_method_issuer_code,
metadata: self.metadata,
payment_method_data: self.payment_method_data.map(|val| val.into()),
locker_id: self.locker_id,
last_used_at: self.last_used_at,
connector_mandate_details: self.connector_mandate_details,
customer_acceptance: self.customer_acceptance,
status: self.status,
network_transaction_id: self.network_transaction_id,
client_secret: self.client_secret,
payment_method_billing_address: self
.payment_method_billing_address
.map(|val| val.into()),
updated_by: self.updated_by,
version: self.version,
})
}
async fn convert_back(
state: &keymanager::KeyManagerState,
item: Self::DstType,
key: &Secret<Vec<u8>>,
key_manager_identifier: keymanager::Identifier,
) -> CustomResult<Self, ValidationError>
where
Self: Sized,
{
async {
Ok::<Self, error_stack::Report<common_utils::errors::CryptoError>>(Self {
customer_id: item.customer_id,
merchant_id: item.merchant_id,
payment_method_id: item.payment_method_id,
accepted_currency: item.accepted_currency,
scheme: item.scheme,
token: item.token,
cardholder_name: item.cardholder_name,
issuer_name: item.issuer_name,
issuer_country: item.issuer_country,
payer_country: item.payer_country,
is_stored: item.is_stored,
swift_code: item.swift_code,
direct_debit_token: item.direct_debit_token,
created_at: item.created_at,
last_modified: item.last_modified,
payment_method: item.payment_method,
payment_method_type: item.payment_method_type,
payment_method_issuer: item.payment_method_issuer,
payment_method_issuer_code: item.payment_method_issuer_code,
metadata: item.metadata,
payment_method_data: item
.payment_method_data
.async_lift(|inner| async {
crypto_operation(
state,
type_name!(Self::DstType),
CryptoOperation::DecryptOptional(inner),
key_manager_identifier.clone(),
key.peek(),
)
.await
.and_then(|val| val.try_into_optionaloperation())
})
.await?,
locker_id: item.locker_id,
last_used_at: item.last_used_at,
connector_mandate_details: item.connector_mandate_details,
customer_acceptance: item.customer_acceptance,
status: item.status,
network_transaction_id: item.network_transaction_id,
client_secret: item.client_secret,
payment_method_billing_address: item
.payment_method_billing_address
.async_lift(|inner| async {
crypto_operation(
state,
type_name!(Self::DstType),
CryptoOperation::DecryptOptional(inner),
key_manager_identifier.clone(),
key.peek(),
)
.await
.and_then(|val| val.try_into_optionaloperation())
})
.await?,
updated_by: item.updated_by,
version: item.version,
})
}
.await
.change_context(ValidationError::InvalidValue {
message: "Failed while decrypting payment method data".to_string(),
})
}
async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
Ok(Self::NewDstType {
customer_id: self.customer_id,
merchant_id: self.merchant_id,
payment_method_id: self.payment_method_id,
accepted_currency: self.accepted_currency,
scheme: self.scheme,
token: self.token,
cardholder_name: self.cardholder_name,
issuer_name: self.issuer_name,
issuer_country: self.issuer_country,
payer_country: self.payer_country,
is_stored: self.is_stored,
swift_code: self.swift_code,
direct_debit_token: self.direct_debit_token,
created_at: self.created_at,
last_modified: self.last_modified,
payment_method: self.payment_method,
payment_method_type: self.payment_method_type,
payment_method_issuer: self.payment_method_issuer,
payment_method_issuer_code: self.payment_method_issuer_code,
metadata: self.metadata,
payment_method_data: self.payment_method_data.map(|val| val.into()),
locker_id: self.locker_id,
last_used_at: self.last_used_at,
connector_mandate_details: self.connector_mandate_details,
customer_acceptance: self.customer_acceptance,
status: self.status,
network_transaction_id: self.network_transaction_id,
client_secret: self.client_secret,
payment_method_billing_address: self
.payment_method_billing_address
.map(|val| val.into()),
updated_by: self.updated_by,
version: self.version,
})
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[async_trait::async_trait]
impl super::behaviour::Conversion for PaymentMethod {
type DstType = diesel_models::payment_method::PaymentMethod;
type NewDstType = diesel_models::payment_method::PaymentMethodNew;
async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
Ok(Self::DstType {
customer_id: self.customer_id,
merchant_id: self.merchant_id,
id: self.id,
created_at: self.created_at,
last_modified: self.last_modified,
payment_method: self.payment_method,
payment_method_type: self.payment_method_type,
metadata: self.metadata,
payment_method_data: self.payment_method_data.map(|val| val.into()),
locker_id: self.locker_id,
last_used_at: self.last_used_at,
connector_mandate_details: self.connector_mandate_details,
customer_acceptance: self.customer_acceptance,
status: self.status,
network_transaction_id: self.network_transaction_id,
client_secret: self.client_secret,
payment_method_billing_address: self
.payment_method_billing_address
.map(|val| val.into()),
updated_by: self.updated_by,
locker_fingerprint_id: self.locker_fingerprint_id,
version: self.version,
})
}
async fn convert_back(
state: &keymanager::KeyManagerState,
item: Self::DstType,
key: &Secret<Vec<u8>>,
key_manager_identifier: keymanager::Identifier,
) -> CustomResult<Self, ValidationError>
where
Self: Sized,
{
async {
Ok::<Self, error_stack::Report<common_utils::errors::CryptoError>>(Self {
customer_id: item.customer_id,
merchant_id: item.merchant_id,
id: item.id,
created_at: item.created_at,
last_modified: item.last_modified,
payment_method: item.payment_method,
payment_method_type: item.payment_method_type,
metadata: item.metadata,
payment_method_data: item
.payment_method_data
.async_lift(|inner| async {
crypto_operation(
state,
type_name!(Self::DstType),
CryptoOperation::DecryptOptional(inner),
key_manager_identifier.clone(),
key.peek(),
)
.await
.and_then(|val| val.try_into_optionaloperation())
})
.await?,
locker_id: item.locker_id,
last_used_at: item.last_used_at,
connector_mandate_details: item.connector_mandate_details,
customer_acceptance: item.customer_acceptance,
status: item.status,
network_transaction_id: item.network_transaction_id,
client_secret: item.client_secret,
payment_method_billing_address: item
.payment_method_billing_address
.async_lift(|inner| async {
crypto_operation(
state,
type_name!(Self::DstType),
CryptoOperation::DecryptOptional(inner),
key_manager_identifier.clone(),
key.peek(),
)
.await
.and_then(|val| val.try_into_optionaloperation())
})
.await?,
updated_by: item.updated_by,
locker_fingerprint_id: item.locker_fingerprint_id,
version: item.version,
})
}
.await
.change_context(ValidationError::InvalidValue {
message: "Failed while decrypting payment method data".to_string(),
})
}
async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
Ok(Self::NewDstType {
customer_id: self.customer_id,
merchant_id: self.merchant_id,
id: self.id,
created_at: self.created_at,
last_modified: self.last_modified,
payment_method: self.payment_method,
payment_method_type: self.payment_method_type,
metadata: self.metadata,
payment_method_data: self.payment_method_data.map(|val| val.into()),
locker_id: self.locker_id,
last_used_at: self.last_used_at,
connector_mandate_details: self.connector_mandate_details,
customer_acceptance: self.customer_acceptance,
status: self.status,
network_transaction_id: self.network_transaction_id,
client_secret: self.client_secret,
payment_method_billing_address: self
.payment_method_billing_address
.map(|val| val.into()),
updated_by: self.updated_by,
locker_fingerprint_id: self.locker_fingerprint_id,
version: self.version,
})
}
}