Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(payments): populate payment_method_type in payment_attempt for cards #6519

Merged
merged 7 commits into from
Nov 13, 2024
60 changes: 60 additions & 0 deletions crates/diesel_models/src/payment_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,10 @@ pub enum PaymentAttemptUpdate {
updated_by: String,
connector_metadata: Option<serde_json::Value>,
},
PaymentMethodTypeUpdate {
payment_method_type: Option<storage_enums::PaymentMethodType>,
updated_by: String,
},
}

#[cfg(feature = "v2")]
Expand Down Expand Up @@ -3279,6 +3283,62 @@ impl From<PaymentAttemptUpdate> 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,
},
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,10 @@ pub enum PaymentAttemptUpdate {
updated_by: String,
connector_metadata: Option<serde_json::Value>,
},
PaymentMethodTypeUpdate {
payment_method_type: Option<storage_enums::PaymentMethodType>,
updated_by: String,
},
}

#[cfg(feature = "v1")]
Expand Down Expand Up @@ -1276,6 +1280,13 @@ impl PaymentAttemptUpdate {
updated_by,
connector_metadata,
},
Self::PaymentMethodTypeUpdate {
payment_method_type,
updated_by,
} => DieselPaymentAttemptUpdate::PaymentMethodTypeUpdate {
payment_method_type,
updated_by,
},
}
}
}
Expand Down
56 changes: 53 additions & 3 deletions crates/router/src/core/payments/operations/payment_response.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{collections::HashMap, str::FromStr};

use api_models::payments::{ConnectorMandateReferenceId, MandateReferenceId};
#[cfg(feature = "dynamic_routing")]
Expand Down Expand Up @@ -36,7 +36,7 @@ use crate::{
},
tokenization,
types::MultipleCaptureData,
PaymentData, PaymentMethodChecker,
OperationSessionGetters, PaymentData, PaymentMethodChecker,
},
utils as core_utils,
},
Expand Down Expand Up @@ -1243,6 +1243,54 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::CompleteAuthorizeData
}
}

async fn update_payment_method_type_for_cards<F: Clone>(
state: &SessionState,
storage_scheme: enums::MerchantStorageScheme,
payment_data: &mut PaymentData<F>,
) -> RouterResult<()> {
// Parse Value to AdditionalPaymentData
let additional_payment_method_data: Option<api_models::payments::AdditionalPaymentData> =
payment_data
.get_payment_attempt()
.payment_method_data
.clone()
.map(|data| data.parse_value("payment_method_data"))
.transpose()
kashif-m marked this conversation as resolved.
Show resolved Hide resolved
.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,
kashif-m marked this conversation as resolved.
Show resolved Hide resolved
};

// 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;
kashif-m marked this conversation as resolved.
Show resolved Hide resolved
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)]
Expand All @@ -1258,8 +1306,10 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
>,
#[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
) -> RouterResult<PaymentData<F>> {
// 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(_)
Expand Down
Loading