mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
refactor(payment_methods): handle card duplication (#3146)
This commit is contained in:
@ -109,7 +109,10 @@ pub fn store_default_payment_method(
|
|||||||
req: &api::PaymentMethodCreate,
|
req: &api::PaymentMethodCreate,
|
||||||
customer_id: &str,
|
customer_id: &str,
|
||||||
merchant_id: &String,
|
merchant_id: &String,
|
||||||
) -> (api::PaymentMethodResponse, bool) {
|
) -> (
|
||||||
|
api::PaymentMethodResponse,
|
||||||
|
Option<payment_methods::DataDuplicationCheck>,
|
||||||
|
) {
|
||||||
let pm_id = generate_id(consts::ID_LENGTH, "pm");
|
let pm_id = generate_id(consts::ID_LENGTH, "pm");
|
||||||
let payment_method_response = api::PaymentMethodResponse {
|
let payment_method_response = api::PaymentMethodResponse {
|
||||||
merchant_id: merchant_id.to_string(),
|
merchant_id: merchant_id.to_string(),
|
||||||
@ -125,7 +128,7 @@ pub fn store_default_payment_method(
|
|||||||
installment_payment_enabled: false, //[#219]
|
installment_payment_enabled: false, //[#219]
|
||||||
payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219]
|
payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219]
|
||||||
};
|
};
|
||||||
(payment_method_response, false)
|
(payment_method_response, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
@ -136,6 +139,7 @@ pub async fn add_payment_method(
|
|||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
) -> errors::RouterResponse<api::PaymentMethodResponse> {
|
) -> errors::RouterResponse<api::PaymentMethodResponse> {
|
||||||
req.validate()?;
|
req.validate()?;
|
||||||
|
let db = &*state.store;
|
||||||
let merchant_id = &merchant_account.merchant_id;
|
let merchant_id = &merchant_account.merchant_id;
|
||||||
let customer_id = req.customer_id.clone().get_required_value("customer_id")?;
|
let customer_id = req.customer_id.clone().get_required_value("customer_id")?;
|
||||||
|
|
||||||
@ -178,34 +182,179 @@ pub async fn add_payment_method(
|
|||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (resp, is_duplicate) = response?;
|
let (resp, duplication_check) = response?;
|
||||||
if !is_duplicate {
|
|
||||||
let pm_metadata = resp.metadata.as_ref().map(|data| data.peek());
|
|
||||||
|
|
||||||
let pm_card_details = resp
|
match duplication_check {
|
||||||
.card
|
Some(duplication_check) => match duplication_check {
|
||||||
.as_ref()
|
payment_methods::DataDuplicationCheck::Duplicated => {
|
||||||
.map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())));
|
let existing_pm = db.find_payment_method(&resp.payment_method_id).await;
|
||||||
|
|
||||||
let pm_data_encrypted =
|
if let Err(err) = existing_pm {
|
||||||
create_encrypted_payment_method_data(key_store, pm_card_details).await;
|
if err.current_context().is_db_not_found() {
|
||||||
|
insert_payment_method(
|
||||||
|
db,
|
||||||
|
&resp,
|
||||||
|
req,
|
||||||
|
key_store,
|
||||||
|
merchant_id,
|
||||||
|
&customer_id,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Error while finding payment method")
|
||||||
|
}?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
create_payment_method(
|
payment_methods::DataDuplicationCheck::MetaDataChanged => {
|
||||||
&*state.store,
|
if let Some(card) = req.card.clone() {
|
||||||
&req,
|
delete_card_from_locker(
|
||||||
&customer_id,
|
&state,
|
||||||
&resp.payment_method_id,
|
&customer_id,
|
||||||
&resp.merchant_id,
|
merchant_id,
|
||||||
pm_metadata.cloned(),
|
&resp.payment_method_id,
|
||||||
pm_data_encrypted,
|
)
|
||||||
key_store,
|
.await?;
|
||||||
)
|
|
||||||
.await?;
|
let add_card_resp = add_card_hs(
|
||||||
}
|
&state,
|
||||||
|
req.clone(),
|
||||||
|
&card,
|
||||||
|
customer_id.clone(),
|
||||||
|
merchant_account,
|
||||||
|
api::enums::LockerChoice::Tartarus,
|
||||||
|
Some(&resp.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,
|
||||||
|
&resp.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(&resp.payment_method_id).await;
|
||||||
|
match existing_pm {
|
||||||
|
Ok(pm) => {
|
||||||
|
let updated_card = Some(api::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 =
|
||||||
|
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() {
|
||||||
|
insert_payment_method(
|
||||||
|
db,
|
||||||
|
&resp,
|
||||||
|
req,
|
||||||
|
key_store,
|
||||||
|
merchant_id,
|
||||||
|
&customer_id,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Error while finding payment method")
|
||||||
|
}?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let pm_metadata = resp.metadata.as_ref().map(|data| data.peek());
|
||||||
|
|
||||||
|
insert_payment_method(
|
||||||
|
db,
|
||||||
|
&resp,
|
||||||
|
req,
|
||||||
|
key_store,
|
||||||
|
merchant_id,
|
||||||
|
&customer_id,
|
||||||
|
pm_metadata.cloned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(services::ApplicationResponse::Json(resp))
|
Ok(services::ApplicationResponse::Json(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn insert_payment_method(
|
||||||
|
db: &dyn db::StorageInterface,
|
||||||
|
resp: &api::PaymentMethodResponse,
|
||||||
|
req: api::PaymentMethodCreate,
|
||||||
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
merchant_id: &str,
|
||||||
|
customer_id: &str,
|
||||||
|
pm_metadata: Option<serde_json::Value>,
|
||||||
|
) -> errors::RouterResult<()> {
|
||||||
|
let pm_card_details = resp
|
||||||
|
.card
|
||||||
|
.as_ref()
|
||||||
|
.map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())));
|
||||||
|
let pm_data_encrypted = create_encrypted_payment_method_data(key_store, pm_card_details).await;
|
||||||
|
create_payment_method(
|
||||||
|
db,
|
||||||
|
&req,
|
||||||
|
customer_id,
|
||||||
|
&resp.payment_method_id,
|
||||||
|
merchant_id,
|
||||||
|
pm_metadata,
|
||||||
|
pm_data_encrypted,
|
||||||
|
key_store,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub async fn update_customer_payment_method(
|
pub async fn update_customer_payment_method(
|
||||||
state: routes::AppState,
|
state: routes::AppState,
|
||||||
@ -264,7 +413,13 @@ pub async fn add_bank_to_locker(
|
|||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
bank: &api::BankPayout,
|
bank: &api::BankPayout,
|
||||||
customer_id: &String,
|
customer_id: &String,
|
||||||
) -> errors::CustomResult<(api::PaymentMethodResponse, bool), errors::VaultError> {
|
) -> errors::CustomResult<
|
||||||
|
(
|
||||||
|
api::PaymentMethodResponse,
|
||||||
|
Option<payment_methods::DataDuplicationCheck>,
|
||||||
|
),
|
||||||
|
errors::VaultError,
|
||||||
|
> {
|
||||||
let key = key_store.key.get_inner().peek();
|
let key = key_store.key.get_inner().peek();
|
||||||
let payout_method_data = api::PayoutMethodData::Bank(bank.clone());
|
let payout_method_data = api::PayoutMethodData::Bank(bank.clone());
|
||||||
let enc_data = async {
|
let enc_data = async {
|
||||||
@ -312,7 +467,7 @@ pub async fn add_bank_to_locker(
|
|||||||
req,
|
req,
|
||||||
&merchant_account.merchant_id,
|
&merchant_account.merchant_id,
|
||||||
);
|
);
|
||||||
Ok((payment_method_resp, store_resp.duplicate.unwrap_or(false)))
|
Ok((payment_method_resp, store_resp.duplication_check))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The response will be the tuple of PaymentMethodResponse and the duplication check of payment_method
|
/// The response will be the tuple of PaymentMethodResponse and the duplication check of payment_method
|
||||||
@ -322,7 +477,13 @@ pub async fn add_card_to_locker(
|
|||||||
card: &api::CardDetail,
|
card: &api::CardDetail,
|
||||||
customer_id: &String,
|
customer_id: &String,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
) -> errors::CustomResult<(api::PaymentMethodResponse, bool), errors::VaultError> {
|
) -> errors::CustomResult<
|
||||||
|
(
|
||||||
|
api::PaymentMethodResponse,
|
||||||
|
Option<payment_methods::DataDuplicationCheck>,
|
||||||
|
),
|
||||||
|
errors::VaultError,
|
||||||
|
> {
|
||||||
metrics::STORED_TO_LOCKER.add(&metrics::CONTEXT, 1, &[]);
|
metrics::STORED_TO_LOCKER.add(&metrics::CONTEXT, 1, &[]);
|
||||||
let add_card_to_hs_resp = request::record_operation_time(
|
let add_card_to_hs_resp = request::record_operation_time(
|
||||||
async {
|
async {
|
||||||
@ -540,7 +701,13 @@ pub async fn add_card_hs(
|
|||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
locker_choice: api_enums::LockerChoice,
|
locker_choice: api_enums::LockerChoice,
|
||||||
card_reference: Option<&str>,
|
card_reference: Option<&str>,
|
||||||
) -> errors::CustomResult<(api::PaymentMethodResponse, bool), errors::VaultError> {
|
) -> errors::CustomResult<
|
||||||
|
(
|
||||||
|
api::PaymentMethodResponse,
|
||||||
|
Option<payment_methods::DataDuplicationCheck>,
|
||||||
|
),
|
||||||
|
errors::VaultError,
|
||||||
|
> {
|
||||||
let payload = payment_methods::StoreLockerReq::LockerCard(payment_methods::StoreCardReq {
|
let payload = payment_methods::StoreLockerReq::LockerCard(payment_methods::StoreCardReq {
|
||||||
merchant_id: &merchant_account.merchant_id,
|
merchant_id: &merchant_account.merchant_id,
|
||||||
merchant_customer_id: customer_id.to_owned(),
|
merchant_customer_id: customer_id.to_owned(),
|
||||||
@ -565,11 +732,7 @@ pub async fn add_card_hs(
|
|||||||
req,
|
req,
|
||||||
&merchant_account.merchant_id,
|
&merchant_account.merchant_id,
|
||||||
);
|
);
|
||||||
|
Ok((payment_method_resp, store_card_payload.duplication_check))
|
||||||
Ok((
|
|
||||||
payment_method_resp,
|
|
||||||
store_card_payload.duplicate.unwrap_or(false),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
@ -875,7 +1038,7 @@ pub async fn mock_call_to_locker_hs<'a>(
|
|||||||
.change_context(errors::VaultError::SaveCardFailed)?;
|
.change_context(errors::VaultError::SaveCardFailed)?;
|
||||||
let payload = payment_methods::StoreCardRespPayload {
|
let payload = payment_methods::StoreCardRespPayload {
|
||||||
card_reference: response.card_id,
|
card_reference: response.card_id,
|
||||||
duplicate: Some(false),
|
duplication_check: None,
|
||||||
};
|
};
|
||||||
Ok(payment_methods::StoreCardResp {
|
Ok(payment_methods::StoreCardResp {
|
||||||
status: "SUCCESS".to_string(),
|
status: "SUCCESS".to_string(),
|
||||||
|
|||||||
@ -62,7 +62,14 @@ pub struct StoreCardResp {
|
|||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct StoreCardRespPayload {
|
pub struct StoreCardRespPayload {
|
||||||
pub card_reference: String,
|
pub card_reference: String,
|
||||||
pub duplicate: Option<bool>,
|
pub duplication_check: Option<DataDuplicationCheck>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum DataDuplicationCheck {
|
||||||
|
Duplicated,
|
||||||
|
MetaDataChanged,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use api_models::payment_methods::PaymentMethodsData;
|
||||||
use common_utils::{ext_traits::ValueExt, pii};
|
use common_utils::{ext_traits::ValueExt, pii};
|
||||||
use error_stack::{report, ResultExt};
|
use error_stack::{report, ResultExt};
|
||||||
use masking::ExposeInterface;
|
use masking::ExposeInterface;
|
||||||
@ -6,7 +7,7 @@ use router_env::{instrument, tracing};
|
|||||||
use super::helpers;
|
use super::helpers;
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{
|
core::{
|
||||||
errors::{self, ConnectorErrorExt, RouterResult},
|
errors::{self, ConnectorErrorExt, RouterResult, StorageErrorExt},
|
||||||
mandate, payment_methods, payments,
|
mandate, payment_methods, payments,
|
||||||
},
|
},
|
||||||
logger,
|
logger,
|
||||||
@ -16,7 +17,7 @@ use crate::{
|
|||||||
self,
|
self,
|
||||||
api::{self, CardDetailFromLocker, CardDetailsPaymentMethod, PaymentMethodCreateExt},
|
api::{self, CardDetailFromLocker, CardDetailsPaymentMethod, PaymentMethodCreateExt},
|
||||||
domain,
|
domain,
|
||||||
storage::enums as storage_enums,
|
storage::{self, enums as storage_enums},
|
||||||
},
|
},
|
||||||
utils::OptionExt,
|
utils::OptionExt,
|
||||||
};
|
};
|
||||||
@ -99,7 +100,7 @@ where
|
|||||||
.await?
|
.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| {
|
let pm_card_details = locker_response.0.card.as_ref().map(|card| {
|
||||||
api::payment_methods::PaymentMethodsData::Card(CardDetailsPaymentMethod::from(
|
api::payment_methods::PaymentMethodsData::Card(CardDetailsPaymentMethod::from(
|
||||||
@ -114,29 +115,31 @@ where
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if is_duplicate {
|
match duplication_check {
|
||||||
let existing_pm = db
|
Some(duplication_check) => match duplication_check {
|
||||||
.find_payment_method(&locker_response.0.payment_method_id)
|
payment_methods::transformers::DataDuplicationCheck::Duplicated => {
|
||||||
.await;
|
let existing_pm = db
|
||||||
match existing_pm {
|
.find_payment_method(&locker_response.0.payment_method_id)
|
||||||
Ok(pm) => {
|
.await;
|
||||||
let pm_metadata = create_payment_method_metadata(
|
match existing_pm {
|
||||||
pm.metadata.as_ref(),
|
Ok(pm) => {
|
||||||
connector_token,
|
let pm_metadata = create_payment_method_metadata(
|
||||||
)?;
|
pm.metadata.as_ref(),
|
||||||
if let Some(metadata) = pm_metadata {
|
connector_token,
|
||||||
payment_methods::cards::update_payment_method(db, pm, metadata)
|
)?;
|
||||||
.await
|
if let Some(metadata) = pm_metadata {
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
payment_methods::cards::update_payment_method(
|
||||||
.attach_printable("Failed to add payment method in db")?;
|
db, pm, metadata,
|
||||||
};
|
)
|
||||||
}
|
.await
|
||||||
Err(error) => {
|
.change_context(
|
||||||
match error.current_context() {
|
errors::ApiErrorResponse::InternalServerError,
|
||||||
errors::StorageError::DatabaseError(err) => match err
|
)
|
||||||
.current_context()
|
.attach_printable("Failed to add payment method in db")?;
|
||||||
{
|
};
|
||||||
diesel_models::errors::DatabaseError::NotFound => {
|
}
|
||||||
|
Err(err) => {
|
||||||
|
if err.current_context().is_db_not_found() {
|
||||||
let pm_metadata =
|
let pm_metadata =
|
||||||
create_payment_method_metadata(None, connector_token)?;
|
create_payment_method_metadata(None, connector_token)?;
|
||||||
payment_methods::cards::create_payment_method(
|
payment_methods::cards::create_payment_method(
|
||||||
@ -150,33 +153,149 @@ where
|
|||||||
key_store,
|
key_store,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
} else {
|
||||||
_ => {
|
Err(err)
|
||||||
Err(report!(errors::ApiErrorResponse::InternalServerError)
|
.change_context(
|
||||||
.attach_printable(
|
errors::ApiErrorResponse::InternalServerError,
|
||||||
"Database Error while finding payment method",
|
)
|
||||||
))
|
.attach_printable("Error while finding payment method")
|
||||||
}
|
}?;
|
||||||
},
|
}
|
||||||
_ => Err(report!(errors::ApiErrorResponse::InternalServerError)
|
};
|
||||||
.attach_printable("Error while finding payment method")),
|
|
||||||
}?;
|
|
||||||
}
|
}
|
||||||
};
|
payment_methods::transformers::DataDuplicationCheck::MetaDataChanged => {
|
||||||
} else {
|
if let Some(card) = payment_method_create_request.card.clone() {
|
||||||
let pm_metadata = create_payment_method_metadata(None, connector_token)?;
|
payment_methods::cards::delete_card_from_locker(
|
||||||
payment_methods::cards::create_payment_method(
|
state,
|
||||||
db,
|
&customer.customer_id,
|
||||||
&payment_method_create_request,
|
merchant_id,
|
||||||
&customer.customer_id,
|
&locker_response.0.payment_method_id,
|
||||||
&locker_response.0.payment_method_id,
|
)
|
||||||
merchant_id,
|
.await?;
|
||||||
pm_metadata,
|
|
||||||
pm_data_encrypted,
|
let add_card_resp = payment_methods::cards::add_card_hs(
|
||||||
key_store,
|
state,
|
||||||
)
|
payment_method_create_request.clone(),
|
||||||
.await?;
|
&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)
|
Some(locker_response.0.payment_method_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -190,7 +309,10 @@ where
|
|||||||
async fn skip_saving_card_in_locker(
|
async fn skip_saving_card_in_locker(
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
payment_method_request: api::PaymentMethodCreate,
|
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 merchant_id = &merchant_account.merchant_id;
|
||||||
let customer_id = payment_method_request
|
let customer_id = payment_method_request
|
||||||
.clone()
|
.clone()
|
||||||
@ -243,7 +365,7 @@ async fn skip_saving_card_in_locker(
|
|||||||
bank_transfer: None,
|
bank_transfer: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((pm_resp, false))
|
Ok((pm_resp, None))
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let pm_id = common_utils::generate_id(crate::consts::ID_LENGTH, "pm");
|
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]),
|
payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
|
||||||
bank_transfer: None,
|
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,
|
state: &AppState,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
payment_method_request: api::PaymentMethodCreate,
|
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()?;
|
payment_method_request.validate()?;
|
||||||
let merchant_id = &merchant_account.merchant_id;
|
let merchant_id = &merchant_account.merchant_id;
|
||||||
let customer_id = payment_method_request
|
let customer_id = payment_method_request
|
||||||
@ -304,7 +429,7 @@ pub async fn save_in_locker(
|
|||||||
installment_payment_enabled: false, //[#219]
|
installment_payment_enabled: false, //[#219]
|
||||||
payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#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