Files
Swangi Kumari 61c2e2c75f feat(connector): [trustpay] introduce instant bank_transfer, finland and poland (#7925)
Co-authored-by: PiX <69745008+pixincreate@users.noreply.github.com>
2025-06-13 06:33:32 +00:00

328 lines
14 KiB
Rust

use api_models::{enums as api_enums, payment_methods as api};
use common_utils::ext_traits::AsyncExt;
pub use hyperswitch_domain_models::{errors::api_error_response, payment_methods as domain};
use router_env::logger;
use crate::state;
#[cfg(feature = "v1")]
pub async fn populate_bin_details_for_payment_method_create(
card_details: api_models::payment_methods::CardDetail,
db: Box<dyn state::PaymentMethodsStorageInterface>,
) -> api_models::payment_methods::CardDetail {
let card_isin: Option<_> = Some(card_details.card_number.get_card_isin());
if card_details.card_issuer.is_some()
&& card_details.card_network.is_some()
&& card_details.card_type.is_some()
&& card_details.card_issuing_country.is_some()
{
api::CardDetail {
card_issuer: card_details.card_issuer.to_owned(),
card_network: card_details.card_network.clone(),
card_type: card_details.card_type.to_owned(),
card_issuing_country: card_details.card_issuing_country.to_owned(),
card_exp_month: card_details.card_exp_month.clone(),
card_exp_year: card_details.card_exp_year.clone(),
card_holder_name: card_details.card_holder_name.clone(),
card_number: card_details.card_number.clone(),
nick_name: card_details.nick_name.clone(),
}
} else {
let card_info = card_isin
.clone()
.async_and_then(|card_isin| async move {
db.get_card_info(&card_isin)
.await
.map_err(|error| logger::error!(card_info_error=?error))
.ok()
})
.await
.flatten()
.map(|card_info| api::CardDetail {
card_issuer: card_info.card_issuer,
card_network: card_info.card_network.clone(),
card_type: card_info.card_type,
card_issuing_country: card_info.card_issuing_country,
card_exp_month: card_details.card_exp_month.clone(),
card_exp_year: card_details.card_exp_year.clone(),
card_holder_name: card_details.card_holder_name.clone(),
card_number: card_details.card_number.clone(),
nick_name: card_details.nick_name.clone(),
});
card_info.unwrap_or_else(|| api::CardDetail {
card_issuer: None,
card_network: None,
card_type: None,
card_issuing_country: None,
card_exp_month: card_details.card_exp_month.clone(),
card_exp_year: card_details.card_exp_year.clone(),
card_holder_name: card_details.card_holder_name.clone(),
card_number: card_details.card_number.clone(),
nick_name: card_details.nick_name.clone(),
})
}
}
#[cfg(feature = "v2")]
pub async fn populate_bin_details_for_payment_method_create(
_card_details: api_models::payment_methods::CardDetail,
_db: &dyn state::PaymentMethodsStorageInterface,
) -> api_models::payment_methods::CardDetail {
todo!()
}
pub fn validate_payment_method_type_against_payment_method(
payment_method: api_enums::PaymentMethod,
payment_method_type: api_enums::PaymentMethodType,
) -> bool {
match payment_method {
#[cfg(feature = "v1")]
api_enums::PaymentMethod::Card => matches!(
payment_method_type,
api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit
),
#[cfg(feature = "v2")]
api_enums::PaymentMethod::Card => matches!(
payment_method_type,
api_enums::PaymentMethodType::Credit
| api_enums::PaymentMethodType::Debit
| api_enums::PaymentMethodType::Card
),
api_enums::PaymentMethod::PayLater => matches!(
payment_method_type,
api_enums::PaymentMethodType::Affirm
| api_enums::PaymentMethodType::Alma
| api_enums::PaymentMethodType::AfterpayClearpay
| api_enums::PaymentMethodType::Klarna
| api_enums::PaymentMethodType::PayBright
| api_enums::PaymentMethodType::Atome
| api_enums::PaymentMethodType::Walley
),
api_enums::PaymentMethod::Wallet => matches!(
payment_method_type,
api_enums::PaymentMethodType::AmazonPay
| api_enums::PaymentMethodType::ApplePay
| api_enums::PaymentMethodType::GooglePay
| api_enums::PaymentMethodType::Paypal
| api_enums::PaymentMethodType::AliPay
| api_enums::PaymentMethodType::AliPayHk
| api_enums::PaymentMethodType::Dana
| api_enums::PaymentMethodType::MbWay
| api_enums::PaymentMethodType::MobilePay
| api_enums::PaymentMethodType::SamsungPay
| api_enums::PaymentMethodType::Twint
| api_enums::PaymentMethodType::Vipps
| api_enums::PaymentMethodType::TouchNGo
| api_enums::PaymentMethodType::Swish
| api_enums::PaymentMethodType::WeChatPay
| api_enums::PaymentMethodType::GoPay
| api_enums::PaymentMethodType::Gcash
| api_enums::PaymentMethodType::Momo
| api_enums::PaymentMethodType::KakaoPay
| api_enums::PaymentMethodType::Cashapp
| api_enums::PaymentMethodType::Mifinity
| api_enums::PaymentMethodType::Paze
| api_enums::PaymentMethodType::RevolutPay
),
api_enums::PaymentMethod::BankRedirect => matches!(
payment_method_type,
api_enums::PaymentMethodType::Giropay
| api_enums::PaymentMethodType::Ideal
| api_enums::PaymentMethodType::Sofort
| api_enums::PaymentMethodType::Eft
| api_enums::PaymentMethodType::Eps
| api_enums::PaymentMethodType::BancontactCard
| api_enums::PaymentMethodType::Blik
| api_enums::PaymentMethodType::LocalBankRedirect
| api_enums::PaymentMethodType::OnlineBankingThailand
| api_enums::PaymentMethodType::OnlineBankingCzechRepublic
| api_enums::PaymentMethodType::OnlineBankingFinland
| api_enums::PaymentMethodType::OnlineBankingFpx
| api_enums::PaymentMethodType::OnlineBankingPoland
| api_enums::PaymentMethodType::OnlineBankingSlovakia
| api_enums::PaymentMethodType::Przelewy24
| api_enums::PaymentMethodType::Trustly
| api_enums::PaymentMethodType::Bizum
| api_enums::PaymentMethodType::Interac
| api_enums::PaymentMethodType::OpenBankingUk
| api_enums::PaymentMethodType::OpenBankingPIS
),
api_enums::PaymentMethod::BankTransfer => matches!(
payment_method_type,
api_enums::PaymentMethodType::Ach
| api_enums::PaymentMethodType::SepaBankTransfer
| api_enums::PaymentMethodType::Bacs
| api_enums::PaymentMethodType::Multibanco
| api_enums::PaymentMethodType::Pix
| api_enums::PaymentMethodType::Pse
| api_enums::PaymentMethodType::PermataBankTransfer
| api_enums::PaymentMethodType::BcaBankTransfer
| api_enums::PaymentMethodType::BniVa
| api_enums::PaymentMethodType::BriVa
| api_enums::PaymentMethodType::CimbVa
| api_enums::PaymentMethodType::DanamonVa
| api_enums::PaymentMethodType::MandiriVa
| api_enums::PaymentMethodType::LocalBankTransfer
| api_enums::PaymentMethodType::InstantBankTransfer
| api_enums::PaymentMethodType::InstantBankTransferFinland
| api_enums::PaymentMethodType::InstantBankTransferPoland
),
api_enums::PaymentMethod::BankDebit => matches!(
payment_method_type,
api_enums::PaymentMethodType::Ach
| api_enums::PaymentMethodType::Sepa
| api_enums::PaymentMethodType::Bacs
| api_enums::PaymentMethodType::Becs
),
api_enums::PaymentMethod::Crypto => matches!(
payment_method_type,
api_enums::PaymentMethodType::CryptoCurrency
),
api_enums::PaymentMethod::Reward => matches!(
payment_method_type,
api_enums::PaymentMethodType::Evoucher | api_enums::PaymentMethodType::ClassicReward
),
api_enums::PaymentMethod::RealTimePayment => matches!(
payment_method_type,
api_enums::PaymentMethodType::Fps
| api_enums::PaymentMethodType::DuitNow
| api_enums::PaymentMethodType::PromptPay
| api_enums::PaymentMethodType::VietQr
),
api_enums::PaymentMethod::Upi => matches!(
payment_method_type,
api_enums::PaymentMethodType::UpiCollect | api_enums::PaymentMethodType::UpiIntent
),
api_enums::PaymentMethod::Voucher => matches!(
payment_method_type,
api_enums::PaymentMethodType::Boleto
| api_enums::PaymentMethodType::Efecty
| api_enums::PaymentMethodType::PagoEfectivo
| api_enums::PaymentMethodType::RedCompra
| api_enums::PaymentMethodType::RedPagos
| api_enums::PaymentMethodType::Indomaret
| api_enums::PaymentMethodType::Alfamart
| api_enums::PaymentMethodType::Oxxo
| api_enums::PaymentMethodType::SevenEleven
| api_enums::PaymentMethodType::Lawson
| api_enums::PaymentMethodType::MiniStop
| api_enums::PaymentMethodType::FamilyMart
| api_enums::PaymentMethodType::Seicomart
| api_enums::PaymentMethodType::PayEasy
),
api_enums::PaymentMethod::GiftCard => {
matches!(
payment_method_type,
api_enums::PaymentMethodType::Givex | api_enums::PaymentMethodType::PaySafeCard
)
}
api_enums::PaymentMethod::CardRedirect => matches!(
payment_method_type,
api_enums::PaymentMethodType::Knet
| api_enums::PaymentMethodType::Benefit
| api_enums::PaymentMethodType::MomoAtm
| api_enums::PaymentMethodType::CardRedirect
),
api_enums::PaymentMethod::OpenBanking => matches!(
payment_method_type,
api_enums::PaymentMethodType::OpenBankingPIS
),
api_enums::PaymentMethod::MobilePayment => matches!(
payment_method_type,
api_enums::PaymentMethodType::DirectCarrierBilling
),
}
}
pub trait ForeignFrom<F> {
fn foreign_from(from: F) -> Self;
}
/// Trait for converting from one foreign type to another
pub trait ForeignTryFrom<F>: Sized {
/// Custom error for conversion failure
type Error;
/// Convert from a foreign type to the current type and return an error if the conversion fails
fn foreign_try_from(from: F) -> Result<Self, Self::Error>;
}
#[cfg(feature = "v1")]
impl ForeignFrom<(Option<api::CardDetailFromLocker>, domain::PaymentMethod)>
for api::PaymentMethodResponse
{
fn foreign_from(
(card_details, item): (Option<api::CardDetailFromLocker>, domain::PaymentMethod),
) -> Self {
Self {
merchant_id: item.merchant_id.to_owned(),
customer_id: Some(item.customer_id.to_owned()),
payment_method_id: item.get_id().clone(),
payment_method: item.get_payment_method_type(),
payment_method_type: item.get_payment_method_subtype(),
card: card_details,
recurring_enabled: Some(false),
installment_payment_enabled: Some(false),
payment_experience: None,
metadata: item.metadata,
created: Some(item.created_at),
#[cfg(feature = "payouts")]
bank_transfer: None,
last_used_at: None,
client_secret: item.client_secret,
}
}
}
#[cfg(feature = "v2")]
impl ForeignFrom<(Option<api::CardDetailFromLocker>, domain::PaymentMethod)>
for api::PaymentMethodResponse
{
fn foreign_from(
(card_details, item): (Option<api::CardDetailFromLocker>, domain::PaymentMethod),
) -> Self {
todo!()
}
}
pub trait StorageErrorExt<T, E> {
#[track_caller]
fn to_not_found_response(self, not_found_response: E) -> error_stack::Result<T, E>;
#[track_caller]
fn to_duplicate_response(self, duplicate_response: E) -> error_stack::Result<T, E>;
}
impl<T> StorageErrorExt<T, api_error_response::ApiErrorResponse>
for error_stack::Result<T, storage_impl::StorageError>
{
#[track_caller]
fn to_not_found_response(
self,
not_found_response: api_error_response::ApiErrorResponse,
) -> error_stack::Result<T, api_error_response::ApiErrorResponse> {
self.map_err(|err| {
let new_err = match err.current_context() {
storage_impl::StorageError::ValueNotFound(_) => not_found_response,
storage_impl::StorageError::CustomerRedacted => {
api_error_response::ApiErrorResponse::CustomerRedacted
}
_ => api_error_response::ApiErrorResponse::InternalServerError,
};
err.change_context(new_err)
})
}
#[track_caller]
fn to_duplicate_response(
self,
duplicate_response: api_error_response::ApiErrorResponse,
) -> error_stack::Result<T, api_error_response::ApiErrorResponse> {
self.map_err(|err| {
let new_err = match err.current_context() {
storage_impl::StorageError::DuplicateValue { .. } => duplicate_response,
_ => api_error_response::ApiErrorResponse::InternalServerError,
};
err.change_context(new_err)
})
}
}