feat(router): add more payment methods to vault (#333)

This commit is contained in:
ItsMeShashank
2023-01-14 20:48:45 +05:30
committed by GitHub
parent d64e5f2df3
commit 4e00b92dc1
12 changed files with 654 additions and 400 deletions

View File

@ -3,7 +3,7 @@ use std::borrow::Cow;
use common_utils::ext_traits::AsyncExt;
// TODO : Evaluate all the helper functions ()
use error_stack::{report, IntoReport, ResultExt};
use masking::{ExposeOptionInterface, PeekInterface};
use masking::ExposeOptionInterface;
use router_env::{instrument, tracing};
use uuid::Uuid;
@ -16,10 +16,9 @@ use crate::{
consts,
core::{
errors::{self, CustomResult, RouterResult, StorageErrorExt},
payment_methods::cards,
payment_methods::{cards, vault},
},
db::StorageInterface,
logger,
routes::AppState,
scheduler::{metrics, workflows::payment_sync},
services,
@ -709,7 +708,6 @@ pub async fn make_pm_data<'a, F: Clone, R>(
payment_data: &mut PaymentData<F>,
) -> RouterResult<(BoxedOperation<'a, F, R>, Option<api::PaymentMethod>)> {
let payment_method_type = payment_data.payment_attempt.payment_method;
let attempt_id = &payment_data.payment_attempt.attempt_id;
let request = &payment_data.payment_method_data;
let token = payment_data.token.clone();
let card_cvc = payment_data.card_cvc.clone();
@ -717,11 +715,11 @@ pub async fn make_pm_data<'a, F: Clone, R>(
let payment_method = match (request, token) {
(_, Some(token)) => Ok::<_, error_stack::Report<errors::ApiErrorResponse>>(
if payment_method_type == Some(storage_enums::PaymentMethodType::Card) {
// [#196]: Handle token expiry
let (pm, tokenize_value2) =
Vault::get_payment_method_data_from_locker(state, &token).await?;
// TODO: Handle token expiry
let (pm, supplementary_data) =
vault::Vault::get_payment_method_data_from_locker(state, &token).await?;
utils::when(
tokenize_value2
supplementary_data
.customer_id
.ne(&payment_data.payment_intent.customer_id),
|| {
@ -733,14 +731,15 @@ pub async fn make_pm_data<'a, F: Clone, R>(
(Some(api::PaymentMethod::Card(card)), Some(card_cvc)) => {
let mut updated_card = card;
updated_card.card_cvc = card_cvc;
Vault::store_payment_method_data_in_locker(
let updated_pm = api::PaymentMethod::Card(updated_card);
vault::Vault::store_payment_method_data_in_locker(
state,
&token,
&updated_card,
Some(token),
&updated_pm,
payment_data.payment_intent.customer_id.to_owned(),
)
.await?;
Some(api::PaymentMethod::Card(updated_card))
Some(updated_pm)
}
(_, _) => pm,
}
@ -754,194 +753,35 @@ pub async fn make_pm_data<'a, F: Clone, R>(
None
},
),
(pm @ Some(api::PaymentMethod::Card(card)), _) => {
Vault::store_payment_method_data_in_locker(
(pm_opt @ Some(pm @ api::PaymentMethod::Card(_)), _) => {
let token = vault::Vault::store_payment_method_data_in_locker(
state,
attempt_id,
card,
None,
pm,
payment_data.payment_intent.customer_id.to_owned(),
)
.await?;
payment_data.token = Some(attempt_id.to_string());
Ok(pm.to_owned())
payment_data.token = Some(token);
Ok(pm_opt.to_owned())
}
(pm @ Some(api::PaymentMethod::PayLater(_)), _) => Ok(pm.to_owned()),
(pm @ Some(api::PaymentMethod::Wallet(_)), _) => Ok(pm.to_owned()),
(pm_opt @ Some(pm @ api::PaymentMethod::Wallet(_)), _) => {
let token = vault::Vault::store_payment_method_data_in_locker(
state,
None,
pm,
payment_data.payment_intent.customer_id.to_owned(),
)
.await?;
payment_data.token = Some(token);
Ok(pm_opt.to_owned())
}
_ => Ok(None),
}?;
Ok((operation, payment_method))
}
pub struct Vault {}
#[cfg(not(feature = "basilisk"))]
impl Vault {
#[instrument(skip_all)]
pub async fn get_payment_method_data_from_locker(
state: &AppState,
lookup_key: &str,
) -> RouterResult<(Option<api::PaymentMethod>, api::TokenizedCardValue2)> {
let (resp, card_cvc) = cards::mock_get_card(&*state.store, lookup_key)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let card = resp.card;
let card_number = card
.card_number
.expose_option()
.get_required_value("card_number")?;
let card_exp_month = card
.card_exp_month
.expose_option()
.get_required_value("expiry_month")?;
let card_exp_year = card
.card_exp_year
.expose_option()
.get_required_value("expiry_year")?;
let card_holder_name = card.name_on_card.expose_option().unwrap_or_default();
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(),
});
let value2 = api::TokenizedCardValue2 {
card_security_code: None,
card_fingerprint: None,
external_id: None,
customer_id: card.customer_id,
payment_method_id: Some(card.card_id),
};
Ok((Some(pm), value2))
}
#[instrument(skip_all)]
async fn store_payment_method_data_in_locker(
state: &AppState,
txn_id: &str,
card: &api::CCard,
customer_id: Option<String>,
) -> RouterResult<String> {
let card_detail = api::CardDetail {
card_number: card.card_number.clone(),
card_exp_month: card.card_exp_month.clone(),
card_exp_year: card.card_exp_year.clone(),
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()),
None,
customer_id.as_deref(),
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Add Card Failed")?;
Ok(txn_id.to_string())
}
#[instrument(skip_all)]
pub async fn delete_locker_payment_method_by_lookup_key(
state: &AppState,
lookup_key: &Option<String>,
) {
let db = &*state.store;
if let Some(id) = lookup_key {
match cards::mock_delete_card(db, id).await {
Ok(_) => logger::info!("Card Deleted from locker mock up"),
Err(err) => logger::error!("Err: Card Delete from locker Failed : {}", err),
}
}
}
}
#[cfg(feature = "basilisk")]
use crate::{core::payment_methods::transformers, utils::StringExt};
#[cfg(feature = "basilisk")]
impl Vault {
#[instrument(skip_all)]
pub async fn get_payment_method_data_from_locker(
state: &AppState,
lookup_key: &str,
) -> RouterResult<(Option<api::PaymentMethod>, 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: api::TokenizedCardValue2 = de_tokenize
.value2
.parse_struct("TokenizedCardValue2")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error parsing TokenizedCardValue2")?;
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: value2.card_security_code.clone().unwrap_or_default().into(),
});
Ok((Some(card), value2))
}
#[instrument(skip_all)]
async fn store_payment_method_data_in_locker(
state: &AppState,
txn_id: &str,
card: &api::CCard,
customer_id: Option<String>,
) -> RouterResult<String> {
let value1 = transformers::mk_card_value1(
card.card_number.peek().clone(),
card.card_exp_year.peek().clone(),
card.card_exp_month.peek().clone(),
Some(card.card_holder_name.peek().clone()),
None,
None,
None,
)
.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,
customer_id,
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
}
#[instrument(skip_all)]
pub async fn delete_locker_payment_method_by_lookup_key(
state: &AppState,
lookup_key: &Option<String>,
) {
if let Some(lookup_key) = lookup_key {
let delete_resp = cards::delete_tokenized_data(state, lookup_key).await;
match delete_resp {
Ok(resp) => {
if resp == "Ok" {
logger::info!("Card From locker deleted Successfully")
} else {
logger::error!("Error: Deleting Card From Locker : {}", resp)
}
}
Err(err) => logger::error!("Err: Deleting Card From Locker : {}", err),
}
}
}
}
#[instrument(skip_all)]
pub(crate) fn validate_capture_method(
capture_method: storage_enums::CaptureMethod,