refactor(payment_methods): handle card duplication (#3146)

This commit is contained in:
Chethan Rao
2024-02-08 17:40:52 +05:30
committed by GitHub
parent 96f82cb212
commit dd5630f070
3 changed files with 386 additions and 91 deletions

View File

@ -1,3 +1,4 @@
use api_models::payment_methods::PaymentMethodsData;
use common_utils::{ext_traits::ValueExt, pii};
use error_stack::{report, ResultExt};
use masking::ExposeInterface;
@ -6,7 +7,7 @@ use router_env::{instrument, tracing};
use super::helpers;
use crate::{
core::{
errors::{self, ConnectorErrorExt, RouterResult},
errors::{self, ConnectorErrorExt, RouterResult, StorageErrorExt},
mandate, payment_methods, payments,
},
logger,
@ -16,7 +17,7 @@ use crate::{
self,
api::{self, CardDetailFromLocker, CardDetailsPaymentMethod, PaymentMethodCreateExt},
domain,
storage::enums as storage_enums,
storage::{self, enums as storage_enums},
},
utils::OptionExt,
};
@ -99,7 +100,7 @@ where
.await?
};
let is_duplicate = locker_response.1;
let duplication_check = locker_response.1;
let pm_card_details = locker_response.0.card.as_ref().map(|card| {
api::payment_methods::PaymentMethodsData::Card(CardDetailsPaymentMethod::from(
@ -114,29 +115,31 @@ where
)
.await;
if is_duplicate {
let existing_pm = db
.find_payment_method(&locker_response.0.payment_method_id)
.await;
match existing_pm {
Ok(pm) => {
let pm_metadata = create_payment_method_metadata(
pm.metadata.as_ref(),
connector_token,
)?;
if let Some(metadata) = pm_metadata {
payment_methods::cards::update_payment_method(db, pm, metadata)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to add payment method in db")?;
};
}
Err(error) => {
match error.current_context() {
errors::StorageError::DatabaseError(err) => match err
.current_context()
{
diesel_models::errors::DatabaseError::NotFound => {
match duplication_check {
Some(duplication_check) => match duplication_check {
payment_methods::transformers::DataDuplicationCheck::Duplicated => {
let existing_pm = db
.find_payment_method(&locker_response.0.payment_method_id)
.await;
match existing_pm {
Ok(pm) => {
let pm_metadata = create_payment_method_metadata(
pm.metadata.as_ref(),
connector_token,
)?;
if let Some(metadata) = pm_metadata {
payment_methods::cards::update_payment_method(
db, pm, metadata,
)
.await
.change_context(
errors::ApiErrorResponse::InternalServerError,
)
.attach_printable("Failed to add payment method in db")?;
};
}
Err(err) => {
if err.current_context().is_db_not_found() {
let pm_metadata =
create_payment_method_metadata(None, connector_token)?;
payment_methods::cards::create_payment_method(
@ -150,33 +153,149 @@ where
key_store,
)
.await
}
_ => {
Err(report!(errors::ApiErrorResponse::InternalServerError)
.attach_printable(
"Database Error while finding payment method",
))
}
},
_ => Err(report!(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error while finding payment method")),
}?;
} else {
Err(err)
.change_context(
errors::ApiErrorResponse::InternalServerError,
)
.attach_printable("Error while finding payment method")
}?;
}
};
}
};
} else {
let pm_metadata = create_payment_method_metadata(None, connector_token)?;
payment_methods::cards::create_payment_method(
db,
&payment_method_create_request,
&customer.customer_id,
&locker_response.0.payment_method_id,
merchant_id,
pm_metadata,
pm_data_encrypted,
key_store,
)
.await?;
};
payment_methods::transformers::DataDuplicationCheck::MetaDataChanged => {
if let Some(card) = payment_method_create_request.card.clone() {
payment_methods::cards::delete_card_from_locker(
state,
&customer.customer_id,
merchant_id,
&locker_response.0.payment_method_id,
)
.await?;
let add_card_resp = payment_methods::cards::add_card_hs(
state,
payment_method_create_request.clone(),
&card,
customer.customer_id.clone(),
merchant_account,
api::enums::LockerChoice::Tartarus,
Some(&locker_response.0.payment_method_id),
)
.await;
if let Err(err) = add_card_resp {
logger::error!(vault_err=?err);
db.delete_payment_method_by_merchant_id_payment_method_id(
merchant_id,
&locker_response.0.payment_method_id,
)
.await
.to_not_found_response(
errors::ApiErrorResponse::PaymentMethodNotFound,
)?;
Err(report!(errors::ApiErrorResponse::InternalServerError)
.attach_printable(
"Failed while updating card metadata changes",
))?
};
let existing_pm = db
.find_payment_method(&locker_response.0.payment_method_id)
.await;
match existing_pm {
Ok(pm) => {
let updated_card = Some(CardDetailFromLocker {
scheme: None,
last4_digits: Some(
card.card_number.to_string().split_off(
card.card_number.to_string().len() - 4,
),
),
issuer_country: None,
card_number: Some(card.card_number),
expiry_month: Some(card.card_exp_month),
expiry_year: Some(card.card_exp_year),
card_token: None,
card_fingerprint: None,
card_holder_name: card.card_holder_name,
nick_name: card.nick_name,
card_network: None,
card_isin: None,
card_issuer: None,
card_type: None,
saved_to_locker: true,
});
let updated_pmd = updated_card.as_ref().map(|card| {
PaymentMethodsData::Card(
CardDetailsPaymentMethod::from(card.clone()),
)
});
let pm_data_encrypted =
payment_methods::cards::create_encrypted_payment_method_data(
key_store,
updated_pmd,
)
.await;
let pm_update =
storage::PaymentMethodUpdate::PaymentMethodDataUpdate {
payment_method_data: pm_data_encrypted,
};
db.update_payment_method(pm, pm_update)
.await
.change_context(
errors::ApiErrorResponse::InternalServerError,
)
.attach_printable(
"Failed to add payment method in db",
)?;
}
Err(err) => {
if err.current_context().is_db_not_found() {
payment_methods::cards::insert_payment_method(
db,
&locker_response.0,
payment_method_create_request,
key_store,
merchant_id,
&customer.customer_id,
None,
)
.await
} else {
Err(err)
.change_context(
errors::ApiErrorResponse::InternalServerError,
)
.attach_printable(
"Error while finding payment method",
)
}?;
}
}
}
}
},
None => {
let pm_metadata = create_payment_method_metadata(None, connector_token)?;
payment_methods::cards::create_payment_method(
db,
&payment_method_create_request,
&customer.customer_id,
&locker_response.0.payment_method_id,
merchant_id,
pm_metadata,
pm_data_encrypted,
key_store,
)
.await?;
}
}
Some(locker_response.0.payment_method_id)
} else {
None
@ -190,7 +309,10 @@ where
async fn skip_saving_card_in_locker(
merchant_account: &domain::MerchantAccount,
payment_method_request: api::PaymentMethodCreate,
) -> RouterResult<(api_models::payment_methods::PaymentMethodResponse, bool)> {
) -> RouterResult<(
api_models::payment_methods::PaymentMethodResponse,
Option<payment_methods::transformers::DataDuplicationCheck>,
)> {
let merchant_id = &merchant_account.merchant_id;
let customer_id = payment_method_request
.clone()
@ -243,7 +365,7 @@ async fn skip_saving_card_in_locker(
bank_transfer: None,
};
Ok((pm_resp, false))
Ok((pm_resp, None))
}
None => {
let pm_id = common_utils::generate_id(crate::consts::ID_LENGTH, "pm");
@ -261,7 +383,7 @@ async fn skip_saving_card_in_locker(
payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
bank_transfer: None,
};
Ok((payment_method_response, false))
Ok((payment_method_response, None))
}
}
}
@ -270,7 +392,10 @@ pub async fn save_in_locker(
state: &AppState,
merchant_account: &domain::MerchantAccount,
payment_method_request: api::PaymentMethodCreate,
) -> RouterResult<(api_models::payment_methods::PaymentMethodResponse, bool)> {
) -> RouterResult<(
api_models::payment_methods::PaymentMethodResponse,
Option<payment_methods::transformers::DataDuplicationCheck>,
)> {
payment_method_request.validate()?;
let merchant_id = &merchant_account.merchant_id;
let customer_id = payment_method_request
@ -304,7 +429,7 @@ pub async fn save_in_locker(
installment_payment_enabled: false, //[#219]
payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219]
};
Ok((payment_method_response, false))
Ok((payment_method_response, None))
}
}
}