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>
This commit is contained in:
Sarthak Soni
2024-09-04 18:00:42 +05:30
committed by GitHub
parent 1c39cc1262
commit c3cc887ea3
39 changed files with 2712 additions and 668 deletions

View File

@ -12,9 +12,9 @@ pub mod transformers;
use common_utils::{
consts,
crypto::{HmacSha256, SignMessage},
ext_traits::AsyncExt,
generate_id, type_name,
types::{self as util_types, keymanager::Identifier, AmountConvertor},
ext_traits::{AsyncExt, ValueExt},
generate_id,
types::{self as util_types, AmountConvertor},
};
use error_stack::ResultExt;
use helpers::PaymentAuthConnectorDataExt;
@ -42,12 +42,7 @@ use crate::{
logger,
routes::SessionState,
services::{pm_auth as pm_auth_services, ApplicationResponse},
types::{
self,
domain::{self, types::crypto_operation},
storage,
transformers::ForeignTryFrom,
},
types::{self, domain, storage, transformers::ForeignTryFrom},
};
pub async fn create_link_token(
@ -303,7 +298,6 @@ async fn store_bank_details_in_payment_methods(
connector_details: (&str, Secret<String>),
mca_id: common_utils::id_type::MerchantConnectorAccountId,
) -> RouterResult<()> {
let key = key_store.key.get_inner().peek();
let db = &*state.clone().store;
let (connector_name, access_token) = connector_details;
@ -322,8 +316,14 @@ async fn store_bank_details_in_payment_methods(
.customer_id
.ok_or(ApiErrorResponse::CustomerNotFound)?;
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
let payment_methods = db
.find_payment_method_by_customer_id_merchant_id_list(
&((&state).into()),
&key_store,
&customer_id,
merchant_account.get_id(),
None,
@ -331,10 +331,24 @@ async fn store_bank_details_in_payment_methods(
.await
.change_context(ApiErrorResponse::InternalServerError)?;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
let payment_methods = db
.find_payment_method_by_customer_id_merchant_id_status(
&((&state).into()),
&key_store,
&customer_id,
merchant_account.get_id(),
common_enums::enums::PaymentMethodStatus::Active,
None,
merchant_account.storage_scheme,
)
.await
.change_context(ApiErrorResponse::InternalServerError)?;
let mut hash_to_payment_method: HashMap<
String,
(
storage::PaymentMethod,
domain::PaymentMethod,
payment_methods::PaymentMethodDataBankCreds,
),
> = HashMap::new();
@ -343,33 +357,24 @@ async fn store_bank_details_in_payment_methods(
if pm.payment_method == Some(enums::PaymentMethod::BankDebit)
&& pm.payment_method_data.is_some()
{
let bank_details_pm_data = crypto_operation::<serde_json::Value, masking::WithType>(
&(&state).into(),
type_name!(storage::PaymentMethod),
domain::types::CryptoOperation::DecryptOptional(pm.payment_method_data.clone()),
Identifier::Merchant(key_store.merchant_id.clone()),
key,
)
.await
.and_then(|val| val.try_into_optionaloperation())
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("unable to decrypt bank account details")?
.map(|x| x.into_inner().expose())
.map(|v| {
serde_json::from_value::<payment_methods::PaymentMethodsData>(v)
.change_context(errors::StorageError::DeserializationFailed)
.attach_printable("Failed to deserialize Payment Method Auth config")
})
.transpose()
.unwrap_or_else(|error| {
logger::error!(?error);
None
})
.and_then(|pmd| match pmd {
payment_methods::PaymentMethodsData::BankDetails(bank_creds) => Some(bank_creds),
_ => None,
})
.ok_or(ApiErrorResponse::InternalServerError)?;
let bank_details_pm_data = pm
.payment_method_data
.clone()
.map(|x| x.into_inner().expose())
.map(|v| v.parse_value("PaymentMethodsData"))
.transpose()
.unwrap_or_else(|error| {
logger::error!(?error);
None
})
.and_then(|pmd| match pmd {
payment_methods::PaymentMethodsData::BankDetails(bank_creds) => {
Some(bank_creds)
}
_ => None,
})
.ok_or(ApiErrorResponse::InternalServerError)
.attach_printable("Unable to parse PaymentMethodsData")?;
hash_to_payment_method.insert(
bank_details_pm_data.hash.clone(),
@ -386,9 +391,8 @@ async fn store_bank_details_in_payment_methods(
.clone()
.expose();
let mut update_entries: Vec<(storage::PaymentMethod, storage::PaymentMethodUpdate)> =
Vec::new();
let mut new_entries: Vec<storage::PaymentMethodNew> = Vec::new();
let mut update_entries: Vec<(domain::PaymentMethod, storage::PaymentMethodUpdate)> = Vec::new();
let mut new_entries: Vec<domain::PaymentMethod> = Vec::new();
for creds in bank_account_details_resp.credentials {
let (account_number, hash_string) = match creds.account_details {
@ -475,7 +479,11 @@ async fn store_bank_details_in_payment_methods(
.attach_printable("Unable to encrypt customer details")?;
let pm_id = generate_id(consts::ID_LENGTH, "pm");
let now = common_utils::date_time::now();
let pm_new = storage::PaymentMethodNew {
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
let pm_new = domain::PaymentMethod {
customer_id: customer_id.clone(),
merchant_id: merchant_account.get_id().clone(),
payment_method_id: pm_id,
@ -485,7 +493,7 @@ async fn store_bank_details_in_payment_methods(
payment_method_issuer: None,
scheme: None,
metadata: None,
payment_method_data: Some(encrypted_data.into()),
payment_method_data: Some(encrypted_data),
payment_method_issuer_code: None,
accepted_currency: None,
token: None,
@ -506,6 +514,31 @@ async fn store_bank_details_in_payment_methods(
client_secret: None,
payment_method_billing_address: None,
updated_by: None,
version: domain::consts::API_VERSION,
};
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
let pm_new = domain::PaymentMethod {
customer_id: customer_id.clone(),
merchant_id: merchant_account.get_id().clone(),
id: pm_id,
payment_method: Some(enums::PaymentMethod::BankDebit),
payment_method_type: Some(creds.payment_method_type),
status: enums::PaymentMethodStatus::Active,
metadata: None,
payment_method_data: Some(encrypted_data.into()),
created_at: now,
last_modified: now,
locker_id: None,
last_used_at: now,
connector_mandate_details: None,
customer_acceptance: None,
network_transaction_id: None,
client_secret: None,
payment_method_billing_address: None,
updated_by: None,
locker_fingerprint_id: None,
version: domain::consts::API_VERSION,
};
new_entries.push(pm_new);
@ -513,6 +546,8 @@ async fn store_bank_details_in_payment_methods(
}
store_in_db(
&state,
&key_store,
update_entries,
new_entries,
db,
@ -524,19 +559,26 @@ async fn store_bank_details_in_payment_methods(
}
async fn store_in_db(
update_entries: Vec<(storage::PaymentMethod, storage::PaymentMethodUpdate)>,
new_entries: Vec<storage::PaymentMethodNew>,
state: &SessionState,
key_store: &domain::MerchantKeyStore,
update_entries: Vec<(domain::PaymentMethod, storage::PaymentMethodUpdate)>,
new_entries: Vec<domain::PaymentMethod>,
db: &dyn StorageInterface,
storage_scheme: MerchantStorageScheme,
) -> RouterResult<()> {
let key_manager_state = &(state.into());
let update_entries_futures = update_entries
.into_iter()
.map(|(pm, pm_update)| db.update_payment_method(pm, pm_update, storage_scheme))
.map(|(pm, pm_update)| {
db.update_payment_method(key_manager_state, key_store, pm, pm_update, storage_scheme)
})
.collect::<Vec<_>>();
let new_entries_futures = new_entries
.into_iter()
.map(|pm_new| db.insert_payment_method(pm_new, storage_scheme))
.map(|pm_new| {
db.insert_payment_method(key_manager_state, key_store, pm_new, storage_scheme)
})
.collect::<Vec<_>>();
let update_futures = futures::future::join_all(update_entries_futures);