From 567e9b537eb8a572113796b5824554aaad8031a5 Mon Sep 17 00:00:00 2001 From: Kashif Date: Fri, 8 Nov 2024 15:20:29 +0530 Subject: [PATCH] fix(payments): populate payment_method_type in payment_attempt for cards --- crates/diesel_models/src/payment_attempt.rs | 60 +++++++++++++++++++ .../src/payments/payment_attempt.rs | 11 ++++ .../payments/operations/payment_response.rs | 56 ++++++++++++++++- 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index f8654d3cd963..ceb2c76550f3 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -549,6 +549,10 @@ pub enum PaymentAttemptUpdate { updated_by: String, connector_metadata: Option, }, + PaymentMethodTypeUpdate { + payment_method_type: Option, + updated_by: String, + }, } #[cfg(feature = "v2")] @@ -3279,6 +3283,62 @@ impl From for PaymentAttemptUpdateInternal { connector_transaction_data: None, connector_mandate_detail: None, }, + PaymentAttemptUpdate::PaymentMethodTypeUpdate { + payment_method_type, + updated_by, + } => Self { + modified_at: common_utils::date_time::now(), + payment_method_type, + updated_by, + status: None, + error_code: None, + error_message: None, + error_reason: None, + unified_code: None, + unified_message: None, + amount: None, + net_amount: None, + currency: None, + connector_transaction_id: None, + amount_to_capture: None, + connector: None, + authentication_type: None, + payment_method: None, + payment_method_id: None, + cancellation_reason: None, + mandate_id: None, + browser_info: None, + payment_token: None, + connector_metadata: None, + payment_method_data: None, + payment_experience: None, + business_sub_label: None, + straight_through_algorithm: None, + preprocessing_step_id: None, + capture_method: None, + connector_response_reference_id: None, + multiple_capture_count: None, + surcharge_amount: None, + tax_amount: None, + amount_capturable: None, + merchant_connector_id: None, + authentication_data: None, + encoded_data: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + payment_method_billing_address_id: None, + charge_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + card_network: None, + shipping_cost: None, + order_tax_amount: None, + connector_transaction_data: None, + connector_mandate_detail: None, + }, } } } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 831e97b54a17..3a126c356f5c 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -914,6 +914,10 @@ pub enum PaymentAttemptUpdate { updated_by: String, connector_metadata: Option, }, + PaymentMethodTypeUpdate { + payment_method_type: Option, + updated_by: String, + }, } #[cfg(feature = "v1")] @@ -1276,6 +1280,13 @@ impl PaymentAttemptUpdate { updated_by, connector_metadata, }, + Self::PaymentMethodTypeUpdate { + payment_method_type, + updated_by, + } => DieselPaymentAttemptUpdate::PaymentMethodTypeUpdate { + payment_method_type, + updated_by, + }, } } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 0234b97032c7..1dac07e33986 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, str::FromStr}; use api_models::payments::{ConnectorMandateReferenceId, MandateReferenceId}; #[cfg(feature = "dynamic_routing")] @@ -36,7 +36,7 @@ use crate::{ }, tokenization, types::MultipleCaptureData, - PaymentData, PaymentMethodChecker, + OperationSessionGetters, PaymentData, PaymentMethodChecker, }, utils as core_utils, }, @@ -1243,6 +1243,54 @@ impl PostUpdateTracker, types::CompleteAuthorizeData } } +async fn update_payment_method_type_for_cards( + state: &SessionState, + storage_scheme: enums::MerchantStorageScheme, + payment_data: &mut PaymentData, +) -> RouterResult<()> { + // Parse Value to AdditionalPaymentData + let additional_payment_method_data: Option = + payment_data + .get_payment_attempt() + .payment_method_data + .clone() + .map(|data| data.parse_value("payment_method_data")) + .transpose() + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "payment_method_data", + })?; + + // Fetch card_type from this struct for cards + let payment_method_type = match additional_payment_method_data { + Some(api_models::payments::AdditionalPaymentData::Card(card)) => card + .card_type + .map(|card_type_str| enums::PaymentMethodType::from_str(&card_type_str.to_lowercase())) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError)?, + _ => None, + }; + + // If payment_method_type in PaymentAttempt does not match the one in payment_method_data + // update payment_method_type in PaymentAttempt table + if payment_data.payment_attempt.payment_method_type.as_ref() != payment_method_type.as_ref() { + payment_data.payment_attempt.payment_method_type = payment_method_type; + let payment_attempt_update = storage::PaymentAttemptUpdate::PaymentMethodTypeUpdate { + payment_method_type, + updated_by: storage_scheme.to_string(), + }; + state + .store + .update_payment_attempt_with_attempt_id( + payment_data.payment_attempt.clone(), + payment_attempt_update, + storage_scheme, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; + } + Ok(()) +} + #[cfg(feature = "v1")] #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] @@ -1258,8 +1306,10 @@ async fn payment_response_update_tracker( >, #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile, ) -> RouterResult> { - // Update additional payment data with the payment method response that we received from connector + // Populate payment_method_type for cards in case it's empty or mismatched + update_payment_method_type_for_cards(state, storage_scheme, &mut payment_data).await?; + // Update additional payment data with the payment method response that we received from connector let additional_payment_method_data = match payment_data.payment_method_data.clone() { Some(payment_method_data) => match payment_method_data { hyperswitch_domain_models::payment_method_data::PaymentMethodData::Card(_)