mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
feat(connector): [Loonio] implement payouts (#9718)
This commit is contained in:
@ -244,6 +244,24 @@ fn get_connector_payment_method_type_fields(
|
||||
)
|
||||
}
|
||||
|
||||
// Bank Redirect
|
||||
PaymentMethodType::Interac => {
|
||||
common_fields.extend(get_interac_fields());
|
||||
(
|
||||
payment_method_type,
|
||||
ConnectorFields {
|
||||
fields: HashMap::from([(
|
||||
connector.into(),
|
||||
RequiredFieldFinal {
|
||||
mandate: HashMap::new(),
|
||||
non_mandate: HashMap::new(),
|
||||
common: common_fields,
|
||||
},
|
||||
)]),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
_ => (
|
||||
payment_method_type,
|
||||
ConnectorFields {
|
||||
@ -375,6 +393,38 @@ fn get_paypal_fields() -> HashMap<String, RequiredFieldInfo> {
|
||||
)])
|
||||
}
|
||||
|
||||
fn get_interac_fields() -> HashMap<String, RequiredFieldInfo> {
|
||||
HashMap::from([
|
||||
(
|
||||
"payout_method_data.bank_redirect.interac.email".to_string(),
|
||||
RequiredFieldInfo {
|
||||
required_field: "payout_method_data.bank_redirect.interac.email".to_string(),
|
||||
display_name: "email".to_string(),
|
||||
field_type: FieldType::Text,
|
||||
value: None,
|
||||
},
|
||||
),
|
||||
(
|
||||
"billing.address.first_name".to_string(),
|
||||
RequiredFieldInfo {
|
||||
required_field: "billing.address.first_name".to_string(),
|
||||
display_name: "billing_address_first_name".to_string(),
|
||||
field_type: FieldType::Text,
|
||||
value: None,
|
||||
},
|
||||
),
|
||||
(
|
||||
"billing.address.last_name".to_string(),
|
||||
RequiredFieldInfo {
|
||||
required_field: "billing.address.last_name".to_string(),
|
||||
display_name: "billing_address_last_name".to_string(),
|
||||
field_type: FieldType::Text,
|
||||
value: None,
|
||||
},
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
fn get_countries_for_connector(connector: PayoutConnectors) -> Vec<CountryAlpha2> {
|
||||
match connector {
|
||||
PayoutConnectors::Adyenplatform => vec![
|
||||
|
||||
@ -4803,6 +4803,12 @@ pub async fn get_bank_from_hs_locker(
|
||||
message: "Expected bank details, found wallet details instead".to_string(),
|
||||
}
|
||||
.into()),
|
||||
api::PayoutMethodData::BankRedirect(_) => {
|
||||
Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "Expected bank details, found bank redirect details instead".to_string(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -824,6 +824,7 @@ pub enum VaultPayoutMethod {
|
||||
Card(String),
|
||||
Bank(String),
|
||||
Wallet(String),
|
||||
BankRedirect(String),
|
||||
}
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
@ -836,6 +837,9 @@ impl Vaultable for api::PayoutMethodData {
|
||||
Self::Card(card) => VaultPayoutMethod::Card(card.get_value1(customer_id)?),
|
||||
Self::Bank(bank) => VaultPayoutMethod::Bank(bank.get_value1(customer_id)?),
|
||||
Self::Wallet(wallet) => VaultPayoutMethod::Wallet(wallet.get_value1(customer_id)?),
|
||||
Self::BankRedirect(bank_redirect) => {
|
||||
VaultPayoutMethod::BankRedirect(bank_redirect.get_value1(customer_id)?)
|
||||
}
|
||||
};
|
||||
|
||||
value1
|
||||
@ -852,6 +856,9 @@ impl Vaultable for api::PayoutMethodData {
|
||||
Self::Card(card) => VaultPayoutMethod::Card(card.get_value2(customer_id)?),
|
||||
Self::Bank(bank) => VaultPayoutMethod::Bank(bank.get_value2(customer_id)?),
|
||||
Self::Wallet(wallet) => VaultPayoutMethod::Wallet(wallet.get_value2(customer_id)?),
|
||||
Self::BankRedirect(bank_redirect) => {
|
||||
VaultPayoutMethod::BankRedirect(bank_redirect.get_value2(customer_id)?)
|
||||
}
|
||||
};
|
||||
|
||||
value2
|
||||
@ -887,12 +894,95 @@ impl Vaultable for api::PayoutMethodData {
|
||||
let (wallet, supp_data) = api::WalletPayout::from_values(mvalue1, mvalue2)?;
|
||||
Ok((Self::Wallet(wallet), supp_data))
|
||||
}
|
||||
(
|
||||
VaultPayoutMethod::BankRedirect(mvalue1),
|
||||
VaultPayoutMethod::BankRedirect(mvalue2),
|
||||
) => {
|
||||
let (bank_redirect, supp_data) =
|
||||
api::BankRedirectPayout::from_values(mvalue1, mvalue2)?;
|
||||
Ok((Self::BankRedirect(bank_redirect), supp_data))
|
||||
}
|
||||
_ => Err(errors::VaultError::PayoutMethodNotSupported)
|
||||
.attach_printable("Payout method not supported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
impl Vaultable for api::BankRedirectPayout {
|
||||
fn get_value1(
|
||||
&self,
|
||||
_customer_id: Option<id_type::CustomerId>,
|
||||
) -> CustomResult<String, errors::VaultError> {
|
||||
let value1 = match self {
|
||||
Self::Interac(interac_data) => TokenizedBankRedirectSensitiveValues {
|
||||
email: interac_data.email.clone(),
|
||||
bank_redirect_type: PaymentMethodType::Interac,
|
||||
},
|
||||
};
|
||||
|
||||
value1
|
||||
.encode_to_string_of_json()
|
||||
.change_context(errors::VaultError::RequestEncodingFailed)
|
||||
.attach_printable(
|
||||
"Failed to encode bank redirect data - TokenizedBankRedirectSensitiveValues",
|
||||
)
|
||||
}
|
||||
|
||||
fn get_value2(
|
||||
&self,
|
||||
customer_id: Option<id_type::CustomerId>,
|
||||
) -> CustomResult<String, errors::VaultError> {
|
||||
let value2 = TokenizedBankRedirectInsensitiveValues { customer_id };
|
||||
|
||||
value2
|
||||
.encode_to_string_of_json()
|
||||
.change_context(errors::VaultError::RequestEncodingFailed)
|
||||
.attach_printable("Failed to encode wallet data value2")
|
||||
}
|
||||
|
||||
fn from_values(
|
||||
value1: String,
|
||||
value2: String,
|
||||
) -> CustomResult<(Self, SupplementaryVaultData), errors::VaultError> {
|
||||
let value1: TokenizedBankRedirectSensitiveValues = value1
|
||||
.parse_struct("TokenizedBankRedirectSensitiveValues")
|
||||
.change_context(errors::VaultError::ResponseDeserializationFailed)
|
||||
.attach_printable("Could not deserialize into wallet data value1")?;
|
||||
|
||||
let value2: TokenizedBankRedirectInsensitiveValues = value2
|
||||
.parse_struct("TokenizedBankRedirectInsensitiveValues")
|
||||
.change_context(errors::VaultError::ResponseDeserializationFailed)
|
||||
.attach_printable("Could not deserialize into wallet data value2")?;
|
||||
|
||||
let bank_redirect = match value1.bank_redirect_type {
|
||||
PaymentMethodType::Interac => Self::Interac(api_models::payouts::Interac {
|
||||
email: value1.email,
|
||||
}),
|
||||
_ => Err(errors::VaultError::PayoutMethodNotSupported)
|
||||
.attach_printable("Payout method not supported")?,
|
||||
};
|
||||
|
||||
let supp_data = SupplementaryVaultData {
|
||||
customer_id: value2.customer_id,
|
||||
payment_method_id: None,
|
||||
};
|
||||
|
||||
Ok((bank_redirect, supp_data))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TokenizedBankRedirectSensitiveValues {
|
||||
pub email: Email,
|
||||
pub bank_redirect_type: PaymentMethodType,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TokenizedBankRedirectInsensitiveValues {
|
||||
pub customer_id: Option<id_type::CustomerId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct MockTokenizeDBValue {
|
||||
pub value1: String,
|
||||
|
||||
@ -377,7 +377,8 @@ pub async fn save_payout_data_to_locker(
|
||||
Some(wallet.to_owned()),
|
||||
api_enums::PaymentMethodType::foreign_from(wallet),
|
||||
),
|
||||
payouts::PayoutMethodData::Card(_) => {
|
||||
payouts::PayoutMethodData::Card(_)
|
||||
| payouts::PayoutMethodData::BankRedirect(_) => {
|
||||
Err(errors::ApiErrorResponse::InternalServerError)?
|
||||
}
|
||||
}
|
||||
@ -1533,6 +1534,11 @@ pub async fn get_additional_payout_data(
|
||||
Box::new(wallet_data.to_owned().into()),
|
||||
))
|
||||
}
|
||||
api::PayoutMethodData::BankRedirect(bank_redirect_data) => {
|
||||
Some(payout_additional::AdditionalPayoutMethodData::BankRedirect(
|
||||
Box::new(bank_redirect_data.to_owned().into()),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
pub use api_models::payouts::{
|
||||
AchBankTransfer, BacsBankTransfer, Bank as BankPayout, CardPayout, PaymentMethodTypeInfo,
|
||||
PayoutActionRequest, PayoutAttemptResponse, PayoutCreateRequest, PayoutCreateResponse,
|
||||
PayoutEnabledPaymentMethodsInfo, PayoutLinkResponse, PayoutListConstraints,
|
||||
PayoutListFilterConstraints, PayoutListFilters, PayoutListResponse, PayoutMethodData,
|
||||
PayoutMethodDataResponse, PayoutRequest, PayoutRetrieveBody, PayoutRetrieveRequest,
|
||||
PixBankTransfer, RequiredFieldsOverrideRequest, SepaBankTransfer, Wallet as WalletPayout,
|
||||
AchBankTransfer, BacsBankTransfer, Bank as BankPayout, BankRedirect as BankRedirectPayout,
|
||||
CardPayout, PaymentMethodTypeInfo, PayoutActionRequest, PayoutAttemptResponse,
|
||||
PayoutCreateRequest, PayoutCreateResponse, PayoutEnabledPaymentMethodsInfo, PayoutLinkResponse,
|
||||
PayoutListConstraints, PayoutListFilterConstraints, PayoutListFilters, PayoutListResponse,
|
||||
PayoutMethodData, PayoutMethodDataResponse, PayoutRequest, PayoutRetrieveBody,
|
||||
PayoutRetrieveRequest, PixBankTransfer, RequiredFieldsOverrideRequest, SepaBankTransfer,
|
||||
Wallet as WalletPayout,
|
||||
};
|
||||
pub use hyperswitch_domain_models::router_flow_types::payouts::{
|
||||
PoCancel, PoCreate, PoEligibility, PoFulfill, PoQuote, PoRecipient, PoRecipientAccount, PoSync,
|
||||
|
||||
@ -1195,6 +1195,9 @@ impl ForeignFrom<&api_models::payouts::PayoutMethodData> for api_enums::PaymentM
|
||||
api_models::payouts::PayoutMethodData::Bank(bank) => Self::foreign_from(bank),
|
||||
api_models::payouts::PayoutMethodData::Card(_) => Self::Debit,
|
||||
api_models::payouts::PayoutMethodData::Wallet(wallet) => Self::foreign_from(wallet),
|
||||
api_models::payouts::PayoutMethodData::BankRedirect(bank_redirect) => {
|
||||
Self::foreign_from(bank_redirect)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1221,6 +1224,15 @@ impl ForeignFrom<&api_models::payouts::Wallet> for api_enums::PaymentMethodType
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
impl ForeignFrom<&api_models::payouts::BankRedirect> for api_enums::PaymentMethodType {
|
||||
fn foreign_from(value: &api_models::payouts::BankRedirect) -> Self {
|
||||
match value {
|
||||
api_models::payouts::BankRedirect::Interac(_) => Self::Interac,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
impl ForeignFrom<&api_models::payouts::PayoutMethodData> for api_enums::PaymentMethod {
|
||||
fn foreign_from(value: &api_models::payouts::PayoutMethodData) -> Self {
|
||||
@ -1228,6 +1240,7 @@ impl ForeignFrom<&api_models::payouts::PayoutMethodData> for api_enums::PaymentM
|
||||
api_models::payouts::PayoutMethodData::Bank(_) => Self::BankTransfer,
|
||||
api_models::payouts::PayoutMethodData::Card(_) => Self::Card,
|
||||
api_models::payouts::PayoutMethodData::Wallet(_) => Self::Wallet,
|
||||
api_models::payouts::PayoutMethodData::BankRedirect(_) => Self::BankRedirect,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1239,6 +1252,7 @@ impl ForeignFrom<&api_models::payouts::PayoutMethodData> for api_models::enums::
|
||||
api_models::payouts::PayoutMethodData::Bank(_) => Self::Bank,
|
||||
api_models::payouts::PayoutMethodData::Card(_) => Self::Card,
|
||||
api_models::payouts::PayoutMethodData::Wallet(_) => Self::Wallet,
|
||||
api_models::payouts::PayoutMethodData::BankRedirect(_) => Self::BankRedirect,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1250,6 +1264,7 @@ impl ForeignFrom<api_models::enums::PayoutType> for api_enums::PaymentMethod {
|
||||
api_models::enums::PayoutType::Bank => Self::BankTransfer,
|
||||
api_models::enums::PayoutType::Card => Self::Card,
|
||||
api_models::enums::PayoutType::Wallet => Self::Wallet,
|
||||
api_models::enums::PayoutType::BankRedirect => Self::BankRedirect,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,6 +128,16 @@ impl AdyenTest {
|
||||
paypal_id: None,
|
||||
}),
|
||||
)),
|
||||
enums::PayoutType::BankRedirect => {
|
||||
Some(types::api::PayoutMethodData::BankRedirect(
|
||||
types::api::payouts::BankRedirectPayout::Interac(
|
||||
api_models::payouts::Interac {
|
||||
email: Email::from_str("EmailUsedForPayPalAccount@example.com")
|
||||
.ok()?,
|
||||
},
|
||||
),
|
||||
))
|
||||
}
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user