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(router): update last used when the customer acceptance is passed in the recurring payment #5116

Merged
merged 9 commits into from
Jul 2, 2024
30 changes: 27 additions & 3 deletions crates/diesel_models/src/payment_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,13 @@ pub struct TokenizeCoreWorkflow {

#[derive(Debug, Serialize, Deserialize)]
pub enum PaymentMethodUpdate {
MetadataUpdate {
MetadataUpdateAndLastUsed {
metadata: Option<serde_json::Value>,
last_used_at: PrimitiveDateTime,
},
UpdatePaymentMethodDataAndLastUsed {
payment_method_data: Option<Encryption>,
last_used_at: PrimitiveDateTime,
},
PaymentMethodDataUpdate {
payment_method_data: Option<Encryption>,
Expand Down Expand Up @@ -191,10 +196,13 @@ impl PaymentMethodUpdateInternal {
impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
fn from(payment_method_update: PaymentMethodUpdate) -> Self {
match payment_method_update {
PaymentMethodUpdate::MetadataUpdate { metadata } => Self {
PaymentMethodUpdate::MetadataUpdateAndLastUsed {
metadata,
last_used_at,
} => Self {
metadata,
payment_method_data: None,
last_used_at: None,
last_used_at: Some(last_used_at),
network_transaction_id: None,
status: None,
locker_id: None,
Expand Down Expand Up @@ -232,6 +240,22 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
payment_method_issuer: None,
payment_method_type: None,
},
PaymentMethodUpdate::UpdatePaymentMethodDataAndLastUsed {
payment_method_data,
last_used_at,
} => Self {
metadata: None,
payment_method_data,
last_used_at: Some(last_used_at),
network_transaction_id: None,
status: None,
locker_id: None,
payment_method: None,
connector_mandate_details: None,
updated_by: None,
payment_method_issuer: None,
payment_method_type: None,
},
PaymentMethodUpdate::NetworkTransactionIdAndStatusUpdate {
network_transaction_id,
status,
Expand Down
25 changes: 21 additions & 4 deletions crates/router/src/core/payment_methods/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1389,14 +1389,31 @@ pub async fn call_to_locker_hs<'a>(
Ok(stored_card)
}

pub async fn update_payment_method(
pub async fn update_payment_method_metadata_and_last_used(
db: &dyn db::StorageInterface,
pm: payment_method::PaymentMethod,
pm_metadata: serde_json::Value,
pm_metadata: Option<serde_json::Value>,
storage_scheme: MerchantStorageScheme,
) -> errors::CustomResult<(), errors::VaultError> {
let pm_update = payment_method::PaymentMethodUpdate::MetadataUpdateAndLastUsed {
metadata: pm_metadata,
last_used_at: common_utils::date_time::now(),
};
db.update_payment_method(pm, pm_update, storage_scheme)
.await
.change_context(errors::VaultError::UpdateInPaymentMethodDataTableFailed)?;
Ok(())
}

pub async fn update_payment_method_and_last_used(
db: &dyn db::StorageInterface,
pm: payment_method::PaymentMethod,
payment_method_update: Option<Encryption>,
storage_scheme: MerchantStorageScheme,
) -> errors::CustomResult<(), errors::VaultError> {
let pm_update = payment_method::PaymentMethodUpdate::MetadataUpdate {
metadata: Some(pm_metadata),
let pm_update = payment_method::PaymentMethodUpdate::UpdatePaymentMethodDataAndLastUsed {
payment_method_data: payment_method_update,
last_used_at: common_utils::date_time::now(),
};
db.update_payment_method(pm, pm_update, storage_scheme)
.await
Expand Down
11 changes: 11 additions & 0 deletions crates/router/src/core/payments/operations/payment_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,14 @@ impl<F: Send + Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthor
.get_payment_method_billing()
.and_then(|billing_details| billing_details.address.as_ref())
.and_then(|address| address.get_optional_full_name());
let mut should_avoid_saving = false;

if let Some(payment_method_info) = &payment_data.payment_method_info {
if payment_data.payment_intent.off_session.is_none() && resp.response.is_ok() {
should_avoid_saving = resp.request.payment_method_type
== Some(enums::PaymentMethodType::ApplePay)
|| resp.request.payment_method_type
== Some(enums::PaymentMethodType::GooglePay);
payment_methods::cards::update_last_used_at(
payment_method_info,
state,
Expand Down Expand Up @@ -179,6 +184,12 @@ impl<F: Send + Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthor
let (payment_method_id, _payment_method_status) = save_payment_call_future.await?;
payment_data.payment_attempt.payment_method_id = payment_method_id;
Ok(())
} else if should_avoid_saving {
if let Some(pm_info) = &payment_data.payment_method_info {
payment_data.payment_attempt.payment_method_id =
Some(pm_info.payment_method_id.clone());
};
Ok(())
} else {
// Save card flow
let save_payment_data = tokenization::SavePaymentMethodData::from(resp);
Expand Down
51 changes: 26 additions & 25 deletions crates/router/src/core/payments/tokenization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,20 +269,15 @@ where
pm.metadata.as_ref(),
connector_token,
)?;
if let Some(metadata) = pm_metadata {
payment_methods::cards::update_payment_method(
db,
pm.clone(),
metadata,
merchant_account.storage_scheme,
)
.await
.change_context(
errors::ApiErrorResponse::InternalServerError,
)
.attach_printable("Failed to add payment method in db")?;
};
// update if its a off-session mit payment
payment_methods::cards::update_payment_method_metadata_and_last_used(
db,
pm.clone(),
pm_metadata,
merchant_account.storage_scheme,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to add payment method in db")?;
if check_for_mit_mandates {
let connector_mandate_details =
update_connector_mandate_details_in_payment_method(
Expand Down Expand Up @@ -511,14 +506,10 @@ where
)
.await;

let pm_update =
storage::PaymentMethodUpdate::PaymentMethodDataUpdate {
payment_method_data: pm_data_encrypted,
};

db.update_payment_method(
payment_methods::cards::update_payment_method_and_last_used(
db,
existing_pm,
pm_update,
pm_data_encrypted,
merchant_account.storage_scheme,
)
.await
Expand All @@ -528,7 +519,7 @@ where
}
},
None => {
let customer_saved_pm_id_option = if payment_method_type
let customer_saved_pm_option = if payment_method_type
== Some(api_models::enums::PaymentMethodType::ApplePay)
|| payment_method_type
== Some(api_models::enums::PaymentMethodType::GooglePay)
Expand All @@ -547,7 +538,7 @@ where
.find(|payment_method| {
payment_method.payment_method_type == payment_method_type
})
.map(|pm| pm.payment_method_id.clone())),
.cloned()),
Err(error) => {
if error.current_context().is_db_not_found() {
Ok(None)
Expand All @@ -566,8 +557,18 @@ where
Ok(None)
}?;

if let Some(customer_saved_pm_id) = customer_saved_pm_id_option {
resp.payment_method_id = customer_saved_pm_id;
if let Some(customer_saved_pm) = customer_saved_pm_option {
payment_methods::cards::update_last_used_at(
&customer_saved_pm,
state,
merchant_account.storage_scheme,
)
.await
.map_err(|e| {
logger::error!("Failed to update last used at: {:?}", e);
})
.ok();
resp.payment_method_id = customer_saved_pm.payment_method_id;
} else {
let pm_metadata =
create_payment_method_metadata(None, connector_token)?;
Expand Down
Loading