From a57b4bd04dbfa0c5c6ec32a19d4b62170b77fd67 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Wed, 27 Nov 2024 23:03:25 +0530 Subject: [PATCH 01/29] core changes --- crates/api_models/src/payouts.rs | 4 + crates/diesel_models/src/enums.rs | 21 ++ crates/diesel_models/src/payment_method.rs | 17 ++ crates/diesel_models/src/schema.rs | 2 + crates/hyperswitch_connectors/src/utils.rs | 22 ++ .../src/payment_methods.rs | 4 + .../src/router_request_types.rs | 1 + .../router/src/core/payment_methods/cards.rs | 16 +- .../payments/operations/payment_response.rs | 1 + crates/router/src/core/payments/routing.rs | 2 +- .../router/src/core/payments/tokenization.rs | 3 + crates/router/src/core/payouts.rs | 235 ++++++++++++++++-- crates/router/src/core/payouts/helpers.rs | 82 +++--- .../router/src/core/payouts/transformers.rs | 1 + crates/router/src/core/payouts/validator.rs | 141 +++++++++-- crates/router/src/core/pm_auth.rs | 1 + crates/router/src/core/utils.rs | 28 +++ crates/router/src/core/webhooks/incoming.rs | 2 +- crates/router/src/types/transformers.rs | 27 +- crates/router/tests/connectors/utils.rs | 1 + .../down.sql | 3 + .../up.sql | 2 + 22 files changed, 529 insertions(+), 87 deletions(-) create mode 100644 migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql create mode 100644 migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql diff --git a/crates/api_models/src/payouts.rs b/crates/api_models/src/payouts.rs index 237d165d572c..d1c356d7792d 100644 --- a/crates/api_models/src/payouts.rs +++ b/crates/api_models/src/payouts.rs @@ -184,6 +184,8 @@ pub struct PayoutCreateRequest { /// Customer's phone country code. _Deprecated: Use customer object instead._ #[schema(deprecated, max_length = 255, example = "+1")] pub phone_country_code: Option, + + pub payment_method_id: Option, } impl PayoutCreateRequest { @@ -568,6 +570,8 @@ pub struct PayoutCreateResponse { #[remove_in(PayoutCreateResponse)] #[schema(value_type = Option, max_length = 1024, example = "Invalid card details")] pub unified_message: Option, + + pub payment_method_id: Option, } /// The payout method information for response diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs index ec6e91a2ecb0..bb9ca1c45cfc 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -326,3 +326,24 @@ pub enum UserRoleVersion { V1, V2, } + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + serde::Serialize, + serde::Deserialize, + strum::EnumString, + strum::Display, +)] +#[router_derive::diesel_enum(storage_type = "text")] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum TransactionFlow { + #[default] + Payment, + Payouts, +} diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 76613984363d..c940844865c8 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -64,6 +64,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, + pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -152,6 +153,7 @@ pub struct PaymentMethodNew { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, + pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -248,6 +250,7 @@ pub enum PaymentMethodUpdate { }, ConnectorMandateDetailsUpdate { connector_mandate_details: Option, + transaction_flow: Option, }, NetworkTokenDataUpdate { network_token_requestor_reference_id: Option, @@ -400,6 +403,7 @@ pub struct PaymentMethodUpdateInternal { last_modified: PrimitiveDateTime, network_token_locker_id: Option, network_token_payment_method_data: Option, + transaction_flow: Option, scheme: Option, } @@ -425,6 +429,7 @@ impl PaymentMethodUpdateInternal { last_modified, network_token_locker_id, network_token_payment_method_data, + transaction_flow, scheme, } = self; @@ -466,6 +471,7 @@ impl PaymentMethodUpdateInternal { network_token_locker_id: network_token_locker_id.or(source.network_token_locker_id), network_token_payment_method_data: network_token_payment_method_data .or(source.network_token_payment_method_data), + transaction_flow: transaction_flow.or(source.transaction_flow), } } } @@ -496,6 +502,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::PaymentMethodDataUpdate { @@ -516,6 +523,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::LastUsedUpdate { last_used_at } => Self { @@ -534,6 +542,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::UpdatePaymentMethodDataAndLastUsed { @@ -556,6 +565,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, scheme, }, PaymentMethodUpdate::NetworkTransactionIdAndStatusUpdate { @@ -577,6 +587,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::StatusUpdate { status } => Self { @@ -595,6 +606,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::AdditionalDataUpdate { @@ -623,10 +635,12 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id, network_token_payment_method_data, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, + transaction_flow, } => Self { metadata: None, payment_method_data: None, @@ -643,6 +657,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow, scheme: None, }, PaymentMethodUpdate::NetworkTokenDataUpdate { @@ -665,6 +680,7 @@ impl From for PaymentMethodUpdateInternal { network_token_requestor_reference_id, network_token_locker_id, network_token_payment_method_data, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::ConnectorNetworkTransactionIdAndMandateDetailsUpdate { @@ -881,6 +897,7 @@ impl From<&PaymentMethodNew> for PaymentMethod { network_token_payment_method_data: payment_method_new .network_token_payment_method_data .clone(), + transaction_flow: payment_method_new.transaction_flow, } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 95bb714cb711..9bef91ffde4d 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -1064,6 +1064,8 @@ diesel::table! { #[max_length = 64] network_token_locker_id -> Nullable, network_token_payment_method_data -> Nullable, + #[max_length = 255] + transaction_flow -> Nullable, } } diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 9061a758beab..62db4d924601 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -15,6 +15,8 @@ use common_utils::{ types::{AmountConvertor, MinorUnit}, }; use error_stack::{report, ResultExt}; +#[cfg(feature = "payouts")] +use hyperswitch_domain_models::router_request_types::PayoutsData; use hyperswitch_domain_models::{ address::{Address, AddressDetails, PhoneDetails}, payment_method_data::{self, Card, PaymentMethodData}, @@ -1239,6 +1241,26 @@ impl PhoneDetailsData for PhoneDetails { } } +#[cfg(feature = "payouts")] +pub trait PayoutFulfillRequestData { + fn get_connector_payout_id(&self) -> Result; + fn get_connector_transfer_method_id(&self) -> Result; +} +#[cfg(feature = "payouts")] +impl PayoutFulfillRequestData for PayoutsData { + fn get_connector_payout_id(&self) -> Result { + self.connector_payout_id + .clone() + .ok_or_else(missing_field_err("connector_payout_id")) + } + + fn get_connector_transfer_method_id(&self) -> Result { + self.connector_transfer_method_id + .clone() + .ok_or_else(missing_field_err("connector_transfer_method_id")) + } +} + pub trait CustomerData { fn get_email(&self) -> Result; } diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index d03762dd64e8..27903f5655d6 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -69,6 +69,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: OptionalEncryptableValue, + pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -188,6 +189,7 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), + transaction_flow: self.transaction_flow, }) } @@ -275,6 +277,7 @@ impl super::behaviour::Conversion for PaymentMethod { .and_then(|val| val.try_into_optionaloperation()) }) .await?, + transaction_flow: item.transaction_flow, }) } .await @@ -323,6 +326,7 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), + transaction_flow: self.transaction_flow, }) } } diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index aa9fb2b5f1f0..c5771d7af66f 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -800,6 +800,7 @@ pub struct PayoutsData { // New minor amount for amount framework pub minor_amount: MinorUnit, pub priority: Option, + pub connector_transfer_method_id: Option, } #[derive(Debug, Default, Clone)] diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 164c0e9557af..8b72a946d6d3 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -37,7 +37,7 @@ use common_utils::{ MinorUnit, }, }; -use diesel_models::payment_method; +use diesel_models::{enums as storage_enums, payment_method}; use error_stack::{report, ResultExt}; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -146,6 +146,7 @@ pub async fn create_payment_method( network_token_requestor_reference_id: Option, network_token_locker_id: Option, network_token_payment_method_data: crypto::OptionalEncryptableValue, + transaction_flow: Option, ) -> errors::CustomResult { let db = &*state.store; let customer = db @@ -205,6 +206,7 @@ pub async fn create_payment_method( network_token_requestor_reference_id, network_token_locker_id, network_token_payment_method_data, + transaction_flow, }, storage_scheme, ) @@ -346,6 +348,7 @@ pub async fn get_or_insert_payment_method( None, None, None, + Some(storage_enums::TransactionFlow::Payment), ) .await } else { @@ -828,6 +831,7 @@ pub async fn skip_locker_call_and_migrate_payment_method( network_token_requestor_reference_id: None, network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: Some(storage_enums::TransactionFlow::Payment), }, merchant_account.storage_scheme, ) @@ -1077,6 +1081,7 @@ pub async fn get_client_secret_or_add_payment_method( None, None, None, + Some(storage_enums::TransactionFlow::Payment), ) .await?; @@ -1170,6 +1175,7 @@ pub async fn get_client_secret_or_add_payment_method_for_migration( None, None, None, + Some(storage_enums::TransactionFlow::Payment), ) .await?; migration_status.connector_mandate_details_migrated( @@ -1689,6 +1695,7 @@ pub async fn add_payment_method( None, None, None, + Some(storage_enums::TransactionFlow::Payment), ) .await?; @@ -1951,6 +1958,7 @@ pub async fn save_migration_payment_method( None, None, None, + Some(storage_enums::TransactionFlow::Payment), ) .await?; @@ -1997,6 +2005,7 @@ pub async fn insert_payment_method( network_token_requestor_reference_id: Option, network_token_locker_id: Option, network_token_payment_method_data: crypto::OptionalEncryptableValue, + transaction_flow: Option, ) -> errors::RouterResult { let pm_card_details = resp .card @@ -2034,6 +2043,7 @@ pub async fn insert_payment_method( network_token_requestor_reference_id, network_token_locker_id, network_token_payment_method_data, + transaction_flow, ) .await } @@ -2843,9 +2853,11 @@ pub async fn update_payment_method_connector_mandate_details( pm: domain::PaymentMethod, connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, + transaction_flow: Option, ) -> errors::CustomResult<(), errors::VaultError> { let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, + transaction_flow, }; db.update_payment_method(&(state.into()), key_store, pm, pm_update, storage_scheme) @@ -5063,7 +5075,7 @@ pub async fn list_customer_payment_method( not(feature = "payment_methods_v2"), not(feature = "customer_v2") ))] -async fn get_pm_list_context( +pub async fn get_pm_list_context( state: &routes::SessionState, payment_method: &enums::PaymentMethod, #[cfg(feature = "payouts")] key_store: &domain::MerchantKeyStore, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 91fdfae63fae..252c2b4a57af 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1647,6 +1647,7 @@ async fn payment_response_update_tracker( payment_method, connector_mandate_details, storage_scheme, + Some(diesel_models::enums::TransactionFlow::Payment), ) .await .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 0a57819816fb..d0ddcd4427a4 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -152,7 +152,7 @@ pub fn make_dsl_input_for_payouts( .map(api_enums::PaymentMethod::foreign_from), payment_method_type: payout_data .payout_method_data - .clone() + .as_ref() .map(api_enums::PaymentMethodType::foreign_from), card_network: None, }; diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 94f221dd722f..58cee57d8250 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -400,6 +400,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), + Some(storage_enums::TransactionFlow::Payment), ) .await } else { @@ -486,6 +487,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), + Some(storage_enums::TransactionFlow::Payment), ) .await } else { @@ -702,6 +704,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), + Some(storage_enums::TransactionFlow::Payment), ) .await?; }; diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index b2d6b2ace45c..7f4dcc78c01d 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -4,11 +4,17 @@ pub mod helpers; pub mod retry; pub mod transformers; pub mod validator; -use std::{collections::HashSet, vec::IntoIter}; +use std::{ + collections::{HashMap, HashSet}, + vec::IntoIter, +}; #[cfg(feature = "olap")] use api_models::payments as payment_enums; -use api_models::{self, enums as api_enums, payouts::PayoutLinkResponse}; +use api_models::{ + self, enums as api_enums, payment_methods::PaymentsMandateReferenceRecord, + payouts::PayoutLinkResponse, +}; #[cfg(feature = "payout_retry")] use common_enums::PayoutRetryType; use common_utils::{ @@ -25,6 +31,7 @@ use diesel_models::{ use error_stack::{report, ResultExt}; #[cfg(feature = "olap")] use futures::future::join_all; +use hyperswitch_domain_models::payment_methods::PaymentMethod; use masking::{PeekInterface, Secret}; #[cfg(feature = "payout_retry")] use retry::GsmValidation; @@ -72,6 +79,7 @@ pub struct PayoutData { pub should_terminate: bool, pub payout_link: Option, pub current_locale: String, + pub payment_method: Option, } // ********************************************** CORE FLOWS ********************************************** @@ -320,7 +328,7 @@ pub async fn payouts_create_core( locale: &str, ) -> RouterResponse { // Validate create request - let (payout_id, payout_method_data, profile_id, customer) = + let (payout_id, payout_method_data, profile_id, customer, payment_method) = validator::validate_create_request(&state, &merchant_account, &req, &key_store).await?; // Create DB entries @@ -334,8 +342,19 @@ pub async fn payouts_create_core( payout_method_data.as_ref(), locale, customer.as_ref(), + payment_method.clone(), ) .await?; + /* + + + + + + + + + */ let payout_attempt = payout_data.payout_attempt.to_owned(); let payout_type = payout_data.payouts.payout_type.to_owned(); @@ -1141,6 +1160,7 @@ pub async fn call_connector_payout( merchant_account, connector_data, payout_data, + key_store, ) .await?; // Payout creation flow @@ -1353,6 +1373,39 @@ pub async fn create_recipient( // Helps callee functions skip the execution payout_data.should_terminate = true; + } else if let Some(status) = recipient_create_data.status { + let updated_payout_attempt = storage::PayoutAttemptUpdate::StatusUpdate { + connector_payout_id: payout_data + .payout_attempt + .connector_payout_id + .to_owned(), + status, + error_code: None, + error_message: None, + is_eligible: recipient_create_data.payout_eligible, + unified_code: None, + unified_message: None, + }; + payout_data.payout_attempt = db + .update_payout_attempt( + &payout_data.payout_attempt, + updated_payout_attempt, + &payout_data.payouts, + merchant_account.storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Error updating payout_attempt in db")?; + payout_data.payouts = db + .update_payout( + &payout_data.payouts, + storage::PayoutsUpdate::StatusUpdate { status }, + &payout_data.payout_attempt, + merchant_account.storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Error updating payouts in db")?; } } Err(err) => Err(errors::ApiErrorResponse::PayoutFailed { @@ -1947,22 +2000,68 @@ pub async fn update_retrieve_payout_tracker( Ok(()) } +/* + */ +fn connector_mandate_id_is_none( + payout_data: &mut PayoutData, + connector_data: &api::ConnectorData, +) -> RouterResult { + if let Some(pm) = &payout_data.payment_method { + let connector_mandate_details = pm + .connector_mandate_details + .clone() + .map(|details| { + details.parse_value::( + "connector_mandate_details", + ) + }) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to deserialize connector mandate details")?; + + if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { + if let Some(_mandate_reference_record) = connector_mandate_details + .clone() + .get_required_value("connector_mandate_details") + .change_context(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) + .attach_printable("there were no connector mandate details")? + .get(merchant_connector_id) + { + return Ok(false); + } + } + return Ok(true); + } + Ok(true) +} + pub async fn complete_create_recipient_disburse_account( state: &SessionState, merchant_account: &domain::MerchantAccount, connector_data: &api::ConnectorData, payout_data: &mut PayoutData, + key_store: &domain::MerchantKeyStore, ) -> RouterResult<()> { if !payout_data.should_terminate - && payout_data.payout_attempt.status - == storage_enums::PayoutStatus::RequiresVendorAccountCreation + && matches!( + payout_data.payout_attempt.status, + storage_enums::PayoutStatus::RequiresVendorAccountCreation + | storage_enums::PayoutStatus::RequiresCreation + ) && connector_data .connector_name .supports_vendor_disburse_account_create_for_payout() + && connector_mandate_id_is_none(payout_data, connector_data)? { - create_recipient_disburse_account(state, merchant_account, connector_data, payout_data) - .await - .attach_printable("Creation of customer failed")?; + create_recipient_disburse_account( + state, + merchant_account, + connector_data, + payout_data, + key_store, + ) + .await + .attach_printable("Creation of customer failed")?; } Ok(()) } @@ -1972,6 +2071,7 @@ pub async fn create_recipient_disburse_account( merchant_account: &domain::MerchantAccount, connector_data: &api::ConnectorData, payout_data: &mut PayoutData, + key_store: &domain::MerchantKeyStore, ) -> RouterResult<()> { // 1. Form Router data let router_data = @@ -2005,7 +2105,7 @@ pub async fn create_recipient_disburse_account( .status .unwrap_or(payout_attempt.status.to_owned()); let updated_payout_attempt = storage::PayoutAttemptUpdate::StatusUpdate { - connector_payout_id: payout_response_data.connector_payout_id, + connector_payout_id: payout_response_data.connector_payout_id.clone(), status, error_code: None, error_message: None, @@ -2023,6 +2123,80 @@ pub async fn create_recipient_disburse_account( .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Error updating payout_attempt in db")?; + + if let ( + true, + Some(ref payout_method_data), + Some(connector_payout_id), + Some(customer_details), + Some(merchant_connector_id), + ) = ( + payout_data.payouts.recurring, + payout_data.payout_method_data.clone(), + payout_response_data.connector_payout_id.clone(), + payout_data.customer_details.clone(), + connector_data.merchant_connector_id.clone(), + ) { + let connector_mandate_details = HashMap::from([( + merchant_connector_id, // which connector was called [MCA] + PaymentsMandateReferenceRecord { + connector_mandate_id: connector_payout_id, // what does the connector return + payment_method_type: Some(api_enums::PaymentMethodType::foreign_from( + payout_method_data, + )), + original_payment_authorized_amount: Some( + payout_data.payouts.amount.get_amount_as_i64(), + ), + original_payment_authorized_currency: Some( + payout_data.payouts.destination_currency, + ), + }, + )]); + + let connector_mandate_details_value = + serde_json::to_value(connector_mandate_details).ok(); + + /**************** above this is correct ********************** + need to fetch connector_mandate_details using payment_method_id + */ + let pm_id = payout_data.payouts.payout_method_id.clone(); + + if let Some(payout_method_id) = pm_id { + let payment_method = db + .find_payment_method( + &(state.into()), + key_store, + &payout_method_id, // need to get from api request + merchant_account.storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::PaymentMethodNotFound) + .attach_printable("Unable to find payment method")?; + + payout_data.payment_method = Some(payment_method.clone()); + payout_data.payouts.payout_method_id = + Some(payment_method.payment_method_id.clone()); + + // router_env::logger::info!("XXXXXXXXXXXXXXXXX"); + // router_env::logger::info!("{:?}", payment_method.payment_method_id.clone()); + // router_env::logger::info!("XXXXXXXXXXXXXXXXX"); + // router_env::logger::info!("{:?}", payment_method.clone()); + // router_env::logger::info!("XXXXXXXXXXXXXXXXX"); + } else { + // router_env::logger::info!("9999999999999999"); + helpers::save_payout_data_to_locker( + state, + payout_data, + &customer_details.customer_id, + &payout_method_data, + connector_mandate_details_value, + merchant_account, + key_store, + ) + .await + .attach_printable("Failed to save payout data to locker")?; + }; + } } Err(err) => { let (error_code, error_message) = (Some(err.code), Some(err.message)); @@ -2293,6 +2467,7 @@ pub async fn fulfill_payout( payout_data, &customer_id, &payout_method_data, + None, merchant_account, key_store, ) @@ -2367,6 +2542,12 @@ pub async fn response_handler( ) -> RouterResponse { let payout_attempt = payout_data.payout_attempt.to_owned(); let payouts = payout_data.payouts.to_owned(); + + let payment_method_id: Option = payout_data + .payment_method + .as_ref() // Safely access the `payment_method` as a reference + .and_then(|pm| Some(pm.payment_method_id.clone())); + let payout_link = payout_data.payout_link.to_owned(); let billing_address = payout_data.billing_address.to_owned(); let customer_details = payout_data.customer_details.to_owned(); @@ -2438,6 +2619,7 @@ pub async fn response_handler( .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to parse payout link's URL")?, + payment_method_id: payment_method_id, }; Ok(services::ApplicationResponse::Json(response)) } @@ -2471,6 +2653,7 @@ pub async fn payout_create_db_entries( stored_payout_method_data: Option<&payouts::PayoutMethodData>, locale: &str, customer: Option<&domain::Customer>, + payment_method: Option, ) -> RouterResult { let db = &*state.store; let merchant_id = merchant_account.get_id(); @@ -2523,13 +2706,18 @@ pub async fn payout_create_db_entries( // Make payouts entry let currency = req.currency.to_owned().get_required_value("currency")?; - let payout_type = req.payout_type.to_owned(); - let payout_method_id = if stored_payout_method_data.is_some() { - req.payout_token.to_owned() - } else { - None + let (payout_method_id, payout_type) = match stored_payout_method_data { + Some(payout_method_data) => ( + req.payout_token.to_owned(), + Some(api_enums::PayoutType::foreign_from(payout_method_data)), + ), + None => ( + payment_method.clone().map(|pm| pm.payment_method_id), + req.payout_type.to_owned(), + ), }; + let client_secret = utils::generate_id( consts::ID_LENGTH, format!("payout_{payout_id}_secret").as_str(), @@ -2648,6 +2836,7 @@ pub async fn payout_create_db_entries( profile_id: profile_id.to_owned(), payout_link, current_locale: locale.to_string(), + payment_method, }) } @@ -2837,6 +3026,23 @@ pub async fn make_payout_data( .await .transpose()?; + let payout_method_id = payouts.payout_method_id.clone(); + let mut payment_method: Option = None; + + if let Some(pm_id) = payout_method_id { + payment_method = Some( + db.find_payment_method( + &(state.into()), + &key_store, + &pm_id, // need to get from api request + merchant_account.storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::PaymentMethodNotFound) + .attach_printable("Unable to find payment method")?, + ); + } + Ok(PayoutData { billing_address, business_profile, @@ -2849,6 +3055,7 @@ pub async fn make_payout_data( profile_id, payout_link, current_locale: locale.to_string(), + payment_method, }) } diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index b07094c321cc..2eda19f08bfe 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -36,7 +36,7 @@ use crate::{ routing::TransactionData, utils as core_utils, }, - db::StorageInterface, + db::{storage::enums as storage_enums, StorageInterface}, routes::{metrics, SessionState}, services, types::{ @@ -203,6 +203,7 @@ pub async fn save_payout_data_to_locker( payout_data: &mut PayoutData, customer_id: &id_type::CustomerId, payout_method_data: &api::PayoutMethodData, + connector_mandate_details: Option, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, ) -> RouterResult<()> { @@ -290,14 +291,14 @@ pub async fn save_payout_data_to_locker( None, Some(bank.to_owned()), None, - api_enums::PaymentMethodType::foreign_from(bank.to_owned()), + api_enums::PaymentMethodType::foreign_from(bank), ), payouts::PayoutMethodData::Wallet(wallet) => ( payload, None, None, Some(wallet.to_owned()), - api_enums::PaymentMethodType::foreign_from(wallet.to_owned()), + api_enums::PaymentMethodType::foreign_from(wallet), ), payouts::PayoutMethodData::Card(_) => { Err(errors::ApiErrorResponse::InternalServerError)? @@ -409,9 +410,7 @@ pub async fn save_payout_data_to_locker( let card_isin = card_details.as_ref().map(|c| c.card_number.get_card_isin()); let mut payment_method = api::PaymentMethodCreate { - payment_method: Some(api_enums::PaymentMethod::foreign_from( - payout_method_data.to_owned(), - )), + payment_method: Some(api_enums::PaymentMethod::foreign_from(payout_method_data)), payment_method_type: Some(payment_method_type), payment_method_issuer: None, payment_method_issuer_code: None, @@ -497,7 +496,7 @@ pub async fn save_payout_data_to_locker( None, api::PaymentMethodCreate { payment_method: Some(api_enums::PaymentMethod::foreign_from( - payout_method_data.to_owned(), + payout_method_data, )), payment_method_type: Some(payment_method_type), payment_method_issuer: None, @@ -520,28 +519,31 @@ pub async fn save_payout_data_to_locker( // Insert new entry in payment_methods table if should_insert_in_pm_table { let payment_method_id = common_utils::generate_id(consts::ID_LENGTH, "pm"); - cards::create_payment_method( - state, - &new_payment_method, - customer_id, - &payment_method_id, - Some(stored_resp.card_reference.clone()), - merchant_account.get_id(), - None, - None, - card_details_encrypted.clone().map(Into::into), - key_store, - None, - None, - None, - merchant_account.storage_scheme, - None, - None, - None, - None, - None, - ) - .await?; + payout_data.payment_method = Some( + cards::create_payment_method( + state, + &new_payment_method, + customer_id, + &payment_method_id, + Some(stored_resp.card_reference.clone()), + merchant_account.get_id(), + None, + None, + card_details_encrypted.clone().map(Into::into), + key_store, + connector_mandate_details, + None, + None, + merchant_account.storage_scheme, + None, + None, + None, + None, + None, + Some(storage_enums::TransactionFlow::Payouts), + ) + .await?, + ); } /* 1. Delete from locker @@ -600,16 +602,18 @@ pub async fn save_payout_data_to_locker( let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate { payment_method_data: card_details_encrypted.map(Into::into), }; - db.update_payment_method( - &(state.into()), - key_store, - existing_pm, - pm_update, - merchant_account.storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to add payment method in db")?; + payout_data.payment_method = Some( + db.update_payment_method( + &(state.into()), + key_store, + existing_pm, + pm_update, + merchant_account.storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to add payment method in db")?, + ); }; // Store card_reference in payouts table diff --git a/crates/router/src/core/payouts/transformers.rs b/crates/router/src/core/payouts/transformers.rs index c1f314043053..38e886707193 100644 --- a/crates/router/src/core/payouts/transformers.rs +++ b/crates/router/src/core/payouts/transformers.rs @@ -115,6 +115,7 @@ impl phone_country_code: customer .as_ref() .and_then(|customer| customer.phone_country_code.clone()), + payment_method_id: payout.payout_method_id, } } } diff --git a/crates/router/src/core/payouts/validator.rs b/crates/router/src/core/payouts/validator.rs index c647d6eaf102..49ce31cb6455 100644 --- a/crates/router/src/core/payouts/validator.rs +++ b/crates/router/src/core/payouts/validator.rs @@ -7,6 +7,7 @@ use common_utils::validation::validate_domain_against_allowed_domains; use diesel_models::generic_link::PayoutLink; use error_stack::{report, ResultExt}; pub use hyperswitch_domain_models::errors::StorageError; +use hyperswitch_domain_models::payment_methods::PaymentMethod; use router_env::{instrument, tracing, which as router_env_which, Env}; use url::Url; @@ -14,12 +15,14 @@ use super::helpers; use crate::{ core::{ errors::{self, RouterResult}, + payment_methods::cards::get_pm_list_context, utils as core_utils, }, db::StorageInterface, routes::SessionState, types::{api::payouts, domain, storage}, utils, + utils::OptionExt, }; #[instrument(skip(db))] @@ -76,6 +79,7 @@ pub async fn validate_create_request( Option, common_utils::id_type::ProfileId, Option, + Option, )> { let merchant_id = merchant_account.get_id(); @@ -137,27 +141,27 @@ pub async fn validate_create_request( None }; - // payout_token - let payout_method_data = match (req.payout_token.as_ref(), customer.as_ref()) { - (Some(_), None) => Err(report!(errors::ApiErrorResponse::MissingRequiredField { - field_name: "customer or customer_id when payout_token is provided" - })), - (Some(payout_token), Some(customer)) => { - helpers::make_payout_method_data( - state, - req.payout_method_data.as_ref(), - Some(payout_token), - &customer.customer_id, - merchant_account.get_id(), - req.payout_type, - merchant_key_store, - None, - merchant_account.storage_scheme, - ) - .await - } - _ => Ok(None), - }?; + // // payout_token + // let payout_method_data = match (req.payout_token.as_ref(), customer.as_ref()) { + // (Some(_), None) => Err(report!(errors::ApiErrorResponse::MissingRequiredField { + // field_name: "customer or customer_id when payout_token is provided" + // })), + // (Some(payout_token), Some(customer)) => { + // helpers::make_payout_method_data( + // state, + // req.payout_method_data.as_ref(), + // Some(payout_token), + // &customer.customer_id, + // merchant_account.get_id(), + // req.payout_type, + // merchant_key_store, + // None, + // merchant_account.storage_scheme, + // ) + // .await + // } + // _ => Ok(None), + // }?; #[cfg(feature = "v1")] let profile_id = core_utils::get_profile_id_from_business_details( @@ -182,7 +186,100 @@ pub async fn validate_create_request( }) .attach_printable("Profile id is a mandatory parameter")?; - Ok((payout_id, payout_method_data, profile_id, customer)) + // fetching payment_method using req.payment_method_id and passing it from here + let payment_method: Option = + if let Some(payment_method_id) = req.payment_method_id.clone() { + match customer.as_ref() { + Some(customer) => { + let payment_method = db + .find_payment_method( + &state.into(), + merchant_key_store, + &payment_method_id, + merchant_account.storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::PaymentMethodNotFound) + .attach_printable("Unable to find payment method")?; + utils::when(payment_method.customer_id != customer.customer_id, || { + Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: "payment method does not belong to this customer_id".to_string() + }) + .attach_printable( + "customer_id in payment_method does not match with customer_id in request", + )) + })?; + Some(payment_method) + } + None => Err(report!(errors::ApiErrorResponse::MissingRequiredField { + field_name: "customer_id when payment_method_id is passed", + }))?, + } + } else { + None + }; + + let payout_method_data = match ( + req.payout_token.as_ref(), + customer.as_ref(), + payment_method.as_ref(), + ) { + (Some(_), None, _) => Err(report!(errors::ApiErrorResponse::MissingRequiredField { + field_name: "customer or customer_id when payout_token is provided" + })), + (Some(payout_token), Some(customer), _) => { + helpers::make_payout_method_data( + state, + req.payout_method_data.as_ref(), + Some(payout_token), + &customer.customer_id, + merchant_account.get_id(), + req.payout_type, + merchant_key_store, + None, + merchant_account.storage_scheme, + ) + .await + } + (_, Some(_), Some(payment_method)) => { + match get_pm_list_context( + state, + payment_method + .payment_method + .as_ref() + .get_required_value("payment_method_id")?, + merchant_key_store, + payment_method, + None, + false, + ) + .await? + { + Some(pm) => match (pm.card_details, pm.bank_transfer_details) { + (Some(card), _) => Ok(Some(payouts::PayoutMethodData::Card( + api_models::payouts::CardPayout { + card_number: card.card_number.get_required_value("card_number")?, + card_holder_name: card.card_holder_name, + expiry_month: card.expiry_month.get_required_value("expiry_month")?, + expiry_year: card.expiry_year.get_required_value("expiry_month")?, + }, + ))), + (_, Some(bank)) => Ok(Some(payouts::PayoutMethodData::Bank(bank))), + _ => Ok(None), + }, + None => Ok(None), + } + } + _ => Ok(None), + }?; + + Ok(( + payout_id, + payout_method_data, + profile_id, + customer, + payment_method, + )) } pub fn validate_payout_link_request( diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index afba73e839c7..0fac975ed70e 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -554,6 +554,7 @@ async fn store_bank_details_in_payment_methods( network_token_requestor_reference_id: None, network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, }; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index c441e32581e8..dd08c6a2577c 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -148,6 +148,33 @@ pub async fn construct_payout_router_data<'a, F>( _ => None, }; + let mut connector_mandate_id = None; + if let Some(pm) = &payout_data.payment_method { + let connector_mandate_details = pm + .connector_mandate_details + .clone() + .map(|details| { + details.parse_value::( + "connector_mandate_details", + ) + }) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to deserialize connector mandate details")?; + + if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { + if let Some(mandate_reference_record) = connector_mandate_details + .clone() + .get_required_value("connector_mandate_details") + .change_context(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) + .attach_printable("there were no connector mandate details")? + .get(merchant_connector_id) + { + connector_mandate_id = Some(mandate_reference_record.connector_mandate_id.clone()); + } + } + } + let router_data = types::RouterData { flow: PhantomData, merchant_id: merchant_account.get_id().to_owned(), @@ -189,6 +216,7 @@ pub async fn construct_payout_router_data<'a, F>( phone: c.phone.map(Encryptable::into_inner), phone_country_code: c.phone_country_code, }), + connector_transfer_method_id: connector_mandate_id, }, response: Ok(types::PayoutsResponseData::default()), access_token: None, diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index ff9849958b51..6b76ec1ab1f1 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -5,7 +5,7 @@ use actix_web::FromRequest; use api_models::payouts as payout_models; use api_models::webhooks::{self, WebhookResponseTracker}; use common_utils::{errors::ReportSwitchExt, events::ApiEventsType, ext_traits::ValueExt}; -use diesel_models::ConnectorMandateReferenceId; +use diesel_models::{enums as storage_enums, ConnectorMandateReferenceId}; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ payments::{payment_attempt::PaymentAttempt, HeaderPayload}, diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index bbcdfc535df8..b458bbf8f745 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1386,8 +1386,8 @@ impl ForeignFrom for payments::CaptureResponse { } #[cfg(feature = "payouts")] -impl ForeignFrom for api_enums::PaymentMethodType { - fn foreign_from(value: api_models::payouts::PayoutMethodData) -> Self { +impl ForeignFrom<&api_models::payouts::PayoutMethodData> for api_enums::PaymentMethodType { + fn foreign_from(value: &api_models::payouts::PayoutMethodData) -> Self { match value { api_models::payouts::PayoutMethodData::Bank(bank) => Self::foreign_from(bank), api_models::payouts::PayoutMethodData::Card(_) => Self::Debit, @@ -1397,8 +1397,8 @@ impl ForeignFrom for api_enums::PaymentMe } #[cfg(feature = "payouts")] -impl ForeignFrom for api_enums::PaymentMethodType { - fn foreign_from(value: api_models::payouts::Bank) -> Self { +impl ForeignFrom<&api_models::payouts::Bank> for api_enums::PaymentMethodType { + fn foreign_from(value: &api_models::payouts::Bank) -> Self { match value { api_models::payouts::Bank::Ach(_) => Self::Ach, api_models::payouts::Bank::Bacs(_) => Self::Bacs, @@ -1409,8 +1409,8 @@ impl ForeignFrom for api_enums::PaymentMethodType { } #[cfg(feature = "payouts")] -impl ForeignFrom for api_enums::PaymentMethodType { - fn foreign_from(value: api_models::payouts::Wallet) -> Self { +impl ForeignFrom<&api_models::payouts::Wallet> for api_enums::PaymentMethodType { + fn foreign_from(value: &api_models::payouts::Wallet) -> Self { match value { api_models::payouts::Wallet::Paypal(_) => Self::Paypal, api_models::payouts::Wallet::Venmo(_) => Self::Venmo, @@ -1419,8 +1419,8 @@ impl ForeignFrom for api_enums::PaymentMethodType { } #[cfg(feature = "payouts")] -impl ForeignFrom for api_enums::PaymentMethod { - fn foreign_from(value: api_models::payouts::PayoutMethodData) -> Self { +impl ForeignFrom<&api_models::payouts::PayoutMethodData> for api_enums::PaymentMethod { + fn foreign_from(value: &api_models::payouts::PayoutMethodData) -> Self { match value { api_models::payouts::PayoutMethodData::Bank(_) => Self::BankTransfer, api_models::payouts::PayoutMethodData::Card(_) => Self::Card, @@ -1429,6 +1429,17 @@ impl ForeignFrom for api_enums::PaymentMe } } +#[cfg(feature = "payouts")] +impl ForeignFrom<&api_models::payouts::PayoutMethodData> for api_models::enums::PayoutType { + fn foreign_from(value: &api_models::payouts::PayoutMethodData) -> Self { + match value { + api_models::payouts::PayoutMethodData::Bank(_) => Self::Bank, + api_models::payouts::PayoutMethodData::Card(_) => Self::Card, + api_models::payouts::PayoutMethodData::Wallet(_) => Self::Wallet, + } + } +} + #[cfg(feature = "payouts")] impl ForeignFrom for api_enums::PaymentMethod { fn foreign_from(value: api_models::enums::PayoutType) -> Self { diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index 305b11fe5b3d..7dffce035b25 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -471,6 +471,7 @@ pub trait ConnectorActions: Connector { }), vendor_details: None, priority: None, + connector_transfer_method_id: None, }, payment_info, ) diff --git a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql new file mode 100644 index 000000000000..5c63b3f5edb9 --- /dev/null +++ b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE payment_methods +DROP COLUMN transaction_flow; \ No newline at end of file diff --git a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql new file mode 100644 index 000000000000..62be9f010282 --- /dev/null +++ b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS transaction_flow VARCHAR(255); \ No newline at end of file From c21ba69706efd15e839b08de814012c9a8bcc9bf Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 28 Nov 2024 00:27:09 +0530 Subject: [PATCH 02/29] clippy error fix --- crates/router/src/core/payouts.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 7f4dcc78c01d..0586fecbbc2d 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -348,7 +348,7 @@ pub async fn payouts_create_core( /* - + dummy commit @@ -1155,13 +1155,13 @@ pub async fn call_connector_payout( ) .await?; // Create customer's disbursement account flow - complete_create_recipient_disburse_account( + Box::pin(complete_create_recipient_disburse_account( state, merchant_account, connector_data, payout_data, key_store, - ) + )) .await?; // Payout creation flow Box::pin(complete_create_payout( @@ -2053,13 +2053,13 @@ pub async fn complete_create_recipient_disburse_account( .supports_vendor_disburse_account_create_for_payout() && connector_mandate_id_is_none(payout_data, connector_data)? { - create_recipient_disburse_account( + Box::pin(create_recipient_disburse_account( state, merchant_account, connector_data, payout_data, key_store, - ) + )) .await .attach_printable("Creation of customer failed")?; } @@ -2188,7 +2188,7 @@ pub async fn create_recipient_disburse_account( state, payout_data, &customer_details.customer_id, - &payout_method_data, + payout_method_data, connector_mandate_details_value, merchant_account, key_store, @@ -2546,7 +2546,7 @@ pub async fn response_handler( let payment_method_id: Option = payout_data .payment_method .as_ref() // Safely access the `payment_method` as a reference - .and_then(|pm| Some(pm.payment_method_id.clone())); + .map(|pm| pm.payment_method_id.clone()); let payout_link = payout_data.payout_link.to_owned(); let billing_address = payout_data.billing_address.to_owned(); @@ -2619,7 +2619,7 @@ pub async fn response_handler( .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to parse payout link's URL")?, - payment_method_id: payment_method_id, + payment_method_id, }; Ok(services::ApplicationResponse::Json(response)) } @@ -3033,7 +3033,7 @@ pub async fn make_payout_data( payment_method = Some( db.find_payment_method( &(state.into()), - &key_store, + key_store, &pm_id, // need to get from api request merchant_account.storage_scheme, ) From de6c818b16c51d15f1d15019b1d309d037fab476 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 28 Nov 2024 16:19:13 +0530 Subject: [PATCH 03/29] clippy fix for v2 --- crates/diesel_models/src/payment_method.rs | 6 +++ crates/diesel_models/src/schema_v2.rs | 2 + .../src/payment_methods.rs | 4 ++ crates/router/src/core/payment_methods.rs | 3 ++ .../router/src/core/payment_methods/cards.rs | 2 + crates/router/src/core/payouts.rs | 44 ++++++++++--------- crates/router/src/core/payouts/helpers.rs | 3 +- crates/router/src/core/payouts/validator.rs | 9 +++- 8 files changed, 50 insertions(+), 23 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index c940844865c8..581a7ef5d020 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -93,6 +93,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, + pub transaction_flow: Option, } impl PaymentMethod { @@ -182,6 +183,7 @@ pub struct PaymentMethodNew { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, + pub transaction_flow: Option, } impl PaymentMethodNew { @@ -297,6 +299,7 @@ pub enum PaymentMethodUpdate { }, ConnectorMandateDetailsUpdate { connector_mandate_details: Option, + transaction_flow: Option, }, } @@ -377,6 +380,7 @@ impl PaymentMethodUpdateInternal { network_token_locker_id: network_token_locker_id.or(source.network_token_locker_id), network_token_payment_method_data: network_token_payment_method_data .or(source.network_token_payment_method_data), + transaction_flow: transaction_flow.or(source.transaction_flow), } } } @@ -830,6 +834,7 @@ impl From for PaymentMethodUpdateInternal { }, PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, + transaction_flow, } => Self { payment_method_data: None, last_used_at: None, @@ -934,6 +939,7 @@ impl From<&PaymentMethodNew> for PaymentMethod { network_token_payment_method_data: payment_method_new .network_token_payment_method_data .clone(), + transaction_flow: payment_method_new.transaction_flow, } } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 8bbb4baf9d74..6a5cfe3d7dbe 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -1009,6 +1009,8 @@ diesel::table! { #[max_length = 64] network_token_locker_id -> Nullable, network_token_payment_method_data -> Nullable, + #[max_length = 255] + transaction_flow -> Nullable, } } diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index 27903f5655d6..c9f46a296e0d 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -98,6 +98,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: OptionalEncryptableValue, + pub transaction_flow: Option, } impl PaymentMethod { @@ -364,6 +365,7 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), + transaction_flow: self.transaction_flow, }) } @@ -439,6 +441,7 @@ impl super::behaviour::Conversion for PaymentMethod { .and_then(|val| val.try_into_optionaloperation()) }) .await?, + transaction_flow: item.transaction_flow, }) } .await @@ -475,6 +478,7 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), + transaction_flow: self.transaction_flow, }) } } diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 6cdadf07320c..dd735733cb52 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -1156,6 +1156,7 @@ pub async fn create_payment_method_in_db( storage_scheme: enums::MerchantStorageScheme, payment_method_billing_address: crypto::OptionalEncryptableValue, card_scheme: Option, + transaction_flow: Option, ) -> errors::CustomResult { let db = &*state.store; let current_time = common_utils::date_time::now(); @@ -1187,6 +1188,7 @@ pub async fn create_payment_method_in_db( network_token_locker_id: None, network_token_payment_method_data: None, network_token_requestor_reference_id: None, + transaction_flow, }, storage_scheme, ) @@ -1250,6 +1252,7 @@ pub async fn create_payment_method_for_intent( network_token_locker_id: None, network_token_payment_method_data: None, network_token_requestor_reference_id: None, + transaction_flow: None, }, storage_scheme, ) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 8b72a946d6d3..5a7f96a98fe7 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2831,9 +2831,11 @@ pub async fn update_payment_method_connector_mandate_details( pm: domain::PaymentMethod, connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, + transaction_flow: Option, ) -> errors::CustomResult<(), errors::VaultError> { let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, + transaction_flow, }; db.update_payment_method(&(state.into()), key_store, pm, pm_update, storage_scheme) diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 0586fecbbc2d..5f15fe38ec98 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -345,16 +345,6 @@ pub async fn payouts_create_core( payment_method.clone(), ) .await?; - /* - - - dummy commit - - - - - - */ let payout_attempt = payout_data.payout_attempt.to_owned(); let payout_type = payout_data.payouts.payout_type.to_owned(); @@ -2006,6 +1996,10 @@ fn connector_mandate_id_is_none( payout_data: &mut PayoutData, connector_data: &api::ConnectorData, ) -> RouterResult { + #[cfg(all( + any(feature = "v2", feature = "v1"), + not(feature = "payment_methods_v2") + ))] if let Some(pm) = &payout_data.payment_method { let connector_mandate_details = pm .connector_mandate_details @@ -2156,11 +2150,12 @@ pub async fn create_recipient_disburse_account( let connector_mandate_details_value = serde_json::to_value(connector_mandate_details).ok(); - /**************** above this is correct ********************** - need to fetch connector_mandate_details using payment_method_id - */ let pm_id = payout_data.payouts.payout_method_id.clone(); + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] if let Some(payout_method_id) = pm_id { let payment_method = db .find_payment_method( @@ -2176,14 +2171,7 @@ pub async fn create_recipient_disburse_account( payout_data.payment_method = Some(payment_method.clone()); payout_data.payouts.payout_method_id = Some(payment_method.payment_method_id.clone()); - - // router_env::logger::info!("XXXXXXXXXXXXXXXXX"); - // router_env::logger::info!("{:?}", payment_method.payment_method_id.clone()); - // router_env::logger::info!("XXXXXXXXXXXXXXXXX"); - // router_env::logger::info!("{:?}", payment_method.clone()); - // router_env::logger::info!("XXXXXXXXXXXXXXXXX"); } else { - // router_env::logger::info!("9999999999999999"); helpers::save_payout_data_to_locker( state, payout_data, @@ -2546,7 +2534,20 @@ pub async fn response_handler( let payment_method_id: Option = payout_data .payment_method .as_ref() // Safely access the `payment_method` as a reference - .map(|pm| pm.payment_method_id.clone()); + .map(|pm| { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] + { + pm.payment_method_id.clone() + } + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + { + pm.id.clone().get_string_repr().to_string() + } + }); let payout_link = payout_data.payout_link.to_owned(); let billing_address = payout_data.billing_address.to_owned(); @@ -2636,6 +2637,7 @@ pub async fn payout_create_db_entries( _stored_payout_method_data: Option<&payouts::PayoutMethodData>, _locale: &str, _customer: Option<&domain::Customer>, + _payment_method: Option, ) -> RouterResult { todo!() } diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 2eda19f08bfe..a5ca5bdba7c1 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -640,10 +640,11 @@ pub async fn save_payout_data_to_locker( _payout_data: &mut PayoutData, _customer_id: &id_type::CustomerId, _payout_method_data: &api::PayoutMethodData, + _connector_mandate_details: Option, _merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, ) -> RouterResult<()> { - todo!() + Ok(()) } #[cfg(all(feature = "v2", feature = "customer_v2"))] diff --git a/crates/router/src/core/payouts/validator.rs b/crates/router/src/core/payouts/validator.rs index 49ce31cb6455..cae7cdfd93d2 100644 --- a/crates/router/src/core/payouts/validator.rs +++ b/crates/router/src/core/payouts/validator.rs @@ -12,10 +12,16 @@ use router_env::{instrument, tracing, which as router_env_which, Env}; use url::Url; use super::helpers; +#[cfg(all( + any(feature = "v2", feature = "v1"), + not(feature = "payment_methods_v2"), + not(feature = "customer_v2") +))] +use crate::core::payment_methods::cards::get_pm_list_context; use crate::{ core::{ errors::{self, RouterResult}, - payment_methods::cards::get_pm_list_context, + // payment_methods::cards::get_pm_list_context, utils as core_utils, }, db::StorageInterface, @@ -60,6 +66,7 @@ pub async fn validate_create_request( Option, String, Option, + Option, )> { todo!() } From d9270d3d6e1a3226c84a9463211247f588f67334 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Mon, 2 Dec 2024 14:18:10 +0530 Subject: [PATCH 04/29] comment resolved --- crates/api_models/src/payouts.rs | 6 +- crates/diesel_models/src/enums.rs | 6 +- crates/diesel_models/src/payment_method.rs | 14 +- .../src/payment_methods.rs | 4 +- crates/router/src/core/payment_methods.rs | 2 +- .../router/src/core/payment_methods/cards.rs | 20 +- .../payments/operations/payment_response.rs | 2 +- .../router/src/core/payments/tokenization.rs | 6 +- crates/router/src/core/payouts.rs | 172 +++++++++--------- crates/router/src/core/payouts/helpers.rs | 50 ++++- .../router/src/core/payouts/transformers.rs | 2 +- crates/router/src/core/payouts/validator.rs | 49 ++--- crates/router/src/core/utils.rs | 30 +-- 13 files changed, 183 insertions(+), 180 deletions(-) diff --git a/crates/api_models/src/payouts.rs b/crates/api_models/src/payouts.rs index d1c356d7792d..4c8a73b75a8d 100644 --- a/crates/api_models/src/payouts.rs +++ b/crates/api_models/src/payouts.rs @@ -185,7 +185,8 @@ pub struct PayoutCreateRequest { #[schema(deprecated, max_length = 255, example = "+1")] pub phone_country_code: Option, - pub payment_method_id: Option, + /// Identifier for payout method + pub payout_method_id: Option, } impl PayoutCreateRequest { @@ -571,7 +572,8 @@ pub struct PayoutCreateResponse { #[schema(value_type = Option, max_length = 1024, example = "Invalid card details")] pub unified_message: Option, - pub payment_method_id: Option, + /// Identifier for payout method + pub payout_method_id: Option, } /// The payout method information for response diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs index bb9ca1c45cfc..a24fbf89ad0f 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -342,8 +342,8 @@ pub enum UserRoleVersion { #[router_derive::diesel_enum(storage_type = "text")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] -pub enum TransactionFlow { +pub enum PaymentDirection { #[default] - Payment, - Payouts, + Payin, + Payout, } diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 581a7ef5d020..eae4437afb16 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -64,7 +64,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, + pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -93,7 +93,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, + pub transaction_flow: Option, } impl PaymentMethod { @@ -154,7 +154,7 @@ pub struct PaymentMethodNew { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, + pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -183,7 +183,7 @@ pub struct PaymentMethodNew { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, + pub transaction_flow: Option, } impl PaymentMethodNew { @@ -252,7 +252,7 @@ pub enum PaymentMethodUpdate { }, ConnectorMandateDetailsUpdate { connector_mandate_details: Option, - transaction_flow: Option, + transaction_flow: Option, }, NetworkTokenDataUpdate { network_token_requestor_reference_id: Option, @@ -299,7 +299,7 @@ pub enum PaymentMethodUpdate { }, ConnectorMandateDetailsUpdate { connector_mandate_details: Option, - transaction_flow: Option, + transaction_flow: Option, }, } @@ -407,7 +407,7 @@ pub struct PaymentMethodUpdateInternal { last_modified: PrimitiveDateTime, network_token_locker_id: Option, network_token_payment_method_data: Option, - transaction_flow: Option, + transaction_flow: Option, scheme: Option, } diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index c9f46a296e0d..f5297cf7def9 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -69,7 +69,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: OptionalEncryptableValue, - pub transaction_flow: Option, + pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -98,7 +98,7 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: OptionalEncryptableValue, - pub transaction_flow: Option, + pub transaction_flow: Option, } impl PaymentMethod { diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index dd735733cb52..07f49b0bd553 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -1156,7 +1156,7 @@ pub async fn create_payment_method_in_db( storage_scheme: enums::MerchantStorageScheme, payment_method_billing_address: crypto::OptionalEncryptableValue, card_scheme: Option, - transaction_flow: Option, + transaction_flow: Option, ) -> errors::CustomResult { let db = &*state.store; let current_time = common_utils::date_time::now(); diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 5a7f96a98fe7..f37cd81e5d8d 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -146,7 +146,7 @@ pub async fn create_payment_method( network_token_requestor_reference_id: Option, network_token_locker_id: Option, network_token_payment_method_data: crypto::OptionalEncryptableValue, - transaction_flow: Option, + transaction_flow: Option, ) -> errors::CustomResult { let db = &*state.store; let customer = db @@ -348,7 +348,7 @@ pub async fn get_or_insert_payment_method( None, None, None, - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await } else { @@ -831,7 +831,7 @@ pub async fn skip_locker_call_and_migrate_payment_method( network_token_requestor_reference_id: None, network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: Some(storage_enums::TransactionFlow::Payment), + transaction_flow: Some(storage_enums::PaymentDirection::Payin), }, merchant_account.storage_scheme, ) @@ -1081,7 +1081,7 @@ pub async fn get_client_secret_or_add_payment_method( None, None, None, - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await?; @@ -1175,7 +1175,7 @@ pub async fn get_client_secret_or_add_payment_method_for_migration( None, None, None, - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await?; migration_status.connector_mandate_details_migrated( @@ -1695,7 +1695,7 @@ pub async fn add_payment_method( None, None, None, - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await?; @@ -1958,7 +1958,7 @@ pub async fn save_migration_payment_method( None, None, None, - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await?; @@ -2005,7 +2005,7 @@ pub async fn insert_payment_method( network_token_requestor_reference_id: Option, network_token_locker_id: Option, network_token_payment_method_data: crypto::OptionalEncryptableValue, - transaction_flow: Option, + transaction_flow: Option, ) -> errors::RouterResult { let pm_card_details = resp .card @@ -2831,7 +2831,7 @@ pub async fn update_payment_method_connector_mandate_details( pm: domain::PaymentMethod, connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, - transaction_flow: Option, + transaction_flow: Option, ) -> errors::CustomResult<(), errors::VaultError> { let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, @@ -2855,7 +2855,7 @@ pub async fn update_payment_method_connector_mandate_details( pm: domain::PaymentMethod, connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, - transaction_flow: Option, + transaction_flow: Option, ) -> errors::CustomResult<(), errors::VaultError> { let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 252c2b4a57af..643798f42379 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1647,7 +1647,7 @@ async fn payment_response_update_tracker( payment_method, connector_mandate_details, storage_scheme, - Some(diesel_models::enums::TransactionFlow::Payment), + Some(diesel_models::enums::PaymentDirection::Payin), ) .await .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 58cee57d8250..1e3a6c500a0f 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -400,7 +400,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await } else { @@ -487,7 +487,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await } else { @@ -704,7 +704,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::TransactionFlow::Payment), + Some(storage_enums::PaymentDirection::Payin), ) .await?; }; diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 5f15fe38ec98..5db3e2983488 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -28,6 +28,10 @@ use diesel_models::{ enums as storage_enums, generic_link::{GenericLinkNew, PayoutLink}, }; +#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] +use diesel_models::{ + PaymentsMandateReference, PaymentsMandateReferenceRecord as PaymentsMandateReferenceRecordV2, +}; use error_stack::{report, ResultExt}; #[cfg(feature = "olap")] use futures::future::join_all; @@ -1990,45 +1994,6 @@ pub async fn update_retrieve_payout_tracker( Ok(()) } -/* - */ -fn connector_mandate_id_is_none( - payout_data: &mut PayoutData, - connector_data: &api::ConnectorData, -) -> RouterResult { - #[cfg(all( - any(feature = "v2", feature = "v1"), - not(feature = "payment_methods_v2") - ))] - if let Some(pm) = &payout_data.payment_method { - let connector_mandate_details = pm - .connector_mandate_details - .clone() - .map(|details| { - details.parse_value::( - "connector_mandate_details", - ) - }) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to deserialize connector mandate details")?; - - if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { - if let Some(_mandate_reference_record) = connector_mandate_details - .clone() - .get_required_value("connector_mandate_details") - .change_context(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) - .attach_printable("there were no connector mandate details")? - .get(merchant_connector_id) - { - return Ok(false); - } - } - return Ok(true); - } - Ok(true) -} - pub async fn complete_create_recipient_disburse_account( state: &SessionState, merchant_account: &domain::MerchantAccount, @@ -2045,7 +2010,8 @@ pub async fn complete_create_recipient_disburse_account( && connector_data .connector_name .supports_vendor_disburse_account_create_for_payout() - && connector_mandate_id_is_none(payout_data, connector_data)? + && helpers::should_create_connector_transfer_method(&*payout_data, connector_data)? + .is_none() { Box::pin(create_recipient_disburse_account( state, @@ -2132,11 +2098,11 @@ pub async fn create_recipient_disburse_account( connector_data.merchant_connector_id.clone(), ) { let connector_mandate_details = HashMap::from([( - merchant_connector_id, // which connector was called [MCA] + merchant_connector_id.clone(), PaymentsMandateReferenceRecord { - connector_mandate_id: connector_payout_id, // what does the connector return + connector_mandate_id: connector_payout_id.clone(), payment_method_type: Some(api_enums::PaymentMethodType::foreign_from( - payout_method_data, + &payout_method_data.clone(), )), original_payment_authorized_amount: Some( payout_data.payouts.amount.get_amount_as_i64(), @@ -2150,39 +2116,74 @@ pub async fn create_recipient_disburse_account( let connector_mandate_details_value = serde_json::to_value(connector_mandate_details).ok(); - let pm_id = payout_data.payouts.payout_method_id.clone(); - - #[cfg(all( - any(feature = "v1", feature = "v2"), - not(feature = "payment_methods_v2") - ))] - if let Some(payout_method_id) = pm_id { - let payment_method = db - .find_payment_method( + if let Some(pm_method) = payout_data.payment_method.clone() { + let pm_update = + diesel_models::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] + connector_mandate_details: connector_mandate_details_value, + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + connector_mandate_details: Some(PaymentsMandateReference( + HashMap::from([( + merchant_connector_id, + PaymentsMandateReferenceRecordV2 { + connector_mandate_id: connector_payout_id, + payment_method_subtype: Some( + api_enums::PaymentMethodType::foreign_from( + payout_method_data, + ), + ), + original_payment_authorized_amount: Some( + payout_data.payouts.amount.get_amount_as_i64(), + ), + original_payment_authorized_currency: Some( + payout_data.payouts.destination_currency, + ), + mandate_metadata: None, + connector_mandate_status: None, + connector_mandate_request_reference_id: None, + }, + )]), + )), + + transaction_flow: Some(storage_enums::PaymentDirection::Payout), + }; + + payout_data.payment_method = Some( + db.update_payment_method( &(state.into()), key_store, - &payout_method_id, // need to get from api request + pm_method, + pm_update, merchant_account.storage_scheme, ) .await .change_context(errors::ApiErrorResponse::PaymentMethodNotFound) - .attach_printable("Unable to find payment method")?; - - payout_data.payment_method = Some(payment_method.clone()); - payout_data.payouts.payout_method_id = - Some(payment_method.payment_method_id.clone()); + .attach_printable("Unable to find payment method")?, + ); } else { - helpers::save_payout_data_to_locker( - state, - payout_data, - &customer_details.customer_id, - payout_method_data, - connector_mandate_details_value, - merchant_account, - key_store, - ) - .await - .attach_printable("Failed to save payout data to locker")?; + #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] + let customer_id = Some(customer_details.customer_id); + + #[cfg(all(feature = "v2", feature = "customer_v2"))] + let customer_id = customer_details.merchant_reference_id; + + if let Some(customer_id) = customer_id { + helpers::save_payout_data_to_locker( + state, + payout_data, + &customer_id, + payout_method_data, + connector_mandate_details_value, + merchant_account, + key_store, + ) + .await + .attach_printable("Failed to save payout data to locker")?; + } }; } } @@ -2531,23 +2532,20 @@ pub async fn response_handler( let payout_attempt = payout_data.payout_attempt.to_owned(); let payouts = payout_data.payouts.to_owned(); - let payment_method_id: Option = payout_data - .payment_method - .as_ref() // Safely access the `payment_method` as a reference - .map(|pm| { - #[cfg(all( - any(feature = "v1", feature = "v2"), - not(feature = "payment_methods_v2") - ))] - { - pm.payment_method_id.clone() - } + let payout_method_id: Option = payout_data.payment_method.as_ref().map(|pm| { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] + { + pm.payment_method_id.clone() + } - #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] - { - pm.id.clone().get_string_repr().to_string() - } - }); + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + { + pm.id.clone().get_string_repr().to_string() + } + }); let payout_link = payout_data.payout_link.to_owned(); let billing_address = payout_data.billing_address.to_owned(); @@ -2620,7 +2618,7 @@ pub async fn response_handler( .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to parse payout link's URL")?, - payment_method_id, + payout_method_id, }; Ok(services::ApplicationResponse::Json(response)) } @@ -3036,7 +3034,7 @@ pub async fn make_payout_data( db.find_payment_method( &(state.into()), key_store, - &pm_id, // need to get from api request + &pm_id, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index a5ca5bdba7c1..cbdb3c26bc13 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -3,7 +3,7 @@ use common_utils::{ crypto::Encryptable, encryption::Encryption, errors::CustomResult, - ext_traits::{AsyncExt, StringExt}, + ext_traits::{AsyncExt, StringExt, ValueExt}, fp_utils, id_type, payout_method_utils as payout_additional, pii, type_name, types::{ keymanager::{Identifier, KeyManagerState}, @@ -194,6 +194,50 @@ pub async fn make_payout_method_data<'a>( } } +pub fn should_create_connector_transfer_method( + payout_data: &PayoutData, + connector_data: &api::ConnectorData, +) -> RouterResult> { + let connector_mandate_id = if let Some(pm) = &payout_data.payment_method { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] + let connector_mandate_details = pm + .connector_mandate_details + .clone() + .map(|details| { + details.parse_value::( + "connector_mandate_details", + ) + }) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to deserialize connector mandate details")?; + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + let connector_mandate_details = pm.connector_mandate_details.clone(); + if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { + connector_mandate_details + .clone() + .and_then(|payments_mandate_reference| { + payments_mandate_reference + .get(merchant_connector_id) + .map(|payments_mandate_reference_record| { + payments_mandate_reference_record + .connector_mandate_id + .clone() + }) + }) + } else { + None + } + } else { + None + }; + + Ok(connector_mandate_id) +} + #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") @@ -540,7 +584,7 @@ pub async fn save_payout_data_to_locker( None, None, None, - Some(storage_enums::TransactionFlow::Payouts), + Some(storage_enums::PaymentDirection::Payout), ) .await?, ); @@ -644,7 +688,7 @@ pub async fn save_payout_data_to_locker( _merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, ) -> RouterResult<()> { - Ok(()) + todo!() } #[cfg(all(feature = "v2", feature = "customer_v2"))] diff --git a/crates/router/src/core/payouts/transformers.rs b/crates/router/src/core/payouts/transformers.rs index 38e886707193..c1a6c6cc23ce 100644 --- a/crates/router/src/core/payouts/transformers.rs +++ b/crates/router/src/core/payouts/transformers.rs @@ -115,7 +115,7 @@ impl phone_country_code: customer .as_ref() .and_then(|customer| customer.phone_country_code.clone()), - payment_method_id: payout.payout_method_id, + payout_method_id: payout.payout_method_id, } } } diff --git a/crates/router/src/core/payouts/validator.rs b/crates/router/src/core/payouts/validator.rs index cae7cdfd93d2..1ff8111fcb7e 100644 --- a/crates/router/src/core/payouts/validator.rs +++ b/crates/router/src/core/payouts/validator.rs @@ -21,7 +21,6 @@ use crate::core::payment_methods::cards::get_pm_list_context; use crate::{ core::{ errors::{self, RouterResult}, - // payment_methods::cards::get_pm_list_context, utils as core_utils, }, db::StorageInterface, @@ -148,28 +147,6 @@ pub async fn validate_create_request( None }; - // // payout_token - // let payout_method_data = match (req.payout_token.as_ref(), customer.as_ref()) { - // (Some(_), None) => Err(report!(errors::ApiErrorResponse::MissingRequiredField { - // field_name: "customer or customer_id when payout_token is provided" - // })), - // (Some(payout_token), Some(customer)) => { - // helpers::make_payout_method_data( - // state, - // req.payout_method_data.as_ref(), - // Some(payout_token), - // &customer.customer_id, - // merchant_account.get_id(), - // req.payout_type, - // merchant_key_store, - // None, - // merchant_account.storage_scheme, - // ) - // .await - // } - // _ => Ok(None), - // }?; - #[cfg(feature = "v1")] let profile_id = core_utils::get_profile_id_from_business_details( &state.into(), @@ -193,10 +170,15 @@ pub async fn validate_create_request( }) .attach_printable("Profile id is a mandatory parameter")?; - // fetching payment_method using req.payment_method_id and passing it from here let payment_method: Option = - if let Some(payment_method_id) = req.payment_method_id.clone() { - match customer.as_ref() { + match (req.payout_token.as_ref(), req.payout_method_id.clone()) { + (Some(_), Some(_)) => { + Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: "Only one of payout_method_id or payout_token should be provided." + .to_string(), + })) + } + (None, Some(payment_method_id)) => match customer.as_ref() { Some(customer) => { let payment_method = db .find_payment_method( @@ -208,24 +190,25 @@ pub async fn validate_create_request( .await .change_context(errors::ApiErrorResponse::PaymentMethodNotFound) .attach_printable("Unable to find payment method")?; + utils::when(payment_method.customer_id != customer.customer_id, || { Err(report!(errors::ApiErrorResponse::InvalidRequestData { - message: "payment method does not belong to this customer_id".to_string() + message: "Payment method does not belong to this customer_id".to_string(), }) .attach_printable( "customer_id in payment_method does not match with customer_id in request", )) })?; - Some(payment_method) + Ok(Some(payment_method)) } None => Err(report!(errors::ApiErrorResponse::MissingRequiredField { field_name: "customer_id when payment_method_id is passed", - }))?, - } - } else { - None - }; + })), + }, + _ => Ok(None), + }?; + // payout_token let payout_method_data = match ( req.payout_token.as_ref(), customer.as_ref(), diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index dd08c6a2577c..6751795a43bf 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -24,7 +24,7 @@ use uuid::Uuid; use super::payments::helpers; #[cfg(feature = "payouts")] -use super::payouts::PayoutData; +use super::payouts::{helpers as payout_helpers, PayoutData}; #[cfg(feature = "payouts")] use crate::core::payments; use crate::{ @@ -148,32 +148,8 @@ pub async fn construct_payout_router_data<'a, F>( _ => None, }; - let mut connector_mandate_id = None; - if let Some(pm) = &payout_data.payment_method { - let connector_mandate_details = pm - .connector_mandate_details - .clone() - .map(|details| { - details.parse_value::( - "connector_mandate_details", - ) - }) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to deserialize connector mandate details")?; - - if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { - if let Some(mandate_reference_record) = connector_mandate_details - .clone() - .get_required_value("connector_mandate_details") - .change_context(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration) - .attach_printable("there were no connector mandate details")? - .get(merchant_connector_id) - { - connector_mandate_id = Some(mandate_reference_record.connector_mandate_id.clone()); - } - } - } + let connector_mandate_id = + payout_helpers::should_create_connector_transfer_method(&*payout_data, connector_data)?; let router_data = types::RouterData { flow: PhantomData, From e694317057e3dfe8b70f30b11b06338c1331b3ed Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 5 Dec 2024 16:33:33 +0530 Subject: [PATCH 05/29] migrations update --- crates/diesel_models/src/enums.rs | 3 ++- crates/diesel_models/src/payment_method.rs | 1 + crates/diesel_models/src/schema.rs | 3 +-- crates/diesel_models/src/schema_v2.rs | 3 +-- crates/router/src/core/payouts/helpers.rs | 10 +++++----- crates/router/src/core/payouts/validator.rs | 10 ++++------ crates/router/src/core/webhooks/incoming.rs | 2 +- .../down.sql | 5 +++-- .../up.sql | 7 ++++++- 9 files changed, 24 insertions(+), 20 deletions(-) diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs index a24fbf89ad0f..601b73f75d9a 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -14,6 +14,7 @@ pub mod diesel_exports { DbIntentStatus as IntentStatus, DbMandateStatus as MandateStatus, DbMandateType as MandateType, DbMerchantStorageScheme as MerchantStorageScheme, DbOrderFulfillmentTimeOrigin as OrderFulfillmentTimeOrigin, + DbPaymentDirection as PaymentDirection, DbPaymentMethodIssuerCode as PaymentMethodIssuerCode, DbPaymentSource as PaymentSource, DbPaymentType as PaymentType, DbPayoutStatus as PayoutStatus, DbPayoutType as PayoutType, DbProcessTrackerStatus as ProcessTrackerStatus, DbReconStatus as ReconStatus, @@ -339,7 +340,7 @@ pub enum UserRoleVersion { strum::EnumString, strum::Display, )] -#[router_derive::diesel_enum(storage_type = "text")] +#[router_derive::diesel_enum(storage_type = "db_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum PaymentDirection { diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index eae4437afb16..ee68283cdf71 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -707,6 +707,7 @@ impl From for PaymentMethodUpdateInternal { network_token_requestor_reference_id: None, network_token_locker_id: None, network_token_payment_method_data: None, + transaction_flow: None, scheme: None, }, } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 9bef91ffde4d..961c55ddd59b 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -1064,8 +1064,7 @@ diesel::table! { #[max_length = 64] network_token_locker_id -> Nullable, network_token_payment_method_data -> Nullable, - #[max_length = 255] - transaction_flow -> Nullable, + transaction_flow -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 6a5cfe3d7dbe..21a3fa67b485 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -1009,8 +1009,7 @@ diesel::table! { #[max_length = 64] network_token_locker_id -> Nullable, network_token_payment_method_data -> Nullable, - #[max_length = 255] - transaction_flow -> Nullable, + transaction_flow -> Nullable, } } diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index cbdb3c26bc13..cc80b3a8865a 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -220,13 +220,13 @@ pub fn should_create_connector_transfer_method( connector_mandate_details .clone() .and_then(|payments_mandate_reference| { - payments_mandate_reference - .get(merchant_connector_id) - .map(|payments_mandate_reference_record| { + payments_mandate_reference.get(merchant_connector_id).map( + |payments_mandate_reference_record| { payments_mandate_reference_record .connector_mandate_id .clone() - }) + }, + ) }) } else { None @@ -234,7 +234,7 @@ pub fn should_create_connector_transfer_method( } else { None }; - + Ok(connector_mandate_id) } diff --git a/crates/router/src/core/payouts/validator.rs b/crates/router/src/core/payouts/validator.rs index 1ff8111fcb7e..3d7d457635cf 100644 --- a/crates/router/src/core/payouts/validator.rs +++ b/crates/router/src/core/payouts/validator.rs @@ -172,12 +172,10 @@ pub async fn validate_create_request( let payment_method: Option = match (req.payout_token.as_ref(), req.payout_method_id.clone()) { - (Some(_), Some(_)) => { - Err(report!(errors::ApiErrorResponse::InvalidRequestData { - message: "Only one of payout_method_id or payout_token should be provided." - .to_string(), - })) - } + (Some(_), Some(_)) => Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: "Only one of payout_method_id or payout_token should be provided." + .to_string(), + })), (None, Some(payment_method_id)) => match customer.as_ref() { Some(customer) => { let payment_method = db diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index 6b76ec1ab1f1..ff9849958b51 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -5,7 +5,7 @@ use actix_web::FromRequest; use api_models::payouts as payout_models; use api_models::webhooks::{self, WebhookResponseTracker}; use common_utils::{errors::ReportSwitchExt, events::ApiEventsType, ext_traits::ValueExt}; -use diesel_models::{enums as storage_enums, ConnectorMandateReferenceId}; +use diesel_models::ConnectorMandateReferenceId; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ payments::{payment_attempt::PaymentAttempt, HeaderPayload}, diff --git a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql index 5c63b3f5edb9..ffe21063b18f 100644 --- a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql +++ b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql @@ -1,3 +1,4 @@ -- This file should undo anything in `up.sql` -ALTER TABLE payment_methods -DROP COLUMN transaction_flow; \ No newline at end of file +ALTER TABLE payment_methods DROP COLUMN transaction_flow; + +DROP TYPE "PaymentDirection"; \ No newline at end of file diff --git a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql index 62be9f010282..17b7b04eaf07 100644 --- a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql +++ b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql @@ -1,2 +1,7 @@ -- Your SQL goes here -ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS transaction_flow VARCHAR(255); \ No newline at end of file +CREATE TYPE "PaymentDirection" AS ENUM ( + 'payin', + 'payout' +); + +ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS transaction_flow "PaymentDirection"; \ No newline at end of file From eb00c916f2850f08946754cb7caf22a5b657fccd Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 6 Dec 2024 16:29:01 +0530 Subject: [PATCH 06/29] comment resolved --- crates/diesel_models/src/payment_method.rs | 6 +----- crates/router/src/core/payment_methods/cards.rs | 4 ---- .../router/src/core/payments/operations/payment_response.rs | 1 - crates/router/src/core/payouts.rs | 2 -- 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index ee68283cdf71..cde68fc68f44 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -252,7 +252,6 @@ pub enum PaymentMethodUpdate { }, ConnectorMandateDetailsUpdate { connector_mandate_details: Option, - transaction_flow: Option, }, NetworkTokenDataUpdate { network_token_requestor_reference_id: Option, @@ -299,7 +298,6 @@ pub enum PaymentMethodUpdate { }, ConnectorMandateDetailsUpdate { connector_mandate_details: Option, - transaction_flow: Option, }, } @@ -644,7 +642,6 @@ impl From for PaymentMethodUpdateInternal { }, PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, - transaction_flow, } => Self { metadata: None, payment_method_data: None, @@ -661,7 +658,7 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow, + transaction_flow: None, scheme: None, }, PaymentMethodUpdate::NetworkTokenDataUpdate { @@ -835,7 +832,6 @@ impl From for PaymentMethodUpdateInternal { }, PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, - transaction_flow, } => Self { payment_method_data: None, last_used_at: None, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index f37cd81e5d8d..6dc0776589e9 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2831,11 +2831,9 @@ pub async fn update_payment_method_connector_mandate_details( pm: domain::PaymentMethod, connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, - transaction_flow: Option, ) -> errors::CustomResult<(), errors::VaultError> { let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, - transaction_flow, }; db.update_payment_method(&(state.into()), key_store, pm, pm_update, storage_scheme) @@ -2855,11 +2853,9 @@ pub async fn update_payment_method_connector_mandate_details( pm: domain::PaymentMethod, connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, - transaction_flow: Option, ) -> errors::CustomResult<(), errors::VaultError> { let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details, - transaction_flow, }; db.update_payment_method(&(state.into()), key_store, pm, pm_update, storage_scheme) diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 643798f42379..91fdfae63fae 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1647,7 +1647,6 @@ async fn payment_response_update_tracker( payment_method, connector_mandate_details, storage_scheme, - Some(diesel_models::enums::PaymentDirection::Payin), ) .await .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 5db3e2983488..689b138d0d5a 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -2148,8 +2148,6 @@ pub async fn create_recipient_disburse_account( }, )]), )), - - transaction_flow: Some(storage_enums::PaymentDirection::Payout), }; payout_data.payment_method = Some( From 3b295c8e8fc9893fb2b06658cbb11a7f8abbd34d Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 12 Dec 2024 12:55:27 +0530 Subject: [PATCH 07/29] wip --- crates/api_models/src/payment_methods.rs | 4 +++- .../hyperswitch_domain_models/src/router_response_types.rs | 3 ++- crates/router/src/core/payment_methods/cards.rs | 4 ++-- crates/router/src/core/payments/tokenization.rs | 6 +++--- crates/router/src/core/payouts.rs | 3 ++- crates/router/src/core/payouts/helpers.rs | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 18d18f08fd24..fcd8a080ac53 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -306,11 +306,12 @@ pub struct PaymentsMandateReference( ); #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct PaymentsMandateReferenceRecord { +pub struct PaymentsMandateReferenceRecord { // here pub connector_mandate_id: String, pub payment_method_type: Option, pub original_payment_authorized_amount: Option, pub original_payment_authorized_currency: Option, + pub payment_instrument_id: Option>, } #[cfg(all( @@ -2288,6 +2289,7 @@ impl Some(PaymentsMandateReference(HashMap::from([( mca_id.get_required_value("merchant_connector_id")?, PaymentsMandateReferenceRecord { + payment_instrument_id: record.clone().payment_instrument_id, //here connector_mandate_id: record .payment_instrument_id .get_required_value("payment_instrument_id")? diff --git a/crates/hyperswitch_domain_models/src/router_response_types.rs b/crates/hyperswitch_domain_models/src/router_response_types.rs index 61453f36b84e..cc64e5a07c8d 100644 --- a/crates/hyperswitch_domain_models/src/router_response_types.rs +++ b/crates/hyperswitch_domain_models/src/router_response_types.rs @@ -446,10 +446,11 @@ pub struct RetrieveFileResponse { #[cfg(feature = "payouts")] #[derive(Clone, Debug, Default)] -pub struct PayoutsResponseData { +pub struct PayoutsResponseData { // here pub status: Option, pub connector_payout_id: Option, pub payout_eligible: Option, + // pub transfer_method_id: Option, pub should_add_next_step_to_process_tracker: bool, pub error_code: Option, pub error_message: Option, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 6dc0776589e9..660aaa89d305 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -348,7 +348,7 @@ pub async fn get_or_insert_payment_method( None, None, None, - Some(storage_enums::PaymentDirection::Payin), + Some(storage_enums::PaymentDirection::Payin), // None ) .await } else { @@ -1958,7 +1958,7 @@ pub async fn save_migration_payment_method( None, None, None, - Some(storage_enums::PaymentDirection::Payin), + Some(storage_enums::PaymentDirection::Payin), // None ) .await?; diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 1e3a6c500a0f..8550a4076b7a 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -400,7 +400,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::PaymentDirection::Payin), + Some(storage_enums::PaymentDirection::Payin), // None ) .await } else { @@ -487,7 +487,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::PaymentDirection::Payin), + Some(storage_enums::PaymentDirection::Payin), // None ) .await } else { @@ -704,7 +704,7 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::PaymentDirection::Payin), + Some(storage_enums::PaymentDirection::Payin), // None ) .await?; }; diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 689b138d0d5a..e481ced7c717 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -2100,7 +2100,7 @@ pub async fn create_recipient_disburse_account( let connector_mandate_details = HashMap::from([( merchant_connector_id.clone(), PaymentsMandateReferenceRecord { - connector_mandate_id: connector_payout_id.clone(), + connector_mandate_id: connector_payout_id.clone(), // then what will connector_mandate_id be payment_method_type: Some(api_enums::PaymentMethodType::foreign_from( &payout_method_data.clone(), )), @@ -2110,6 +2110,7 @@ pub async fn create_recipient_disburse_account( original_payment_authorized_currency: Some( payout_data.payouts.destination_currency, ), + payment_instrument_id: Some(Secret::new(connector_payout_id.clone())), }, )]); diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index cc80b3a8865a..9294bb3f50cf 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -223,7 +223,7 @@ pub fn should_create_connector_transfer_method( payments_mandate_reference.get(merchant_connector_id).map( |payments_mandate_reference_record| { payments_mandate_reference_record - .connector_mandate_id + .connector_mandate_id //here should be change .clone() }, ) From 5ca24f85f1eed6418abc67695e68c28aad594190 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Wed, 18 Dec 2024 17:41:31 +0530 Subject: [PATCH 08/29] CommonMandateReference added --- crates/api_models/src/payment_methods.rs | 4 +- crates/diesel_models/src/payment_method.rs | 204 +++++++++++++++++- .../src/router_response_types.rs | 3 +- crates/router/src/core/payouts.rs | 56 +---- crates/router/src/core/payouts/helpers.rs | 24 ++- 5 files changed, 230 insertions(+), 61 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index fcd8a080ac53..18d18f08fd24 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -306,12 +306,11 @@ pub struct PaymentsMandateReference( ); #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct PaymentsMandateReferenceRecord { // here +pub struct PaymentsMandateReferenceRecord { pub connector_mandate_id: String, pub payment_method_type: Option, pub original_payment_authorized_amount: Option, pub original_payment_authorized_currency: Option, - pub payment_instrument_id: Option>, } #[cfg(all( @@ -2289,7 +2288,6 @@ impl Some(PaymentsMandateReference(HashMap::from([( mca_id.get_required_value("merchant_connector_id")?, PaymentsMandateReferenceRecord { - payment_instrument_id: record.clone().payment_instrument_id, //here connector_mandate_id: record .payment_instrument_id .get_required_value("payment_instrument_id")? diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index cde68fc68f44..0b9639494c02 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -8,7 +8,7 @@ use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; not(feature = "payment_methods_v2") ))] use masking::{ExposeInterface, Secret}; -use serde::{Deserialize, Serialize}; +use serde::{de, Deserialize, Deserializer, Serialize}; use time::PrimitiveDateTime; #[cfg(all( @@ -105,6 +105,175 @@ impl PaymentMethod { &self.payment_method_id } + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + #[derive(serde::Deserialize, Debug)] + pub struct __InnerPaymentMethodData { + 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>, + pub scheme: Option, + pub token: Option, + pub cardholder_name: Option>, + pub issuer_name: Option, + pub issuer_country: Option, + pub payer_country: Option>, + pub is_stored: Option, + pub swift_code: Option, + pub direct_debit_token: Option, + pub created_at: PrimitiveDateTime, + pub last_modified: PrimitiveDateTime, + pub payment_method: Option, + pub payment_method_type: Option, + pub payment_method_issuer: Option, + pub payment_method_issuer_code: Option, + pub metadata: Option, + pub payment_method_data: Option, + pub locker_id: Option, + pub last_used_at: PrimitiveDateTime, + pub connector_mandate_details: Option, + pub customer_acceptance: Option, + pub status: storage_enums::PaymentMethodStatus, + pub network_transaction_id: Option, + pub client_secret: Option, + pub payment_method_billing_address: Option, + pub updated_by: Option, + pub version: common_enums::ApiVersion, + pub network_token_requestor_reference_id: Option, + pub network_token_locker_id: Option, + pub network_token_payment_method_data: Option, + pub transaction_flow: Option, + } + + let mut deserialize_to_inner = __InnerPaymentMethodData::deserialize(deserializer)?; + + if let Some(connector_mandate_details) = deserialize_to_inner.connector_mandate_details { + match serde_json::from_value::( + connector_mandate_details.clone(), + ) { + Ok(common_mandate_reference) => { + let common_mandate_reference_value = serde_json::to_value( + common_mandate_reference, + ) + .map_err(|serde_json_error| de::Error::custom(serde_json_error.to_string()))?; + + deserialize_to_inner.connector_mandate_details = + Some(common_mandate_reference_value); + + Ok(Some(PaymentMethod { + customer_id: deserialize_to_inner.customer_id, + merchant_id: deserialize_to_inner.merchant_id, + payment_method_id: deserialize_to_inner.payment_method_id, + accepted_currency: deserialize_to_inner.accepted_currency, + scheme: deserialize_to_inner.scheme, + token: deserialize_to_inner.token, + cardholder_name: deserialize_to_inner.cardholder_name, + issuer_name: deserialize_to_inner.issuer_name, + issuer_country: deserialize_to_inner.issuer_country, + payer_country: deserialize_to_inner.payer_country, + is_stored: deserialize_to_inner.is_stored, + swift_code: deserialize_to_inner.swift_code, + direct_debit_token: deserialize_to_inner.direct_debit_token, + created_at: deserialize_to_inner.created_at, + last_modified: deserialize_to_inner.last_modified, + payment_method: deserialize_to_inner.payment_method, + payment_method_type: deserialize_to_inner.payment_method_type, + payment_method_issuer: deserialize_to_inner.payment_method_issuer, + payment_method_issuer_code: deserialize_to_inner.payment_method_issuer_code, + metadata: deserialize_to_inner.metadata, + payment_method_data: deserialize_to_inner.payment_method_data, + locker_id: deserialize_to_inner.locker_id, + last_used_at: deserialize_to_inner.last_used_at, + connector_mandate_details: deserialize_to_inner.connector_mandate_details, // can we reuse this code? + customer_acceptance: deserialize_to_inner.customer_acceptance, + status: deserialize_to_inner.status, + network_transaction_id: deserialize_to_inner.network_transaction_id, + client_secret: deserialize_to_inner.client_secret, + payment_method_billing_address: deserialize_to_inner + .payment_method_billing_address, + updated_by: deserialize_to_inner.updated_by, + version: deserialize_to_inner.version, + network_token_requestor_reference_id: deserialize_to_inner + .network_token_requestor_reference_id, + network_token_locker_id: deserialize_to_inner.network_token_locker_id, + network_token_payment_method_data: deserialize_to_inner + .network_token_payment_method_data, + transaction_flow: deserialize_to_inner.transaction_flow, + })) + } + Err(_) => { + match serde_json::from_value::( + connector_mandate_details, + ) { + Ok(payment_mandate_reference) => { + let common_mandate_reference_value = + serde_json::to_value(CommonMandateReference { + payments: Some(payment_mandate_reference), + payouts: None, + }) + .map_err(|serde_json_error| { + de::Error::custom(serde_json_error.to_string()) + })?; + + deserialize_to_inner.connector_mandate_details = + Some(common_mandate_reference_value); + + Ok(Some(PaymentMethod { + customer_id: deserialize_to_inner.customer_id, + merchant_id: deserialize_to_inner.merchant_id, + payment_method_id: deserialize_to_inner.payment_method_id, + accepted_currency: deserialize_to_inner.accepted_currency, + scheme: deserialize_to_inner.scheme, + token: deserialize_to_inner.token, + cardholder_name: deserialize_to_inner.cardholder_name, + issuer_name: deserialize_to_inner.issuer_name, + issuer_country: deserialize_to_inner.issuer_country, + payer_country: deserialize_to_inner.payer_country, + is_stored: deserialize_to_inner.is_stored, + swift_code: deserialize_to_inner.swift_code, + direct_debit_token: deserialize_to_inner.direct_debit_token, + created_at: deserialize_to_inner.created_at, + last_modified: deserialize_to_inner.last_modified, + payment_method: deserialize_to_inner.payment_method, + payment_method_type: deserialize_to_inner.payment_method_type, + payment_method_issuer: deserialize_to_inner.payment_method_issuer, + payment_method_issuer_code: deserialize_to_inner + .payment_method_issuer_code, + metadata: deserialize_to_inner.metadata, + payment_method_data: deserialize_to_inner.payment_method_data, + locker_id: deserialize_to_inner.locker_id, + last_used_at: deserialize_to_inner.last_used_at, + connector_mandate_details: deserialize_to_inner + .connector_mandate_details, + customer_acceptance: deserialize_to_inner.customer_acceptance, + status: deserialize_to_inner.status, + network_transaction_id: deserialize_to_inner.network_transaction_id, + client_secret: deserialize_to_inner.client_secret, + payment_method_billing_address: deserialize_to_inner + .payment_method_billing_address, + updated_by: deserialize_to_inner.updated_by, + version: deserialize_to_inner.version, + network_token_requestor_reference_id: deserialize_to_inner + .network_token_requestor_reference_id, + network_token_locker_id: deserialize_to_inner + .network_token_locker_id, + network_token_payment_method_data: deserialize_to_inner + .network_token_payment_method_data, + transaction_flow: deserialize_to_inner.transaction_flow, + })) + } + Err(_) => Err(de::Error::custom("Faild to deserialize PaymentMethod"))?, + } + } + } + } else { + Err(de::Error::custom("Faild to deserialize PaymentMethod"))? + } + } + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] pub fn get_id(&self) -> &common_utils::id_type::GlobalPaymentMethodId { &self.id @@ -990,3 +1159,36 @@ impl std::ops::DerefMut for PaymentsMandateReference { } common_utils::impl_to_sql_from_sql_json!(PaymentsMandateReference); + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PayoutsMandateReferenceRecord { + pub transfer_method_id: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, diesel::AsExpression)] +#[diesel(sql_type = diesel::sql_types::Jsonb)] +pub struct PayoutsMandateReference( + pub HashMap, +); + +impl std::ops::Deref for PayoutsMandateReference { + type Target = + HashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for PayoutsMandateReference { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, diesel::AsExpression)] +#[diesel(sql_type = diesel::sql_types::Jsonb)] +pub struct CommonMandateReference { + pub payments: Option, + pub payouts: Option, +} diff --git a/crates/hyperswitch_domain_models/src/router_response_types.rs b/crates/hyperswitch_domain_models/src/router_response_types.rs index cc64e5a07c8d..61453f36b84e 100644 --- a/crates/hyperswitch_domain_models/src/router_response_types.rs +++ b/crates/hyperswitch_domain_models/src/router_response_types.rs @@ -446,11 +446,10 @@ pub struct RetrieveFileResponse { #[cfg(feature = "payouts")] #[derive(Clone, Debug, Default)] -pub struct PayoutsResponseData { // here +pub struct PayoutsResponseData { pub status: Option, pub connector_payout_id: Option, pub payout_eligible: Option, - // pub transfer_method_id: Option, pub should_add_next_step_to_process_tracker: bool, pub error_code: Option, pub error_message: Option, diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index e481ced7c717..5bf277942923 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -11,10 +11,7 @@ use std::{ #[cfg(feature = "olap")] use api_models::payments as payment_enums; -use api_models::{ - self, enums as api_enums, payment_methods::PaymentsMandateReferenceRecord, - payouts::PayoutLinkResponse, -}; +use api_models::{self, enums as api_enums, payouts::PayoutLinkResponse}; #[cfg(feature = "payout_retry")] use common_enums::PayoutRetryType; use common_utils::{ @@ -27,6 +24,8 @@ use common_utils::{ use diesel_models::{ enums as storage_enums, generic_link::{GenericLinkNew, PayoutLink}, + CommonMandateReference, PaymentsMandateReference, PaymentsMandateReferenceRecord, + PayoutsMandateReference, PayoutsMandateReferenceRecord, }; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] use diesel_models::{ @@ -2099,56 +2098,23 @@ pub async fn create_recipient_disburse_account( ) { let connector_mandate_details = HashMap::from([( merchant_connector_id.clone(), - PaymentsMandateReferenceRecord { - connector_mandate_id: connector_payout_id.clone(), // then what will connector_mandate_id be - payment_method_type: Some(api_enums::PaymentMethodType::foreign_from( - &payout_method_data.clone(), - )), - original_payment_authorized_amount: Some( - payout_data.payouts.amount.get_amount_as_i64(), - ), - original_payment_authorized_currency: Some( - payout_data.payouts.destination_currency, - ), - payment_instrument_id: Some(Secret::new(connector_payout_id.clone())), + PayoutsMandateReferenceRecord { + transfer_method_id: Some(connector_payout_id), }, )]); + let common_connector_mandate = CommonMandateReference { + payments: None, // doubt here, i think i need to fetch it here. + payouts: Some(PayoutsMandateReference(connector_mandate_details)), + }; + let connector_mandate_details_value = - serde_json::to_value(connector_mandate_details).ok(); + serde_json::to_value(common_connector_mandate).ok(); if let Some(pm_method) = payout_data.payment_method.clone() { let pm_update = diesel_models::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { - #[cfg(all( - any(feature = "v1", feature = "v2"), - not(feature = "payment_methods_v2") - ))] connector_mandate_details: connector_mandate_details_value, - - #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] - connector_mandate_details: Some(PaymentsMandateReference( - HashMap::from([( - merchant_connector_id, - PaymentsMandateReferenceRecordV2 { - connector_mandate_id: connector_payout_id, - payment_method_subtype: Some( - api_enums::PaymentMethodType::foreign_from( - payout_method_data, - ), - ), - original_payment_authorized_amount: Some( - payout_data.payouts.amount.get_amount_as_i64(), - ), - original_payment_authorized_currency: Some( - payout_data.payouts.destination_currency, - ), - mandate_metadata: None, - connector_mandate_status: None, - connector_mandate_request_reference_id: None, - }, - )]), - )), }; payout_data.payment_method = Some( diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 9294bb3f50cf..78abab40fe67 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -207,8 +207,8 @@ pub fn should_create_connector_transfer_method( .connector_mandate_details .clone() .map(|details| { - details.parse_value::( - "connector_mandate_details", + details.parse_value::( + "connector_common_mandate_details", ) }) .transpose() @@ -219,14 +219,18 @@ pub fn should_create_connector_transfer_method( if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { connector_mandate_details .clone() - .and_then(|payments_mandate_reference| { - payments_mandate_reference.get(merchant_connector_id).map( - |payments_mandate_reference_record| { - payments_mandate_reference_record - .connector_mandate_id //here should be change - .clone() - }, - ) + .and_then(|common_mandate_reference| { + common_mandate_reference + .payouts + .clone() + .and_then(|payouts_mandate_reference| { + payouts_mandate_reference.get(merchant_connector_id).map( + |payouts_mandate_reference_record| { + payouts_mandate_reference_record.transfer_method_id.clone() + }, + ) + }) + .flatten() }) } else { None From d2dd0c10a6c9ae3a694e2d5e0c8fb9cfb59b64ae Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 19 Dec 2024 13:34:16 +0530 Subject: [PATCH 09/29] update should_create_connector_transfer_method --- crates/diesel_models/src/payment_method.rs | 25 +++++++++++- crates/router/src/core/payouts/helpers.rs | 47 ++++++++-------------- crates/router/src/core/utils.rs | 4 +- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 0b9639494c02..7c1de7698222 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use common_enums::MerchantStorageScheme; -use common_utils::{encryption::Encryption, pii}; +use common_utils::{encryption::Encryption, errors::ParsingError, pii}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -105,6 +105,29 @@ impl PaymentMethod { &self.payment_method_id } + pub fn get_common_mandate_reference( + connector_mandate_details: Option, + ) -> Result { + if let Some(value) = connector_mandate_details { + match serde_json::from_value::(value.clone()) { + Ok(common_mandate_reference) => Ok(common_mandate_reference), + Err(_) => match serde_json::from_value::(value.clone()) { + Ok(payment_mandate_reference) => Ok(CommonMandateReference { + payments: Some(payment_mandate_reference), + payouts: None, + }), + Err(_) => Err(ParsingError::StructParseFailure( + "Faild to deserialize PaymentMethod", + ))?, + }, + } + } else { + Err(ParsingError::StructParseFailure( + "Faild to deserialize PaymentMethod", + ))? + } + } + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 78abab40fe67..4ebcf1c14105 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -198,48 +198,35 @@ pub fn should_create_connector_transfer_method( payout_data: &PayoutData, connector_data: &api::ConnectorData, ) -> RouterResult> { - let connector_mandate_id = if let Some(pm) = &payout_data.payment_method { + let connector_transfer_method_id = if let Some(pm) = &payout_data.payment_method { #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") ))] - let connector_mandate_details = pm - .connector_mandate_details - .clone() - .map(|details| { - details.parse_value::( - "connector_common_mandate_details", - ) - }) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to deserialize connector mandate details")?; - #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] - let connector_mandate_details = pm.connector_mandate_details.clone(); + let common_mandate_reference = storage::PaymentMethod::get_common_mandate_reference( + pm.connector_mandate_details.clone(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to deserialize connector mandate details")?; + if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { - connector_mandate_details - .clone() - .and_then(|common_mandate_reference| { - common_mandate_reference - .payouts - .clone() - .and_then(|payouts_mandate_reference| { - payouts_mandate_reference.get(merchant_connector_id).map( - |payouts_mandate_reference_record| { - payouts_mandate_reference_record.transfer_method_id.clone() - }, - ) - }) - .flatten() + common_mandate_reference + .payouts + .and_then(|payouts_mandate_reference| { + payouts_mandate_reference.get(merchant_connector_id).map( + |payouts_mandate_reference_record| { + payouts_mandate_reference_record.transfer_method_id.clone() + }, + ) }) + .flatten() } else { None } } else { None }; - - Ok(connector_mandate_id) + Ok(connector_transfer_method_id) } #[cfg(all( diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 6751795a43bf..046b81413eb3 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -148,7 +148,7 @@ pub async fn construct_payout_router_data<'a, F>( _ => None, }; - let connector_mandate_id = + let connector_transfer_method_id = payout_helpers::should_create_connector_transfer_method(&*payout_data, connector_data)?; let router_data = types::RouterData { @@ -192,7 +192,7 @@ pub async fn construct_payout_router_data<'a, F>( phone: c.phone.map(Encryptable::into_inner), phone_country_code: c.phone_country_code, }), - connector_transfer_method_id: connector_mandate_id, + connector_transfer_method_id: connector_transfer_method_id, }, response: Ok(types::PayoutsResponseData::default()), access_token: None, From 03dc5e91928f27bf4868197f656ae8e0902a6fca Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 19 Dec 2024 18:30:29 +0530 Subject: [PATCH 10/29] PaymentsMandate to CommonMandate Reference --- crates/diesel_models/src/payment_method.rs | 10 ++-- .../src/merchant_connector_account.rs | 16 ++++-- .../src/payment_methods.rs | 2 +- crates/router/src/core/payment_methods.rs | 2 +- .../router/src/core/payment_methods/cards.rs | 10 ++-- crates/router/src/core/payments.rs | 28 ++++++---- .../payments/operations/payment_response.rs | 10 ++-- .../router/src/core/payments/tokenization.rs | 53 +++++++++++++------ crates/router/src/core/webhooks/incoming.rs | 12 +++-- 9 files changed, 92 insertions(+), 51 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 7c1de7698222..e999a8803f21 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -78,7 +78,7 @@ pub struct PaymentMethod { pub payment_method_data: Option, pub locker_id: Option, pub last_used_at: PrimitiveDateTime, - pub connector_mandate_details: Option, + pub connector_mandate_details: Option, pub customer_acceptance: Option, pub status: storage_enums::PaymentMethodStatus, pub network_transaction_id: Option, @@ -128,6 +128,7 @@ impl PaymentMethod { } } + /* pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, @@ -296,6 +297,7 @@ impl PaymentMethod { Err(de::Error::custom("Faild to deserialize PaymentMethod"))? } } + */ #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] pub fn get_id(&self) -> &common_utils::id_type::GlobalPaymentMethodId { @@ -360,7 +362,7 @@ pub struct PaymentMethodNew { pub payment_method_data: Option, pub locker_id: Option, pub last_used_at: PrimitiveDateTime, - pub connector_mandate_details: Option, + pub connector_mandate_details: Option, pub customer_acceptance: Option, pub status: storage_enums::PaymentMethodStatus, pub network_transaction_id: Option, @@ -489,7 +491,7 @@ pub enum PaymentMethodUpdate { locker_fingerprint_id: Option, }, ConnectorMandateDetailsUpdate { - connector_mandate_details: Option, + connector_mandate_details: Option, }, } @@ -514,7 +516,7 @@ pub struct PaymentMethodUpdateInternal { status: Option, locker_id: Option, payment_method_type_v2: Option, - connector_mandate_details: Option, + connector_mandate_details: Option, updated_by: Option, payment_method_subtype: Option, last_modified: PrimitiveDateTime, diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index 7789c05e9902..e9243bf82e1d 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -659,7 +659,7 @@ common_utils::create_list_wrapper!( pub fn is_merchant_connector_account_id_in_connector_mandate_details( &self, profile_id: Option<&id_type::ProfileId>, - connector_mandate_details: &diesel_models::PaymentsMandateReference, + connector_mandate_details: &diesel_models::CommonMandateReference, ) -> bool { let mca_ids = self .iter() @@ -671,8 +671,18 @@ common_utils::create_list_wrapper!( .collect::>(); connector_mandate_details - .keys() - .any(|mca_id| mca_ids.contains(mca_id)) + .payments + .as_ref() + .map_or(false, |payments| { + payments.0.keys().any(|mca_id| mca_ids.contains(mca_id)) + }) || + connector_mandate_details + .payouts + .as_ref() + .map_or(false, |payouts| { + payouts.0.keys().any(|mca_id| mca_ids.contains(mca_id)) + }) + } } ); diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index f5297cf7def9..988c86e2f0f7 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -85,7 +85,7 @@ pub struct PaymentMethod { OptionalEncryptableJsonType, pub locker_id: Option, pub last_used_at: PrimitiveDateTime, - pub connector_mandate_details: Option, + pub connector_mandate_details: Option, pub customer_acceptance: Option, pub status: storage_enums::PaymentMethodStatus, pub network_transaction_id: Option, diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 07f49b0bd553..6f76448ba7e2 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -1150,7 +1150,7 @@ pub async fn create_payment_method_in_db( api::payment_methods::PaymentMethodsData, >, key_store: &domain::MerchantKeyStore, - connector_mandate_details: Option, + connector_mandate_details: Option, status: Option, network_transaction_id: Option, storage_scheme: enums::MerchantStorageScheme, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 660aaa89d305..b9a2c59ea761 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2829,7 +2829,7 @@ pub async fn update_payment_method_connector_mandate_details( key_store: &domain::MerchantKeyStore, db: &dyn db::StorageInterface, pm: domain::PaymentMethod, - connector_mandate_details: Option, + connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, ) -> errors::CustomResult<(), errors::VaultError> { let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { @@ -4949,9 +4949,7 @@ pub async fn list_customer_payment_method( .connector_mandate_details .clone() .map(|val| { - val.parse_value::( - "PaymentsMandateReference", - ) + val.parse_value::("CommonMandateReference") }) .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) @@ -5228,7 +5226,7 @@ pub async fn get_mca_status( profile_id: Option, merchant_id: &id_type::MerchantId, is_connector_agnostic_mit_enabled: bool, - connector_mandate_details: Option, + connector_mandate_details: Option, network_transaction_id: Option<&String>, ) -> errors::RouterResult { if is_connector_agnostic_mit_enabled && network_transaction_id.is_some() { @@ -5266,7 +5264,7 @@ pub async fn get_mca_status( profile_id: Option, merchant_id: &id_type::MerchantId, is_connector_agnostic_mit_enabled: bool, - connector_mandate_details: Option<&payment_method::PaymentsMandateReference>, + connector_mandate_details: Option<&payment_method::CommonMandateReference>, network_transaction_id: Option<&String>, merchant_connector_accounts: &domain::MerchantConnectorAccounts, ) -> bool { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index cbf2cdea5384..27f61a17de61 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5778,16 +5778,24 @@ pub async fn decide_connector_for_normal_or_recurring_payment( where D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { - let connector_mandate_details = &payment_method_info - .connector_mandate_details - .clone() - .map(|details| { - details - .parse_value::("connector_mandate_details") - }) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to deserialize connector mandate details")?; + // let connector_mandate_details = &payment_method_info + // .connector_mandate_details + // .clone() + // .map(|details| { + // details + // .parse_value::("connector_mandate_details") + // }) + // .transpose() + // .change_context(errors::ApiErrorResponse::InternalServerError) + // .attach_printable("unable to deserialize connector mandate details")?; + + let connector_common_mandate_details = storage::PaymentMethod::get_common_mandate_reference( + payment_method_info.connector_mandate_details.clone(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to get the common mandate reference")?; + + let connector_mandate_details = connector_common_mandate_details.payments; let mut connector_choice = None; diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 91fdfae63fae..17d523b82f98 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1591,8 +1591,8 @@ async fn payment_response_update_tracker( .connector_mandate_details .clone() .map(|val| { - val.parse_value::( - "PaymentsMandateReference", + val.parse_value::( + "CommonMandateReference", ) }) .transpose() @@ -1609,9 +1609,11 @@ async fn payment_response_update_tracker( // check if the mandate has not already been set to active if !mandate_details .as_ref() - .map(|payment_mandate_reference| { + .map(|common_mandate_reference| { - payment_mandate_reference.0.get(&mca_id) + common_mandate_reference.payments + .as_ref() + .and_then(|payments| payments.0.get(&mca_id)) .map(|payment_mandate_reference_record| payment_mandate_reference_record.connector_mandate_status == Some(common_enums::ConnectorMandateStatus::Active)) .unwrap_or(false) }) diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 8550a4076b7a..bfaf1968dfac 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -1176,7 +1176,7 @@ pub fn add_connector_mandate_details_in_payment_method( connector_mandate_id: Option, mandate_metadata: Option>, connector_mandate_request_reference_id: Option, -) -> Option { +) -> Option { let mut mandate_details = HashMap::new(); if let Some((mca_id, connector_mandate_id)) = @@ -1194,7 +1194,11 @@ pub fn add_connector_mandate_details_in_payment_method( connector_mandate_request_reference_id, }, ); - Some(diesel_models::PaymentsMandateReference(mandate_details)) + // Some(diesel_models::PaymentsMandateReference(mandate_details)) + Some(diesel_models::CommonMandateReference { + payments: Some(diesel_models::PaymentsMandateReference(mandate_details)), + payouts: None, + }) } else { None } @@ -1203,7 +1207,7 @@ pub fn add_connector_mandate_details_in_payment_method( #[allow(clippy::too_many_arguments)] #[cfg(feature = "v1")] pub fn update_connector_mandate_details( - mandate_details: Option, + mandate_details: Option, payment_method_type: Option, authorized_amount: Option, authorized_currency: Option, @@ -1213,7 +1217,7 @@ pub fn update_connector_mandate_details( connector_mandate_request_reference_id: Option, ) -> RouterResult> { let mandate_reference = match mandate_details { - Some(mut payment_mandate_reference) => { + Some(mut common_mandate_reference) => { if let Some((mca_id, connector_mandate_id)) = merchant_connector_id.clone().zip(connector_mandate_id) { @@ -1228,19 +1232,34 @@ pub fn update_connector_mandate_details( .clone(), }; - payment_mandate_reference - .entry(mca_id) - .and_modify(|pm| *pm = updated_record) - .or_insert(diesel_models::PaymentsMandateReferenceRecord { - connector_mandate_id, - payment_method_type, - original_payment_authorized_amount: authorized_amount, - original_payment_authorized_currency: authorized_currency, - mandate_metadata: mandate_metadata.clone(), - connector_mandate_status: Some(ConnectorMandateStatus::Active), - connector_mandate_request_reference_id, - }); - Some(payment_mandate_reference) + if let Some(payments_mandate_reference) = common_mandate_reference.payments.as_mut() + { + payments_mandate_reference + .entry(mca_id) + .and_modify(|pm| *pm = updated_record) + .or_insert(diesel_models::PaymentsMandateReferenceRecord { + connector_mandate_id, + payment_method_type, + original_payment_authorized_amount: authorized_amount, + original_payment_authorized_currency: authorized_currency, + mandate_metadata: mandate_metadata.clone(), + connector_mandate_status: Some(ConnectorMandateStatus::Active), + connector_mandate_request_reference_id, + }); + } + // common_mandate_reference + // .entry(mca_id) + // .and_modify(|pm| *pm = updated_record) + // .or_insert(diesel_models::PaymentsMandateReferenceRecord { + // connector_mandate_id, + // payment_method_type, + // original_payment_authorized_amount: authorized_amount, + // original_payment_authorized_currency: authorized_currency, + // mandate_metadata: mandate_metadata.clone(), + // connector_mandate_status: Some(ConnectorMandateStatus::Active), + // connector_mandate_request_reference_id, + // }); + Some(common_mandate_reference) } else { None } diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index ff9849958b51..fcef17c2235a 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -1846,8 +1846,8 @@ async fn update_connector_mandate_details( .connector_mandate_details .clone() .map(|val| { - val.parse_value::( - "PaymentsMandateReference", + val.parse_value::( + "CommonMandateReference", ) }) .transpose() @@ -1861,8 +1861,10 @@ async fn update_connector_mandate_details( if mandate_details .as_ref() - .map(|details: &diesel_models::PaymentsMandateReference| { - !details.0.contains_key(&merchant_connector_account_id) + .map(|details: &diesel_models::CommonMandateReference| { + !details.payments.as_ref().map_or(false, |payments| { + payments.0.contains_key(&merchant_connector_account_id) + }) }) .unwrap_or(true) { @@ -1948,7 +1950,7 @@ async fn update_connector_mandate_details( fn insert_mandate_details( payment_attempt: &PaymentAttempt, webhook_mandate_details: &hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails, - payment_method_mandate_details: Option, + payment_method_mandate_details: Option, ) -> CustomResult, errors::ApiErrorResponse> { let (mandate_metadata, connector_mandate_request_reference_id) = payment_attempt .connector_mandate_detail From 3371764d2537c27ced0b6a2444f73df6e16dc7a2 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 20 Dec 2024 15:36:55 +0530 Subject: [PATCH 11/29] wip --- crates/common_utils/src/macros.rs | 4 + crates/diesel_models/src/payment_method.rs | 192 +++++++++++---------- crates/router/src/core/payouts.rs | 11 +- crates/router/src/core/payouts/helpers.rs | 2 + crates/router/src/core/utils.rs | 2 +- 5 files changed, 117 insertions(+), 94 deletions(-) diff --git a/crates/common_utils/src/macros.rs b/crates/common_utils/src/macros.rs index fe1289acba03..da4046ddf01b 100644 --- a/crates/common_utils/src/macros.rs +++ b/crates/common_utils/src/macros.rs @@ -143,6 +143,10 @@ macro_rules! impl_to_sql_from_sql_json { }; } + + + + mod id_type { /// Defines an ID type. #[macro_export] diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index e999a8803f21..fd1b68b88071 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -10,6 +10,13 @@ use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; use masking::{ExposeInterface, Secret}; use serde::{de, Deserialize, Deserializer, Serialize}; use time::PrimitiveDateTime; +use error_stack::report; +// use diesel::{ +// backend::Backend, +// deserialize, +// deserialize::FromSql, +// // serialize::{Output, ToSql}, +// }; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -128,33 +135,18 @@ impl PaymentMethod { } } - /* - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { #[derive(serde::Deserialize, Debug)] pub struct __InnerPaymentMethodData { - pub customer_id: common_utils::id_type::CustomerId, + pub customer_id: common_utils::id_type::GlobalCustomerId, pub merchant_id: common_utils::id_type::MerchantId, - pub payment_method_id: String, - pub accepted_currency: Option>, - pub scheme: Option, - pub token: Option, - pub cardholder_name: Option>, - pub issuer_name: Option, - pub issuer_country: Option, - pub payer_country: Option>, - pub is_stored: Option, - pub swift_code: Option, - pub direct_debit_token: Option, pub created_at: PrimitiveDateTime, pub last_modified: PrimitiveDateTime, - pub payment_method: Option, - pub payment_method_type: Option, - pub payment_method_issuer: Option, - pub payment_method_issuer_code: Option, - pub metadata: Option, pub payment_method_data: Option, pub locker_id: Option, pub last_used_at: PrimitiveDateTime, @@ -165,6 +157,10 @@ impl PaymentMethod { pub client_secret: Option, pub payment_method_billing_address: Option, pub updated_by: Option, + pub locker_fingerprint_id: Option, + pub payment_method_type_v2: Option, + pub payment_method_subtype: Option, + pub id: common_utils::id_type::GlobalPaymentMethodId, pub version: common_enums::ApiVersion, pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, @@ -179,52 +175,37 @@ impl PaymentMethod { connector_mandate_details.clone(), ) { Ok(common_mandate_reference) => { - let common_mandate_reference_value = serde_json::to_value( - common_mandate_reference, - ) - .map_err(|serde_json_error| de::Error::custom(serde_json_error.to_string()))?; + // let common_mandate_reference_value = serde_json::to_value( + // common_mandate_reference, + // ) + // .map_err(|serde_json_error| de::Error::custom(serde_json_error.to_string()))?; - deserialize_to_inner.connector_mandate_details = - Some(common_mandate_reference_value); + // deserialize_to_inner.connector_mandate_details = + // Some(common_mandate_reference); - Ok(Some(PaymentMethod { + Ok(Some(Self { customer_id: deserialize_to_inner.customer_id, merchant_id: deserialize_to_inner.merchant_id, - payment_method_id: deserialize_to_inner.payment_method_id, - accepted_currency: deserialize_to_inner.accepted_currency, - scheme: deserialize_to_inner.scheme, - token: deserialize_to_inner.token, - cardholder_name: deserialize_to_inner.cardholder_name, - issuer_name: deserialize_to_inner.issuer_name, - issuer_country: deserialize_to_inner.issuer_country, - payer_country: deserialize_to_inner.payer_country, - is_stored: deserialize_to_inner.is_stored, - swift_code: deserialize_to_inner.swift_code, - direct_debit_token: deserialize_to_inner.direct_debit_token, created_at: deserialize_to_inner.created_at, last_modified: deserialize_to_inner.last_modified, - payment_method: deserialize_to_inner.payment_method, - payment_method_type: deserialize_to_inner.payment_method_type, - payment_method_issuer: deserialize_to_inner.payment_method_issuer, - payment_method_issuer_code: deserialize_to_inner.payment_method_issuer_code, - metadata: deserialize_to_inner.metadata, payment_method_data: deserialize_to_inner.payment_method_data, locker_id: deserialize_to_inner.locker_id, last_used_at: deserialize_to_inner.last_used_at, - connector_mandate_details: deserialize_to_inner.connector_mandate_details, // can we reuse this code? + connector_mandate_details: Some(common_mandate_reference), customer_acceptance: deserialize_to_inner.customer_acceptance, status: deserialize_to_inner.status, network_transaction_id: deserialize_to_inner.network_transaction_id, client_secret: deserialize_to_inner.client_secret, - payment_method_billing_address: deserialize_to_inner - .payment_method_billing_address, + payment_method_billing_address: deserialize_to_inner.payment_method_billing_address, updated_by: deserialize_to_inner.updated_by, + locker_fingerprint_id: deserialize_to_inner.locker_fingerprint_id, + payment_method_type_v2: deserialize_to_inner.payment_method_type_v2, + payment_method_subtype: deserialize_to_inner.payment_method_subtype, + id: deserialize_to_inner.id, version: deserialize_to_inner.version, - network_token_requestor_reference_id: deserialize_to_inner - .network_token_requestor_reference_id, + network_token_requestor_reference_id: deserialize_to_inner.network_token_requestor_reference_id, network_token_locker_id: deserialize_to_inner.network_token_locker_id, - network_token_payment_method_data: deserialize_to_inner - .network_token_payment_method_data, + network_token_payment_method_data: deserialize_to_inner.network_token_payment_method_data, transaction_flow: deserialize_to_inner.transaction_flow, })) } @@ -233,71 +214,49 @@ impl PaymentMethod { connector_mandate_details, ) { Ok(payment_mandate_reference) => { - let common_mandate_reference_value = - serde_json::to_value(CommonMandateReference { - payments: Some(payment_mandate_reference), - payouts: None, - }) - .map_err(|serde_json_error| { - de::Error::custom(serde_json_error.to_string()) - })?; - - deserialize_to_inner.connector_mandate_details = - Some(common_mandate_reference_value); + let common_mandate_reference = CommonMandateReference { + payments: Some(payment_mandate_reference), + payouts: None, + }; + + // deserialize_to_inner.connector_mandate_details = + // Some(common_mandate_reference); - Ok(Some(PaymentMethod { + Ok(Some(Self { customer_id: deserialize_to_inner.customer_id, merchant_id: deserialize_to_inner.merchant_id, - payment_method_id: deserialize_to_inner.payment_method_id, - accepted_currency: deserialize_to_inner.accepted_currency, - scheme: deserialize_to_inner.scheme, - token: deserialize_to_inner.token, - cardholder_name: deserialize_to_inner.cardholder_name, - issuer_name: deserialize_to_inner.issuer_name, - issuer_country: deserialize_to_inner.issuer_country, - payer_country: deserialize_to_inner.payer_country, - is_stored: deserialize_to_inner.is_stored, - swift_code: deserialize_to_inner.swift_code, - direct_debit_token: deserialize_to_inner.direct_debit_token, created_at: deserialize_to_inner.created_at, last_modified: deserialize_to_inner.last_modified, - payment_method: deserialize_to_inner.payment_method, - payment_method_type: deserialize_to_inner.payment_method_type, - payment_method_issuer: deserialize_to_inner.payment_method_issuer, - payment_method_issuer_code: deserialize_to_inner - .payment_method_issuer_code, - metadata: deserialize_to_inner.metadata, payment_method_data: deserialize_to_inner.payment_method_data, locker_id: deserialize_to_inner.locker_id, last_used_at: deserialize_to_inner.last_used_at, - connector_mandate_details: deserialize_to_inner - .connector_mandate_details, + connector_mandate_details: Some(common_mandate_reference), customer_acceptance: deserialize_to_inner.customer_acceptance, status: deserialize_to_inner.status, network_transaction_id: deserialize_to_inner.network_transaction_id, client_secret: deserialize_to_inner.client_secret, - payment_method_billing_address: deserialize_to_inner - .payment_method_billing_address, + payment_method_billing_address: deserialize_to_inner.payment_method_billing_address, updated_by: deserialize_to_inner.updated_by, + locker_fingerprint_id: deserialize_to_inner.locker_fingerprint_id, + payment_method_type_v2: deserialize_to_inner.payment_method_type_v2, + payment_method_subtype: deserialize_to_inner.payment_method_subtype, + id: deserialize_to_inner.id, version: deserialize_to_inner.version, - network_token_requestor_reference_id: deserialize_to_inner - .network_token_requestor_reference_id, - network_token_locker_id: deserialize_to_inner - .network_token_locker_id, - network_token_payment_method_data: deserialize_to_inner - .network_token_payment_method_data, + network_token_requestor_reference_id: deserialize_to_inner.network_token_requestor_reference_id, + network_token_locker_id: deserialize_to_inner.network_token_locker_id, + network_token_payment_method_data: deserialize_to_inner.network_token_payment_method_data, transaction_flow: deserialize_to_inner.transaction_flow, })) } - Err(_) => Err(de::Error::custom("Faild to deserialize PaymentMethod"))?, + Err(_) => Err(de::Error::custom("Faild to deserialize PaymentMethod_V2"))?, } } } } else { - Err(de::Error::custom("Faild to deserialize PaymentMethod"))? + Err(de::Error::custom("Faild to deserialize PaymentMethod_V2"))? } } - */ + //*/ #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] pub fn get_id(&self) -> &common_utils::id_type::GlobalPaymentMethodId { @@ -1213,7 +1172,58 @@ impl std::ops::DerefMut for PayoutsMandateReference { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, diesel::AsExpression)] #[diesel(sql_type = diesel::sql_types::Jsonb)] +// #[derive(Debug, Clone, Serialize, Deserialize, diesel::AsExpression, diesel::FromSqlRow)] +// #[diesel(sql_type = Nullable)] pub struct CommonMandateReference { pub payments: Option, pub payouts: Option, } + +// common_utils::impl_to_sql_from_sql_json!(CommonMandateReference); + +impl diesel::serialize::ToSql for CommonMandateReference { + fn to_sql<'b>( + &'b self, + out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>, + ) -> diesel::serialize::Result { + let value = serde_json::to_value(self)?; + >::to_sql(&value, &mut out.reborrow()) + } +} + +impl diesel::deserialize::FromSql for CommonMandateReference +where + serde_json::Value: diesel::deserialize::FromSql, +{ + fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result { + // Deserialize into a generic serde_json::Value first + let value = >::from_sql(bytes)?; + + // Try to directly deserialize into CommonMandateReference + if let Ok(common_reference) = serde_json::from_value::(value.clone()) { + return Ok(common_reference); + } + + // If that fails, try deserializing into PaymentsMandateReference + if let Ok(payment_reference) = serde_json::from_value::(value) { + // Convert PaymentsMandateReference to CommonMandateReference + return Ok(Self::from(payment_reference)); + } + + // If neither succeeds, return an error + Err(report!(ParsingError::StructParseFailure("CommonMandateReference")) + .attach_printable("Failed to parse JSON into CommonMandateReference or PaymentsMandateReference"))? + } +} + +impl From for CommonMandateReference { + fn from(payment_reference: PaymentsMandateReference) -> Self { + Self{ + payments: Some(payment_reference), + payouts: None, + } + } +} \ No newline at end of file diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 5bf277942923..a531f2fa314e 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -24,7 +24,7 @@ use common_utils::{ use diesel_models::{ enums as storage_enums, generic_link::{GenericLinkNew, PayoutLink}, - CommonMandateReference, PaymentsMandateReference, PaymentsMandateReferenceRecord, + CommonMandateReference, PaymentsMandateReferenceRecord, PayoutsMandateReference, PayoutsMandateReferenceRecord, }; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -2109,12 +2109,19 @@ pub async fn create_recipient_disburse_account( }; let connector_mandate_details_value = - serde_json::to_value(common_connector_mandate).ok(); + serde_json::to_value(common_connector_mandate.clone()).ok(); if let Some(pm_method) = payout_data.payment_method.clone() { let pm_update = diesel_models::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] connector_mandate_details: connector_mandate_details_value, + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + connector_mandate_details: Some(common_connector_mandate), }; payout_data.payment_method = Some( diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 4ebcf1c14105..9d670e728ac3 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -209,6 +209,8 @@ pub fn should_create_connector_transfer_method( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to deserialize connector mandate details")?; + + if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { common_mandate_reference .payouts diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 046b81413eb3..ac525e24009d 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -192,7 +192,7 @@ pub async fn construct_payout_router_data<'a, F>( phone: c.phone.map(Encryptable::into_inner), phone_country_code: c.phone_country_code, }), - connector_transfer_method_id: connector_transfer_method_id, + connector_transfer_method_id, }, response: Ok(types::PayoutsResponseData::default()), access_token: None, From 356b277f7c48a161703c773c537a37f3f65969e4 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 20 Dec 2024 20:34:52 +0530 Subject: [PATCH 12/29] clippy fix --- crates/api_models/src/payment_methods.rs | 111 +++++++++++- crates/common_utils/src/macros.rs | 4 - crates/diesel_models/src/payment_method.rs | 158 ++---------------- .../router/src/core/payment_methods/cards.rs | 6 +- crates/router/src/core/payments/helpers.rs | 78 +++++---- crates/router/src/core/payouts.rs | 3 +- crates/router/src/core/payouts/helpers.rs | 5 +- 7 files changed, 170 insertions(+), 195 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 18d18f08fd24..f429fbe6c212 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -227,7 +227,7 @@ impl From for PaymentMethodIntentConfirm { } } } -#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] +#[derive(Debug, serde::Serialize, Clone)] /// This struct is only used by and internal api to migrate payment method pub struct PaymentMethodMigrate { /// Merchant id @@ -276,7 +276,7 @@ pub struct PaymentMethodMigrate { pub billing: Option, /// The connector mandate details of the payment method - pub connector_mandate_details: Option, + pub connector_mandate_details: Option, // The CIT (customer initiated transaction) transaction id associated with the payment method pub network_transaction_id: Option, @@ -300,11 +300,21 @@ pub struct PaymentMethodMigrateResponse { pub network_transaction_id_migrated: Option, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] pub struct PaymentsMandateReference( pub HashMap, ); +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PayoutsMandateReference( + pub HashMap, +); + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PayoutsMandateReferenceRecord { + pub transfer_method_id: Option, +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct PaymentsMandateReferenceRecord { pub connector_mandate_id: String, @@ -313,6 +323,95 @@ pub struct PaymentsMandateReferenceRecord { pub original_payment_authorized_currency: Option, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct CommonMandateReference { + pub payments: Option, + pub payouts: Option, +} + +impl<'de> serde::Deserialize<'de> for PaymentMethodMigrate { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Debug, serde::Deserialize)] + struct InnerPaymentMethodMigrate { + pub merchant_id: id_type::MerchantId, + pub payment_method: Option, + pub payment_method_type: Option, + pub payment_method_issuer: Option, + pub payment_method_issuer_code: Option, + pub card: Option, + pub network_token: Option, + pub metadata: Option, + pub customer_id: Option, + pub card_network: Option, + pub bank_transfer: Option, + pub wallet: Option, + pub payment_method_data: Option, + pub billing: Option, + pub connector_mandate_details: Option, + pub network_transaction_id: Option, + } + + let inner = InnerPaymentMethodMigrate::deserialize(deserializer)?; + + let connector_mandate_details = + if let Some(connector_mandate_value) = inner.connector_mandate_details { + if let Ok(common_mandate) = serde_json::from_value::( + connector_mandate_value.clone(), + ) { + Some(common_mandate) + } else if let Ok(payment_mandate_record) = + serde_json::from_value::(connector_mandate_value) + { + Some(CommonMandateReference { + payments: Some(payment_mandate_record), + payouts: None, + }) + } else { + return Err(de::Error::custom("Faild to deserialize PaymentMethod_V2")); + } + } else { + None + }; + + Ok(Self { + merchant_id: inner.merchant_id, + payment_method: inner.payment_method, + payment_method_type: inner.payment_method_type, + payment_method_issuer: inner.payment_method_issuer, + payment_method_issuer_code: inner.payment_method_issuer_code, + card: inner.card, + network_token: inner.network_token, + metadata: inner.metadata, + customer_id: inner.customer_id, + card_network: inner.card_network, + bank_transfer: inner.bank_transfer, + wallet: inner.wallet, + payment_method_data: inner.payment_method_data, + billing: inner.billing, + connector_mandate_details, + network_transaction_id: inner.network_transaction_id, + }) + } +} + +pub fn convert_to_payments_reference( + common_mandate: Option, +) -> Option { + common_mandate.and_then(|cm| cm.payments) +} + +pub fn convert_to_common_reference( + payments_reference: Option, +) -> Option { + payments_reference.map(|payments| CommonMandateReference { + payments: Some(payments), + payouts: None, + }) +} + #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") @@ -346,7 +445,9 @@ impl PaymentMethodCreate { payment_method_issuer_code: payment_method_migrate.payment_method_issuer_code, metadata: payment_method_migrate.metadata.clone(), payment_method_data: payment_method_migrate.payment_method_data.clone(), - connector_mandate_details: payment_method_migrate.connector_mandate_details.clone(), + connector_mandate_details: convert_to_payments_reference( + payment_method_migrate.connector_mandate_details.clone(), + ), client_secret: None, billing: payment_method_migrate.billing.clone(), card: card_details, @@ -2352,7 +2453,7 @@ impl }), email: record.email, }), - connector_mandate_details, + connector_mandate_details: convert_to_common_reference(connector_mandate_details), metadata: None, payment_method_issuer_code: None, card_network: None, diff --git a/crates/common_utils/src/macros.rs b/crates/common_utils/src/macros.rs index da4046ddf01b..fe1289acba03 100644 --- a/crates/common_utils/src/macros.rs +++ b/crates/common_utils/src/macros.rs @@ -143,10 +143,6 @@ macro_rules! impl_to_sql_from_sql_json { }; } - - - - mod id_type { /// Defines an ID type. #[macro_export] diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index fd1b68b88071..5884dcfd7e5f 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -3,20 +3,14 @@ use std::collections::HashMap; use common_enums::MerchantStorageScheme; use common_utils::{encryption::Encryption, errors::ParsingError, pii}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; +use error_stack::report; #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") ))] use masking::{ExposeInterface, Secret}; -use serde::{de, Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; -use error_stack::report; -// use diesel::{ -// backend::Backend, -// deserialize, -// deserialize::FromSql, -// // serialize::{Output, ToSql}, -// }; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -135,129 +129,6 @@ impl PaymentMethod { } } - - #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - #[derive(serde::Deserialize, Debug)] - pub struct __InnerPaymentMethodData { - pub customer_id: common_utils::id_type::GlobalCustomerId, - pub merchant_id: common_utils::id_type::MerchantId, - pub created_at: PrimitiveDateTime, - pub last_modified: PrimitiveDateTime, - pub payment_method_data: Option, - pub locker_id: Option, - pub last_used_at: PrimitiveDateTime, - pub connector_mandate_details: Option, - pub customer_acceptance: Option, - pub status: storage_enums::PaymentMethodStatus, - pub network_transaction_id: Option, - pub client_secret: Option, - pub payment_method_billing_address: Option, - pub updated_by: Option, - pub locker_fingerprint_id: Option, - pub payment_method_type_v2: Option, - pub payment_method_subtype: Option, - pub id: common_utils::id_type::GlobalPaymentMethodId, - pub version: common_enums::ApiVersion, - pub network_token_requestor_reference_id: Option, - pub network_token_locker_id: Option, - pub network_token_payment_method_data: Option, - pub transaction_flow: Option, - } - - let mut deserialize_to_inner = __InnerPaymentMethodData::deserialize(deserializer)?; - - if let Some(connector_mandate_details) = deserialize_to_inner.connector_mandate_details { - match serde_json::from_value::( - connector_mandate_details.clone(), - ) { - Ok(common_mandate_reference) => { - // let common_mandate_reference_value = serde_json::to_value( - // common_mandate_reference, - // ) - // .map_err(|serde_json_error| de::Error::custom(serde_json_error.to_string()))?; - - // deserialize_to_inner.connector_mandate_details = - // Some(common_mandate_reference); - - Ok(Some(Self { - customer_id: deserialize_to_inner.customer_id, - merchant_id: deserialize_to_inner.merchant_id, - created_at: deserialize_to_inner.created_at, - last_modified: deserialize_to_inner.last_modified, - payment_method_data: deserialize_to_inner.payment_method_data, - locker_id: deserialize_to_inner.locker_id, - last_used_at: deserialize_to_inner.last_used_at, - connector_mandate_details: Some(common_mandate_reference), - customer_acceptance: deserialize_to_inner.customer_acceptance, - status: deserialize_to_inner.status, - network_transaction_id: deserialize_to_inner.network_transaction_id, - client_secret: deserialize_to_inner.client_secret, - payment_method_billing_address: deserialize_to_inner.payment_method_billing_address, - updated_by: deserialize_to_inner.updated_by, - locker_fingerprint_id: deserialize_to_inner.locker_fingerprint_id, - payment_method_type_v2: deserialize_to_inner.payment_method_type_v2, - payment_method_subtype: deserialize_to_inner.payment_method_subtype, - id: deserialize_to_inner.id, - version: deserialize_to_inner.version, - network_token_requestor_reference_id: deserialize_to_inner.network_token_requestor_reference_id, - network_token_locker_id: deserialize_to_inner.network_token_locker_id, - network_token_payment_method_data: deserialize_to_inner.network_token_payment_method_data, - transaction_flow: deserialize_to_inner.transaction_flow, - })) - } - Err(_) => { - match serde_json::from_value::( - connector_mandate_details, - ) { - Ok(payment_mandate_reference) => { - let common_mandate_reference = CommonMandateReference { - payments: Some(payment_mandate_reference), - payouts: None, - }; - - // deserialize_to_inner.connector_mandate_details = - // Some(common_mandate_reference); - - Ok(Some(Self { - customer_id: deserialize_to_inner.customer_id, - merchant_id: deserialize_to_inner.merchant_id, - created_at: deserialize_to_inner.created_at, - last_modified: deserialize_to_inner.last_modified, - payment_method_data: deserialize_to_inner.payment_method_data, - locker_id: deserialize_to_inner.locker_id, - last_used_at: deserialize_to_inner.last_used_at, - connector_mandate_details: Some(common_mandate_reference), - customer_acceptance: deserialize_to_inner.customer_acceptance, - status: deserialize_to_inner.status, - network_transaction_id: deserialize_to_inner.network_transaction_id, - client_secret: deserialize_to_inner.client_secret, - payment_method_billing_address: deserialize_to_inner.payment_method_billing_address, - updated_by: deserialize_to_inner.updated_by, - locker_fingerprint_id: deserialize_to_inner.locker_fingerprint_id, - payment_method_type_v2: deserialize_to_inner.payment_method_type_v2, - payment_method_subtype: deserialize_to_inner.payment_method_subtype, - id: deserialize_to_inner.id, - version: deserialize_to_inner.version, - network_token_requestor_reference_id: deserialize_to_inner.network_token_requestor_reference_id, - network_token_locker_id: deserialize_to_inner.network_token_locker_id, - network_token_payment_method_data: deserialize_to_inner.network_token_payment_method_data, - transaction_flow: deserialize_to_inner.transaction_flow, - })) - } - Err(_) => Err(de::Error::custom("Faild to deserialize PaymentMethod_V2"))?, - } - } - } - } else { - Err(de::Error::custom("Faild to deserialize PaymentMethod_V2"))? - } - } - //*/ - #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] pub fn get_id(&self) -> &common_utils::id_type::GlobalPaymentMethodId { &self.id @@ -1170,17 +1041,13 @@ impl std::ops::DerefMut for PayoutsMandateReference { } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, diesel::AsExpression)] +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, diesel::AsExpression)] #[diesel(sql_type = diesel::sql_types::Jsonb)] -// #[derive(Debug, Clone, Serialize, Deserialize, diesel::AsExpression, diesel::FromSqlRow)] -// #[diesel(sql_type = Nullable)] pub struct CommonMandateReference { pub payments: Option, pub payouts: Option, } -// common_utils::impl_to_sql_from_sql_json!(CommonMandateReference); - impl diesel::serialize::ToSql for CommonMandateReference { fn to_sql<'b>( &'b self, @@ -1194,13 +1061,17 @@ impl diesel::serialize::ToSql for Comm } } -impl diesel::deserialize::FromSql for CommonMandateReference +impl diesel::deserialize::FromSql + for CommonMandateReference where serde_json::Value: diesel::deserialize::FromSql, { fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result { // Deserialize into a generic serde_json::Value first - let value = >::from_sql(bytes)?; + let value = >::from_sql(bytes)?; // Try to directly deserialize into CommonMandateReference if let Ok(common_reference) = serde_json::from_value::(value.clone()) { @@ -1214,16 +1085,19 @@ where } // If neither succeeds, return an error - Err(report!(ParsingError::StructParseFailure("CommonMandateReference")) - .attach_printable("Failed to parse JSON into CommonMandateReference or PaymentsMandateReference"))? + Err( + report!(ParsingError::StructParseFailure("CommonMandateReference")).attach_printable( + "Failed to parse JSON into CommonMandateReference or PaymentsMandateReference", + ), + )? } } impl From for CommonMandateReference { fn from(payment_reference: PaymentsMandateReference) -> Self { - Self{ + Self { payments: Some(payment_reference), payouts: None, } } -} \ No newline at end of file +} diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index b9a2c59ea761..d901596c4a7c 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -850,9 +850,9 @@ pub async fn skip_locker_call_and_migrate_payment_method( .clone() .and_then(|val| if val == json!({}) { None } else { Some(true) }) .or_else(|| { - req.connector_mandate_details - .clone() - .and_then(|val| (!val.0.is_empty()).then_some(false)) + req.connector_mandate_details.clone().and_then(|val| { + (!val.payments.unwrap_or_default().0.is_empty()).then_some(false) + }) }), ); diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index b2c90e03b589..9413a45eea57 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -6169,7 +6169,8 @@ where pub async fn validate_merchant_connector_ids_in_connector_mandate_details( state: &SessionState, key_store: &domain::MerchantKeyStore, - connector_mandate_details: &api_models::payment_methods::PaymentsMandateReference, + // connector_mandate_details: &api_models::payment_methods::PaymentsMandateReference, + connector_mandate_details: &api_models::payment_methods::CommonMandateReference, merchant_id: &id_type::MerchantId, card_network: Option, ) -> CustomResult<(), errors::ApiErrorResponse> { @@ -6197,45 +6198,48 @@ pub async fn validate_merchant_connector_ids_in_connector_mandate_details( }) .collect(); - for (migrating_merchant_connector_id, migrating_connector_mandate_details) in - connector_mandate_details.0.clone() - { - match ( - card_network.clone(), - merchant_connector_account_details_hash_map.get(&migrating_merchant_connector_id), - ) { - (Some(enums::CardNetwork::Discover), Some(merchant_connector_account_details)) => { - if let ("cybersource", None) = ( - merchant_connector_account_details.connector_name.as_str(), - migrating_connector_mandate_details - .original_payment_authorized_amount - .zip( - migrating_connector_mandate_details - .original_payment_authorized_currency, - ), - ) { - Err(errors::ApiErrorResponse::MissingRequiredFields { - field_names: vec![ - "original_payment_authorized_currency", - "original_payment_authorized_amount", - ], + if let Some(payment_mandate_reference) = &connector_mandate_details.payments { + let payments_map = payment_mandate_reference.0.clone(); + for (migrating_merchant_connector_id, migrating_connector_mandate_details) in payments_map { + match ( + card_network.clone(), + merchant_connector_account_details_hash_map.get(&migrating_merchant_connector_id), + ) { + (Some(enums::CardNetwork::Discover), Some(merchant_connector_account_details)) => { + if let ("cybersource", None) = ( + merchant_connector_account_details.connector_name.as_str(), + migrating_connector_mandate_details + .original_payment_authorized_amount + .zip( + migrating_connector_mandate_details + .original_payment_authorized_currency, + ), + ) { + return Err(errors::ApiErrorResponse::MissingRequiredFields { + field_names: vec![ + "original_payment_authorized_currency", + "original_payment_authorized_amount", + ], + }) + .attach_printable(format!( + "Invalid connector_mandate_details provided for connector {:?}", + migrating_merchant_connector_id + ))?; + } + } + (_, Some(_)) => (), + (_, None) => { + return Err(errors::ApiErrorResponse::InvalidDataValue { + field_name: "merchant_connector_id", }) - .attach_printable(format!( - "Invalid connector_mandate_details provided for connector {:?}", - migrating_merchant_connector_id - ))? + .attach_printable_lazy(|| { + format!( + "{:?} invalid merchant connector id in connector_mandate_details", + migrating_merchant_connector_id + ) + })? } } - (_, Some(_)) => (), - (_, None) => Err(errors::ApiErrorResponse::InvalidDataValue { - field_name: "merchant_connector_id", - }) - .attach_printable_lazy(|| { - format!( - "{:?} invalid merchant connector id in connector_mandate_details", - migrating_merchant_connector_id - ) - })?, } } Ok(()) diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index a531f2fa314e..29d1b70ea4b9 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -24,8 +24,7 @@ use common_utils::{ use diesel_models::{ enums as storage_enums, generic_link::{GenericLinkNew, PayoutLink}, - CommonMandateReference, PaymentsMandateReferenceRecord, - PayoutsMandateReference, PayoutsMandateReferenceRecord, + CommonMandateReference, PayoutsMandateReference, PayoutsMandateReferenceRecord, }; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] use diesel_models::{ diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 9d670e728ac3..79350d6d989d 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -3,7 +3,7 @@ use common_utils::{ crypto::Encryptable, encryption::Encryption, errors::CustomResult, - ext_traits::{AsyncExt, StringExt, ValueExt}, + ext_traits::{AsyncExt, StringExt}, fp_utils, id_type, payout_method_utils as payout_additional, pii, type_name, types::{ keymanager::{Identifier, KeyManagerState}, @@ -209,7 +209,8 @@ pub fn should_create_connector_transfer_method( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to deserialize connector mandate details")?; - + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + let common_mandate_reference = pm.connector_mandate_details.clone().unwrap_or_default(); if let Some(merchant_connector_id) = connector_data.merchant_connector_id.as_ref() { common_mandate_reference From 761d6711bdb57ae6b02cc7a7bc8bb5f74ae0a6fe Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 26 Dec 2024 12:17:56 +0530 Subject: [PATCH 13/29] clippy fix --- crates/api_models/src/payment_methods.rs | 7 +++++- crates/diesel_models/src/payment_method.rs | 4 ++-- .../router/src/core/payments/transformers.rs | 24 ++++++++++++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index f429fbe6c212..bd895a996e3f 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -346,7 +346,9 @@ impl<'de> serde::Deserialize<'de> for PaymentMethodMigrate { pub metadata: Option, pub customer_id: Option, pub card_network: Option, + #[cfg(feature = "payouts")] pub bank_transfer: Option, + #[cfg(feature = "payouts")] pub wallet: Option, pub payment_method_data: Option, pub billing: Option, @@ -370,7 +372,7 @@ impl<'de> serde::Deserialize<'de> for PaymentMethodMigrate { payouts: None, }) } else { - return Err(de::Error::custom("Faild to deserialize PaymentMethod_V2")); + return Err(de::Error::custom("Failed to deserialize PaymentMethod_V2")); } } else { None @@ -387,7 +389,9 @@ impl<'de> serde::Deserialize<'de> for PaymentMethodMigrate { metadata: inner.metadata, customer_id: inner.customer_id, card_network: inner.card_network, + #[cfg(feature = "payouts")] bank_transfer: inner.bank_transfer, + #[cfg(feature = "payouts")] wallet: inner.wallet, payment_method_data: inner.payment_method_data, billing: inner.billing, @@ -448,6 +452,7 @@ impl PaymentMethodCreate { connector_mandate_details: convert_to_payments_reference( payment_method_migrate.connector_mandate_details.clone(), ), + // connector_mandate_details: Option::::foreign_from(payment_method_migrate.connector_mandate_details.clone()), client_secret: None, billing: payment_method_migrate.billing.clone(), card: card_details, diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 5884dcfd7e5f..ecec57ec29db 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -118,13 +118,13 @@ impl PaymentMethod { payouts: None, }), Err(_) => Err(ParsingError::StructParseFailure( - "Faild to deserialize PaymentMethod", + "Failed to deserialize PaymentMethod", ))?, }, } } else { Err(ParsingError::StructParseFailure( - "Faild to deserialize PaymentMethod", + "Failed to deserialize PaymentMethod", ))? } } diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index e532abaa7ea6..c6ba465d5fb1 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1,8 +1,11 @@ use std::{fmt::Debug, marker::PhantomData, str::FromStr}; -use api_models::payments::{ - Address, ConnectorMandateReferenceId, CustomerDetails, CustomerDetailsResponse, FrmMessage, - RequestSurchargeDetails, +use api_models::{ + payment_methods::{CommonMandateReference, PaymentsMandateReference}, + payments::{ + Address, ConnectorMandateReferenceId, CustomerDetails, CustomerDetailsResponse, FrmMessage, + RequestSurchargeDetails, + }, }; use common_enums::{Currency, RequestIncrementalAuthorization}; use common_utils::{ @@ -4151,3 +4154,18 @@ impl ForeignFrom<(Self, Option<&api_models::payments::AdditionalPaymentData>)> }) } } + +impl ForeignFrom> for Option { + fn foreign_from(common_mandate: Option) -> Self { + common_mandate.and_then(|cm| cm.payments) + } +} + +impl ForeignFrom> for Option { + fn foreign_from(payments_reference: Option) -> Self { + payments_reference.map(|payments| CommonMandateReference { + payments: Some(payments), + payouts: None, + }) + } +} From 1d0edb91af4769f2faf146baac3f93d44ab66157 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 26 Dec 2024 14:53:11 +0530 Subject: [PATCH 14/29] transaction_flow removed from pmt --- crates/diesel_models/src/enums.rs | 21 ------------------- crates/diesel_models/src/payment_method.rs | 20 ------------------ crates/diesel_models/src/schema.rs | 1 - crates/diesel_models/src/schema_v2.rs | 1 - .../src/payment_methods.rs | 8 ------- crates/router/src/core/payment_methods.rs | 3 --- .../router/src/core/payment_methods/cards.rs | 12 +---------- .../router/src/core/payments/tokenization.rs | 3 --- crates/router/src/core/payouts/helpers.rs | 3 +-- crates/router/src/core/pm_auth.rs | 1 - .../down.sql | 7 +++++++ .../up.sql | 4 ++++ 12 files changed, 13 insertions(+), 71 deletions(-) create mode 100644 migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql create mode 100644 migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs index 601b73f75d9a..e27e3d43114c 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -14,7 +14,6 @@ pub mod diesel_exports { DbIntentStatus as IntentStatus, DbMandateStatus as MandateStatus, DbMandateType as MandateType, DbMerchantStorageScheme as MerchantStorageScheme, DbOrderFulfillmentTimeOrigin as OrderFulfillmentTimeOrigin, - DbPaymentDirection as PaymentDirection, DbPaymentMethodIssuerCode as PaymentMethodIssuerCode, DbPaymentSource as PaymentSource, DbPaymentType as PaymentType, DbPayoutStatus as PayoutStatus, DbPayoutType as PayoutType, DbProcessTrackerStatus as ProcessTrackerStatus, DbReconStatus as ReconStatus, @@ -328,23 +327,3 @@ pub enum UserRoleVersion { V2, } -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - PartialEq, - serde::Serialize, - serde::Deserialize, - strum::EnumString, - strum::Display, -)] -#[router_derive::diesel_enum(storage_type = "db_enum")] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum PaymentDirection { - #[default] - Payin, - Payout, -} diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index ecec57ec29db..c87995e59de2 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -65,7 +65,6 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -94,7 +93,6 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, } impl PaymentMethod { @@ -178,7 +176,6 @@ pub struct PaymentMethodNew { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -207,7 +204,6 @@ pub struct PaymentMethodNew { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: Option, - pub transaction_flow: Option, } impl PaymentMethodNew { @@ -402,7 +398,6 @@ impl PaymentMethodUpdateInternal { network_token_locker_id: network_token_locker_id.or(source.network_token_locker_id), network_token_payment_method_data: network_token_payment_method_data .or(source.network_token_payment_method_data), - transaction_flow: transaction_flow.or(source.transaction_flow), } } } @@ -429,7 +424,6 @@ pub struct PaymentMethodUpdateInternal { last_modified: PrimitiveDateTime, network_token_locker_id: Option, network_token_payment_method_data: Option, - transaction_flow: Option, scheme: Option, } @@ -455,7 +449,6 @@ impl PaymentMethodUpdateInternal { last_modified, network_token_locker_id, network_token_payment_method_data, - transaction_flow, scheme, } = self; @@ -497,7 +490,6 @@ impl PaymentMethodUpdateInternal { network_token_locker_id: network_token_locker_id.or(source.network_token_locker_id), network_token_payment_method_data: network_token_payment_method_data .or(source.network_token_payment_method_data), - transaction_flow: transaction_flow.or(source.transaction_flow), } } } @@ -528,7 +520,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::PaymentMethodDataUpdate { @@ -549,7 +540,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::LastUsedUpdate { last_used_at } => Self { @@ -568,7 +558,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::UpdatePaymentMethodDataAndLastUsed { @@ -591,7 +580,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme, }, PaymentMethodUpdate::NetworkTransactionIdAndStatusUpdate { @@ -613,7 +601,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::StatusUpdate { status } => Self { @@ -632,7 +619,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::AdditionalDataUpdate { @@ -661,7 +647,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id, network_token_payment_method_data, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::ConnectorMandateDetailsUpdate { @@ -682,7 +667,6 @@ impl From for PaymentMethodUpdateInternal { last_modified: common_utils::date_time::now(), network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::NetworkTokenDataUpdate { @@ -705,7 +689,6 @@ impl From for PaymentMethodUpdateInternal { network_token_requestor_reference_id, network_token_locker_id, network_token_payment_method_data, - transaction_flow: None, scheme: None, }, PaymentMethodUpdate::ConnectorNetworkTransactionIdAndMandateDetailsUpdate { @@ -728,7 +711,6 @@ impl From for PaymentMethodUpdateInternal { network_token_requestor_reference_id: None, network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, scheme: None, }, } @@ -923,7 +905,6 @@ impl From<&PaymentMethodNew> for PaymentMethod { network_token_payment_method_data: payment_method_new .network_token_payment_method_data .clone(), - transaction_flow: payment_method_new.transaction_flow, } } } @@ -960,7 +941,6 @@ impl From<&PaymentMethodNew> for PaymentMethod { network_token_payment_method_data: payment_method_new .network_token_payment_method_data .clone(), - transaction_flow: payment_method_new.transaction_flow, } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 961c55ddd59b..95bb714cb711 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -1064,7 +1064,6 @@ diesel::table! { #[max_length = 64] network_token_locker_id -> Nullable, network_token_payment_method_data -> Nullable, - transaction_flow -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 21a3fa67b485..8bbb4baf9d74 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -1009,7 +1009,6 @@ diesel::table! { #[max_length = 64] network_token_locker_id -> Nullable, network_token_payment_method_data -> Nullable, - transaction_flow -> Nullable, } } diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index 988c86e2f0f7..586175d6e33a 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -69,7 +69,6 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: OptionalEncryptableValue, - pub transaction_flow: Option, } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -98,7 +97,6 @@ pub struct PaymentMethod { pub network_token_requestor_reference_id: Option, pub network_token_locker_id: Option, pub network_token_payment_method_data: OptionalEncryptableValue, - pub transaction_flow: Option, } impl PaymentMethod { @@ -190,7 +188,6 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), - transaction_flow: self.transaction_flow, }) } @@ -278,7 +275,6 @@ impl super::behaviour::Conversion for PaymentMethod { .and_then(|val| val.try_into_optionaloperation()) }) .await?, - transaction_flow: item.transaction_flow, }) } .await @@ -327,7 +323,6 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), - transaction_flow: self.transaction_flow, }) } } @@ -365,7 +360,6 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), - transaction_flow: self.transaction_flow, }) } @@ -441,7 +435,6 @@ impl super::behaviour::Conversion for PaymentMethod { .and_then(|val| val.try_into_optionaloperation()) }) .await?, - transaction_flow: item.transaction_flow, }) } .await @@ -478,7 +471,6 @@ impl super::behaviour::Conversion for PaymentMethod { network_token_payment_method_data: self .network_token_payment_method_data .map(|val| val.into()), - transaction_flow: self.transaction_flow, }) } } diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 6f76448ba7e2..a7f0a4b113fb 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -1156,7 +1156,6 @@ pub async fn create_payment_method_in_db( storage_scheme: enums::MerchantStorageScheme, payment_method_billing_address: crypto::OptionalEncryptableValue, card_scheme: Option, - transaction_flow: Option, ) -> errors::CustomResult { let db = &*state.store; let current_time = common_utils::date_time::now(); @@ -1188,7 +1187,6 @@ pub async fn create_payment_method_in_db( network_token_locker_id: None, network_token_payment_method_data: None, network_token_requestor_reference_id: None, - transaction_flow, }, storage_scheme, ) @@ -1252,7 +1250,6 @@ pub async fn create_payment_method_for_intent( network_token_locker_id: None, network_token_payment_method_data: None, network_token_requestor_reference_id: None, - transaction_flow: None, }, storage_scheme, ) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index d901596c4a7c..287a0ae2a707 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -37,7 +37,7 @@ use common_utils::{ MinorUnit, }, }; -use diesel_models::{enums as storage_enums, payment_method}; +use diesel_models::payment_method; use error_stack::{report, ResultExt}; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -146,7 +146,6 @@ pub async fn create_payment_method( network_token_requestor_reference_id: Option, network_token_locker_id: Option, network_token_payment_method_data: crypto::OptionalEncryptableValue, - transaction_flow: Option, ) -> errors::CustomResult { let db = &*state.store; let customer = db @@ -206,7 +205,6 @@ pub async fn create_payment_method( network_token_requestor_reference_id, network_token_locker_id, network_token_payment_method_data, - transaction_flow, }, storage_scheme, ) @@ -348,7 +346,6 @@ pub async fn get_or_insert_payment_method( None, None, None, - Some(storage_enums::PaymentDirection::Payin), // None ) .await } else { @@ -831,7 +828,6 @@ pub async fn skip_locker_call_and_migrate_payment_method( network_token_requestor_reference_id: None, network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: Some(storage_enums::PaymentDirection::Payin), }, merchant_account.storage_scheme, ) @@ -1081,7 +1077,6 @@ pub async fn get_client_secret_or_add_payment_method( None, None, None, - Some(storage_enums::PaymentDirection::Payin), ) .await?; @@ -1175,7 +1170,6 @@ pub async fn get_client_secret_or_add_payment_method_for_migration( None, None, None, - Some(storage_enums::PaymentDirection::Payin), ) .await?; migration_status.connector_mandate_details_migrated( @@ -1695,7 +1689,6 @@ pub async fn add_payment_method( None, None, None, - Some(storage_enums::PaymentDirection::Payin), ) .await?; @@ -1958,7 +1951,6 @@ pub async fn save_migration_payment_method( None, None, None, - Some(storage_enums::PaymentDirection::Payin), // None ) .await?; @@ -2005,7 +1997,6 @@ pub async fn insert_payment_method( network_token_requestor_reference_id: Option, network_token_locker_id: Option, network_token_payment_method_data: crypto::OptionalEncryptableValue, - transaction_flow: Option, ) -> errors::RouterResult { let pm_card_details = resp .card @@ -2043,7 +2034,6 @@ pub async fn insert_payment_method( network_token_requestor_reference_id, network_token_locker_id, network_token_payment_method_data, - transaction_flow, ) .await } diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index bfaf1968dfac..356f01e4a5bd 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -400,7 +400,6 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::PaymentDirection::Payin), // None ) .await } else { @@ -487,7 +486,6 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::PaymentDirection::Payin), // None ) .await } else { @@ -704,7 +702,6 @@ where network_token_requestor_ref_id, network_token_locker_id, pm_network_token_data_encrypted.map(Into::into), - Some(storage_enums::PaymentDirection::Payin), // None ) .await?; }; diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 79350d6d989d..da56f9753474 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -36,7 +36,7 @@ use crate::{ routing::TransactionData, utils as core_utils, }, - db::{storage::enums as storage_enums, StorageInterface}, + db::StorageInterface, routes::{metrics, SessionState}, services, types::{ @@ -578,7 +578,6 @@ pub async fn save_payout_data_to_locker( None, None, None, - Some(storage_enums::PaymentDirection::Payout), ) .await?, ); diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 0fac975ed70e..afba73e839c7 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -554,7 +554,6 @@ async fn store_bank_details_in_payment_methods( network_token_requestor_reference_id: None, network_token_locker_id: None, network_token_payment_method_data: None, - transaction_flow: None, }; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] diff --git a/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql b/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql new file mode 100644 index 000000000000..536bd1b18ed7 --- /dev/null +++ b/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql @@ -0,0 +1,7 @@ +-- This file should undo anything in `up.sql` +CREATE TYPE "PaymentDirection" AS ENUM ( + 'payin', + 'payout' +); + +ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS transaction_flow "PaymentDirection"; \ No newline at end of file diff --git a/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql b/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql new file mode 100644 index 000000000000..57cf054e341a --- /dev/null +++ b/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql @@ -0,0 +1,4 @@ +-- Your SQL goes here +ALTER TABLE payment_methods DROP COLUMN transaction_flow; + +DROP TYPE "PaymentDirection"; \ No newline at end of file From 8b39f8bf660f35db35b5de38f76d6052115cfe3f Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 26 Dec 2024 20:05:09 +0530 Subject: [PATCH 15/29] impl from added --- crates/api_models/src/payment_methods.rs | 50 +++++++++++-------- crates/diesel_models/src/enums.rs | 1 - .../router/src/core/payments/transformers.rs | 24 ++------- 3 files changed, 33 insertions(+), 42 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index bd895a996e3f..d11c44abde4a 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -329,6 +329,25 @@ pub struct CommonMandateReference { pub payouts: Option, } +impl From for PaymentsMandateReference { + fn from(common_mandate: CommonMandateReference) -> Self { + if let Some(payments) = common_mandate.payments { + payments + } else { + Self(HashMap::new()) + } + } +} + +impl From for CommonMandateReference { + fn from(payments_reference: PaymentsMandateReference) -> Self { + Self { + payments: Some(payments_reference), + payouts: None, + } + } +} + impl<'de> serde::Deserialize<'de> for PaymentMethodMigrate { fn deserialize(deserializer: D) -> Result where @@ -401,21 +420,6 @@ impl<'de> serde::Deserialize<'de> for PaymentMethodMigrate { } } -pub fn convert_to_payments_reference( - common_mandate: Option, -) -> Option { - common_mandate.and_then(|cm| cm.payments) -} - -pub fn convert_to_common_reference( - payments_reference: Option, -) -> Option { - payments_reference.map(|payments| CommonMandateReference { - payments: Some(payments), - payouts: None, - }) -} - #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") @@ -449,10 +453,12 @@ impl PaymentMethodCreate { payment_method_issuer_code: payment_method_migrate.payment_method_issuer_code, metadata: payment_method_migrate.metadata.clone(), payment_method_data: payment_method_migrate.payment_method_data.clone(), - connector_mandate_details: convert_to_payments_reference( - payment_method_migrate.connector_mandate_details.clone(), - ), - // connector_mandate_details: Option::::foreign_from(payment_method_migrate.connector_mandate_details.clone()), + connector_mandate_details: payment_method_migrate + .connector_mandate_details + .clone() + .map(|common_mandate_reference| { + PaymentsMandateReference::from(common_mandate_reference) + }), client_secret: None, billing: payment_method_migrate.billing.clone(), card: card_details, @@ -2458,7 +2464,11 @@ impl }), email: record.email, }), - connector_mandate_details: convert_to_common_reference(connector_mandate_details), + connector_mandate_details: connector_mandate_details.map( + |payments_mandate_reference| { + CommonMandateReference::from(payments_mandate_reference) + }, + ), metadata: None, payment_method_issuer_code: None, card_network: None, diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs index e27e3d43114c..ec6e91a2ecb0 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -326,4 +326,3 @@ pub enum UserRoleVersion { V1, V2, } - diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index c6ba465d5fb1..e532abaa7ea6 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1,11 +1,8 @@ use std::{fmt::Debug, marker::PhantomData, str::FromStr}; -use api_models::{ - payment_methods::{CommonMandateReference, PaymentsMandateReference}, - payments::{ - Address, ConnectorMandateReferenceId, CustomerDetails, CustomerDetailsResponse, FrmMessage, - RequestSurchargeDetails, - }, +use api_models::payments::{ + Address, ConnectorMandateReferenceId, CustomerDetails, CustomerDetailsResponse, FrmMessage, + RequestSurchargeDetails, }; use common_enums::{Currency, RequestIncrementalAuthorization}; use common_utils::{ @@ -4154,18 +4151,3 @@ impl ForeignFrom<(Self, Option<&api_models::payments::AdditionalPaymentData>)> }) } } - -impl ForeignFrom> for Option { - fn foreign_from(common_mandate: Option) -> Self { - common_mandate.and_then(|cm| cm.payments) - } -} - -impl ForeignFrom> for Option { - fn foreign_from(payments_reference: Option) -> Self { - payments_reference.map(|payments| CommonMandateReference { - payments: Some(payments), - payouts: None, - }) - } -} From f77bce98bb277dda9751e455857f812073b6ab47 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2024 15:47:29 +0000 Subject: [PATCH 16/29] docs(openapi): re-generate OpenAPI specification --- api-reference-v2/openapi_spec.json | 10 ++++++++++ api-reference/openapi_spec.json | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 636723d808a4..bc0f37a31deb 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -17092,6 +17092,11 @@ "example": "+1", "nullable": true, "maxLength": 255 + }, + "payout_method_id": { + "type": "string", + "description": "Identifier for payout method", + "nullable": true } }, "additionalProperties": false @@ -17331,6 +17336,11 @@ "example": "Invalid card details", "nullable": true, "maxLength": 1024 + }, + "payout_method_id": { + "type": "string", + "description": "Identifier for payout method", + "nullable": true } }, "additionalProperties": false diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 186aa6dc9c3b..03edecc70f2a 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -20886,6 +20886,11 @@ "example": "+1", "nullable": true, "maxLength": 255 + }, + "payout_method_id": { + "type": "string", + "description": "Identifier for payout method", + "nullable": true } } }, @@ -21184,6 +21189,11 @@ "example": "Invalid card details", "nullable": true, "maxLength": 1024 + }, + "payout_method_id": { + "type": "string", + "description": "Identifier for payout method", + "nullable": true } }, "additionalProperties": false @@ -21830,6 +21840,11 @@ "example": "+1", "nullable": true, "maxLength": 255 + }, + "payout_method_id": { + "type": "string", + "description": "Identifier for payout method", + "nullable": true } } }, @@ -22042,6 +22057,11 @@ "example": "+1", "nullable": true, "maxLength": 255 + }, + "payout_method_id": { + "type": "string", + "description": "Identifier for payout method", + "nullable": true } } }, From 856ea38ca008540e8465f64d70ce18e9b6a526f4 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Sun, 29 Dec 2024 21:15:09 +0530 Subject: [PATCH 17/29] retrieve and payout in stages fix --- crates/diesel_models/src/payment_method.rs | 14 ++++++++------ crates/router/src/core/payouts/helpers.rs | 8 ++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index c87995e59de2..c253ae46dd84 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -115,15 +115,17 @@ impl PaymentMethod { payments: Some(payment_mandate_reference), payouts: None, }), - Err(_) => Err(ParsingError::StructParseFailure( - "Failed to deserialize PaymentMethod", - ))?, + Err(_) => Ok(CommonMandateReference { + payments: None, + payouts: None, + }), }, } } else { - Err(ParsingError::StructParseFailure( - "Failed to deserialize PaymentMethod", - ))? + Ok(CommonMandateReference { + payments: None, + payouts: None, + }) } } diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index da56f9753474..c697fd86daa4 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -654,9 +654,13 @@ pub async fn save_payout_data_to_locker( }; // Store card_reference in payouts table - let updated_payout = storage::PayoutsUpdate::PayoutMethodIdUpdate { - payout_method_id: stored_resp.card_reference.to_owned(), + let payout_method_id = match &payout_data.payment_method { + Some(pm) => pm.payment_method_id.clone(), + None => stored_resp.card_reference.to_owned(), }; + + let updated_payout = storage::PayoutsUpdate::PayoutMethodIdUpdate { payout_method_id }; + payout_data.payouts = db .update_payout( payouts, From 6cfc57fe8327ff2762c5f6d698541d9860ca64bf Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 2 Jan 2025 18:54:49 +0530 Subject: [PATCH 18/29] comments resolved --- crates/api_models/src/payment_methods.rs | 108 +++++------------- crates/diesel_models/src/payment_method.rs | 7 +- .../src/merchant_connector_account.rs | 7 -- .../router/src/core/payment_methods/cards.rs | 17 ++- crates/router/src/core/payments.rs | 11 -- crates/router/src/core/payments/helpers.rs | 1 - .../payments/operations/payment_response.rs | 12 +- .../router/src/core/payments/tokenization.rs | 13 --- crates/router/src/core/payouts.rs | 6 +- crates/router/src/core/webhooks/incoming.rs | 18 ++- 10 files changed, 77 insertions(+), 123 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index d11c44abde4a..86a3f75dd8d1 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -11,7 +11,7 @@ use common_utils::{ id_type, link_utils, pii, types::{MinorUnit, Percentage, Surcharge}, }; -use masking::PeekInterface; +use masking::{self, Deserialize, PeekInterface}; use serde::de; use utoipa::{schema, ToSchema}; @@ -227,7 +227,7 @@ impl From for PaymentMethodIntentConfirm { } } } -#[derive(Debug, serde::Serialize, Clone)] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] /// This struct is only used by and internal api to migrate payment method pub struct PaymentMethodMigrate { /// Merchant id @@ -276,6 +276,7 @@ pub struct PaymentMethodMigrate { pub billing: Option, /// The connector mandate details of the payment method + #[serde(deserialize_with = "deserialize_connector_mandate_details")] pub connector_mandate_details: Option, // The CIT (customer initiated transaction) transaction id associated with the payment method @@ -331,11 +332,7 @@ pub struct CommonMandateReference { impl From for PaymentsMandateReference { fn from(common_mandate: CommonMandateReference) -> Self { - if let Some(payments) = common_mandate.payments { - payments - } else { - Self(HashMap::new()) - } + common_mandate.payments.unwrap_or_default() } } @@ -348,75 +345,32 @@ impl From for CommonMandateReference { } } -impl<'de> serde::Deserialize<'de> for PaymentMethodMigrate { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - #[derive(Debug, serde::Deserialize)] - struct InnerPaymentMethodMigrate { - pub merchant_id: id_type::MerchantId, - pub payment_method: Option, - pub payment_method_type: Option, - pub payment_method_issuer: Option, - pub payment_method_issuer_code: Option, - pub card: Option, - pub network_token: Option, - pub metadata: Option, - pub customer_id: Option, - pub card_network: Option, - #[cfg(feature = "payouts")] - pub bank_transfer: Option, - #[cfg(feature = "payouts")] - pub wallet: Option, - pub payment_method_data: Option, - pub billing: Option, - pub connector_mandate_details: Option, - pub network_transaction_id: Option, +fn deserialize_connector_mandate_details<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let value: Option = Option::::deserialize(deserializer)?; + if let Some(connector_mandate_value) = value { + if let Ok(common_mandate) = + serde_json::from_value::(connector_mandate_value.clone()) + { + Ok(Some(common_mandate)) + } else if let Ok(payment_mandate_record) = + serde_json::from_value::(connector_mandate_value) + { + Ok(Some(CommonMandateReference { + payments: Some(payment_mandate_record), + payouts: None, + })) + } else { + Err(de::Error::custom( + "Failed to deserialize connector_mandate_details", + )) } - - let inner = InnerPaymentMethodMigrate::deserialize(deserializer)?; - - let connector_mandate_details = - if let Some(connector_mandate_value) = inner.connector_mandate_details { - if let Ok(common_mandate) = serde_json::from_value::( - connector_mandate_value.clone(), - ) { - Some(common_mandate) - } else if let Ok(payment_mandate_record) = - serde_json::from_value::(connector_mandate_value) - { - Some(CommonMandateReference { - payments: Some(payment_mandate_record), - payouts: None, - }) - } else { - return Err(de::Error::custom("Failed to deserialize PaymentMethod_V2")); - } - } else { - None - }; - - Ok(Self { - merchant_id: inner.merchant_id, - payment_method: inner.payment_method, - payment_method_type: inner.payment_method_type, - payment_method_issuer: inner.payment_method_issuer, - payment_method_issuer_code: inner.payment_method_issuer_code, - card: inner.card, - network_token: inner.network_token, - metadata: inner.metadata, - customer_id: inner.customer_id, - card_network: inner.card_network, - #[cfg(feature = "payouts")] - bank_transfer: inner.bank_transfer, - #[cfg(feature = "payouts")] - wallet: inner.wallet, - payment_method_data: inner.payment_method_data, - billing: inner.billing, - connector_mandate_details, - network_transaction_id: inner.network_transaction_id, - }) + } else { + Ok(None) } } @@ -1585,7 +1539,7 @@ pub struct PaymentMethodListRequest { any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") ))] -impl<'de> serde::Deserialize<'de> for PaymentMethodListRequest { +impl<'de> Deserialize<'de> for PaymentMethodListRequest { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -1701,7 +1655,7 @@ pub struct PaymentMethodListRequest { } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] -impl<'de> serde::Deserialize<'de> for PaymentMethodListRequest { +impl<'de> Deserialize<'de> for PaymentMethodListRequest { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index c253ae46dd84..360773ddd75a 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -115,10 +115,9 @@ impl PaymentMethod { payments: Some(payment_mandate_reference), payouts: None, }), - Err(_) => Ok(CommonMandateReference { - payments: None, - payouts: None, - }), + Err(_) => Err(ParsingError::StructParseFailure( + "Failed to deserialize PaymentMethod", + ))?, }, } } else { diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index e9243bf82e1d..0f9fdd3cbbe2 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -675,14 +675,7 @@ common_utils::create_list_wrapper!( .as_ref() .map_or(false, |payments| { payments.0.keys().any(|mca_id| mca_ids.contains(mca_id)) - }) || - connector_mandate_details - .payouts - .as_ref() - .map_or(false, |payouts| { - payouts.0.keys().any(|mca_id| mca_ids.contains(mca_id)) }) - } } ); diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 287a0ae2a707..cb883bea53f4 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -847,7 +847,8 @@ pub async fn skip_locker_call_and_migrate_payment_method( .and_then(|val| if val == json!({}) { None } else { Some(true) }) .or_else(|| { req.connector_mandate_details.clone().and_then(|val| { - (!val.payments.unwrap_or_default().0.is_empty()).then_some(false) + val.payments + .and_then(|payin_val| (!payin_val.0.is_empty()).then_some(false)) }) }), ); @@ -4939,7 +4940,19 @@ pub async fn list_customer_payment_method( .connector_mandate_details .clone() .map(|val| { - val.parse_value::("CommonMandateReference") + val.clone() + .parse_value::("CommonMandateReference") + .or_else(|_| { + val.parse_value::( + "PaymentsMandateReference", + ) + .map(|payments| { + diesel_models::CommonMandateReference { + payments: Some(payments), + payouts: None, + } + }) + }) }) .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 27f61a17de61..c0c89eebbaed 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5778,17 +5778,6 @@ pub async fn decide_connector_for_normal_or_recurring_payment( where D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { - // let connector_mandate_details = &payment_method_info - // .connector_mandate_details - // .clone() - // .map(|details| { - // details - // .parse_value::("connector_mandate_details") - // }) - // .transpose() - // .change_context(errors::ApiErrorResponse::InternalServerError) - // .attach_printable("unable to deserialize connector mandate details")?; - let connector_common_mandate_details = storage::PaymentMethod::get_common_mandate_reference( payment_method_info.connector_mandate_details.clone(), ) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 9413a45eea57..56cbfa020da9 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -6169,7 +6169,6 @@ where pub async fn validate_merchant_connector_ids_in_connector_mandate_details( state: &SessionState, key_store: &domain::MerchantKeyStore, - // connector_mandate_details: &api_models::payment_methods::PaymentsMandateReference, connector_mandate_details: &api_models::payment_methods::CommonMandateReference, merchant_id: &id_type::MerchantId, card_network: Option, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 17d523b82f98..cc7be1caffc7 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1591,9 +1591,15 @@ async fn payment_response_update_tracker( .connector_mandate_details .clone() .map(|val| { - val.parse_value::( - "CommonMandateReference", - ) + val.clone() + .parse_value::("CommonMandateReference") + .or_else(|_| { + val.parse_value::("PaymentsMandateReference") + .map(|payments| diesel_models::CommonMandateReference { + payments: Some(payments), + payouts: None, + }) + }) }) .transpose() .change_context( diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 356f01e4a5bd..3f2e0a13c848 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -1191,7 +1191,6 @@ pub fn add_connector_mandate_details_in_payment_method( connector_mandate_request_reference_id, }, ); - // Some(diesel_models::PaymentsMandateReference(mandate_details)) Some(diesel_models::CommonMandateReference { payments: Some(diesel_models::PaymentsMandateReference(mandate_details)), payouts: None, @@ -1244,18 +1243,6 @@ pub fn update_connector_mandate_details( connector_mandate_request_reference_id, }); } - // common_mandate_reference - // .entry(mca_id) - // .and_modify(|pm| *pm = updated_record) - // .or_insert(diesel_models::PaymentsMandateReferenceRecord { - // connector_mandate_id, - // payment_method_type, - // original_payment_authorized_amount: authorized_amount, - // original_payment_authorized_currency: authorized_currency, - // mandate_metadata: mandate_metadata.clone(), - // connector_mandate_status: Some(ConnectorMandateStatus::Active), - // connector_mandate_request_reference_id, - // }); Some(common_mandate_reference) } else { None diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 29d1b70ea4b9..920e181680f3 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -2103,7 +2103,7 @@ pub async fn create_recipient_disburse_account( )]); let common_connector_mandate = CommonMandateReference { - payments: None, // doubt here, i think i need to fetch it here. + payments: None, payouts: Some(PayoutsMandateReference(connector_mandate_details)), }; @@ -2684,7 +2684,9 @@ pub async fn payout_create_db_entries( Some(api_enums::PayoutType::foreign_from(payout_method_data)), ), None => ( - payment_method.clone().map(|pm| pm.payment_method_id), + payment_method + .as_ref() + .map(|pm| pm.payment_method_id.clone()), req.payout_type.to_owned(), ), }; diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index fcef17c2235a..7f41ac09476d 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -1846,9 +1846,21 @@ async fn update_connector_mandate_details( .connector_mandate_details .clone() .map(|val| { - val.parse_value::( - "CommonMandateReference", - ) + val.clone() + .parse_value::( + "CommonMandateReference", + ) + .or_else(|_| { + val.parse_value::( + "PaymentsMandateReference", + ) + .map(|payments| { + diesel_models::CommonMandateReference { + payments: Some(payments), + payouts: None, + } + }) + }) }) .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) From 9e4afc52c452323c2368e8ff39e20ae854eeeda5 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Thu, 2 Jan 2025 20:30:24 +0530 Subject: [PATCH 19/29] retrieve call fix and comment resolve --- crates/router/src/core/payouts.rs | 4 +++- .../down.sql | 4 ---- .../up.sql | 7 ------- .../down.sql | 7 ------- .../up.sql | 4 ---- 5 files changed, 3 insertions(+), 23 deletions(-) delete mode 100644 migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql delete mode 100644 migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql delete mode 100644 migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql delete mode 100644 migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 920e181680f3..81e656623b84 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -2680,7 +2680,9 @@ pub async fn payout_create_db_entries( let (payout_method_id, payout_type) = match stored_payout_method_data { Some(payout_method_data) => ( - req.payout_token.to_owned(), + payment_method + .as_ref() + .map(|pm| pm.payment_method_id.clone()), Some(api_enums::PayoutType::foreign_from(payout_method_data)), ), None => ( diff --git a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql deleted file mode 100644 index ffe21063b18f..000000000000 --- a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/down.sql +++ /dev/null @@ -1,4 +0,0 @@ --- This file should undo anything in `up.sql` -ALTER TABLE payment_methods DROP COLUMN transaction_flow; - -DROP TYPE "PaymentDirection"; \ No newline at end of file diff --git a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql b/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql deleted file mode 100644 index 17b7b04eaf07..000000000000 --- a/migrations/2024-11-27-143958_add_transaction_flow_in_payment_method/up.sql +++ /dev/null @@ -1,7 +0,0 @@ --- Your SQL goes here -CREATE TYPE "PaymentDirection" AS ENUM ( - 'payin', - 'payout' -); - -ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS transaction_flow "PaymentDirection"; \ No newline at end of file diff --git a/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql b/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql deleted file mode 100644 index 536bd1b18ed7..000000000000 --- a/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/down.sql +++ /dev/null @@ -1,7 +0,0 @@ --- This file should undo anything in `up.sql` -CREATE TYPE "PaymentDirection" AS ENUM ( - 'payin', - 'payout' -); - -ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS transaction_flow "PaymentDirection"; \ No newline at end of file diff --git a/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql b/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql deleted file mode 100644 index 57cf054e341a..000000000000 --- a/migrations/2024-12-26-073157_remove_transaction_flow_from_payment_method/up.sql +++ /dev/null @@ -1,4 +0,0 @@ --- Your SQL goes here -ALTER TABLE payment_methods DROP COLUMN transaction_flow; - -DROP TYPE "PaymentDirection"; \ No newline at end of file From 7c4544cbdaf2bf48cbb3a941d751479544973169 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 3 Jan 2025 14:39:34 +0530 Subject: [PATCH 20/29] nit fix --- crates/api_models/src/payment_methods.rs | 2 +- .../router/src/core/payment_methods/cards.rs | 28 +++--------- crates/router/src/core/payments/helpers.rs | 24 +++++----- .../payments/operations/payment_response.rs | 31 +++---------- crates/router/src/core/webhooks/incoming.rs | 44 +++++-------------- 5 files changed, 35 insertions(+), 94 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 86a3f75dd8d1..4da698d9dd7c 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -227,7 +227,7 @@ impl From for PaymentMethodIntentConfirm { } } } -#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] /// This struct is only used by and internal api to migrate payment method pub struct PaymentMethodMigrate { /// Merchant id diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index cb883bea53f4..981886a3fc6c 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -4936,34 +4936,18 @@ pub async fn list_customer_payment_method( .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to decrypt payment method billing address details")?; - let connector_mandate_details = pm - .connector_mandate_details - .clone() - .map(|val| { - val.clone() - .parse_value::("CommonMandateReference") - .or_else(|_| { - val.parse_value::( - "PaymentsMandateReference", - ) - .map(|payments| { - diesel_models::CommonMandateReference { - payments: Some(payments), - payouts: None, - } - }) - }) - }) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to deserialize to Payment Mandate Reference ")?; + let connector_mandate_details = storage::PaymentMethod::get_common_mandate_reference( + pm.connector_mandate_details.clone(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to deserialize to Payment Mandate Reference ")?; let mca_enabled = get_mca_status( state, &key_store, profile_id.clone(), merchant_account.get_id(), is_connector_agnostic_mit_enabled, - connector_mandate_details, + Some(connector_mandate_details), pm.network_transaction_id.as_ref(), ) .await?; diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 56cbfa020da9..09b29e014fc5 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -6214,7 +6214,7 @@ pub async fn validate_merchant_connector_ids_in_connector_mandate_details( .original_payment_authorized_currency, ), ) { - return Err(errors::ApiErrorResponse::MissingRequiredFields { + Err(errors::ApiErrorResponse::MissingRequiredFields { field_names: vec![ "original_payment_authorized_currency", "original_payment_authorized_amount", @@ -6223,21 +6223,19 @@ pub async fn validate_merchant_connector_ids_in_connector_mandate_details( .attach_printable(format!( "Invalid connector_mandate_details provided for connector {:?}", migrating_merchant_connector_id - ))?; + ))? } } (_, Some(_)) => (), - (_, None) => { - return Err(errors::ApiErrorResponse::InvalidDataValue { - field_name: "merchant_connector_id", - }) - .attach_printable_lazy(|| { - format!( - "{:?} invalid merchant connector id in connector_mandate_details", - migrating_merchant_connector_id - ) - })? - } + (_, None) => Err(errors::ApiErrorResponse::InvalidDataValue { + field_name: "merchant_connector_id", + }) + .attach_printable_lazy(|| { + format!( + "{:?} invalid merchant connector id in connector_mandate_details", + migrating_merchant_connector_id + ) + })?, } } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index cc7be1caffc7..12a7a3a42c73 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -6,7 +6,7 @@ use api_models::routing::RoutableConnectorChoice; use async_trait::async_trait; use common_enums::{AuthorizationStatus, SessionUpdateStatus}; use common_utils::{ - ext_traits::{AsyncExt, Encode, ValueExt}, + ext_traits::{AsyncExt, Encode}, types::{keymanager::KeyManagerState, ConnectorTransactionId, MinorUnit}, }; use error_stack::{report, ResultExt}; @@ -1587,21 +1587,10 @@ async fn payment_response_update_tracker( payment_data.payment_method_info.clone() { // Parse value to check for mandates' existence - let mandate_details = payment_method - .connector_mandate_details - .clone() - .map(|val| { - val.clone() - .parse_value::("CommonMandateReference") - .or_else(|_| { - val.parse_value::("PaymentsMandateReference") - .map(|payments| diesel_models::CommonMandateReference { - payments: Some(payments), - payouts: None, - }) - }) - }) - .transpose() + let mandate_details = + storage::PaymentMethod::get_common_mandate_reference( + payment_method.connector_mandate_details.clone(), + ) .change_context( errors::ApiErrorResponse::InternalServerError, ) @@ -1613,17 +1602,11 @@ async fn payment_response_update_tracker( payment_data.payment_attempt.merchant_connector_id.clone() { // check if the mandate has not already been set to active - if !mandate_details - .as_ref() - .map(|common_mandate_reference| { - - common_mandate_reference.payments + if !mandate_details.payments .as_ref() .and_then(|payments| payments.0.get(&mca_id)) .map(|payment_mandate_reference_record| payment_mandate_reference_record.connector_mandate_status == Some(common_enums::ConnectorMandateStatus::Active)) .unwrap_or(false) - }) - .unwrap_or(false) { let (connector_mandate_id, mandate_metadata,connector_mandate_request_reference_id) = payment_data.payment_attempt.connector_mandate_detail.clone() @@ -1632,7 +1615,7 @@ async fn payment_response_update_tracker( // Update the connector mandate details with the payment attempt connector mandate id let connector_mandate_details = tokenization::update_connector_mandate_details( - mandate_details, + Some(mandate_details), payment_data.payment_attempt.payment_method_type, Some( payment_data diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index 7f41ac09476d..e8cb33db24c3 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -4,7 +4,7 @@ use actix_web::FromRequest; #[cfg(feature = "payouts")] use api_models::payouts as payout_models; use api_models::webhooks::{self, WebhookResponseTracker}; -use common_utils::{errors::ReportSwitchExt, events::ApiEventsType, ext_traits::ValueExt}; +use common_utils::{errors::ReportSwitchExt, events::ApiEventsType}; use diesel_models::ConnectorMandateReferenceId; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ @@ -1842,44 +1842,20 @@ async fn update_connector_mandate_details( // Update connector's mandate details let updated_connector_mandate_details = if let Some(webhook_mandate_details) = webhook_connector_mandate_details { - let mandate_details = payment_method_info - .connector_mandate_details - .clone() - .map(|val| { - val.clone() - .parse_value::( - "CommonMandateReference", - ) - .or_else(|_| { - val.parse_value::( - "PaymentsMandateReference", - ) - .map(|payments| { - diesel_models::CommonMandateReference { - payments: Some(payments), - payouts: None, - } - }) - }) - }) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to deserialize to Payment Mandate Reference")?; + let mandate_details = storage::PaymentMethod::get_common_mandate_reference( + payment_method_info.connector_mandate_details.clone(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to deserialize to Payment Mandate Reference")?; let merchant_connector_account_id = payment_attempt .merchant_connector_id .clone() .get_required_value("merchant_connector_id")?; - if mandate_details - .as_ref() - .map(|details: &diesel_models::CommonMandateReference| { - !details.payments.as_ref().map_or(false, |payments| { - payments.0.contains_key(&merchant_connector_account_id) - }) - }) - .unwrap_or(true) - { + if !mandate_details.payments.as_ref().map_or(false, |payments| { + payments.0.contains_key(&merchant_connector_account_id) + }) { // Update the payment attempt to maintain consistency across tables. let (mandate_metadata, connector_mandate_request_reference_id) = payment_attempt @@ -1924,7 +1900,7 @@ async fn update_connector_mandate_details( insert_mandate_details( &payment_attempt, &webhook_mandate_details, - mandate_details, + Some(mandate_details), )? } else { logger::info!( From db69664c819bf2cd35f21cb6bbc9b78a93d601db Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 3 Jan 2025 23:50:01 +0530 Subject: [PATCH 21/29] MIT fix --- crates/diesel_models/src/payment_method.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 360773ddd75a..e4ff5b3fe4c6 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -108,13 +108,13 @@ impl PaymentMethod { connector_mandate_details: Option, ) -> Result { if let Some(value) = connector_mandate_details { - match serde_json::from_value::(value.clone()) { - Ok(common_mandate_reference) => Ok(common_mandate_reference), - Err(_) => match serde_json::from_value::(value.clone()) { - Ok(payment_mandate_reference) => Ok(CommonMandateReference { - payments: Some(payment_mandate_reference), - payouts: None, - }), + match serde_json::from_value::(value.clone()) { + Ok(payment_mandate_reference) => Ok(CommonMandateReference { + payments: Some(payment_mandate_reference), + payouts: None, + }), + Err(_) => match serde_json::from_value::(value.clone()) { + Ok(common_mandate_reference) => Ok(common_mandate_reference), Err(_) => Err(ParsingError::StructParseFailure( "Failed to deserialize PaymentMethod", ))?, From 32220335f42c1b403e44bb1ccda75c0397e150b8 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Tue, 7 Jan 2025 17:51:36 +0530 Subject: [PATCH 22/29] MIT fix --- .../router/src/core/payments/tokenization.rs | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 3f2e0a13c848..aca4a2c1dfd2 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -1212,8 +1212,12 @@ pub fn update_connector_mandate_details( mandate_metadata: Option>, connector_mandate_request_reference_id: Option, ) -> RouterResult> { - let mandate_reference = match mandate_details { - Some(mut common_mandate_reference) => { + let mandate_reference = match mandate_details + .as_ref() + .and_then(|common_mandate| common_mandate.payments.clone()) + { + Some(mut payments_mandate_reference) => { + router_env::logger::info!("here : {:?}", payments_mandate_reference.clone()); if let Some((mca_id, connector_mandate_id)) = merchant_connector_id.clone().zip(connector_mandate_id) { @@ -1228,22 +1232,25 @@ pub fn update_connector_mandate_details( .clone(), }; - if let Some(payments_mandate_reference) = common_mandate_reference.payments.as_mut() - { - payments_mandate_reference - .entry(mca_id) - .and_modify(|pm| *pm = updated_record) - .or_insert(diesel_models::PaymentsMandateReferenceRecord { - connector_mandate_id, - payment_method_type, - original_payment_authorized_amount: authorized_amount, - original_payment_authorized_currency: authorized_currency, - mandate_metadata: mandate_metadata.clone(), - connector_mandate_status: Some(ConnectorMandateStatus::Active), - connector_mandate_request_reference_id, - }); - } - Some(common_mandate_reference) + payments_mandate_reference + .entry(mca_id) + .and_modify(|pm| *pm = updated_record) + .or_insert(diesel_models::PaymentsMandateReferenceRecord { + connector_mandate_id, + payment_method_type, + original_payment_authorized_amount: authorized_amount, + original_payment_authorized_currency: authorized_currency, + mandate_metadata: mandate_metadata.clone(), + connector_mandate_status: Some(ConnectorMandateStatus::Active), + connector_mandate_request_reference_id, + }); + + let payout_data = mandate_details.and_then(|common_mandate| common_mandate.payouts); + + Some(diesel_models::CommonMandateReference { + payments: Some(payments_mandate_reference), + payouts: payout_data, + }) } else { None } @@ -1263,6 +1270,5 @@ pub fn update_connector_mandate_details( .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to serialize customer acceptance to value")?; - Ok(connector_mandate_details) } From acd3a204c02b6aa0815acc687de793fb6d067d58 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Tue, 7 Jan 2025 23:32:00 +0530 Subject: [PATCH 23/29] nit fix --- crates/api_models/src/payment_methods.rs | 20 ++++++++++---------- crates/diesel_models/src/payment_method.rs | 18 +++++++----------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 4da698d9dd7c..cfe72c506d52 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -306,17 +306,17 @@ pub struct PaymentsMandateReference( pub HashMap, ); -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct PayoutsMandateReference( pub HashMap, ); -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct PayoutsMandateReferenceRecord { pub transfer_method_id: Option, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct PaymentsMandateReferenceRecord { pub connector_mandate_id: String, pub payment_method_type: Option, @@ -324,7 +324,7 @@ pub struct PaymentsMandateReferenceRecord { pub original_payment_authorized_currency: Option, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct CommonMandateReference { pub payments: Option, pub payouts: Option, @@ -353,17 +353,17 @@ where { let value: Option = Option::::deserialize(deserializer)?; if let Some(connector_mandate_value) = value { - if let Ok(common_mandate) = - serde_json::from_value::(connector_mandate_value.clone()) - { - Ok(Some(common_mandate)) - } else if let Ok(payment_mandate_record) = - serde_json::from_value::(connector_mandate_value) + if let Ok(payment_mandate_record) = + serde_json::from_value::(connector_mandate_value.clone()) { Ok(Some(CommonMandateReference { payments: Some(payment_mandate_record), payouts: None, })) + } else if let Ok(common_mandate) = + serde_json::from_value::(connector_mandate_value) + { + Ok(Some(common_mandate)) } else { Err(de::Error::custom( "Failed to deserialize connector_mandate_details", diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index e4ff5b3fe4c6..fb376a4c51e2 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -996,7 +996,7 @@ impl std::ops::DerefMut for PaymentsMandateReference { common_utils::impl_to_sql_from_sql_json!(PaymentsMandateReference); -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct PayoutsMandateReferenceRecord { pub transfer_method_id: Option, } @@ -1048,24 +1048,20 @@ where serde_json::Value: diesel::deserialize::FromSql, { fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result { - // Deserialize into a generic serde_json::Value first let value = >::from_sql(bytes)?; - // Try to directly deserialize into CommonMandateReference - if let Ok(common_reference) = serde_json::from_value::(value.clone()) { - return Ok(common_reference); - } - - // If that fails, try deserializing into PaymentsMandateReference - if let Ok(payment_reference) = serde_json::from_value::(value) { - // Convert PaymentsMandateReference to CommonMandateReference + if let Ok(payment_reference) = + serde_json::from_value::(value.clone()) + { return Ok(Self::from(payment_reference)); } - // If neither succeeds, return an error + if let Ok(common_reference) = serde_json::from_value::(value) { + return Ok(common_reference); + } Err( report!(ParsingError::StructParseFailure("CommonMandateReference")).attach_printable( "Failed to parse JSON into CommonMandateReference or PaymentsMandateReference", From 7a4d295917ae2515946fc7d304bfdb2fde7c40b6 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Wed, 8 Jan 2025 16:54:16 +0530 Subject: [PATCH 24/29] comments resolved --- crates/api_models/src/payment_methods.rs | 9 ++-- crates/diesel_models/src/payment_method.rs | 24 ---------- .../src/payment_methods.rs | 46 ++++++++++++++++++- .../router/src/core/payment_methods/cards.rs | 9 ++-- crates/router/src/core/payments.rs | 9 ++-- .../payments/operations/payment_response.rs | 6 +-- .../router/src/core/payments/tokenization.rs | 7 ++- crates/router/src/core/payouts/helpers.rs | 9 ++-- crates/router/src/core/webhooks/incoming.rs | 13 +++--- 9 files changed, 73 insertions(+), 59 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index cfe72c506d52..1703bbd80de4 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -11,7 +11,7 @@ use common_utils::{ id_type, link_utils, pii, types::{MinorUnit, Percentage, Surcharge}, }; -use masking::{self, Deserialize, PeekInterface}; +use masking::PeekInterface; use serde::de; use utoipa::{schema, ToSchema}; @@ -351,7 +351,8 @@ fn deserialize_connector_mandate_details<'de, D>( where D: serde::Deserializer<'de>, { - let value: Option = Option::::deserialize(deserializer)?; + let value: Option = + as de::Deserialize>::deserialize(deserializer)?; if let Some(connector_mandate_value) = value { if let Ok(payment_mandate_record) = serde_json::from_value::(connector_mandate_value.clone()) @@ -1539,7 +1540,7 @@ pub struct PaymentMethodListRequest { any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") ))] -impl<'de> Deserialize<'de> for PaymentMethodListRequest { +impl<'de> serde::Deserialize<'de> for PaymentMethodListRequest { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -1655,7 +1656,7 @@ pub struct PaymentMethodListRequest { } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] -impl<'de> Deserialize<'de> for PaymentMethodListRequest { +impl<'de> serde::Deserialize<'de> for PaymentMethodListRequest { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index fb376a4c51e2..962eada78a45 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -104,30 +104,6 @@ impl PaymentMethod { &self.payment_method_id } - pub fn get_common_mandate_reference( - connector_mandate_details: Option, - ) -> Result { - if let Some(value) = connector_mandate_details { - match serde_json::from_value::(value.clone()) { - Ok(payment_mandate_reference) => Ok(CommonMandateReference { - payments: Some(payment_mandate_reference), - payouts: None, - }), - Err(_) => match serde_json::from_value::(value.clone()) { - Ok(common_mandate_reference) => Ok(common_mandate_reference), - Err(_) => Err(ParsingError::StructParseFailure( - "Failed to deserialize PaymentMethod", - ))?, - }, - } - } else { - Ok(CommonMandateReference { - payments: None, - payouts: None, - }) - } - } - #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] pub fn get_id(&self) -> &common_utils::id_type::GlobalPaymentMethodId { &self.id diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index 586175d6e33a..1a6152d4b963 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -2,7 +2,7 @@ use common_utils::crypto::Encryptable; use common_utils::{ crypto::OptionalEncryptableValue, - errors::{CustomResult, ValidationError}, + errors::{CustomResult, ParsingError, ValidationError}, pii, type_name, types::keymanager, }; @@ -138,6 +138,50 @@ impl PaymentMethod { pub fn get_payment_method_subtype(&self) -> Option { self.payment_method_subtype } + + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "payment_methods_v2") + ))] + pub fn get_common_mandate_reference( + &self, + ) -> Result { + if let Some(value) = &self.connector_mandate_details { + match serde_json::from_value::(value.clone()) { + Ok(payment_mandate_reference) => Ok(diesel_models::CommonMandateReference { + payments: Some(payment_mandate_reference), + payouts: None, + }), + Err(_) => match serde_json::from_value::( + value.clone(), + ) { + Ok(common_mandate_reference) => Ok(common_mandate_reference), + Err(_) => Err(ParsingError::StructParseFailure( + "Failed to deserialize PaymentMethod", + ))?, + }, + } + } else { + Ok(diesel_models::CommonMandateReference { + payments: None, + payouts: None, + }) + } + } + + #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] + pub fn get_common_mandate_reference( + &self, + ) -> Result { + if let Some(value) = &self.connector_mandate_details { + Ok(value.clone()) + } else { + Ok(diesel_models::CommonMandateReference { + payments: None, + payouts: None, + }) + } + } } #[cfg(all( diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 981886a3fc6c..cf4ae8e626f2 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -4936,11 +4936,10 @@ pub async fn list_customer_payment_method( .transpose() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to decrypt payment method billing address details")?; - let connector_mandate_details = storage::PaymentMethod::get_common_mandate_reference( - pm.connector_mandate_details.clone(), - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to deserialize to Payment Mandate Reference ")?; + let connector_mandate_details = pm + .get_common_mandate_reference() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to deserialize to Payment Mandate Reference ")?; let mca_enabled = get_mca_status( state, &key_store, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index c0c89eebbaed..c062118330ee 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5778,11 +5778,10 @@ pub async fn decide_connector_for_normal_or_recurring_payment( where D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { - let connector_common_mandate_details = storage::PaymentMethod::get_common_mandate_reference( - payment_method_info.connector_mandate_details.clone(), - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to get the common mandate reference")?; + let connector_common_mandate_details = payment_method_info + .get_common_mandate_reference() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to get the common mandate reference")?; let connector_mandate_details = connector_common_mandate_details.payments; diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 12a7a3a42c73..3a1e35a218fa 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1587,10 +1587,8 @@ async fn payment_response_update_tracker( payment_data.payment_method_info.clone() { // Parse value to check for mandates' existence - let mandate_details = - storage::PaymentMethod::get_common_mandate_reference( - payment_method.connector_mandate_details.clone(), - ) + let mandate_details = payment_method + .get_common_mandate_reference() .change_context( errors::ApiErrorResponse::InternalServerError, ) diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index aca4a2c1dfd2..4c56f9218e2e 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -1216,8 +1216,7 @@ pub fn update_connector_mandate_details( .as_ref() .and_then(|common_mandate| common_mandate.payments.clone()) { - Some(mut payments_mandate_reference) => { - router_env::logger::info!("here : {:?}", payments_mandate_reference.clone()); + Some(mut payment_mandate_reference) => { if let Some((mca_id, connector_mandate_id)) = merchant_connector_id.clone().zip(connector_mandate_id) { @@ -1232,7 +1231,7 @@ pub fn update_connector_mandate_details( .clone(), }; - payments_mandate_reference + payment_mandate_reference .entry(mca_id) .and_modify(|pm| *pm = updated_record) .or_insert(diesel_models::PaymentsMandateReferenceRecord { @@ -1248,7 +1247,7 @@ pub fn update_connector_mandate_details( let payout_data = mandate_details.and_then(|common_mandate| common_mandate.payouts); Some(diesel_models::CommonMandateReference { - payments: Some(payments_mandate_reference), + payments: Some(payment_mandate_reference), payouts: payout_data, }) } else { diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index c697fd86daa4..938a8edd5082 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -203,11 +203,10 @@ pub fn should_create_connector_transfer_method( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") ))] - let common_mandate_reference = storage::PaymentMethod::get_common_mandate_reference( - pm.connector_mandate_details.clone(), - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to deserialize connector mandate details")?; + let common_mandate_reference = pm + .get_common_mandate_reference() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to deserialize connector mandate details")?; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] let common_mandate_reference = pm.connector_mandate_details.clone().unwrap_or_default(); diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index e8cb33db24c3..d29846b97cb2 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -1842,19 +1842,18 @@ async fn update_connector_mandate_details( // Update connector's mandate details let updated_connector_mandate_details = if let Some(webhook_mandate_details) = webhook_connector_mandate_details { - let mandate_details = storage::PaymentMethod::get_common_mandate_reference( - payment_method_info.connector_mandate_details.clone(), - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to deserialize to Payment Mandate Reference")?; + let mandate_details = payment_method_info + .get_common_mandate_reference() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to deserialize to Payment Mandate Reference")?; let merchant_connector_account_id = payment_attempt .merchant_connector_id .clone() .get_required_value("merchant_connector_id")?; - if !mandate_details.payments.as_ref().map_or(false, |payments| { - payments.0.contains_key(&merchant_connector_account_id) + if mandate_details.payments.as_ref().map_or(true, |payments| { + !payments.0.contains_key(&merchant_connector_account_id) }) { // Update the payment attempt to maintain consistency across tables. let (mandate_metadata, connector_mandate_request_reference_id) = From ea7f04c3fd21a6357b9dff3613e78f85c7651bf2 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 10 Jan 2025 12:29:49 +0530 Subject: [PATCH 25/29] WIP --- crates/api_models/src/payment_methods.rs | 33 +++++++--- crates/diesel_models/src/payment_method.rs | 62 +++++++++++++++---- .../src/payment_methods.rs | 55 ++++++++++++---- .../router/src/core/payment_methods/cards.rs | 20 +++++- .../router/src/core/payments/tokenization.rs | 14 ++--- crates/router/src/core/webhooks/incoming.rs | 20 +++++- 6 files changed, 158 insertions(+), 46 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 1703bbd80de4..d6db9b56b64a 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -306,7 +306,7 @@ pub struct PaymentsMandateReference( pub HashMap, ); -#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)] pub struct PayoutsMandateReference( pub HashMap, ); @@ -330,6 +330,11 @@ pub struct CommonMandateReference { pub payouts: Option, } +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] +pub struct PayoutsMandateReferenceStruct { + pub payouts: PayoutsMandateReference, +} + impl From for PaymentsMandateReference { fn from(common_mandate: CommonMandateReference) -> Self { common_mandate.payments.unwrap_or_default() @@ -344,7 +349,7 @@ impl From for CommonMandateReference { } } } - +// here fn deserialize_connector_mandate_details<'de, D>( deserializer: D, ) -> Result, D::Error> @@ -354,21 +359,29 @@ where let value: Option = as de::Deserialize>::deserialize(deserializer)?; if let Some(connector_mandate_value) = value { + let mut payments_data = None; + let mut payouts_data = None; + if let Ok(payment_mandate_record) = serde_json::from_value::(connector_mandate_value.clone()) { - Ok(Some(CommonMandateReference { - payments: Some(payment_mandate_record), - payouts: None, - })) - } else if let Ok(common_mandate) = - serde_json::from_value::(connector_mandate_value) + payments_data = Some(payment_mandate_record); + } + if let Ok(payouts) = + serde_json::from_value::(connector_mandate_value) { - Ok(Some(common_mandate)) - } else { + payouts_data = Some(payouts.payouts); + } + + if payments_data.is_none() && payouts_data.is_none() { Err(de::Error::custom( "Failed to deserialize connector_mandate_details", )) + } else { + Ok(Some(CommonMandateReference { + payments: payments_data, + payouts: payouts_data, + })) } } else { Ok(None) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 962eada78a45..a89f5671291f 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -983,6 +983,11 @@ pub struct PayoutsMandateReference( pub HashMap, ); +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PayoutsMandateReferenceStruct { + pub payouts: PayoutsMandateReference, +} + impl std::ops::Deref for PayoutsMandateReference { type Target = HashMap; @@ -1010,14 +1015,21 @@ impl diesel::serialize::ToSql for Comm &'b self, out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>, ) -> diesel::serialize::Result { - let value = serde_json::to_value(self)?; + let mut payments = serde_json::to_value(self.payments.as_ref())?; + let payouts = serde_json::to_value(self.payouts.as_ref())?; + + if let Some(payments_object) = payments.as_object_mut() { + payments_object.insert("payouts".to_string(), payouts); + } + + router_env::logger::info!("here : {:?}", payments.clone()); >::to_sql(&value, &mut out.reborrow()) + >>::to_sql(&payments, &mut out.reborrow()) } } - +// here impl diesel::deserialize::FromSql for CommonMandateReference where @@ -1029,20 +1041,46 @@ where DB, >>::from_sql(bytes)?; - if let Ok(payment_reference) = + let mut payments_data = None; + let mut payouts_data = None; + + if let Ok(payment_mandate_record) = serde_json::from_value::(value.clone()) { - return Ok(Self::from(payment_reference)); + payments_data = Some(payment_mandate_record); + } + if let Ok(payouts) = serde_json::from_value::(value) { + payouts_data = Some(payouts.payouts); } - if let Ok(common_reference) = serde_json::from_value::(value) { - return Ok(common_reference); + if payments_data.is_none() && payouts_data.is_none() { + Err( + report!(ParsingError::StructParseFailure("CommonMandateReference")) + .attach_printable( + "Failed to parse JSON into CommonMandateReference or PaymentsMandateReference", + ), + )? + } else { + Ok(CommonMandateReference { + payments: payments_data, + payouts: payouts_data, + }) } - Err( - report!(ParsingError::StructParseFailure("CommonMandateReference")).attach_printable( - "Failed to parse JSON into CommonMandateReference or PaymentsMandateReference", - ), - )? + + // if let Ok(payment_reference) = + // serde_json::from_value::(value.clone()) + // { + // return Ok(Self::from(payment_reference)); + // } + + // if let Ok(common_reference) = serde_json::from_value::(value) { + // return Ok(common_reference); + // } + // Err( + // report!(ParsingError::StructParseFailure("CommonMandateReference")).attach_printable( + // "Failed to parse JSON into CommonMandateReference or PaymentsMandateReference", + // ), + // )? } } diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index 1a6152d4b963..bfe6fed4bf7b 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -144,23 +144,52 @@ impl PaymentMethod { not(feature = "payment_methods_v2") ))] pub fn get_common_mandate_reference( + // here &self, ) -> Result { if let Some(value) = &self.connector_mandate_details { - match serde_json::from_value::(value.clone()) { - Ok(payment_mandate_reference) => Ok(diesel_models::CommonMandateReference { - payments: Some(payment_mandate_reference), - payouts: None, - }), - Err(_) => match serde_json::from_value::( - value.clone(), - ) { - Ok(common_mandate_reference) => Ok(common_mandate_reference), - Err(_) => Err(ParsingError::StructParseFailure( - "Failed to deserialize PaymentMethod", - ))?, - }, + router_env::logger::info!("hereeee : {:?}", value.clone()); + let mut payments_data = None; + let mut payouts_data = None; + + if let Ok(payment_mandate_record) = + serde_json::from_value::(value.clone()) + { + router_env::logger::info!("hereeee : {:?}", payment_mandate_record.clone()); + payments_data = Some(payment_mandate_record); + } + if let Ok(payouts) = + serde_json::from_value::(value.clone()) + { + router_env::logger::info!("hereeee : {:?}", payouts.clone()); + payouts_data = Some(payouts.payouts); } + + if payments_data.is_none() && payouts_data.is_none() { + Err(ParsingError::StructParseFailure( + "Failed to deserialize PaymentMethod", + ))? + } else { + Ok(diesel_models::CommonMandateReference { + payments: payments_data, + payouts: payouts_data, + }) + } + + // match serde_json::from_value::(value.clone()) { + // Ok(payment_mandate_reference) => Ok(diesel_models::CommonMandateReference { + // payments: Some(payment_mandate_reference), + // payouts: None, + // }), + // Err(_) => match serde_json::from_value::( + // value.clone(), + // ) { + // Ok(common_mandate_reference) => Ok(common_mandate_reference), + // Err(_) => Err(ParsingError::StructParseFailure( + // "Failed to deserialize PaymentMethod", + // ))?, + // }, + // } } else { Ok(diesel_models::CommonMandateReference { payments: None, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index cf4ae8e626f2..0622dd90a0a1 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2842,11 +2842,27 @@ pub async fn update_payment_method_connector_mandate_details( key_store: &domain::MerchantKeyStore, db: &dyn db::StorageInterface, pm: domain::PaymentMethod, - connector_mandate_details: Option, + connector_mandate_details: Option, storage_scheme: MerchantStorageScheme, ) -> errors::CustomResult<(), errors::VaultError> { + let mut connector_mandate_details_value = None; + if let Some(common_mandate) = connector_mandate_details { + let mut payments = serde_json::to_value(common_mandate.payments.as_ref()) + .change_context(errors::VaultError::UpdateInPaymentMethodDataTableFailed)?; + + let payouts = serde_json::to_value(common_mandate.payouts.as_ref()) + .change_context(errors::VaultError::UpdateInPaymentMethodDataTableFailed)?; + + if let Some(payments_object) = payments.as_object_mut() { + payments_object.insert("payouts".to_string(), payouts); + } + connector_mandate_details_value = Some(payments) + } + + router_env::logger::info!("here : {:?}", connector_mandate_details_value.clone()); + let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { - connector_mandate_details, + connector_mandate_details: connector_mandate_details_value, }; db.update_payment_method(&(state.into()), key_store, pm, pm_update, storage_scheme) diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 4c56f9218e2e..bcaf6f1162f4 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -1211,7 +1211,7 @@ pub fn update_connector_mandate_details( connector_mandate_id: Option, mandate_metadata: Option>, connector_mandate_request_reference_id: Option, -) -> RouterResult> { +) -> RouterResult> { let mandate_reference = match mandate_details .as_ref() .and_then(|common_mandate| common_mandate.payments.clone()) @@ -1264,10 +1264,10 @@ pub fn update_connector_mandate_details( connector_mandate_request_reference_id, ), }; - let connector_mandate_details = mandate_reference - .map(|mand| mand.encode_to_value()) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to serialize customer acceptance to value")?; - Ok(connector_mandate_details) + // let connector_mandate_details = mandate_reference + // .map(|mand| mand.encode_to_value()) + // .transpose() + // .change_context(errors::ApiErrorResponse::InternalServerError) + // .attach_printable("Unable to serialize customer acceptance to value")?; + Ok(mandate_reference) } diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index d29846b97cb2..d0ce4898f7d2 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -1911,8 +1911,24 @@ async fn update_connector_mandate_details( None }; + let mut connector_mandate_details_value = None; + if let Some(common_mandate) = updated_connector_mandate_details { + let mut payments = serde_json::to_value(common_mandate.payments.as_ref()) + .change_context(errors::ApiErrorResponse::MandateUpdateFailed)?; + + let payouts = serde_json::to_value(common_mandate.payouts.as_ref()) + .change_context(errors::ApiErrorResponse::MandateUpdateFailed)?; + + if let Some(payments_object) = payments.as_object_mut() { + payments_object.insert("payouts".to_string(), payouts); + } + connector_mandate_details_value = Some(payments) + } + + router_env::logger::info!("here : {:?}", connector_mandate_details_value); + let pm_update = diesel_models::PaymentMethodUpdate::ConnectorNetworkTransactionIdAndMandateDetailsUpdate { - connector_mandate_details: updated_connector_mandate_details.map(masking::Secret::new), + connector_mandate_details: connector_mandate_details_value.map(masking::Secret::new), network_transaction_id: webhook_connector_network_transaction_id .map(|webhook_network_transaction_id| webhook_network_transaction_id.get_id().clone()), }; @@ -1938,7 +1954,7 @@ fn insert_mandate_details( payment_attempt: &PaymentAttempt, webhook_mandate_details: &hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails, payment_method_mandate_details: Option, -) -> CustomResult, errors::ApiErrorResponse> { +) -> CustomResult, errors::ApiErrorResponse> { let (mandate_metadata, connector_mandate_request_reference_id) = payment_attempt .connector_mandate_detail .clone() From 7f3a7763dca5fee4c57bc3ce8da153ff6e09ab81 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 10 Jan 2025 15:51:23 +0530 Subject: [PATCH 26/29] mandate structure change --- crates/api_models/src/payment_methods.rs | 27 ++++++------- crates/diesel_models/src/payment_method.rs | 40 ++++++------------- .../src/payment_methods.rs | 38 ++++++------------ .../router/src/core/payment_methods/cards.rs | 2 - .../router/src/core/payments/tokenization.rs | 5 --- crates/router/src/core/webhooks/incoming.rs | 2 - 6 files changed, 38 insertions(+), 76 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index d6db9b56b64a..814d688e15a6 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -306,7 +306,7 @@ pub struct PaymentsMandateReference( pub HashMap, ); -#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct PayoutsMandateReference( pub HashMap, ); @@ -330,11 +330,6 @@ pub struct CommonMandateReference { pub payouts: Option, } -#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] -pub struct PayoutsMandateReferenceStruct { - pub payouts: PayoutsMandateReference, -} - impl From for PaymentsMandateReference { fn from(common_mandate: CommonMandateReference) -> Self { common_mandate.payments.unwrap_or_default() @@ -349,7 +344,7 @@ impl From for CommonMandateReference { } } } -// here + fn deserialize_connector_mandate_details<'de, D>( deserializer: D, ) -> Result, D::Error> @@ -362,15 +357,19 @@ where let mut payments_data = None; let mut payouts_data = None; - if let Ok(payment_mandate_record) = - serde_json::from_value::(connector_mandate_value.clone()) - { - payments_data = Some(payment_mandate_record); + if let Some(obj) = connector_mandate_value.clone().as_object_mut() { + obj.remove("payouts"); + + if let Ok(payment_mandate_record) = + serde_json::from_value::(serde_json::json!(obj)) + { + payments_data = Some(payment_mandate_record); + } } - if let Ok(payouts) = - serde_json::from_value::(connector_mandate_value) + if let Ok(payment_mandate_record) = + serde_json::from_value::(connector_mandate_value) { - payouts_data = Some(payouts.payouts); + payouts_data = payment_mandate_record.payouts; } if payments_data.is_none() && payouts_data.is_none() { diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index a89f5671291f..e25e75e73c01 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -983,11 +983,6 @@ pub struct PayoutsMandateReference( pub HashMap, ); -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct PayoutsMandateReferenceStruct { - pub payouts: PayoutsMandateReference, -} - impl std::ops::Deref for PayoutsMandateReference { type Target = HashMap; @@ -1022,14 +1017,13 @@ impl diesel::serialize::ToSql for Comm payments_object.insert("payouts".to_string(), payouts); } - router_env::logger::info!("here : {:?}", payments.clone()); >::to_sql(&payments, &mut out.reborrow()) } } -// here + impl diesel::deserialize::FromSql for CommonMandateReference where @@ -1044,13 +1038,20 @@ where let mut payments_data = None; let mut payouts_data = None; + if let Some(obj) = value.clone().as_object_mut() { + obj.remove("payouts"); + + if let Ok(payment_mandate_record) = + serde_json::from_value::(serde_json::json!(obj)) + { + payments_data = Some(payment_mandate_record); + } + } + if let Ok(payment_mandate_record) = - serde_json::from_value::(value.clone()) + serde_json::from_value::(value.clone()) { - payments_data = Some(payment_mandate_record); - } - if let Ok(payouts) = serde_json::from_value::(value) { - payouts_data = Some(payouts.payouts); + payouts_data = payment_mandate_record.payouts } if payments_data.is_none() && payouts_data.is_none() { @@ -1066,21 +1067,6 @@ where payouts: payouts_data, }) } - - // if let Ok(payment_reference) = - // serde_json::from_value::(value.clone()) - // { - // return Ok(Self::from(payment_reference)); - // } - - // if let Ok(common_reference) = serde_json::from_value::(value) { - // return Ok(common_reference); - // } - // Err( - // report!(ParsingError::StructParseFailure("CommonMandateReference")).attach_printable( - // "Failed to parse JSON into CommonMandateReference or PaymentsMandateReference", - // ), - // )? } } diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs index bfe6fed4bf7b..f85696889af6 100644 --- a/crates/hyperswitch_domain_models/src/payment_methods.rs +++ b/crates/hyperswitch_domain_models/src/payment_methods.rs @@ -144,25 +144,26 @@ impl PaymentMethod { not(feature = "payment_methods_v2") ))] pub fn get_common_mandate_reference( - // here &self, ) -> Result { if let Some(value) = &self.connector_mandate_details { - router_env::logger::info!("hereeee : {:?}", value.clone()); let mut payments_data = None; let mut payouts_data = None; - if let Ok(payment_mandate_record) = - serde_json::from_value::(value.clone()) - { - router_env::logger::info!("hereeee : {:?}", payment_mandate_record.clone()); - payments_data = Some(payment_mandate_record); + if let Some(obj) = value.clone().as_object_mut() { + obj.remove("payouts"); + + if let Ok(payment_mandate_record) = serde_json::from_value::< + diesel_models::PaymentsMandateReference, + >(serde_json::json!(obj)) + { + payments_data = Some(payment_mandate_record); + } } - if let Ok(payouts) = - serde_json::from_value::(value.clone()) + if let Ok(payment_mandate_record) = + serde_json::from_value::(value.clone()) { - router_env::logger::info!("hereeee : {:?}", payouts.clone()); - payouts_data = Some(payouts.payouts); + payouts_data = payment_mandate_record.payouts } if payments_data.is_none() && payouts_data.is_none() { @@ -175,21 +176,6 @@ impl PaymentMethod { payouts: payouts_data, }) } - - // match serde_json::from_value::(value.clone()) { - // Ok(payment_mandate_reference) => Ok(diesel_models::CommonMandateReference { - // payments: Some(payment_mandate_reference), - // payouts: None, - // }), - // Err(_) => match serde_json::from_value::( - // value.clone(), - // ) { - // Ok(common_mandate_reference) => Ok(common_mandate_reference), - // Err(_) => Err(ParsingError::StructParseFailure( - // "Failed to deserialize PaymentMethod", - // ))?, - // }, - // } } else { Ok(diesel_models::CommonMandateReference { payments: None, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 0622dd90a0a1..9ab025b576a7 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2859,8 +2859,6 @@ pub async fn update_payment_method_connector_mandate_details( connector_mandate_details_value = Some(payments) } - router_env::logger::info!("here : {:?}", connector_mandate_details_value.clone()); - let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate { connector_mandate_details: connector_mandate_details_value, }; diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index bcaf6f1162f4..4e4db44ca9f4 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -1264,10 +1264,5 @@ pub fn update_connector_mandate_details( connector_mandate_request_reference_id, ), }; - // let connector_mandate_details = mandate_reference - // .map(|mand| mand.encode_to_value()) - // .transpose() - // .change_context(errors::ApiErrorResponse::InternalServerError) - // .attach_printable("Unable to serialize customer acceptance to value")?; Ok(mandate_reference) } diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index d0ce4898f7d2..87fd464cdfb1 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -1925,8 +1925,6 @@ async fn update_connector_mandate_details( connector_mandate_details_value = Some(payments) } - router_env::logger::info!("here : {:?}", connector_mandate_details_value); - let pm_update = diesel_models::PaymentMethodUpdate::ConnectorNetworkTransactionIdAndMandateDetailsUpdate { connector_mandate_details: connector_mandate_details_value.map(masking::Secret::new), network_transaction_id: webhook_connector_network_transaction_id From 8fb8eb9d3002f65ffc72beaed7b68e32f4e675da Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 10 Jan 2025 16:05:50 +0530 Subject: [PATCH 27/29] clippy fix --- crates/diesel_models/src/payment_method.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index e25e75e73c01..381ceeb099ba 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -1049,7 +1049,7 @@ where } if let Ok(payment_mandate_record) = - serde_json::from_value::(value.clone()) + serde_json::from_value::(value.clone()) { payouts_data = payment_mandate_record.payouts } @@ -1062,7 +1062,7 @@ where ), )? } else { - Ok(CommonMandateReference { + Ok(Self { payments: payments_data, payouts: payouts_data, }) From 9df8109ac28b094a56ae818de8854f15d76a199b Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 11:04:59 +0000 Subject: [PATCH 28/29] chore: run formatter --- crates/diesel_models/src/payment_method.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 381ceeb099ba..42f02f65ef3a 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -1048,9 +1048,7 @@ where } } - if let Ok(payment_mandate_record) = - serde_json::from_value::(value.clone()) - { + if let Ok(payment_mandate_record) = serde_json::from_value::(value.clone()) { payouts_data = payment_mandate_record.payouts } From f8d4d53fc7739303c9bce1322bf8260f37660c55 Mon Sep 17 00:00:00 2001 From: sumanmaji4 Date: Fri, 10 Jan 2025 17:06:17 +0530 Subject: [PATCH 29/29] removed payout from mandate if null --- crates/diesel_models/src/payment_method.rs | 4 +++- crates/router/src/core/payment_methods/cards.rs | 4 +++- crates/router/src/core/webhooks/incoming.rs | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index 42f02f65ef3a..d24bd1ead165 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -1014,7 +1014,9 @@ impl diesel::serialize::ToSql for Comm let payouts = serde_json::to_value(self.payouts.as_ref())?; if let Some(payments_object) = payments.as_object_mut() { - payments_object.insert("payouts".to_string(), payouts); + if !payouts.is_null() { + payments_object.insert("payouts".to_string(), payouts); + } }