feat(payment_methods_v2): Update and Retrieve payment method APIs for v2 (#5939)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Sarthak Soni
2024-09-26 18:45:18 +05:30
committed by GitHub
parent 8c128624f6
commit f096992218
10 changed files with 432 additions and 67 deletions

View File

@ -374,7 +374,7 @@ pub struct PaymentMethodUpdate {
#[serde(deny_unknown_fields)]
pub struct PaymentMethodUpdate {
/// payment method data to be passed
pub payment_method_data: Option<PaymentMethodUpdateData>,
pub payment_method_data: PaymentMethodUpdateData,
/// This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK
#[schema(max_length = 30, min_length = 30, example = "secret_k2uj3he2893eiu2d")]
@ -990,6 +990,27 @@ impl From<CardDetailsPaymentMethod> for CardDetailFromLocker {
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl From<CardDetail> for CardDetailFromLocker {
fn from(item: CardDetail) -> Self {
Self {
issuer_country: item.card_issuing_country,
last4_digits: Some(item.card_number.get_last4()),
card_number: Some(item.card_number),
expiry_month: Some(item.card_exp_month),
expiry_year: Some(item.card_exp_year),
card_holder_name: item.card_holder_name,
nick_name: item.nick_name,
card_isin: None,
card_issuer: item.card_issuer,
card_network: item.card_network,
card_type: item.card_type.map(|card| card.to_string()),
saved_to_locker: true,
card_fingerprint: None,
}
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl From<CardDetail> for CardDetailsPaymentMethod {
fn from(item: CardDetail) -> Self {

View File

@ -144,6 +144,10 @@ pub const ADD_VAULT_REQUEST_URL: &str = "/vault/add";
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
pub const VAULT_FINGERPRINT_REQUEST_URL: &str = "/fingerprint";
/// Vault Retrieve request url
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
pub const VAULT_RETRIEVE_REQUEST_URL: &str = "/vault/retrieve";
/// Vault Header content type
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
pub const VAULT_HEADER_CONTENT_TYPE: &str = "application/json";

View File

@ -25,7 +25,7 @@ use common_utils::{consts::DEFAULT_LOCALE, id_type};
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use common_utils::{
crypto::{self, Encryptable},
ext_traits::{AsyncExt, Encode, ValueExt},
ext_traits::{AsyncExt, Encode, StringExt, ValueExt},
fp_utils::when,
generate_id,
request::RequestContent,
@ -80,7 +80,7 @@ const PAYMENT_METHOD_STATUS_UPDATE_TASK: &str = "PAYMENT_METHOD_STATUS_UPDATE";
const PAYMENT_METHOD_STATUS_TAG: &str = "PAYMENT_METHOD_STATUS";
#[instrument(skip_all)]
pub async fn retrieve_payment_method(
pub async fn retrieve_payment_method_core(
pm_data: &Option<domain::PaymentMethodData>,
state: &SessionState,
payment_intent: &PaymentIntent,
@ -877,16 +877,24 @@ pub async fn create_payment_method(
.await
.attach_printable("Failed to add Payment method to DB")?;
let vaulting_result =
vault_payment_method(state, &req.payment_method_data, merchant_account, key_store).await;
let payment_method_data = pm_types::PaymentMethodVaultingData::from(req.payment_method_data);
let vaulting_result = vault_payment_method(
state,
&payment_method_data,
merchant_account,
key_store,
None,
)
.await;
let response = match vaulting_result {
Ok(resp) => {
let pm_update = create_pm_additional_data_update(
&req.payment_method_data,
&payment_method_data,
state,
key_store,
Some(resp.vault_id),
Some(resp.vault_id.get_string_repr().clone()),
Some(req.payment_method),
Some(req.payment_method_type),
)
@ -1041,16 +1049,24 @@ pub async fn payment_method_intent_confirm(
.await
.to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
let vaulting_result =
vault_payment_method(state, &req.payment_method_data, merchant_account, key_store).await;
let payment_method_data = pm_types::PaymentMethodVaultingData::from(req.payment_method_data);
let vaulting_result = vault_payment_method(
state,
&payment_method_data,
merchant_account,
key_store,
None,
)
.await;
let response = match vaulting_result {
Ok(resp) => {
let pm_update = create_pm_additional_data_update(
&req.payment_method_data,
&payment_method_data,
state,
key_store,
Some(resp.vault_id),
Some(resp.vault_id.get_string_repr().clone()),
Some(req.payment_method),
Some(req.payment_method_type),
)
@ -1220,15 +1236,17 @@ pub async fn create_payment_method_for_intent(
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
pub async fn create_pm_additional_data_update(
pmd: &api::PaymentMethodCreateData,
pmd: &pm_types::PaymentMethodVaultingData,
state: &SessionState,
key_store: &domain::MerchantKeyStore,
vault_id: Option<String>,
payment_method: Option<api_enums::PaymentMethod>,
payment_method_type: Option<api_enums::PaymentMethodType>,
) -> RouterResult<storage::PaymentMethodUpdate> {
let card = match pmd.clone() {
api::PaymentMethodCreateData::Card(card) => api::PaymentMethodsData::Card(card.into()),
let card = match pmd {
pm_types::PaymentMethodVaultingData::Card(card) => {
api::PaymentMethodsData::Card(card.clone().into())
}
};
let pmd: Encryptable<Secret<serde_json::Value>> =
@ -1255,15 +1273,17 @@ pub async fn create_pm_additional_data_update(
#[instrument(skip_all)]
pub async fn vault_payment_method(
state: &SessionState,
pmd: &api::PaymentMethodCreateData,
pmd: &pm_types::PaymentMethodVaultingData,
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
existing_vault_id: Option<String>,
) -> RouterResult<pm_types::AddVaultResponse> {
let db = &*state.store;
// get fingerprint_id from locker
let fingerprint_id_from_locker = cards::get_fingerprint_id_from_locker(state, pmd)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to get fingerprint_id from vault")?;
// throw back error if payment method is duplicated
@ -1286,7 +1306,10 @@ pub async fn vault_payment_method(
)?;
let resp_from_locker =
cards::vault_payment_method_in_locker(state, merchant_account, pmd).await?;
cards::vault_payment_method_in_locker(state, merchant_account, pmd, existing_vault_id)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to vault payment method in locker")?;
Ok(resp_from_locker)
}
@ -1656,6 +1679,152 @@ async fn generate_saved_pm_response(
Ok(pma)
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[instrument(skip_all)]
pub async fn retrieve_payment_method(
state: SessionState,
pm: api::PaymentMethodId,
key_store: domain::MerchantKeyStore,
merchant_account: domain::MerchantAccount,
) -> RouterResponse<api::PaymentMethodResponse> {
let db = state.store.as_ref();
let pm_id = id_type::GlobalPaymentMethodId::generate_from_string(pm.payment_method_id)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to generate GlobalPaymentMethodId")?;
let payment_method = db
.find_payment_method(
&((&state).into()),
&key_store,
&pm_id,
merchant_account.storage_scheme,
)
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
let pmd = payment_method
.payment_method_data
.clone()
.map(|x| x.into_inner().expose())
.and_then(|v| serde_json::from_value::<api::PaymentMethodsData>(v).ok())
.and_then(|pmd| match pmd {
api::PaymentMethodsData::Card(card) => {
Some(api::PaymentMethodResponseData::Card(card.into()))
}
_ => None,
});
let resp = api::PaymentMethodResponse {
merchant_id: payment_method.merchant_id.to_owned(),
customer_id: payment_method.customer_id.to_owned(),
payment_method_id: payment_method.id.get_string_repr().to_string(),
payment_method: payment_method.payment_method,
payment_method_type: payment_method.payment_method_type,
metadata: payment_method.metadata.clone(),
created: Some(payment_method.created_at),
recurring_enabled: false,
last_used_at: Some(payment_method.last_used_at),
client_secret: payment_method.client_secret.clone(),
payment_method_data: pmd,
};
Ok(services::ApplicationResponse::Json(resp))
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[instrument(skip_all)]
pub async fn update_payment_method(
state: SessionState,
merchant_account: domain::MerchantAccount,
req: api::PaymentMethodUpdate,
payment_method_id: &str,
key_store: domain::MerchantKeyStore,
) -> RouterResponse<api::PaymentMethodResponse> {
let db = state.store.as_ref();
let pm_id = id_type::GlobalPaymentMethodId::generate_from_string(payment_method_id.to_string())
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to generate GlobalPaymentMethodId")?;
let payment_method = db
.find_payment_method(
&((&state).into()),
&key_store,
&pm_id,
merchant_account.storage_scheme,
)
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
let current_vault_id = payment_method.locker_id.clone();
when(
payment_method.status == enums::PaymentMethodStatus::AwaitingData,
|| {
Err(errors::ApiErrorResponse::InvalidRequestData {
message: "This Payment method is awaiting data and hence cannot be updated"
.to_string(),
})
},
)?;
let pmd: pm_types::PaymentMethodVaultingData = cards::retrieve_payment_method_from_vault(
&state,
&merchant_account,
&payment_method.customer_id,
&payment_method,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to retrieve payment method from vault")?
.data
.expose()
.parse_struct("PaymentMethodCreateData")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to parse PaymentMethodCreateData")?;
let vault_request_data =
pm_transforms::generate_pm_vaulting_req_from_update_request(pmd, req.payment_method_data);
let vaulting_response = vault_payment_method(
&state,
&vault_request_data,
&merchant_account,
&key_store,
current_vault_id, // using current vault_id for now, will have to refactor this
) // to generate new one on each vaulting later on
.await
.attach_printable("Failed to add payment method in vault")?;
let pm_update = create_pm_additional_data_update(
&vault_request_data,
&state,
&key_store,
Some(vaulting_response.vault_id.get_string_repr().clone()),
payment_method.payment_method,
payment_method.payment_method_type,
)
.await
.attach_printable("Unable to create Payment method data")?;
let payment_method = db
.update_payment_method(
&((&state).into()),
&key_store,
payment_method,
pm_update,
merchant_account.storage_scheme,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to update payment method in db")?;
let response = pm_transforms::generate_payment_method_response(&payment_method)?;
// Add a PT task to handle payment_method delete from vault
Ok(services::ApplicationResponse::Json(response))
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl pm_types::SavedPMLPaymentsInfo {
pub async fn form_payments_info(

View File

@ -1418,26 +1418,26 @@ pub async fn get_fingerprint_id_from_locker<
>(
state: &routes::SessionState,
data: &D,
) -> errors::RouterResult<String> {
) -> errors::CustomResult<String, errors::VaultError> {
let key = data.get_vaulting_data_key();
let data = serde_json::to_value(data)
.change_context(errors::ApiErrorResponse::InternalServerError)
.change_context(errors::VaultError::RequestEncodingFailed)
.attach_printable("Failed to encode Vaulting data to value")?
.to_string();
let payload = pm_types::VaultFingerprintRequest { key, data }
.encode_to_vec()
.change_context(errors::ApiErrorResponse::InternalServerError)
.change_context(errors::VaultError::RequestEncodingFailed)
.attach_printable("Failed to encode VaultFingerprintRequest")?;
let resp = call_to_vault::<pm_types::GetVaultFingerprint>(state, payload)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.change_context(errors::VaultError::VaultAPIError)
.attach_printable("Failed to get response from locker")?;
let fingerprint_resp: pm_types::VaultFingerprintResponse = resp
.parse_struct("VaultFingerprintResp")
.change_context(errors::ApiErrorResponse::InternalServerError)
.change_context(errors::VaultError::ResponseDeserializationFailed)
.attach_printable("Failed to parse data into VaultFingerprintResp")?;
Ok(fingerprint_resp.fingerprint_id)
@ -1448,31 +1448,70 @@ pub async fn get_fingerprint_id_from_locker<
pub async fn vault_payment_method_in_locker(
state: &routes::SessionState,
merchant_account: &domain::MerchantAccount,
pmd: &api::PaymentMethodCreateData,
) -> errors::RouterResult<pm_types::AddVaultResponse> {
pmd: &pm_types::PaymentMethodVaultingData,
existing_vault_id: Option<String>,
) -> errors::CustomResult<pm_types::AddVaultResponse, errors::VaultError> {
let payload = pm_types::AddVaultRequest {
entity_id: merchant_account.get_id().to_owned(),
vault_id: uuid::Uuid::now_v7().to_string(),
data: pmd.clone(),
vault_id: pm_types::VaultId::generate(
existing_vault_id.unwrap_or(uuid::Uuid::now_v7().to_string()),
),
data: pmd,
ttl: state.conf.locker.ttl_for_storage_in_secs,
}
.encode_to_vec()
.change_context(errors::ApiErrorResponse::InternalServerError)
.change_context(errors::VaultError::RequestEncodingFailed)
.attach_printable("Failed to encode AddVaultRequest")?;
let resp = call_to_vault::<pm_types::AddVault>(state, payload)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.change_context(errors::VaultError::VaultAPIError)
.attach_printable("Failed to get response from locker")?;
let stored_pm_resp: pm_types::AddVaultResponse = resp
.parse_struct("AddVaultResponse")
.change_context(errors::ApiErrorResponse::InternalServerError)
.change_context(errors::VaultError::ResponseDeserializationFailed)
.attach_printable("Failed to parse data into AddVaultResponse")?;
Ok(stored_pm_resp)
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[instrument(skip_all)]
pub async fn retrieve_payment_method_from_vault(
state: &routes::SessionState,
merchant_account: &domain::MerchantAccount,
customer_id: &id_type::CustomerId,
pm: &domain::PaymentMethod,
) -> errors::CustomResult<pm_types::VaultRetrieveResponse, errors::VaultError> {
let payload = pm_types::VaultRetrieveRequest {
entity_id: merchant_account.get_id().to_owned(),
vault_id: pm_types::VaultId::generate(
pm.locker_id
.clone()
.ok_or(errors::VaultError::MissingRequiredField {
field_name: "locker_id",
})
.attach_printable("Missing locker_id for VaultRetrieveRequest")?,
),
}
.encode_to_vec()
.change_context(errors::VaultError::RequestEncodingFailed)
.attach_printable("Failed to encode VaultRetrieveRequest")?;
let resp = call_to_vault::<pm_types::VaultRetrieve>(state, payload)
.await
.change_context(errors::VaultError::VaultAPIError)
.attach_printable("Failed to get response from locker")?;
let stored_pm_resp: pm_types::VaultRetrieveResponse = resp
.parse_struct("VaultRetrieveResponse")
.change_context(errors::VaultError::ResponseDeserializationFailed)
.attach_printable("Failed to parse data into VaultRetrieveResponse")?;
Ok(stored_pm_resp)
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
@ -1783,18 +1822,6 @@ pub async fn update_customer_payment_method(
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[instrument(skip_all)]
pub async fn update_customer_payment_method(
_state: routes::SessionState,
_merchant_account: domain::MerchantAccount,
_req: api::PaymentMethodUpdate,
_payment_method_id: &str,
_key_store: domain::MerchantKeyStore,
) -> errors::RouterResponse<api::PaymentMethodResponse> {
todo!()
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
@ -5378,17 +5405,6 @@ pub async fn retrieve_payment_method(
))
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[instrument(skip_all)]
pub async fn retrieve_payment_method(
state: routes::SessionState,
pm: api::PaymentMethodId,
key_store: domain::MerchantKeyStore,
merchant_account: domain::MerchantAccount,
) -> errors::RouterResponse<api::PaymentMethodResponse> {
todo!()
}
#[cfg(all(
any(feature = "v2", feature = "v1"),
not(feature = "payment_methods_v2")

View File

@ -15,6 +15,8 @@ use josekit::jwe;
use router_env::tracing_actix_web::RequestId;
use serde::{Deserialize, Serialize};
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use crate::types::payment_methods as pm_types;
use crate::{
configs::settings,
core::errors::{self, CustomResult},
@ -520,6 +522,29 @@ pub fn mk_add_card_response_hs(
todo!()
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
pub fn generate_pm_vaulting_req_from_update_request(
pm_create: pm_types::PaymentMethodVaultingData,
pm_update: api::PaymentMethodUpdateData,
) -> pm_types::PaymentMethodVaultingData {
match (pm_create, pm_update) {
(
pm_types::PaymentMethodVaultingData::Card(card_create),
api::PaymentMethodUpdateData::Card(update_card),
) => pm_types::PaymentMethodVaultingData::Card(api::CardDetail {
card_number: card_create.card_number,
card_exp_month: card_create.card_exp_month,
card_exp_year: card_create.card_exp_year,
card_issuing_country: card_create.card_issuing_country,
card_network: card_create.card_network,
card_issuer: card_create.card_issuer,
card_type: card_create.card_type,
card_holder_name: update_card.card_holder_name,
nick_name: update_card.nick_name,
}),
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
pub fn generate_payment_method_response(
pm: &domain::PaymentMethod,
@ -798,6 +823,15 @@ pub fn get_card_detail(
Ok(card_detail)
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl From<api::PaymentMethodCreateData> for pm_types::PaymentMethodVaultingData {
fn from(item: api::PaymentMethodCreateData) -> Self {
match item {
api::PaymentMethodCreateData::Card(card) => Self::Card(card),
}
}
}
//------------------------------------------------TokenizeService------------------------------------------------
pub fn mk_crud_locker_request(
locker: &settings::Locker,

View File

@ -2226,7 +2226,8 @@ pub async fn make_pm_data<'a, F: Clone, R, D>(
}
(Some(_), _) => {
let (payment_method_data, payment_token) = payment_methods::retrieve_payment_method(
let (payment_method_data, payment_token) =
payment_methods::retrieve_payment_method_core(
&request,
state,
&payment_data.payment_intent,

View File

@ -1087,7 +1087,12 @@ impl PaymentMethods {
.service(
web::resource("/{id}/confirm-intent")
.route(web::post().to(confirm_payment_method_intent_api)),
);
)
.service(
web::resource("/{id}/update_saved_payment_method")
.route(web::patch().to(payment_method_update_api)),
)
.service(web::resource("/{id}").route(web::get().to(payment_method_retrieve_api)));
route
}

View File

@ -15,7 +15,7 @@ use super::app::{AppState, SessionState};
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use crate::core::payment_methods::{
create_payment_method, list_customer_payment_method_util, payment_method_intent_confirm,
payment_method_intent_create,
payment_method_intent_create, retrieve_payment_method, update_payment_method,
};
use crate::{
core::{
@ -180,6 +180,65 @@ pub async fn confirm_payment_method_intent_api(
.await
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsUpdate))]
pub async fn payment_method_update_api(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<String>,
json_payload: web::Json<payment_methods::PaymentMethodUpdate>,
) -> HttpResponse {
let flow = Flow::PaymentMethodsUpdate;
let payment_method_id = path.into_inner();
let payload = json_payload.into_inner();
Box::pin(api::server_wrap(
flow,
state,
&req,
payload,
|state, auth, req, _| {
update_payment_method(
state,
auth.merchant_account,
req,
&payment_method_id,
auth.key_store,
)
},
&auth::HeaderAuth(auth::ApiKeyAuth),
api_locking::LockAction::NotApplicable,
))
.await
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsRetrieve))]
pub async fn payment_method_retrieve_api(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<String>,
) -> HttpResponse {
let flow = Flow::PaymentMethodsRetrieve;
let payload = web::Json(PaymentMethodId {
payment_method_id: path.into_inner(),
})
.into_inner();
Box::pin(api::server_wrap(
flow,
state,
&req,
payload,
|state, auth, pm, _| {
retrieve_payment_method(state, pm, auth.key_store, auth.merchant_account)
},
&auth::HeaderAuth(auth::ApiKeyAuth),
api_locking::LockAction::NotApplicable,
))
.await
}
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsMigrate))]
pub async fn migrate_payment_method_api(
state: web::Data<AppState>,
@ -667,6 +726,10 @@ pub async fn render_pm_collect_link(
.await
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsRetrieve))]
pub async fn payment_method_retrieve_api(
state: web::Data<AppState>,
@ -693,6 +756,10 @@ pub async fn payment_method_retrieve_api(
.await
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsUpdate))]
pub async fn payment_method_update_api(
state: web::Data<AppState>,

View File

@ -8,8 +8,8 @@ pub use api_models::payment_methods::{
PaymentMethodIntentConfirm, PaymentMethodIntentConfirmInternal, PaymentMethodIntentCreate,
PaymentMethodList, PaymentMethodListData, PaymentMethodListRequest, PaymentMethodListResponse,
PaymentMethodMigrate, PaymentMethodResponse, PaymentMethodResponseData, PaymentMethodUpdate,
PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1,
TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
PaymentMethodUpdateData, PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest,
TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
};
#[cfg(all(
any(feature = "v2", feature = "v1"),

View File

@ -1,5 +1,7 @@
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use common_utils::generate_id;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use masking::Secret;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use crate::{
@ -19,6 +21,21 @@ pub trait VaultingDataInterface {
fn get_vaulting_data_key(&self) -> String;
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct VaultId(String);
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
impl VaultId {
pub fn get_string_repr(&self) -> &String {
&self.0
}
pub fn generate(id: String) -> Self {
Self(id)
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct VaultFingerprintRequest {
@ -36,7 +53,7 @@ pub struct VaultFingerprintResponse {
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct AddVaultRequest<D> {
pub entity_id: common_utils::id_type::MerchantId,
pub vault_id: String,
pub vault_id: VaultId,
pub data: D,
pub ttl: i64,
}
@ -45,7 +62,7 @@ pub struct AddVaultRequest<D> {
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct AddVaultResponse {
pub entity_id: common_utils::id_type::MerchantId,
pub vault_id: String,
pub vault_id: VaultId,
pub fingerprint_id: Option<String>,
}
@ -57,6 +74,10 @@ pub struct AddVault;
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct GetVaultFingerprint;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct VaultRetrieve;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[async_trait::async_trait]
impl VaultingInterface for AddVault {
@ -75,7 +96,21 @@ impl VaultingInterface for GetVaultFingerprint {
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[async_trait::async_trait]
impl VaultingDataInterface for api::PaymentMethodCreateData {
impl VaultingInterface for VaultRetrieve {
fn get_vaulting_request_url() -> &'static str {
consts::VAULT_RETRIEVE_REQUEST_URL
}
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub enum PaymentMethodVaultingData {
Card(api::CardDetail),
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[async_trait::async_trait]
impl VaultingDataInterface for PaymentMethodVaultingData {
fn get_vaulting_data_key(&self) -> String {
match &self {
Self::Card(card) => card.card_number.to_string(),
@ -101,3 +136,16 @@ pub struct SavedPMLPaymentsInfo {
pub off_session_payment_flag: bool,
pub is_connector_agnostic_mit_enabled: bool,
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct VaultRetrieveRequest {
pub entity_id: common_utils::id_type::MerchantId,
pub vault_id: VaultId,
}
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct VaultRetrieveResponse {
pub data: Secret<String>,
}