mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 18:17:13 +08:00 
			
		
		
		
	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:
		| @ -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); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Sarthak Soni
					Sarthak Soni