mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 21:07:58 +08:00
feat(payment_methods): delete payment method using payment token (#258)
Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com> Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
@ -285,4 +285,5 @@ pub struct TokenizedCardValue2 {
|
||||
pub card_fingerprint: Option<String>,
|
||||
pub external_id: Option<String>,
|
||||
pub customer_id: Option<String>,
|
||||
pub payment_method_id: Option<String>,
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ pub async fn add_card(
|
||||
response
|
||||
} else {
|
||||
let card_id = generate_id(consts::ID_LENGTH, "card");
|
||||
mock_add_card(db, &card_id, &card, None).await?
|
||||
mock_add_card(db, &card_id, &card, None, None).await?
|
||||
};
|
||||
|
||||
if let Some(false) = response.duplicate {
|
||||
@ -187,6 +187,7 @@ pub async fn mock_add_card(
|
||||
card_id: &str,
|
||||
card: &api::CardDetail,
|
||||
card_cvc: Option<String>,
|
||||
payment_method_id: Option<String>,
|
||||
) -> errors::CustomResult<payment_methods::AddCardResponse, errors::CardVaultError> {
|
||||
let locker_mock_up = storage::LockerMockUpNew {
|
||||
card_id: card_id.to_string(),
|
||||
@ -198,6 +199,7 @@ pub async fn mock_add_card(
|
||||
card_exp_year: card.card_exp_year.peek().to_string(),
|
||||
card_exp_month: card.card_exp_month.peek().to_string(),
|
||||
card_cvc,
|
||||
payment_method_id,
|
||||
};
|
||||
|
||||
let response = db
|
||||
@ -231,7 +233,9 @@ pub async fn mock_get_card<'a>(
|
||||
.await
|
||||
.change_context(errors::CardVaultError::FetchCardFailed)?;
|
||||
let add_card_response = payment_methods::AddCardResponse {
|
||||
card_id: locker_mock_up.card_id,
|
||||
card_id: locker_mock_up
|
||||
.payment_method_id
|
||||
.unwrap_or(locker_mock_up.card_id),
|
||||
external_id: locker_mock_up.external_id,
|
||||
card_fingerprint: locker_mock_up.card_fingerprint.into(),
|
||||
card_global_fingerprint: locker_mock_up.card_global_fingerprint.into(),
|
||||
@ -563,7 +567,7 @@ pub async fn get_lookup_key_from_locker(
|
||||
.attach_printable("Get Card Details Failed")?;
|
||||
let card = card_detail.clone();
|
||||
let resp =
|
||||
BasiliskCardSupport::create_payment_method_data_in_locker(state, payment_token, card)
|
||||
BasiliskCardSupport::create_payment_method_data_in_locker(state, payment_token, card, pm)
|
||||
.await?;
|
||||
Ok(resp)
|
||||
}
|
||||
@ -576,6 +580,7 @@ impl BasiliskCardSupport {
|
||||
state: &routes::AppState,
|
||||
payment_token: &str,
|
||||
card: api::CardDetailFromLocker,
|
||||
pm: &storage::PaymentMethod,
|
||||
) -> errors::RouterResult<api::CardDetailFromLocker> {
|
||||
let card_number = card
|
||||
.card_number
|
||||
@ -604,7 +609,13 @@ impl BasiliskCardSupport {
|
||||
card_holder_name: Some(card_holder_name.into()),
|
||||
};
|
||||
let db = &*state.store;
|
||||
mock_add_card(db, payment_token, &card_detail, None)
|
||||
mock_add_card(
|
||||
db,
|
||||
payment_token,
|
||||
&card_detail,
|
||||
None,
|
||||
Some(pm.payment_method_id.to_string()),
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Add Card Failed")?;
|
||||
@ -619,6 +630,7 @@ impl BasiliskCardSupport {
|
||||
state: &routes::AppState,
|
||||
payment_token: &str,
|
||||
card: api::CardDetailFromLocker,
|
||||
pm: &storage::PaymentMethod,
|
||||
) -> errors::RouterResult<api::CardDetailFromLocker> {
|
||||
let card_number = card
|
||||
.card_number
|
||||
@ -656,7 +668,13 @@ impl BasiliskCardSupport {
|
||||
)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error getting Value1 for locker")?;
|
||||
let value2 = payment_methods::mk_card_value2(None, Some(card_fingerprint), None, None)
|
||||
let value2 = payment_methods::mk_card_value2(
|
||||
None,
|
||||
Some(card_fingerprint),
|
||||
None,
|
||||
Some(pm.customer_id.to_string()),
|
||||
Some(pm.payment_method_id.to_string()),
|
||||
)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error getting Value2 for locker")?;
|
||||
create_tokenize(state, value1, Some(value2), payment_token.to_string()).await?;
|
||||
@ -738,11 +756,23 @@ pub async fn delete_payment_method(
|
||||
merchant_account: storage::MerchantAccount,
|
||||
pm: api::PaymentMethodId,
|
||||
) -> errors::RouterResponse<api::DeletePaymentMethodResponse> {
|
||||
let (_, value2) =
|
||||
helpers::Vault::get_payment_method_data_from_locker(state, &pm.payment_method_id).await?;
|
||||
let payment_method_id = value2.map_or(
|
||||
Err(errors::ApiErrorResponse::PaymentMethodNotFound),
|
||||
|pm_value2| {
|
||||
pm_value2
|
||||
.payment_method_id
|
||||
.map_or(Err(errors::ApiErrorResponse::PaymentMethodNotFound), |x| {
|
||||
Ok(x)
|
||||
})
|
||||
},
|
||||
)?;
|
||||
let pm = state
|
||||
.store
|
||||
.delete_payment_method_by_merchant_id_payment_method_id(
|
||||
&merchant_account.merchant_id,
|
||||
&pm.payment_method_id,
|
||||
&payment_method_id,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| {
|
||||
@ -750,7 +780,7 @@ pub async fn delete_payment_method(
|
||||
})?;
|
||||
|
||||
if pm.payment_method == enums::PaymentMethodType::Card {
|
||||
let response = delete_card(state, &pm.merchant_id, &pm.payment_method_id).await?;
|
||||
let response = delete_card(state, &pm.merchant_id, &payment_method_id).await?;
|
||||
if response.status == "success" {
|
||||
print!("Card From locker deleted Successfully")
|
||||
} else {
|
||||
|
||||
@ -235,12 +235,14 @@ pub fn mk_card_value2(
|
||||
card_fingerprint: Option<String>,
|
||||
external_id: Option<String>,
|
||||
customer_id: Option<String>,
|
||||
payment_method_id: Option<String>,
|
||||
) -> CustomResult<String, errors::CardVaultError> {
|
||||
let value2 = api::TokenizedCardValue2 {
|
||||
card_security_code,
|
||||
card_fingerprint,
|
||||
external_id,
|
||||
customer_id,
|
||||
payment_method_id,
|
||||
};
|
||||
let value2_req = utils::Encode::<api::TokenizedCardValue2>::encode_to_string_of_json(&value2)
|
||||
.change_context(errors::CardVaultError::FetchCardFailed)?;
|
||||
|
||||
@ -727,7 +727,7 @@ pub async fn make_pm_data<'a, F: Clone, R>(
|
||||
(_, Some(token)) => Ok::<_, error_stack::Report<errors::ApiErrorResponse>>(
|
||||
if payment_method_type == Some(storage_enums::PaymentMethodType::Card) {
|
||||
// TODO: Handle token expiry
|
||||
let pm = Vault::get_payment_method_data_from_locker(state, token).await?;
|
||||
let (pm, _) = Vault::get_payment_method_data_from_locker(state, token).await?;
|
||||
let updated_pm = match (pm.clone(), card_cvc) {
|
||||
(Some(api::PaymentMethod::Card(card)), Some(card_cvc)) => {
|
||||
let mut updated_card = card;
|
||||
@ -764,7 +764,7 @@ impl Vault {
|
||||
pub async fn get_payment_method_data_from_locker(
|
||||
state: &AppState,
|
||||
lookup_key: &str,
|
||||
) -> RouterResult<Option<api::PaymentMethod>> {
|
||||
) -> RouterResult<(Option<api::PaymentMethod>, Option<api::TokenizedCardValue2>)> {
|
||||
let (resp, card_cvc) = cards::mock_get_card(&*state.store, lookup_key)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
@ -782,14 +782,21 @@ impl Vault {
|
||||
.expose_option()
|
||||
.get_required_value("expiry_year")?;
|
||||
let card_holder_name = card.name_on_card.expose_option().unwrap_or_default();
|
||||
let card = api::PaymentMethod::Card(api::CCard {
|
||||
let pm = api::PaymentMethod::Card(api::CCard {
|
||||
card_number: card_number.into(),
|
||||
card_exp_month: card_exp_month.into(),
|
||||
card_exp_year: card_exp_year.into(),
|
||||
card_holder_name: card_holder_name.into(),
|
||||
card_cvc: card_cvc.unwrap_or_default().into(),
|
||||
});
|
||||
Ok(Some(card))
|
||||
let value2 = api::TokenizedCardValue2 {
|
||||
card_security_code: None,
|
||||
card_fingerprint: None,
|
||||
external_id: None,
|
||||
customer_id: None,
|
||||
payment_method_id: Some(card.card_id),
|
||||
};
|
||||
Ok((Some(pm), Some(value2)))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@ -805,7 +812,13 @@ impl Vault {
|
||||
card_holder_name: Some(card.card_holder_name.clone()),
|
||||
};
|
||||
let db = &*state.store;
|
||||
cards::mock_add_card(db, txn_id, &card_detail, Some(card.card_cvc.peek().clone()))
|
||||
cards::mock_add_card(
|
||||
db,
|
||||
txn_id,
|
||||
&card_detail,
|
||||
Some(card.card_cvc.peek().clone()),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Add Card Failed")?;
|
||||
@ -836,32 +849,27 @@ impl Vault {
|
||||
pub async fn get_payment_method_data_from_locker(
|
||||
state: &AppState,
|
||||
lookup_key: &str,
|
||||
) -> RouterResult<Option<api::PaymentMethod>> {
|
||||
) -> RouterResult<(Option<api::PaymentMethod>, Option<api::TokenizedCardValue2>)> {
|
||||
let de_tokenize = cards::get_tokenized_data(state, lookup_key, true).await?;
|
||||
let value1: api::TokenizedCardValue1 = de_tokenize
|
||||
.value1
|
||||
.parse_struct("TokenizedCardValue1")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error parsing TokenizedCardValue1")?;
|
||||
let value2 = de_tokenize.value2;
|
||||
let card_cvc = if value2.is_empty() {
|
||||
//mandatory field in api contract (when querying from legacy locker we don't get cvv), cvv handling needs to done
|
||||
"".to_string()
|
||||
} else {
|
||||
let tk_value2: api::TokenizedCardValue2 = value2
|
||||
let value2: api::TokenizedCardValue2 = de_tokenize
|
||||
.value2
|
||||
.parse_struct("TokenizedCardValue2")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error parsing TokenizedCardValue2")?;
|
||||
tk_value2.card_security_code.unwrap_or_default()
|
||||
};
|
||||
|
||||
let card = api::PaymentMethod::Card(api::CCard {
|
||||
card_number: value1.card_number.into(),
|
||||
card_exp_month: value1.exp_month.into(),
|
||||
card_exp_year: value1.exp_year.into(),
|
||||
card_holder_name: value1.name_on_card.unwrap_or_default().into(),
|
||||
card_cvc: card_cvc.into(),
|
||||
card_cvc: value2.card_security_code.clone().unwrap_or_default().into(),
|
||||
});
|
||||
Ok(Some(card))
|
||||
Ok((Some(card), Some(value2)))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@ -881,8 +889,13 @@ impl Vault {
|
||||
)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error getting Value1 for locker")?;
|
||||
let value2 =
|
||||
transformers::mk_card_value2(Some(card.card_cvc.peek().clone()), None, None, None)
|
||||
let value2 = transformers::mk_card_value2(
|
||||
Some(card.card_cvc.peek().clone()),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error getting Value12 for locker")?;
|
||||
cards::create_tokenize(state, value1, Some(value2), txn_id.to_string()).await
|
||||
|
||||
@ -52,9 +52,12 @@ pub async fn construct_refund_router_data<'a, F>(
|
||||
let payment_method_data = match payment_method_data.cloned() {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
helpers::Vault::get_payment_method_data_from_locker(state, &payment_attempt.attempt_id)
|
||||
.await?
|
||||
.get_required_value("payment_method_data")?
|
||||
let (pm, _) = helpers::Vault::get_payment_method_data_from_locker(
|
||||
state,
|
||||
&payment_attempt.attempt_id,
|
||||
)
|
||||
.await?;
|
||||
pm.get_required_value("payment_method_data")?
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ pub struct LockerMockUp {
|
||||
pub customer_id: Option<String>,
|
||||
pub duplicate: Option<bool>,
|
||||
pub card_cvc: Option<String>,
|
||||
pub payment_method_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Insertable, router_derive::DebugAsDisplay)]
|
||||
@ -33,4 +34,5 @@ pub struct LockerMockUpNew {
|
||||
pub card_exp_year: String,
|
||||
pub card_exp_month: String,
|
||||
pub card_cvc: Option<String>,
|
||||
pub payment_method_id: Option<String>,
|
||||
}
|
||||
|
||||
@ -108,6 +108,7 @@ diesel::table! {
|
||||
customer_id -> Nullable<Varchar>,
|
||||
duplicate -> Nullable<Bool>,
|
||||
card_cvc -> Nullable<Varchar>,
|
||||
payment_method_id -> Nullable<Varchar>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
ALTER TABLE locker_mock_up
|
||||
DROP COLUMN payment_method_id;
|
||||
@ -0,0 +1,3 @@
|
||||
-- Your SQL goes here
|
||||
ALTER TABLE locker_mock_up
|
||||
ADD COLUMN payment_method_id VARCHAR(64);
|
||||
Reference in New Issue
Block a user