mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
feat(core): [Stripe] add bank debits payment method to stripe (#906)
This commit is contained in:
@ -409,11 +409,14 @@ pub enum PaymentExperience {
|
|||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
pub enum PaymentMethodType {
|
pub enum PaymentMethodType {
|
||||||
|
Ach,
|
||||||
Affirm,
|
Affirm,
|
||||||
AfterpayClearpay,
|
AfterpayClearpay,
|
||||||
AliPay,
|
AliPay,
|
||||||
ApplePay,
|
ApplePay,
|
||||||
|
Bacs,
|
||||||
BancontactCard,
|
BancontactCard,
|
||||||
|
Becs,
|
||||||
Blik,
|
Blik,
|
||||||
Credit,
|
Credit,
|
||||||
CryptoCurrency,
|
CryptoCurrency,
|
||||||
@ -432,6 +435,7 @@ pub enum PaymentMethodType {
|
|||||||
PayBright,
|
PayBright,
|
||||||
Paypal,
|
Paypal,
|
||||||
Przelewy24,
|
Przelewy24,
|
||||||
|
Sepa,
|
||||||
Sofort,
|
Sofort,
|
||||||
Swish,
|
Swish,
|
||||||
Trustly,
|
Trustly,
|
||||||
@ -463,6 +467,7 @@ pub enum PaymentMethod {
|
|||||||
Wallet,
|
Wallet,
|
||||||
BankRedirect,
|
BankRedirect,
|
||||||
Crypto,
|
Crypto,
|
||||||
|
BankDebit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
|
|||||||
@ -462,13 +462,57 @@ pub enum PayLaterData {
|
|||||||
Walley {},
|
Walley {},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
|
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, ToSchema, Eq, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum BankDebitData {
|
||||||
|
/// Payment Method data for Ach bank debit
|
||||||
|
AchBankDebit {
|
||||||
|
/// Billing details for bank debit
|
||||||
|
billing_details: BankDebitBilling,
|
||||||
|
/// Account number for ach bank debit payment
|
||||||
|
#[schema(value_type = String, example = "000123456789")]
|
||||||
|
account_number: Secret<String>,
|
||||||
|
/// Routing number for ach bank debit payment
|
||||||
|
#[schema(value_type = String, example = "110000000")]
|
||||||
|
routing_number: Secret<String>,
|
||||||
|
},
|
||||||
|
SepaBankDebit {
|
||||||
|
/// Billing details for bank debit
|
||||||
|
billing_details: BankDebitBilling,
|
||||||
|
/// International bank account number (iban) for SEPA
|
||||||
|
#[schema(value_type = String, example = "DE89370400440532013000")]
|
||||||
|
iban: Secret<String>,
|
||||||
|
},
|
||||||
|
BecsBankDebit {
|
||||||
|
/// Billing details for bank debit
|
||||||
|
billing_details: BankDebitBilling,
|
||||||
|
/// Account number for Becs payment method
|
||||||
|
#[schema(value_type = String, example = "000123456")]
|
||||||
|
account_number: Secret<String>,
|
||||||
|
/// Bank-State-Branch (bsb) number
|
||||||
|
#[schema(value_type = String, example = "000000")]
|
||||||
|
bsb_number: Secret<String>,
|
||||||
|
},
|
||||||
|
BacsBankDebit {
|
||||||
|
/// Billing details for bank debit
|
||||||
|
billing_details: BankDebitBilling,
|
||||||
|
/// Account number for Bacs payment method
|
||||||
|
#[schema(value_type = String, example = "00012345")]
|
||||||
|
account_number: Secret<String>,
|
||||||
|
/// Sort code for Bacs payment method
|
||||||
|
#[schema(value_type = String, example = "108800")]
|
||||||
|
sort_code: Secret<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum PaymentMethodData {
|
pub enum PaymentMethodData {
|
||||||
Card(Card),
|
Card(Card),
|
||||||
Wallet(WalletData),
|
Wallet(WalletData),
|
||||||
PayLater(PayLaterData),
|
PayLater(PayLaterData),
|
||||||
BankRedirect(BankRedirectData),
|
BankRedirect(BankRedirectData),
|
||||||
|
BankDebit(BankDebitData),
|
||||||
Crypto(CryptoData),
|
Crypto(CryptoData),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,6 +529,7 @@ pub enum AdditionalPaymentData {
|
|||||||
Wallet {},
|
Wallet {},
|
||||||
PayLater {},
|
PayLater {},
|
||||||
Crypto {},
|
Crypto {},
|
||||||
|
BankDebit {},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&PaymentMethodData> for AdditionalPaymentData {
|
impl From<&PaymentMethodData> for AdditionalPaymentData {
|
||||||
@ -509,6 +554,7 @@ impl From<&PaymentMethodData> for AdditionalPaymentData {
|
|||||||
PaymentMethodData::Wallet(_) => Self::Wallet {},
|
PaymentMethodData::Wallet(_) => Self::Wallet {},
|
||||||
PaymentMethodData::PayLater(_) => Self::PayLater {},
|
PaymentMethodData::PayLater(_) => Self::PayLater {},
|
||||||
PaymentMethodData::Crypto(_) => Self::Crypto {},
|
PaymentMethodData::Crypto(_) => Self::Crypto {},
|
||||||
|
PaymentMethodData::BankDebit(_) => Self::BankDebit {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -607,6 +653,18 @@ pub struct BankRedirectBilling {
|
|||||||
pub billing_name: Secret<String>,
|
pub billing_name: Secret<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, ToSchema, Eq, PartialEq)]
|
||||||
|
pub struct BankDebitBilling {
|
||||||
|
/// The billing name for bank debits
|
||||||
|
#[schema(value_type = String, example = "John Doe")]
|
||||||
|
pub name: Secret<String>,
|
||||||
|
/// The billing email for bank debits
|
||||||
|
#[schema(value_type = String, example = "example@example.com")]
|
||||||
|
pub email: Secret<String, pii::Email>,
|
||||||
|
/// The billing address for bank debits
|
||||||
|
pub address: Option<AddressDetails>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
|
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WalletData {
|
pub enum WalletData {
|
||||||
@ -722,6 +780,7 @@ pub enum PaymentMethodDataResponse {
|
|||||||
Paypal,
|
Paypal,
|
||||||
BankRedirect(BankRedirectData),
|
BankRedirect(BankRedirectData),
|
||||||
Crypto(CryptoData),
|
Crypto(CryptoData),
|
||||||
|
BankDebit(BankDebitData),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, ToSchema)]
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, ToSchema)]
|
||||||
@ -1137,7 +1196,7 @@ pub struct PaymentListResponse {
|
|||||||
pub data: Vec<PaymentsResponse>,
|
pub data: Vec<PaymentsResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Setter, Clone, Default, Debug, Eq, PartialEq, serde::Serialize)]
|
#[derive(Setter, Clone, Default, Debug, serde::Serialize)]
|
||||||
pub struct VerifyResponse {
|
pub struct VerifyResponse {
|
||||||
pub verify_id: Option<String>,
|
pub verify_id: Option<String>,
|
||||||
pub merchant_id: Option<String>,
|
pub merchant_id: Option<String>,
|
||||||
@ -1262,6 +1321,7 @@ impl From<PaymentMethodData> for PaymentMethodDataResponse {
|
|||||||
Self::BankRedirect(bank_redirect_data)
|
Self::BankRedirect(bank_redirect_data)
|
||||||
}
|
}
|
||||||
PaymentMethodData::Crypto(crpto_data) => Self::Crypto(crpto_data),
|
PaymentMethodData::Crypto(crpto_data) => Self::Crypto(crpto_data),
|
||||||
|
PaymentMethodData::BankDebit(bank_debit_data) => Self::BankDebit(bank_debit_data),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,11 +111,14 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AciPaymentsRequest {
|
|||||||
api::PaymentMethodData::PayLater(_) => PaymentDetails::Klarna,
|
api::PaymentMethodData::PayLater(_) => PaymentDetails::Klarna,
|
||||||
api::PaymentMethodData::Wallet(_) => PaymentDetails::Wallet,
|
api::PaymentMethodData::Wallet(_) => PaymentDetails::Wallet,
|
||||||
api::PaymentMethodData::BankRedirect(_) => PaymentDetails::BankRedirect,
|
api::PaymentMethodData::BankRedirect(_) => PaymentDetails::BankRedirect,
|
||||||
api::PaymentMethodData::Crypto(_) => Err(errors::ConnectorError::NotSupported {
|
api::PaymentMethodData::Crypto(_) | api::PaymentMethodData::BankDebit(_) => {
|
||||||
|
Err(errors::ConnectorError::NotSupported {
|
||||||
payment_method: format!("{:?}", item.payment_method),
|
payment_method: format!("{:?}", item.payment_method),
|
||||||
connector: "Aci",
|
connector: "Aci",
|
||||||
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl.to_string(),
|
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl
|
||||||
})?,
|
.to_string(),
|
||||||
|
})?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth = AciAuthType::try_from(&item.connector_auth_type)?;
|
let auth = AciAuthType::try_from(&item.connector_auth_type)?;
|
||||||
|
|||||||
@ -87,11 +87,14 @@ impl TryFrom<api_models::payments::PaymentMethodData> for PaymentDetails {
|
|||||||
api::PaymentMethodData::PayLater(_) => Ok(Self::Klarna),
|
api::PaymentMethodData::PayLater(_) => Ok(Self::Klarna),
|
||||||
api::PaymentMethodData::Wallet(_) => Ok(Self::Wallet),
|
api::PaymentMethodData::Wallet(_) => Ok(Self::Wallet),
|
||||||
api::PaymentMethodData::BankRedirect(_) => Ok(Self::BankRedirect),
|
api::PaymentMethodData::BankRedirect(_) => Ok(Self::BankRedirect),
|
||||||
api::PaymentMethodData::Crypto(_) => Err(errors::ConnectorError::NotSupported {
|
api::PaymentMethodData::Crypto(_) | api::PaymentMethodData::BankDebit(_) => {
|
||||||
|
Err(errors::ConnectorError::NotSupported {
|
||||||
payment_method: format!("{value:?}"),
|
payment_method: format!("{value:?}"),
|
||||||
connector: "AuthorizeDotNet",
|
connector: "AuthorizeDotNet",
|
||||||
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl.to_string(),
|
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl
|
||||||
})?,
|
.to_string(),
|
||||||
|
})?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use api_models::{self, enums as api_enums, payments};
|
use api_models::{self, enums as api_enums, payments};
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use common_utils::{fp_utils, pii::Email};
|
use common_utils::{fp_utils, pii};
|
||||||
use error_stack::{IntoReport, ResultExt};
|
use error_stack::{IntoReport, ResultExt};
|
||||||
use masking::ExposeInterface;
|
use masking::{ExposeInterface, ExposeOptionInterface, Secret};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -10,7 +10,6 @@ use uuid::Uuid;
|
|||||||
use crate::{
|
use crate::{
|
||||||
consts,
|
consts,
|
||||||
core::errors,
|
core::errors,
|
||||||
pii::{self, ExposeOptionInterface, Secret},
|
|
||||||
services,
|
services,
|
||||||
types::{self, api, storage::enums},
|
types::{self, api, storage::enums},
|
||||||
utils::OptionExt,
|
utils::OptionExt,
|
||||||
@ -63,6 +62,22 @@ pub enum Auth3ds {
|
|||||||
Any,
|
Any,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum StripeMandateType {
|
||||||
|
Online,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
|
pub struct StripeMandateRequest {
|
||||||
|
#[serde(rename = "mandate_data[customer_acceptance][type]")]
|
||||||
|
pub mandate_type: StripeMandateType,
|
||||||
|
#[serde(rename = "mandate_data[customer_acceptance][online][ip_address]")]
|
||||||
|
pub ip_address: Secret<String, pii::IpAddress>,
|
||||||
|
#[serde(rename = "mandate_data[customer_acceptance][online][user_agent]")]
|
||||||
|
pub user_agent: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
pub struct PaymentIntentRequest {
|
pub struct PaymentIntentRequest {
|
||||||
pub amount: i64, //amount in cents, hence passed as integer
|
pub amount: i64, //amount in cents, hence passed as integer
|
||||||
@ -78,6 +93,8 @@ pub struct PaymentIntentRequest {
|
|||||||
pub return_url: String,
|
pub return_url: String,
|
||||||
pub confirm: bool,
|
pub confirm: bool,
|
||||||
pub mandate: Option<String>,
|
pub mandate: Option<String>,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub setup_mandate_details: Option<StripeMandateRequest>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub shipping: StripeShippingAddress,
|
pub shipping: StripeShippingAddress,
|
||||||
@ -198,6 +215,47 @@ pub struct StripeBankRedirectData {
|
|||||||
pub bank_specific_data: Option<BankSpecificData>,
|
pub bank_specific_data: Option<BankSpecificData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
|
#[serde(tag = "payment_method_data[type]")]
|
||||||
|
pub enum BankDebitData {
|
||||||
|
#[serde(rename = "us_bank_account")]
|
||||||
|
Ach {
|
||||||
|
#[serde(rename = "payment_method_data[us_bank_account][account_holder_type]")]
|
||||||
|
account_holder_type: String,
|
||||||
|
#[serde(rename = "payment_method_data[us_bank_account][account_number]")]
|
||||||
|
account_number: Secret<String>,
|
||||||
|
#[serde(rename = "payment_method_data[us_bank_account][routing_number]")]
|
||||||
|
routing_number: Secret<String>,
|
||||||
|
},
|
||||||
|
#[serde(rename = "sepa_debit")]
|
||||||
|
Sepa {
|
||||||
|
#[serde(rename = "payment_method_data[sepa_debit][iban]")]
|
||||||
|
iban: Secret<String>,
|
||||||
|
},
|
||||||
|
#[serde(rename = "au_becs_debit")]
|
||||||
|
Becs {
|
||||||
|
#[serde(rename = "payment_method_data[au_becs_debit][account_number]")]
|
||||||
|
account_number: Secret<String>,
|
||||||
|
#[serde(rename = "payment_method_data[au_becs_debit][bsb_number]")]
|
||||||
|
bsb_number: Secret<String>,
|
||||||
|
},
|
||||||
|
#[serde(rename = "bacs_debit")]
|
||||||
|
Bacs {
|
||||||
|
#[serde(rename = "payment_method_data[bacs_debit][account_number]")]
|
||||||
|
account_number: Secret<String>,
|
||||||
|
#[serde(rename = "payment_method_data[bacs_debit][sort_code]")]
|
||||||
|
sort_code: Secret<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
|
pub struct StripeBankDebitData {
|
||||||
|
#[serde(rename = "payment_method_types[]")]
|
||||||
|
pub payment_method_types: StripePaymentMethodType,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub bank_specific_data: BankDebitData,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum StripePaymentMethodData {
|
pub enum StripePaymentMethodData {
|
||||||
@ -205,6 +263,7 @@ pub enum StripePaymentMethodData {
|
|||||||
PayLater(StripePayLaterData),
|
PayLater(StripePayLaterData),
|
||||||
Wallet(StripeWallet),
|
Wallet(StripeWallet),
|
||||||
BankRedirect(StripeBankRedirectData),
|
BankRedirect(StripeBankRedirectData),
|
||||||
|
BankDebit(StripeBankDebitData),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
@ -230,7 +289,7 @@ pub struct ApplepayPayment {
|
|||||||
pub payment_method_types: StripePaymentMethodType,
|
pub payment_method_types: StripePaymentMethodType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize, Clone)]
|
#[derive(Debug, Eq, PartialEq, Serialize, Clone, Copy)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum StripePaymentMethodType {
|
pub enum StripePaymentMethodType {
|
||||||
Card,
|
Card,
|
||||||
@ -242,6 +301,14 @@ pub enum StripePaymentMethodType {
|
|||||||
Ideal,
|
Ideal,
|
||||||
Sofort,
|
Sofort,
|
||||||
ApplePay,
|
ApplePay,
|
||||||
|
#[serde(rename = "us_bank_account")]
|
||||||
|
Ach,
|
||||||
|
#[serde(rename = "sepa_debit")]
|
||||||
|
Sepa,
|
||||||
|
#[serde(rename = "au_becs_debit")]
|
||||||
|
Becs,
|
||||||
|
#[serde(rename = "bacs_debit")]
|
||||||
|
Bacs,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize, Clone)]
|
#[derive(Debug, Eq, PartialEq, Serialize, Clone)]
|
||||||
@ -472,6 +539,35 @@ impl TryFrom<(&api_models::payments::PayLaterData, StripePaymentMethodType)>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&payments::BankDebitBilling> for StripeBillingAddress {
|
||||||
|
fn from(item: &payments::BankDebitBilling) -> Self {
|
||||||
|
Self {
|
||||||
|
email: Some(item.email.to_owned()),
|
||||||
|
country: item
|
||||||
|
.address
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|address| address.country.to_owned()),
|
||||||
|
name: Some(item.name.to_owned()),
|
||||||
|
city: item
|
||||||
|
.address
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|address| address.city.to_owned()),
|
||||||
|
address_line1: item
|
||||||
|
.address
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|address| address.line1.to_owned()),
|
||||||
|
address_line2: item
|
||||||
|
.address
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|address| address.line2.to_owned()),
|
||||||
|
zip_code: item
|
||||||
|
.address
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|address| address.zip.to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<&payments::BankRedirectData> for StripeBillingAddress {
|
impl TryFrom<&payments::BankRedirectData> for StripeBillingAddress {
|
||||||
type Error = errors::ConnectorError;
|
type Error = errors::ConnectorError;
|
||||||
|
|
||||||
@ -514,6 +610,64 @@ fn get_bank_specific_data(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bank_debit_data(
|
||||||
|
bank_debit_data: &payments::BankDebitData,
|
||||||
|
) -> (StripePaymentMethodType, BankDebitData, StripeBillingAddress) {
|
||||||
|
match bank_debit_data {
|
||||||
|
payments::BankDebitData::AchBankDebit {
|
||||||
|
billing_details,
|
||||||
|
account_number,
|
||||||
|
routing_number,
|
||||||
|
} => {
|
||||||
|
let ach_data = BankDebitData::Ach {
|
||||||
|
account_holder_type: "individual".to_string(),
|
||||||
|
account_number: account_number.to_owned(),
|
||||||
|
routing_number: routing_number.to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let billing_data = StripeBillingAddress::from(billing_details);
|
||||||
|
(StripePaymentMethodType::Ach, ach_data, billing_data)
|
||||||
|
}
|
||||||
|
payments::BankDebitData::SepaBankDebit {
|
||||||
|
billing_details,
|
||||||
|
iban,
|
||||||
|
} => {
|
||||||
|
let sepa_data = BankDebitData::Sepa {
|
||||||
|
iban: iban.to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let billing_data = StripeBillingAddress::from(billing_details);
|
||||||
|
(StripePaymentMethodType::Sepa, sepa_data, billing_data)
|
||||||
|
}
|
||||||
|
payments::BankDebitData::BecsBankDebit {
|
||||||
|
billing_details,
|
||||||
|
account_number,
|
||||||
|
bsb_number,
|
||||||
|
} => {
|
||||||
|
let becs_data = BankDebitData::Becs {
|
||||||
|
account_number: account_number.to_owned(),
|
||||||
|
bsb_number: bsb_number.to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let billing_data = StripeBillingAddress::from(billing_details);
|
||||||
|
(StripePaymentMethodType::Becs, becs_data, billing_data)
|
||||||
|
}
|
||||||
|
payments::BankDebitData::BacsBankDebit {
|
||||||
|
billing_details,
|
||||||
|
account_number,
|
||||||
|
sort_code,
|
||||||
|
} => {
|
||||||
|
let bacs_data = BankDebitData::Bacs {
|
||||||
|
account_number: account_number.to_owned(),
|
||||||
|
sort_code: sort_code.to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let billing_data = StripeBillingAddress::from(billing_details);
|
||||||
|
(StripePaymentMethodType::Bacs, bacs_data, billing_data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn create_stripe_payment_method(
|
fn create_stripe_payment_method(
|
||||||
pm_type: Option<&enums::PaymentMethodType>,
|
pm_type: Option<&enums::PaymentMethodType>,
|
||||||
experience: Option<&enums::PaymentExperience>,
|
experience: Option<&enums::PaymentExperience>,
|
||||||
@ -558,13 +712,12 @@ fn create_stripe_payment_method(
|
|||||||
|
|
||||||
let stripe_pm_type = infer_stripe_pay_later_type(pm_type, pm_experience)?;
|
let stripe_pm_type = infer_stripe_pay_later_type(pm_type, pm_experience)?;
|
||||||
|
|
||||||
let billing_address =
|
let billing_address = StripeBillingAddress::try_from((pay_later_data, stripe_pm_type))?;
|
||||||
StripeBillingAddress::try_from((pay_later_data, stripe_pm_type.clone()))?;
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
StripePaymentMethodData::PayLater(StripePayLaterData {
|
StripePaymentMethodData::PayLater(StripePayLaterData {
|
||||||
payment_method_types: stripe_pm_type.clone(),
|
payment_method_types: stripe_pm_type,
|
||||||
payment_method_data_type: stripe_pm_type.clone(),
|
payment_method_data_type: stripe_pm_type,
|
||||||
}),
|
}),
|
||||||
stripe_pm_type,
|
stripe_pm_type,
|
||||||
billing_address,
|
billing_address,
|
||||||
@ -577,8 +730,8 @@ fn create_stripe_payment_method(
|
|||||||
let bank_name = get_bank_name(&pm_type, bank_redirect_data)?;
|
let bank_name = get_bank_name(&pm_type, bank_redirect_data)?;
|
||||||
Ok((
|
Ok((
|
||||||
StripePaymentMethodData::BankRedirect(StripeBankRedirectData {
|
StripePaymentMethodData::BankRedirect(StripeBankRedirectData {
|
||||||
payment_method_types: pm_type.clone(),
|
payment_method_types: pm_type,
|
||||||
payment_method_data_type: pm_type.clone(),
|
payment_method_data_type: pm_type,
|
||||||
bank_name,
|
bank_name,
|
||||||
bank_specific_data,
|
bank_specific_data,
|
||||||
}),
|
}),
|
||||||
@ -609,6 +762,16 @@ fn create_stripe_payment_method(
|
|||||||
)
|
)
|
||||||
.into()),
|
.into()),
|
||||||
},
|
},
|
||||||
|
payments::PaymentMethodData::BankDebit(bank_debit_data) => {
|
||||||
|
let (pm_type, bank_debit_data, billing_address) = get_bank_debit_data(bank_debit_data);
|
||||||
|
|
||||||
|
let pm_data = StripePaymentMethodData::BankDebit(StripeBankDebitData {
|
||||||
|
payment_method_types: pm_type,
|
||||||
|
bank_specific_data: bank_debit_data,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok((pm_data, pm_type, billing_address))
|
||||||
|
}
|
||||||
_ => Err(errors::ConnectorError::NotImplemented(
|
_ => Err(errors::ConnectorError::NotImplemented(
|
||||||
"stripe does not support this payment method".to_string(),
|
"stripe does not support this payment method".to_string(),
|
||||||
)
|
)
|
||||||
@ -694,6 +857,22 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest {
|
|||||||
_ => payment_data,
|
_ => payment_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let setup_mandate_details =
|
||||||
|
item.request
|
||||||
|
.setup_mandate_details
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|mandate_details| {
|
||||||
|
mandate_details
|
||||||
|
.customer_acceptance
|
||||||
|
.online
|
||||||
|
.as_ref()
|
||||||
|
.map(|online_details| StripeMandateRequest {
|
||||||
|
mandate_type: StripeMandateType::Online,
|
||||||
|
ip_address: online_details.ip_address.to_owned(),
|
||||||
|
user_agent: online_details.user_agent.to_owned(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
amount: item.request.amount, //hopefully we don't loose some cents here
|
amount: item.request.amount, //hopefully we don't loose some cents here
|
||||||
currency: item.request.currency.to_string(), //we need to copy the value and not transfer ownership
|
currency: item.request.currency.to_string(), //we need to copy the value and not transfer ownership
|
||||||
@ -715,6 +894,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest {
|
|||||||
capture_method: StripeCaptureMethod::from(item.request.capture_method),
|
capture_method: StripeCaptureMethod::from(item.request.capture_method),
|
||||||
payment_data,
|
payment_data,
|
||||||
mandate,
|
mandate,
|
||||||
|
setup_mandate_details,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -881,11 +1061,8 @@ impl<F, T>
|
|||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::ResponseRouterData<F, PaymentIntentResponse, T, types::PaymentsResponseData>,
|
item: types::ResponseRouterData<F, PaymentIntentResponse, T, types::PaymentsResponseData>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
let redirection_data =
|
let redirection_data = item.response.next_action.map(|next_action_response| {
|
||||||
item.response
|
services::RedirectForm::from((next_action_response.get_url(), services::Method::Get))
|
||||||
.next_action
|
|
||||||
.map(|StripeNextActionResponse::RedirectToUrl(response)| {
|
|
||||||
services::RedirectForm::from((response.url, services::Method::Get))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mandate_reference =
|
let mandate_reference =
|
||||||
@ -929,11 +1106,16 @@ impl<F, T>
|
|||||||
types::PaymentsResponseData,
|
types::PaymentsResponseData,
|
||||||
>,
|
>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
let redirection_data = item.response.next_action.as_ref().map(
|
let redirection_data = item
|
||||||
|StripeNextActionResponse::RedirectToUrl(response)| {
|
.response
|
||||||
services::RedirectForm::from((response.url.clone(), services::Method::Get))
|
.next_action
|
||||||
},
|
.as_ref()
|
||||||
);
|
.map(|next_action_response| {
|
||||||
|
services::RedirectForm::from((
|
||||||
|
next_action_response.get_url(),
|
||||||
|
services::Method::Get,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
let mandate_reference =
|
let mandate_reference =
|
||||||
item.response
|
item.response
|
||||||
@ -949,7 +1131,11 @@ impl<F, T>
|
|||||||
| StripePaymentMethodOptions::Eps {}
|
| StripePaymentMethodOptions::Eps {}
|
||||||
| StripePaymentMethodOptions::Giropay {}
|
| StripePaymentMethodOptions::Giropay {}
|
||||||
| StripePaymentMethodOptions::Ideal {}
|
| StripePaymentMethodOptions::Ideal {}
|
||||||
| StripePaymentMethodOptions::Sofort {} => None,
|
| StripePaymentMethodOptions::Sofort {}
|
||||||
|
| StripePaymentMethodOptions::Ach {}
|
||||||
|
| StripePaymentMethodOptions::Bacs {}
|
||||||
|
| StripePaymentMethodOptions::Becs {}
|
||||||
|
| StripePaymentMethodOptions::Sepa {} => None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let error_res =
|
let error_res =
|
||||||
@ -990,11 +1176,8 @@ impl<F, T>
|
|||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::ResponseRouterData<F, SetupIntentResponse, T, types::PaymentsResponseData>,
|
item: types::ResponseRouterData<F, SetupIntentResponse, T, types::PaymentsResponseData>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
let redirection_data =
|
let redirection_data = item.response.next_action.map(|next_action_response| {
|
||||||
item.response
|
services::RedirectForm::from((next_action_response.get_url(), services::Method::Get))
|
||||||
.next_action
|
|
||||||
.map(|StripeNextActionResponse::RedirectToUrl(response)| {
|
|
||||||
services::RedirectForm::from((response.url, services::Method::Get))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mandate_reference =
|
let mandate_reference =
|
||||||
@ -1024,6 +1207,18 @@ impl<F, T>
|
|||||||
#[serde(rename_all = "snake_case", remote = "Self")]
|
#[serde(rename_all = "snake_case", remote = "Self")]
|
||||||
pub enum StripeNextActionResponse {
|
pub enum StripeNextActionResponse {
|
||||||
RedirectToUrl(StripeRedirectToUrlResponse),
|
RedirectToUrl(StripeRedirectToUrlResponse),
|
||||||
|
VerifyWithMicrodeposits(StripeVerifyWithMicroDepositsResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StripeNextActionResponse {
|
||||||
|
fn get_url(&self) -> Url {
|
||||||
|
match self {
|
||||||
|
Self::RedirectToUrl(redirect_to_url) => redirect_to_url.url.to_owned(),
|
||||||
|
Self::VerifyWithMicrodeposits(verify_with_microdeposits) => {
|
||||||
|
verify_with_microdeposits.hosted_verification_url.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This impl is required because Stripe's response is of the below format, which is externally
|
// This impl is required because Stripe's response is of the below format, which is externally
|
||||||
@ -1052,6 +1247,11 @@ pub struct StripeRedirectToUrlResponse {
|
|||||||
url: Url,
|
url: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
|
||||||
|
pub struct StripeVerifyWithMicroDepositsResponse {
|
||||||
|
hosted_verification_url: Url,
|
||||||
|
}
|
||||||
|
|
||||||
// REFUND :
|
// REFUND :
|
||||||
// Type definition for Stripe RefundRequest
|
// Type definition for Stripe RefundRequest
|
||||||
|
|
||||||
@ -1189,11 +1389,19 @@ pub struct StripeShippingAddress {
|
|||||||
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
pub struct StripeBillingAddress {
|
pub struct StripeBillingAddress {
|
||||||
#[serde(rename = "payment_method_data[billing_details][email]")]
|
#[serde(rename = "payment_method_data[billing_details][email]")]
|
||||||
pub email: Option<Secret<String, Email>>,
|
pub email: Option<Secret<String, pii::Email>>,
|
||||||
#[serde(rename = "payment_method_data[billing_details][address][country]")]
|
#[serde(rename = "payment_method_data[billing_details][address][country]")]
|
||||||
pub country: Option<api_enums::CountryCode>,
|
pub country: Option<api_enums::CountryCode>,
|
||||||
#[serde(rename = "payment_method_data[billing_details][name]")]
|
#[serde(rename = "payment_method_data[billing_details][name]")]
|
||||||
pub name: Option<Secret<String>>,
|
pub name: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "payment_method_data[billing_details][address][city]")]
|
||||||
|
pub city: Option<String>,
|
||||||
|
#[serde(rename = "payment_method_data[billing_details][address][line1]")]
|
||||||
|
pub address_line1: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "payment_method_data[billing_details][address][line2]")]
|
||||||
|
pub address_line2: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "payment_method_data[billing_details][address][postal_code]")]
|
||||||
|
pub zip_code: Option<Secret<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, serde::Deserialize, Eq, PartialEq)]
|
||||||
@ -1233,6 +1441,14 @@ pub enum StripePaymentMethodOptions {
|
|||||||
Giropay {},
|
Giropay {},
|
||||||
Ideal {},
|
Ideal {},
|
||||||
Sofort {},
|
Sofort {},
|
||||||
|
#[serde(rename = "us_bank_account")]
|
||||||
|
Ach {},
|
||||||
|
#[serde(rename = "sepa_debit")]
|
||||||
|
Sepa {},
|
||||||
|
#[serde(rename = "au_becs_debit")]
|
||||||
|
Becs {},
|
||||||
|
#[serde(rename = "bacs_debit")]
|
||||||
|
Bacs {},
|
||||||
}
|
}
|
||||||
// #[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
// #[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||||
// pub struct Card
|
// pub struct Card
|
||||||
@ -1373,12 +1589,12 @@ impl
|
|||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
api::PaymentMethodData::PayLater(_) => Ok(Self::PayLater(StripePayLaterData {
|
api::PaymentMethodData::PayLater(_) => Ok(Self::PayLater(StripePayLaterData {
|
||||||
payment_method_types: pm_type.clone(),
|
payment_method_types: pm_type,
|
||||||
payment_method_data_type: pm_type,
|
payment_method_data_type: pm_type,
|
||||||
})),
|
})),
|
||||||
api::PaymentMethodData::BankRedirect(_) => {
|
api::PaymentMethodData::BankRedirect(_) => {
|
||||||
Ok(Self::BankRedirect(StripeBankRedirectData {
|
Ok(Self::BankRedirect(StripeBankRedirectData {
|
||||||
payment_method_types: pm_type.clone(),
|
payment_method_types: pm_type,
|
||||||
payment_method_data_type: pm_type,
|
payment_method_data_type: pm_type,
|
||||||
bank_name: None,
|
bank_name: None,
|
||||||
bank_specific_data: None,
|
bank_specific_data: None,
|
||||||
@ -1403,6 +1619,14 @@ impl
|
|||||||
}
|
}
|
||||||
_ => Err(errors::ConnectorError::InvalidWallet.into()),
|
_ => Err(errors::ConnectorError::InvalidWallet.into()),
|
||||||
},
|
},
|
||||||
|
api::PaymentMethodData::BankDebit(bank_debit_data) => {
|
||||||
|
let (pm_type, bank_data, _) = get_bank_debit_data(&bank_debit_data);
|
||||||
|
|
||||||
|
Ok(Self::BankDebit(StripeBankDebitData {
|
||||||
|
payment_method_types: pm_type,
|
||||||
|
bank_specific_data: bank_data,
|
||||||
|
}))
|
||||||
|
}
|
||||||
api::PaymentMethodData::Crypto(_) => Err(errors::ConnectorError::NotSupported {
|
api::PaymentMethodData::Crypto(_) => Err(errors::ConnectorError::NotSupported {
|
||||||
payment_method: format!("{pm_type:?}"),
|
payment_method: format!("{pm_type:?}"),
|
||||||
connector: "Stripe",
|
connector: "Stripe",
|
||||||
|
|||||||
@ -802,6 +802,7 @@ pub async fn make_pm_data<'a, F: Clone, R>(
|
|||||||
(pm @ Some(api::PaymentMethodData::PayLater(_)), _) => Ok(pm.to_owned()),
|
(pm @ Some(api::PaymentMethodData::PayLater(_)), _) => Ok(pm.to_owned()),
|
||||||
(pm @ Some(api::PaymentMethodData::BankRedirect(_)), _) => Ok(pm.to_owned()),
|
(pm @ Some(api::PaymentMethodData::BankRedirect(_)), _) => Ok(pm.to_owned()),
|
||||||
(pm @ Some(api::PaymentMethodData::Crypto(_)), _) => Ok(pm.to_owned()),
|
(pm @ Some(api::PaymentMethodData::Crypto(_)), _) => Ok(pm.to_owned()),
|
||||||
|
(pm @ Some(api::PaymentMethodData::BankDebit(_)), _) => Ok(pm.to_owned()),
|
||||||
(pm_opt @ Some(pm @ api::PaymentMethodData::Wallet(_)), _) => {
|
(pm_opt @ Some(pm @ api::PaymentMethodData::Wallet(_)), _) => {
|
||||||
let token = vault::Vault::store_payment_method_data_in_locker(
|
let token = vault::Vault::store_payment_method_data_in_locker(
|
||||||
state,
|
state,
|
||||||
|
|||||||
@ -155,6 +155,7 @@ Never share your secret api keys. Keep them guarded and secure.
|
|||||||
api_models::payments::Address,
|
api_models::payments::Address,
|
||||||
api_models::payments::BankRedirectData,
|
api_models::payments::BankRedirectData,
|
||||||
api_models::payments::BankRedirectBilling,
|
api_models::payments::BankRedirectBilling,
|
||||||
|
api_models::payments::BankRedirectBilling,
|
||||||
api_models::payments::OrderDetails,
|
api_models::payments::OrderDetails,
|
||||||
api_models::payments::NextActionType,
|
api_models::payments::NextActionType,
|
||||||
api_models::payments::Metadata,
|
api_models::payments::Metadata,
|
||||||
|
|||||||
@ -456,6 +456,7 @@ pub enum PaymentMethod {
|
|||||||
Wallet,
|
Wallet,
|
||||||
BankRedirect,
|
BankRedirect,
|
||||||
Crypto,
|
Crypto,
|
||||||
|
BankDebit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
@ -612,11 +613,14 @@ pub enum MandateStatus {
|
|||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum PaymentMethodType {
|
pub enum PaymentMethodType {
|
||||||
|
Ach,
|
||||||
Affirm,
|
Affirm,
|
||||||
AfterpayClearpay,
|
AfterpayClearpay,
|
||||||
AliPay,
|
AliPay,
|
||||||
ApplePay,
|
ApplePay,
|
||||||
|
Bacs,
|
||||||
BancontactCard,
|
BancontactCard,
|
||||||
|
Becs,
|
||||||
Blik,
|
Blik,
|
||||||
Credit,
|
Credit,
|
||||||
CryptoCurrency,
|
CryptoCurrency,
|
||||||
@ -635,6 +639,7 @@ pub enum PaymentMethodType {
|
|||||||
PayBright,
|
PayBright,
|
||||||
Paypal,
|
Paypal,
|
||||||
Przelewy24,
|
Przelewy24,
|
||||||
|
Sepa,
|
||||||
Sofort,
|
Sofort,
|
||||||
Swish,
|
Swish,
|
||||||
Trustly,
|
Trustly,
|
||||||
|
|||||||
Reference in New Issue
Block a user