mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
fix(connector): [Tokenex] fix tokenize flow response handling for tokenex (#9528)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -151,11 +151,13 @@ impl ConnectorCommon for Tokenex {
|
|||||||
event_builder.map(|i| i.set_response_body(&response));
|
event_builder.map(|i| i.set_response_body(&response));
|
||||||
router_env::logger::info!(connector_response=?response);
|
router_env::logger::info!(connector_response=?response);
|
||||||
|
|
||||||
|
let (code, message) = response.error.split_once(':').unwrap_or(("", ""));
|
||||||
|
|
||||||
Ok(ErrorResponse {
|
Ok(ErrorResponse {
|
||||||
status_code: res.status_code,
|
status_code: res.status_code,
|
||||||
code: response.code,
|
code: code.to_string(),
|
||||||
message: response.message,
|
message: message.to_string(),
|
||||||
reason: response.reason,
|
reason: Some(response.message),
|
||||||
attempt_status: None,
|
attempt_status: None,
|
||||||
connector_transaction_id: None,
|
connector_transaction_id: None,
|
||||||
network_advice_code: None,
|
network_advice_code: None,
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
use common_utils::{
|
use common_utils::types::StringMinorUnit;
|
||||||
ext_traits::{Encode, StringExt},
|
|
||||||
types::StringMinorUnit,
|
|
||||||
};
|
|
||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
use hyperswitch_domain_models::{
|
use hyperswitch_domain_models::{
|
||||||
router_data::{ConnectorAuthType, RouterData},
|
router_data::{ConnectorAuthType, ErrorResponse, RouterData},
|
||||||
router_flow_types::{ExternalVaultInsertFlow, ExternalVaultRetrieveFlow},
|
router_flow_types::{ExternalVaultInsertFlow, ExternalVaultRetrieveFlow},
|
||||||
router_request_types::VaultRequestData,
|
router_request_types::VaultRequestData,
|
||||||
router_response_types::VaultResponseData,
|
router_response_types::VaultResponseData,
|
||||||
@ -12,7 +9,7 @@ use hyperswitch_domain_models::{
|
|||||||
vault::PaymentMethodVaultingData,
|
vault::PaymentMethodVaultingData,
|
||||||
};
|
};
|
||||||
use hyperswitch_interfaces::errors;
|
use hyperswitch_interfaces::errors;
|
||||||
use masking::{ExposeInterface, Secret};
|
use masking::Secret;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::ResponseRouterData;
|
use crate::types::ResponseRouterData;
|
||||||
@ -24,7 +21,6 @@ pub struct TokenexRouterData<T> {
|
|||||||
|
|
||||||
impl<T> From<(StringMinorUnit, T)> for TokenexRouterData<T> {
|
impl<T> From<(StringMinorUnit, T)> for TokenexRouterData<T> {
|
||||||
fn from((amount, item): (StringMinorUnit, T)) -> Self {
|
fn from((amount, item): (StringMinorUnit, T)) -> Self {
|
||||||
//Todo : use utils to convert the amount to the type of amount that a connector accepts
|
|
||||||
Self {
|
Self {
|
||||||
amount,
|
amount,
|
||||||
router_data: item,
|
router_data: item,
|
||||||
@ -34,21 +30,16 @@ impl<T> From<(StringMinorUnit, T)> for TokenexRouterData<T> {
|
|||||||
|
|
||||||
#[derive(Default, Debug, Serialize, PartialEq)]
|
#[derive(Default, Debug, Serialize, PartialEq)]
|
||||||
pub struct TokenexInsertRequest {
|
pub struct TokenexInsertRequest {
|
||||||
data: Secret<String>,
|
data: cards::CardNumber, //Currently only card number is tokenized. Data can be stringified and can be tokenized
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> TryFrom<&VaultRouterData<F>> for TokenexInsertRequest {
|
impl<F> TryFrom<&VaultRouterData<F>> for TokenexInsertRequest {
|
||||||
type Error = error_stack::Report<errors::ConnectorError>;
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
fn try_from(item: &VaultRouterData<F>) -> Result<Self, Self::Error> {
|
fn try_from(item: &VaultRouterData<F>) -> Result<Self, Self::Error> {
|
||||||
match item.request.payment_method_vaulting_data.clone() {
|
match item.request.payment_method_vaulting_data.clone() {
|
||||||
Some(PaymentMethodVaultingData::Card(req_card)) => {
|
Some(PaymentMethodVaultingData::Card(req_card)) => Ok(Self {
|
||||||
let stringified_card = req_card
|
data: req_card.card_number.clone(),
|
||||||
.encode_to_string_of_json()
|
}),
|
||||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
|
||||||
Ok(Self {
|
|
||||||
data: Secret::new(stringified_card),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => Err(errors::ConnectorError::NotImplemented(
|
_ => Err(errors::ConnectorError::NotImplemented(
|
||||||
"Payment method apart from card".to_string(),
|
"Payment method apart from card".to_string(),
|
||||||
)
|
)
|
||||||
@ -56,9 +47,6 @@ impl<F> TryFrom<&VaultRouterData<F>> for TokenexInsertRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Fill the struct with respective fields
|
|
||||||
// Auth Struct
|
|
||||||
pub struct TokenexAuthType {
|
pub struct TokenexAuthType {
|
||||||
pub(super) api_key: Secret<String>,
|
pub(super) api_key: Secret<String>,
|
||||||
pub(super) tokenex_id: Secret<String>,
|
pub(super) tokenex_id: Secret<String>,
|
||||||
@ -78,10 +66,14 @@ impl TryFrom<&ConnectorAuthType> for TokenexAuthType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TokenexInsertResponse {
|
pub struct TokenexInsertResponse {
|
||||||
token: String,
|
token: Option<String>,
|
||||||
first_six: String,
|
first_six: Option<String>,
|
||||||
|
last_four: Option<String>,
|
||||||
success: bool,
|
success: bool,
|
||||||
|
error: String,
|
||||||
|
message: Option<String>,
|
||||||
}
|
}
|
||||||
impl
|
impl
|
||||||
TryFrom<
|
TryFrom<
|
||||||
@ -103,20 +95,49 @@ impl
|
|||||||
>,
|
>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
let resp = item.response;
|
let resp = item.response;
|
||||||
|
match resp.success && resp.error.is_empty() {
|
||||||
|
true => {
|
||||||
|
let token = resp
|
||||||
|
.token
|
||||||
|
.clone()
|
||||||
|
.ok_or(errors::ConnectorError::ResponseDeserializationFailed)
|
||||||
|
.attach_printable("Token is missing in tokenex response")?;
|
||||||
|
Ok(Self {
|
||||||
|
status: common_enums::AttemptStatus::Started,
|
||||||
|
response: Ok(VaultResponseData::ExternalVaultInsertResponse {
|
||||||
|
connector_vault_id: token.clone(),
|
||||||
|
//fingerprint is not provided by tokenex, using token as fingerprint
|
||||||
|
fingerprint_id: token.clone(),
|
||||||
|
}),
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
let (code, message) = resp.error.split_once(':').unwrap_or(("", ""));
|
||||||
|
|
||||||
Ok(Self {
|
let response = Err(ErrorResponse {
|
||||||
status: common_enums::AttemptStatus::Started,
|
code: code.to_string(),
|
||||||
response: Ok(VaultResponseData::ExternalVaultInsertResponse {
|
message: message.to_string(),
|
||||||
connector_vault_id: resp.token.clone(),
|
reason: resp.message,
|
||||||
//fingerprint is not provided by tokenex, using token as fingerprint
|
status_code: item.http_code,
|
||||||
fingerprint_id: resp.token.clone(),
|
attempt_status: None,
|
||||||
}),
|
connector_transaction_id: None,
|
||||||
..item.data
|
network_decline_code: None,
|
||||||
})
|
network_advice_code: None,
|
||||||
|
network_error_message: None,
|
||||||
|
connector_metadata: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
response,
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TokenexRetrieveRequest {
|
pub struct TokenexRetrieveRequest {
|
||||||
token: Secret<String>, //Currently only card number is tokenized. Data can be stringified and can be tokenized
|
token: Secret<String>, //Currently only card number is tokenized. Data can be stringified and can be tokenized
|
||||||
cache_cvv: bool,
|
cache_cvv: bool,
|
||||||
@ -124,8 +145,10 @@ pub struct TokenexRetrieveRequest {
|
|||||||
|
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TokenexRetrieveResponse {
|
pub struct TokenexRetrieveResponse {
|
||||||
value: Secret<String>,
|
value: Option<cards::CardNumber>,
|
||||||
success: bool,
|
success: bool,
|
||||||
|
error: String,
|
||||||
|
message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> TryFrom<&VaultRouterData<F>> for TokenexRetrieveRequest {
|
impl<F> TryFrom<&VaultRouterData<F>> for TokenexRetrieveRequest {
|
||||||
@ -164,30 +187,48 @@ impl
|
|||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
let resp = item.response;
|
let resp = item.response;
|
||||||
|
|
||||||
let card_detail: api_models::payment_methods::CardDetail = resp
|
match resp.success && resp.error.is_empty() {
|
||||||
.value
|
true => {
|
||||||
.clone()
|
let data = resp
|
||||||
.expose()
|
.value
|
||||||
.parse_struct("CardDetail")
|
.clone()
|
||||||
.change_context(errors::ConnectorError::ParsingFailed)?;
|
.ok_or(errors::ConnectorError::ResponseDeserializationFailed)
|
||||||
|
.attach_printable("Card number is missing in tokenex response")?;
|
||||||
|
Ok(Self {
|
||||||
|
status: common_enums::AttemptStatus::Started,
|
||||||
|
response: Ok(VaultResponseData::ExternalVaultRetrieveResponse {
|
||||||
|
vault_data: PaymentMethodVaultingData::CardNumber(data),
|
||||||
|
}),
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
let (code, message) = resp.error.split_once(':').unwrap_or(("", ""));
|
||||||
|
|
||||||
Ok(Self {
|
let response = Err(ErrorResponse {
|
||||||
status: common_enums::AttemptStatus::Started,
|
code: code.to_string(),
|
||||||
response: Ok(VaultResponseData::ExternalVaultRetrieveResponse {
|
message: message.to_string(),
|
||||||
vault_data: PaymentMethodVaultingData::Card(card_detail),
|
reason: resp.message,
|
||||||
}),
|
status_code: item.http_code,
|
||||||
..item.data
|
attempt_status: None,
|
||||||
})
|
connector_transaction_id: None,
|
||||||
|
network_decline_code: None,
|
||||||
|
network_advice_code: None,
|
||||||
|
network_error_message: None,
|
||||||
|
connector_metadata: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
response,
|
||||||
|
..item.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct TokenexErrorResponse {
|
pub struct TokenexErrorResponse {
|
||||||
pub status_code: u16,
|
pub error: String,
|
||||||
pub code: String,
|
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub reason: Option<String>,
|
|
||||||
pub network_advice_code: Option<String>,
|
|
||||||
pub network_decline_code: Option<String>,
|
|
||||||
pub network_error_message: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,10 +7,8 @@ use api_models::{
|
|||||||
payments::{additional_info as payment_additional_types, ExtendedCardInfo},
|
payments::{additional_info as payment_additional_types, ExtendedCardInfo},
|
||||||
};
|
};
|
||||||
use common_enums::enums as api_enums;
|
use common_enums::enums as api_enums;
|
||||||
#[cfg(feature = "v2")]
|
|
||||||
use common_utils::ext_traits::OptionExt;
|
|
||||||
use common_utils::{
|
use common_utils::{
|
||||||
ext_traits::StringExt,
|
ext_traits::{OptionExt, StringExt},
|
||||||
id_type,
|
id_type,
|
||||||
new_type::{
|
new_type::{
|
||||||
MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, MaskedUpiVpaId,
|
MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, MaskedUpiVpaId,
|
||||||
@ -18,7 +16,7 @@ use common_utils::{
|
|||||||
payout_method_utils,
|
payout_method_utils,
|
||||||
pii::{self, Email},
|
pii::{self, Email},
|
||||||
};
|
};
|
||||||
use masking::{PeekInterface, Secret};
|
use masking::{ExposeInterface, PeekInterface, Secret};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use time::Date;
|
use time::Date;
|
||||||
|
|
||||||
@ -2327,6 +2325,13 @@ impl PaymentMethodsData {
|
|||||||
Self::BankDetails(_) | Self::WalletDetails(_) | Self::NetworkToken(_) => None,
|
Self::BankDetails(_) | Self::WalletDetails(_) | Self::NetworkToken(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn get_card_details(&self) -> Option<CardDetailsPaymentMethod> {
|
||||||
|
if let Self::Card(card) = self {
|
||||||
|
Some(card.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||||
@ -2593,8 +2598,6 @@ impl
|
|||||||
|
|
||||||
// The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
|
// The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
|
||||||
let name_on_card = if let Some(name) = card_holder_name.clone() {
|
let name_on_card = if let Some(name) = card_holder_name.clone() {
|
||||||
use masking::ExposeInterface;
|
|
||||||
|
|
||||||
if name.clone().expose().is_empty() {
|
if name.clone().expose().is_empty() {
|
||||||
card_token_data
|
card_token_data
|
||||||
.and_then(|token_data| token_data.card_holder_name.clone())
|
.and_then(|token_data| token_data.card_holder_name.clone())
|
||||||
@ -2626,3 +2629,63 @@ impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "v1")]
|
||||||
|
impl
|
||||||
|
TryFrom<(
|
||||||
|
cards::CardNumber,
|
||||||
|
Option<&CardToken>,
|
||||||
|
Option<payment_methods::CoBadgedCardData>,
|
||||||
|
CardDetailsPaymentMethod,
|
||||||
|
)> for Card
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<common_utils::errors::ValidationError>;
|
||||||
|
fn try_from(
|
||||||
|
value: (
|
||||||
|
cards::CardNumber,
|
||||||
|
Option<&CardToken>,
|
||||||
|
Option<payment_methods::CoBadgedCardData>,
|
||||||
|
CardDetailsPaymentMethod,
|
||||||
|
),
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let (card_number, card_token_data, co_badged_card_data, card_details) = value;
|
||||||
|
|
||||||
|
// The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
|
||||||
|
let name_on_card = if let Some(name) = card_details.card_holder_name.clone() {
|
||||||
|
if name.clone().expose().is_empty() {
|
||||||
|
card_token_data
|
||||||
|
.and_then(|token_data| token_data.card_holder_name.clone())
|
||||||
|
.or(Some(name))
|
||||||
|
} else {
|
||||||
|
Some(name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
card_token_data.and_then(|token_data| token_data.card_holder_name.clone())
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
card_number,
|
||||||
|
card_exp_month: card_details
|
||||||
|
.expiry_month
|
||||||
|
.get_required_value("expiry_month")?
|
||||||
|
.clone(),
|
||||||
|
card_exp_year: card_details
|
||||||
|
.expiry_year
|
||||||
|
.get_required_value("expiry_year")?
|
||||||
|
.clone(),
|
||||||
|
card_holder_name: name_on_card,
|
||||||
|
card_cvc: card_token_data
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.card_cvc
|
||||||
|
.unwrap_or_default(),
|
||||||
|
card_issuer: card_details.card_issuer,
|
||||||
|
card_network: card_details.card_network,
|
||||||
|
card_type: card_details.card_type,
|
||||||
|
card_issuing_country: card_details.issuer_country,
|
||||||
|
bank_code: None,
|
||||||
|
nick_name: card_details.nick_name,
|
||||||
|
co_badged_card_data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ pub enum PaymentMethodVaultingData {
|
|||||||
Card(payment_methods::CardDetail),
|
Card(payment_methods::CardDetail),
|
||||||
#[cfg(feature = "v2")]
|
#[cfg(feature = "v2")]
|
||||||
NetworkToken(payment_method_data::NetworkTokenDetails),
|
NetworkToken(payment_method_data::NetworkTokenDetails),
|
||||||
|
CardNumber(cards::CardNumber),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PaymentMethodVaultingData {
|
impl PaymentMethodVaultingData {
|
||||||
@ -20,6 +21,7 @@ impl PaymentMethodVaultingData {
|
|||||||
Self::Card(card) => Some(card),
|
Self::Card(card) => Some(card),
|
||||||
#[cfg(feature = "v2")]
|
#[cfg(feature = "v2")]
|
||||||
Self::NetworkToken(_) => None,
|
Self::NetworkToken(_) => None,
|
||||||
|
Self::CardNumber(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_payment_methods_data(&self) -> payment_method_data::PaymentMethodsData {
|
pub fn get_payment_methods_data(&self) -> payment_method_data::PaymentMethodsData {
|
||||||
@ -35,6 +37,23 @@ impl PaymentMethodVaultingData {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Self::CardNumber(_card_number) => payment_method_data::PaymentMethodsData::Card(
|
||||||
|
payment_method_data::CardDetailsPaymentMethod {
|
||||||
|
last4_digits: None,
|
||||||
|
issuer_country: None,
|
||||||
|
expiry_month: None,
|
||||||
|
expiry_year: None,
|
||||||
|
nick_name: None,
|
||||||
|
card_holder_name: None,
|
||||||
|
card_isin: None,
|
||||||
|
card_issuer: None,
|
||||||
|
card_network: None,
|
||||||
|
card_type: None,
|
||||||
|
saved_to_locker: false,
|
||||||
|
#[cfg(feature = "v1")]
|
||||||
|
co_badged_card_data: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +68,7 @@ impl VaultingDataInterface for PaymentMethodVaultingData {
|
|||||||
Self::Card(card) => card.card_number.to_string(),
|
Self::Card(card) => card.card_number.to_string(),
|
||||||
#[cfg(feature = "v2")]
|
#[cfg(feature = "v2")]
|
||||||
Self::NetworkToken(network_token) => network_token.network_token.to_string(),
|
Self::NetworkToken(network_token) => network_token.network_token.to_string(),
|
||||||
|
Self::CardNumber(card_number) => card_number.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2201,18 +2201,7 @@ pub async fn create_pm_additional_data_update(
|
|||||||
external_vault_source: Option<id_type::MerchantConnectorAccountId>,
|
external_vault_source: Option<id_type::MerchantConnectorAccountId>,
|
||||||
) -> RouterResult<storage::PaymentMethodUpdate> {
|
) -> RouterResult<storage::PaymentMethodUpdate> {
|
||||||
let encrypted_payment_method_data = pmd
|
let encrypted_payment_method_data = pmd
|
||||||
.map(
|
.map(|payment_method_vaulting_data| payment_method_vaulting_data.get_payment_methods_data())
|
||||||
|payment_method_vaulting_data| match payment_method_vaulting_data {
|
|
||||||
domain::PaymentMethodVaultingData::Card(card) => domain::PaymentMethodsData::Card(
|
|
||||||
domain::CardDetailsPaymentMethod::from(card.clone()),
|
|
||||||
),
|
|
||||||
domain::PaymentMethodVaultingData::NetworkToken(network_token) => {
|
|
||||||
domain::PaymentMethodsData::NetworkToken(
|
|
||||||
domain::NetworkTokenDetailsPaymentMethod::from(network_token.clone()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.async_map(|payment_method_details| async {
|
.async_map(|payment_method_details| async {
|
||||||
let key_manager_state = &(state).into();
|
let key_manager_state = &(state).into();
|
||||||
|
|
||||||
|
|||||||
@ -1964,9 +1964,12 @@ pub fn get_vault_response_for_retrieve_payment_method_data_v1<F>(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
logger::error!("Failed to retrieve payment method: {:?}", err);
|
logger::error!(
|
||||||
|
"Failed to retrieve payment method from external vault: {:?}",
|
||||||
|
err
|
||||||
|
);
|
||||||
Err(report!(errors::ApiErrorResponse::InternalServerError)
|
Err(report!(errors::ApiErrorResponse::InternalServerError)
|
||||||
.attach_printable("Failed to retrieve payment method"))
|
.attach_printable("Failed to retrieve payment method from external vault"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2512,10 +2512,30 @@ pub async fn fetch_card_details_from_external_vault(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let payment_methods_data = payment_method_info.get_payment_methods_data();
|
||||||
|
|
||||||
match vault_resp {
|
match vault_resp {
|
||||||
hyperswitch_domain_models::vault::PaymentMethodVaultingData::Card(card) => Ok(
|
hyperswitch_domain_models::vault::PaymentMethodVaultingData::Card(card) => Ok(
|
||||||
domain::Card::from((card, card_token_data, co_badged_card_data)),
|
domain::Card::from((card, card_token_data, co_badged_card_data)),
|
||||||
),
|
),
|
||||||
|
hyperswitch_domain_models::vault::PaymentMethodVaultingData::CardNumber(card_number) => {
|
||||||
|
let payment_methods_data = payment_methods_data
|
||||||
|
.get_required_value("PaymentMethodsData")
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Payment methods data not present")?;
|
||||||
|
|
||||||
|
let card = payment_methods_data
|
||||||
|
.get_card_details()
|
||||||
|
.get_required_value("CardDetails")
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Card details not present")?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
domain::Card::try_from((card_number, card_token_data, co_badged_card_data, card))
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to generate card data")?,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "v1")]
|
#[cfg(feature = "v1")]
|
||||||
|
|||||||
Reference in New Issue
Block a user