mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 19:42:27 +08:00
refactor(payment_methods): handle card duplication (#3146)
This commit is contained in:
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user