mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 11:24:45 +08:00
refactor(connector): [STRIPE] Bank Transfer Api Refactor (#7599)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
pub mod transformers;
|
||||
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use common_utils::{
|
||||
request::RequestContent,
|
||||
@ -19,7 +19,6 @@ use super::utils::{self as connector_utils, PaymentMethodDataType, RefundsReques
|
||||
use super::utils::{PayoutsData, RouterData};
|
||||
use crate::{
|
||||
configs::settings,
|
||||
connector::utils::PaymentsPreProcessingData,
|
||||
consts,
|
||||
core::{
|
||||
errors::{self, CustomResult},
|
||||
@ -203,142 +202,6 @@ impl
|
||||
// Not Implemented (R)
|
||||
}
|
||||
|
||||
impl api::PaymentsPreProcessing for Stripe {}
|
||||
|
||||
impl
|
||||
services::ConnectorIntegration<
|
||||
api::PreProcessing,
|
||||
types::PaymentsPreProcessingData,
|
||||
types::PaymentsResponseData,
|
||||
> for Stripe
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &types::PaymentsPreProcessingRouterData,
|
||||
_connectors: &settings::Connectors,
|
||||
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
|
||||
let mut header = vec![(
|
||||
headers::CONTENT_TYPE.to_string(),
|
||||
types::PaymentsPreProcessingType::get_content_type(self)
|
||||
.to_string()
|
||||
.into(),
|
||||
)];
|
||||
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
||||
header.append(&mut api_key);
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
self.common_get_content_type()
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &types::PaymentsPreProcessingRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
Ok(format!("{}{}", self.base_url(connectors), "v1/sources"))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &types::PaymentsPreProcessingRouterData,
|
||||
_connectors: &settings::Connectors,
|
||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||
let req_currency = req.request.get_currency()?;
|
||||
let req_amount = req.request.get_minor_amount()?;
|
||||
let amount =
|
||||
connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?;
|
||||
let connector_req =
|
||||
stripe::StripeCreditTransferSourceRequest::try_from((req, amount, req_currency))?;
|
||||
Ok(RequestContent::FormUrlEncoded(Box::new(connector_req)))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &types::PaymentsPreProcessingRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||
Ok(Some(
|
||||
services::RequestBuilder::new()
|
||||
.method(services::Method::Post)
|
||||
.url(&types::PaymentsPreProcessingType::get_url(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.attach_default_headers()
|
||||
.headers(types::PaymentsPreProcessingType::get_headers(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.set_body(types::PaymentsPreProcessingType::get_request_body(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &types::PaymentsPreProcessingRouterData,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
res: types::Response,
|
||||
) -> CustomResult<types::PaymentsPreProcessingRouterData, errors::ConnectorError> {
|
||||
let response: stripe::StripeSourceResponse = res
|
||||
.response
|
||||
.parse_struct("StripeSourceResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: types::Response,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||
let response: stripe::ErrorResponse = res
|
||||
.response
|
||||
.parse_struct("ErrorResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
event_builder.map(|i| i.set_error_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
|
||||
Ok(types::ErrorResponse {
|
||||
status_code: res.status_code,
|
||||
code: response
|
||||
.error
|
||||
.code
|
||||
.clone()
|
||||
.unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
|
||||
message: response
|
||||
.error
|
||||
.code
|
||||
.unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
|
||||
reason: response.error.message.map(|message| {
|
||||
response
|
||||
.error
|
||||
.decline_code
|
||||
.map(|decline_code| {
|
||||
format!("message - {}, decline_code - {}", message, decline_code)
|
||||
})
|
||||
.unwrap_or(message)
|
||||
}),
|
||||
attempt_status: None,
|
||||
connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
|
||||
issuer_error_code: None,
|
||||
issuer_error_message: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl api::ConnectorCustomer for Stripe {}
|
||||
|
||||
impl
|
||||
@ -978,29 +841,14 @@ impl
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
req: &types::PaymentsAuthorizeRouterData,
|
||||
_req: &types::PaymentsAuthorizeRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
match &req.request.payment_method_data {
|
||||
domain::PaymentMethodData::BankTransfer(bank_transfer_data) => {
|
||||
match bank_transfer_data.deref() {
|
||||
domain::BankTransferData::AchBankTransfer { .. }
|
||||
| domain::BankTransferData::MultibancoBankTransfer { .. } => {
|
||||
Ok(format!("{}{}", self.base_url(connectors), "v1/charges"))
|
||||
}
|
||||
_ => Ok(format!(
|
||||
"{}{}",
|
||||
self.base_url(connectors),
|
||||
"v1/payment_intents"
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => Ok(format!(
|
||||
"{}{}",
|
||||
self.base_url(connectors),
|
||||
"v1/payment_intents"
|
||||
)),
|
||||
}
|
||||
Ok(format!(
|
||||
"{}{}",
|
||||
self.base_url(connectors),
|
||||
"v1/payment_intents"
|
||||
))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
@ -1013,16 +861,9 @@ impl
|
||||
req.request.minor_amount,
|
||||
req.request.currency,
|
||||
)?;
|
||||
match &req.request.payment_method_data {
|
||||
domain::PaymentMethodData::BankTransfer(bank_transfer_data) => {
|
||||
stripe::get_bank_transfer_request_data(req, bank_transfer_data.deref(), amount)
|
||||
}
|
||||
_ => {
|
||||
let connector_req = stripe::PaymentIntentRequest::try_from((req, amount))?;
|
||||
let connector_req = stripe::PaymentIntentRequest::try_from((req, amount))?;
|
||||
|
||||
Ok(RequestContent::FormUrlEncoded(Box::new(connector_req)))
|
||||
}
|
||||
}
|
||||
Ok(RequestContent::FormUrlEncoded(Box::new(connector_req)))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
@ -1053,94 +894,31 @@ impl
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
res: types::Response,
|
||||
) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
|
||||
match &data.request.payment_method_data {
|
||||
domain::PaymentMethodData::BankTransfer(bank_transfer_data) => match bank_transfer_data
|
||||
.deref()
|
||||
{
|
||||
domain::BankTransferData::AchBankTransfer { .. }
|
||||
| domain::BankTransferData::MultibancoBankTransfer { .. } => {
|
||||
let response: stripe::ChargesResponse = res
|
||||
.response
|
||||
.parse_struct("ChargesResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
let response: stripe::PaymentIntentResponse = res
|
||||
.response
|
||||
.parse_struct("PaymentIntentResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
let response_integrity_object =
|
||||
connector_utils::get_authorise_integrity_object(
|
||||
self.amount_converter,
|
||||
response.amount,
|
||||
response.currency.clone(),
|
||||
)?;
|
||||
let response_integrity_object = connector_utils::get_authorise_integrity_object(
|
||||
self.amount_converter,
|
||||
response.amount,
|
||||
response.currency.clone(),
|
||||
)?;
|
||||
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
|
||||
let new_router_data = types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
});
|
||||
let new_router_data = types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed);
|
||||
|
||||
new_router_data.map(|mut router_data| {
|
||||
router_data.request.integrity_object = Some(response_integrity_object);
|
||||
router_data
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
let response: stripe::PaymentIntentResponse = res
|
||||
.response
|
||||
.parse_struct("PaymentIntentResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
let response_integrity_object =
|
||||
connector_utils::get_authorise_integrity_object(
|
||||
self.amount_converter,
|
||||
response.amount,
|
||||
response.currency.clone(),
|
||||
)?;
|
||||
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
|
||||
let new_router_data = types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
});
|
||||
|
||||
new_router_data.map(|mut router_data| {
|
||||
router_data.request.integrity_object = Some(response_integrity_object);
|
||||
router_data
|
||||
})
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
let response: stripe::PaymentIntentResponse = res
|
||||
.response
|
||||
.parse_struct("PaymentIntentResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
|
||||
let response_integrity_object = connector_utils::get_authorise_integrity_object(
|
||||
self.amount_converter,
|
||||
response.amount,
|
||||
response.currency.clone(),
|
||||
)?;
|
||||
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
|
||||
let new_router_data = types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed);
|
||||
|
||||
new_router_data.map(|mut router_data| {
|
||||
router_data.request.integrity_object = Some(response_integrity_object);
|
||||
router_data
|
||||
})
|
||||
}
|
||||
}
|
||||
new_router_data.map(|mut router_data| {
|
||||
router_data.request.integrity_object = Some(response_integrity_object);
|
||||
router_data
|
||||
})
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
use api_models::{self, enums as api_enums};
|
||||
use api_models::{self, enums as api_enums, payments};
|
||||
use common_utils::{
|
||||
errors::CustomResult,
|
||||
ext_traits::{ByteSliceExt, Encode},
|
||||
@ -8,7 +8,6 @@ use common_utils::{
|
||||
request::RequestContent,
|
||||
types::MinorUnit,
|
||||
};
|
||||
use diesel_models::enums as storage_enums;
|
||||
use error_stack::ResultExt;
|
||||
use hyperswitch_domain_models::mandates::AcceptanceType;
|
||||
use masking::{ExposeInterface, ExposeOptionInterface, Mask, PeekInterface, Secret};
|
||||
@ -22,9 +21,7 @@ pub mod connect;
|
||||
pub use self::connect::*;
|
||||
use crate::{
|
||||
collect_missing_value_keys,
|
||||
connector::utils::{
|
||||
self as connector_util, ApplePay, ApplePayDecrypt, PaymentsPreProcessingData, RouterData,
|
||||
},
|
||||
connector::utils::{self as connector_util, ApplePay, ApplePayDecrypt, RouterData},
|
||||
consts,
|
||||
core::errors,
|
||||
headers, services,
|
||||
@ -394,13 +391,23 @@ pub struct StripeOnlineBankingFpx {
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct AchTransferData {
|
||||
#[serde(rename = "owner[email]")]
|
||||
pub email: Email,
|
||||
#[serde(rename = "payment_method_data[type]")]
|
||||
pub payment_method_data_type: StripePaymentMethodType,
|
||||
#[serde(rename = "payment_method_options[customer_balance][bank_transfer][type]")]
|
||||
pub bank_transfer_type: StripeCreditTransferTypes,
|
||||
#[serde(rename = "payment_method_types[0]")]
|
||||
pub payment_method_type: StripePaymentMethodType,
|
||||
#[serde(rename = "payment_method_options[customer_balance][funding_type]")]
|
||||
pub balance_funding_type: BankTransferType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct MultibancoTransferData {
|
||||
#[serde(rename = "owner[email]")]
|
||||
#[serde(rename = "payment_method_data[type]")]
|
||||
pub payment_method_data_type: StripeCreditTransferTypes,
|
||||
#[serde(rename = "payment_method_types[0]")]
|
||||
pub payment_method_type: StripeCreditTransferTypes,
|
||||
#[serde(rename = "payment_method_data[billing_details][email]")]
|
||||
pub email: Email,
|
||||
}
|
||||
|
||||
@ -658,6 +665,7 @@ pub enum StripePaymentMethodType {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[allow(dead_code)]
|
||||
pub enum StripeCreditTransferTypes {
|
||||
#[serde(rename = "us_bank_transfer")]
|
||||
AchCreditTransfer,
|
||||
Multibanco,
|
||||
Blik,
|
||||
@ -1233,11 +1241,10 @@ fn create_stripe_payment_method(
|
||||
domain::BankTransferData::AchBankTransfer {} => Ok((
|
||||
StripePaymentMethodData::BankTransfer(StripeBankTransferData::AchBankTransfer(
|
||||
Box::new(AchTransferData {
|
||||
email: billing_address.email.ok_or(
|
||||
errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "billing_address.email",
|
||||
},
|
||||
)?,
|
||||
payment_method_data_type: StripePaymentMethodType::CustomerBalance,
|
||||
bank_transfer_type: StripeCreditTransferTypes::AchCreditTransfer,
|
||||
payment_method_type: StripePaymentMethodType::CustomerBalance,
|
||||
balance_funding_type: BankTransferType::BankTransfers,
|
||||
}),
|
||||
)),
|
||||
None,
|
||||
@ -1247,6 +1254,8 @@ fn create_stripe_payment_method(
|
||||
StripePaymentMethodData::BankTransfer(
|
||||
StripeBankTransferData::MultibancoBankTransfers(Box::new(
|
||||
MultibancoTransferData {
|
||||
payment_method_data_type: StripeCreditTransferTypes::Multibanco,
|
||||
payment_method_type: StripeCreditTransferTypes::Multibanco,
|
||||
email: billing_address.email.ok_or(
|
||||
errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "billing_address.email",
|
||||
@ -1739,18 +1748,14 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent
|
||||
.clone()
|
||||
.and_then(|mandate_ids| mandate_ids.mandate_reference_id)
|
||||
{
|
||||
Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
|
||||
connector_mandate_ids,
|
||||
)) => (
|
||||
Some(payments::MandateReferenceId::ConnectorMandateId(connector_mandate_ids)) => (
|
||||
None,
|
||||
connector_mandate_ids.get_connector_mandate_id(),
|
||||
StripeBillingAddress::default(),
|
||||
get_payment_method_type_for_saved_payment_method_payment(item)?,
|
||||
None,
|
||||
),
|
||||
Some(api_models::payments::MandateReferenceId::NetworkMandateId(
|
||||
network_transaction_id,
|
||||
)) => {
|
||||
Some(payments::MandateReferenceId::NetworkMandateId(network_transaction_id)) => {
|
||||
payment_method_options = Some(StripePaymentMethodOptions::Card {
|
||||
mandate_options: None,
|
||||
network_transaction_id: None,
|
||||
@ -1815,7 +1820,7 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent
|
||||
None,
|
||||
)
|
||||
}
|
||||
Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI(_)) | None => {
|
||||
Some(payments::MandateReferenceId::NetworkTokenWithNTI(_)) | None => {
|
||||
let (payment_method_data, payment_method_type, billing_address) =
|
||||
create_stripe_payment_method(
|
||||
&item.request.payment_method_data,
|
||||
@ -2589,34 +2594,75 @@ pub fn get_connector_metadata(
|
||||
let next_action_response = next_action
|
||||
.and_then(|next_action_response| match next_action_response {
|
||||
StripeNextActionResponse::DisplayBankTransferInstructions(response) => {
|
||||
let bank_instructions = response.financial_addresses.first();
|
||||
let (sepa_bank_instructions, bacs_bank_instructions) =
|
||||
bank_instructions.map_or((None, None), |financial_address| {
|
||||
(
|
||||
financial_address
|
||||
.iban
|
||||
.to_owned()
|
||||
.map(|sepa_financial_details| SepaFinancialDetails {
|
||||
account_holder_name: sepa_financial_details.account_holder_name,
|
||||
bic: sepa_financial_details.bic,
|
||||
country: sepa_financial_details.country,
|
||||
iban: sepa_financial_details.iban,
|
||||
reference: response.reference.to_owned(),
|
||||
}),
|
||||
financial_address.sort_code.to_owned(),
|
||||
)
|
||||
});
|
||||
match response.financial_addresses.clone() {
|
||||
FinancialInformation::StripeFinancialInformation(financial_addresses) => {
|
||||
let bank_instructions = financial_addresses.first();
|
||||
let (sepa_bank_instructions, bacs_bank_instructions) = bank_instructions
|
||||
.map_or((None, None), |financial_address| {
|
||||
(
|
||||
financial_address.iban.to_owned().map(
|
||||
|sepa_financial_details| SepaFinancialDetails {
|
||||
account_holder_name: sepa_financial_details
|
||||
.account_holder_name,
|
||||
bic: sepa_financial_details.bic,
|
||||
country: sepa_financial_details.country,
|
||||
iban: sepa_financial_details.iban,
|
||||
reference: response.reference.to_owned(),
|
||||
},
|
||||
),
|
||||
financial_address.sort_code.to_owned(),
|
||||
)
|
||||
});
|
||||
let bank_transfer_instructions = SepaAndBacsBankTransferInstructions {
|
||||
sepa_bank_instructions,
|
||||
bacs_bank_instructions,
|
||||
receiver: SepaAndBacsReceiver {
|
||||
amount_received: amount - response.amount_remaining,
|
||||
amount_remaining: response.amount_remaining,
|
||||
},
|
||||
};
|
||||
|
||||
let bank_transfer_instructions = SepaAndBacsBankTransferInstructions {
|
||||
sepa_bank_instructions,
|
||||
bacs_bank_instructions,
|
||||
receiver: SepaAndBacsReceiver {
|
||||
amount_received: amount - response.amount_remaining,
|
||||
amount_remaining: response.amount_remaining,
|
||||
},
|
||||
};
|
||||
Some(bank_transfer_instructions.encode_to_value())
|
||||
}
|
||||
FinancialInformation::AchFinancialInformation(financial_addresses) => {
|
||||
let mut ach_financial_information = HashMap::new();
|
||||
for address in financial_addresses {
|
||||
match address.financial_details {
|
||||
AchFinancialDetails::Aba(aba_details) => {
|
||||
ach_financial_information
|
||||
.insert("account_number", aba_details.account_number);
|
||||
ach_financial_information
|
||||
.insert("bank_name", aba_details.bank_name);
|
||||
ach_financial_information
|
||||
.insert("routing_number", aba_details.routing_number);
|
||||
}
|
||||
AchFinancialDetails::Swift(swift_details) => {
|
||||
ach_financial_information
|
||||
.insert("swift_code", swift_details.swift_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(bank_transfer_instructions.encode_to_value())
|
||||
let ach_financial_information_value =
|
||||
serde_json::to_value(ach_financial_information).ok()?;
|
||||
|
||||
let ach_transfer_instruction =
|
||||
serde_json::from_value::<payments::AchTransfer>(
|
||||
ach_financial_information_value,
|
||||
)
|
||||
.ok()?;
|
||||
|
||||
let bank_transfer_instructions = payments::BankTransferNextStepsData {
|
||||
bank_transfer_instructions:
|
||||
payments::BankTransferInstructions::AchCreditTransfer(Box::new(
|
||||
ach_transfer_instruction,
|
||||
)),
|
||||
receiver: None,
|
||||
};
|
||||
|
||||
Some(bank_transfer_instructions.encode_to_value())
|
||||
}
|
||||
}
|
||||
}
|
||||
StripeNextActionResponse::WechatPayDisplayQrCode(response) => {
|
||||
let wechat_pay_instructions = QrCodeNextInstructions {
|
||||
@ -2633,6 +2679,18 @@ pub fn get_connector_metadata(
|
||||
};
|
||||
Some(cashapp_qr_instructions.encode_to_value())
|
||||
}
|
||||
StripeNextActionResponse::MultibancoDisplayDetails(response) => {
|
||||
let multibanco_bank_transfer_instructions = payments::BankTransferNextStepsData {
|
||||
bank_transfer_instructions: payments::BankTransferInstructions::Multibanco(
|
||||
Box::new(payments::MultibancoTransferInstructions {
|
||||
reference: response.clone().reference,
|
||||
entity: response.clone().entity.expose(),
|
||||
}),
|
||||
),
|
||||
receiver: None,
|
||||
};
|
||||
Some(multibanco_bank_transfer_instructions.encode_to_value())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.transpose()
|
||||
@ -2886,6 +2944,7 @@ pub enum StripeNextActionResponse {
|
||||
VerifyWithMicrodeposits(StripeVerifyWithMicroDepositsResponse),
|
||||
WechatPayDisplayQrCode(WechatPayRedirectToQr),
|
||||
DisplayBankTransferInstructions(StripeBankTransferDetails),
|
||||
MultibancoDisplayDetails(MultibancoCreditTansferResponse),
|
||||
NoNextActionBody,
|
||||
}
|
||||
|
||||
@ -2901,6 +2960,7 @@ impl StripeNextActionResponse {
|
||||
}
|
||||
Self::CashappHandleRedirectOrDisplayQrCode(_) => None,
|
||||
Self::DisplayBankTransferInstructions(_) => None,
|
||||
Self::MultibancoDisplayDetails(_) => None,
|
||||
Self::NoNextActionBody => None,
|
||||
}
|
||||
}
|
||||
@ -2950,6 +3010,7 @@ impl Serialize for StripeNextActionResponse {
|
||||
Self::VerifyWithMicrodeposits(ref i) => Serialize::serialize(i, serializer),
|
||||
Self::WechatPayDisplayQrCode(ref i) => Serialize::serialize(i, serializer),
|
||||
Self::DisplayBankTransferInstructions(ref i) => Serialize::serialize(i, serializer),
|
||||
Self::MultibancoDisplayDetails(ref i) => Serialize::serialize(i, serializer),
|
||||
Self::NoNextActionBody => Serialize::serialize("NoNextActionBody", serializer),
|
||||
}
|
||||
}
|
||||
@ -2975,11 +3036,18 @@ pub struct StripeVerifyWithMicroDepositsResponse {
|
||||
hosted_verification_url: Url,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum FinancialInformation {
|
||||
AchFinancialInformation(Vec<AchFinancialInformation>),
|
||||
StripeFinancialInformation(Vec<StripeFinancialInformation>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct StripeBankTransferDetails {
|
||||
pub amount_remaining: MinorUnit,
|
||||
pub currency: String,
|
||||
pub financial_addresses: Vec<StripeFinancialInformation>,
|
||||
pub financial_addresses: FinancialInformation,
|
||||
pub hosted_instructions_url: Option<String>,
|
||||
pub reference: Option<String>,
|
||||
#[serde(rename = "type")]
|
||||
@ -3000,6 +3068,27 @@ pub struct QrCodeResponse {
|
||||
pub image_url_svg: Url,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct AbaDetails {
|
||||
pub account_number: Secret<String>,
|
||||
pub bank_name: Secret<String>,
|
||||
pub routing_number: Secret<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct SwiftDetails {
|
||||
pub account_number: Secret<String>,
|
||||
pub bank_name: Secret<String>,
|
||||
pub swift_code: Secret<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AchFinancialDetails {
|
||||
Aba(AbaDetails),
|
||||
Swift(SwiftDetails),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct StripeFinancialInformation {
|
||||
pub iban: Option<SepaFinancialDetails>,
|
||||
@ -3009,6 +3098,15 @@ pub struct StripeFinancialInformation {
|
||||
pub financial_info_type: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct AchFinancialInformation {
|
||||
#[serde(flatten)]
|
||||
pub financial_details: AchFinancialDetails,
|
||||
pub supported_networks: Vec<String>,
|
||||
#[serde(rename = "type")]
|
||||
pub financial_info_type: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct SepaFinancialDetails {
|
||||
pub account_holder_name: Secret<String>,
|
||||
@ -3380,95 +3478,6 @@ impl TryFrom<MinorUnit> for CaptureRequest {
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<(
|
||||
&types::PaymentsPreProcessingRouterData,
|
||||
MinorUnit,
|
||||
storage_enums::Currency,
|
||||
)> for StripeCreditTransferSourceRequest
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(
|
||||
data: (
|
||||
&types::PaymentsPreProcessingRouterData,
|
||||
MinorUnit,
|
||||
storage_enums::Currency,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let item = data.0;
|
||||
let currency = data.2;
|
||||
let amount = data.1;
|
||||
match &item.request.payment_method_data {
|
||||
Some(domain::PaymentMethodData::BankTransfer(bank_transfer_data)) => {
|
||||
match **bank_transfer_data {
|
||||
domain::BankTransferData::MultibancoBankTransfer { .. } => Ok(
|
||||
Self::MultibancoBankTansfer(MultibancoCreditTransferSourceRequest {
|
||||
transfer_type: StripeCreditTransferTypes::Multibanco,
|
||||
currency,
|
||||
payment_method_data: MultibancoTransferData {
|
||||
email: item.get_billing_email().or(item.request.get_email())?,
|
||||
},
|
||||
amount: Some(amount),
|
||||
return_url: Some(item.request.get_router_return_url()?),
|
||||
}),
|
||||
),
|
||||
domain::BankTransferData::AchBankTransfer { .. } => {
|
||||
Ok(Self::AchBankTansfer(AchCreditTransferSourceRequest {
|
||||
transfer_type: StripeCreditTransferTypes::AchCreditTransfer,
|
||||
payment_method_data: AchTransferData {
|
||||
email: item.get_billing_email().or(item.request.get_email())?,
|
||||
},
|
||||
currency,
|
||||
}))
|
||||
}
|
||||
domain::BankTransferData::SepaBankTransfer { .. }
|
||||
| domain::BankTransferData::BacsBankTransfer { .. }
|
||||
| domain::BankTransferData::PermataBankTransfer { .. }
|
||||
| domain::BankTransferData::BcaBankTransfer { .. }
|
||||
| domain::BankTransferData::BniVaBankTransfer { .. }
|
||||
| domain::BankTransferData::BriVaBankTransfer { .. }
|
||||
| domain::BankTransferData::CimbVaBankTransfer { .. }
|
||||
| domain::BankTransferData::DanamonVaBankTransfer { .. }
|
||||
| domain::BankTransferData::MandiriVaBankTransfer { .. }
|
||||
| domain::BankTransferData::LocalBankTransfer { .. }
|
||||
| domain::BankTransferData::InstantBankTransfer {}
|
||||
| domain::BankTransferData::Pix { .. }
|
||||
| domain::BankTransferData::Pse { .. } => {
|
||||
Err(errors::ConnectorError::NotImplemented(
|
||||
connector_util::get_unimplemented_payment_method_error_message(
|
||||
"stripe",
|
||||
),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(domain::PaymentMethodData::Card(..))
|
||||
| Some(domain::PaymentMethodData::Wallet(..))
|
||||
| Some(domain::PaymentMethodData::BankDebit(..))
|
||||
| Some(domain::PaymentMethodData::BankRedirect(..))
|
||||
| Some(domain::PaymentMethodData::PayLater(..))
|
||||
| Some(domain::PaymentMethodData::Crypto(..))
|
||||
| Some(domain::PaymentMethodData::Reward)
|
||||
| Some(domain::PaymentMethodData::RealTimePayment(..))
|
||||
| Some(domain::PaymentMethodData::MobilePayment(..))
|
||||
| Some(domain::PaymentMethodData::MandatePayment)
|
||||
| Some(domain::PaymentMethodData::Upi(..))
|
||||
| Some(domain::PaymentMethodData::GiftCard(..))
|
||||
| Some(domain::PaymentMethodData::CardRedirect(..))
|
||||
| Some(domain::PaymentMethodData::Voucher(..))
|
||||
| Some(domain::PaymentMethodData::OpenBanking(..))
|
||||
| Some(domain::PaymentMethodData::CardToken(..))
|
||||
| Some(domain::PaymentMethodData::NetworkToken(..))
|
||||
| Some(domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_))
|
||||
| None => Err(errors::ConnectorError::NotImplemented(
|
||||
connector_util::get_unimplemented_payment_method_error_message("stripe"),
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T>
|
||||
TryFrom<types::ResponseRouterData<F, StripeSourceResponse, T, types::PaymentsResponseData>>
|
||||
for types::RouterData<F, T, types::PaymentsResponseData>
|
||||
@ -3865,12 +3874,17 @@ impl
|
||||
{
|
||||
domain::BankTransferData::AchBankTransfer {} => Ok(Self::BankTransfer(
|
||||
StripeBankTransferData::AchBankTransfer(Box::new(AchTransferData {
|
||||
email: item.get_billing_email()?,
|
||||
payment_method_data_type: StripePaymentMethodType::CustomerBalance,
|
||||
bank_transfer_type: StripeCreditTransferTypes::AchCreditTransfer,
|
||||
payment_method_type: StripePaymentMethodType::CustomerBalance,
|
||||
balance_funding_type: BankTransferType::BankTransfers,
|
||||
})),
|
||||
)),
|
||||
domain::BankTransferData::MultibancoBankTransfer {} => Ok(Self::BankTransfer(
|
||||
StripeBankTransferData::MultibancoBankTransfers(Box::new(
|
||||
MultibancoTransferData {
|
||||
payment_method_data_type: StripeCreditTransferTypes::Multibanco,
|
||||
payment_method_type: StripeCreditTransferTypes::Multibanco,
|
||||
email: item.get_billing_email()?,
|
||||
},
|
||||
)),
|
||||
|
||||
@ -4479,26 +4479,7 @@ where
|
||||
}
|
||||
//TODO: For ACH transfers, if preprocessing_step is not required for connectors encountered in future, add the check
|
||||
let router_data_and_should_continue_payment = match payment_data.get_payment_method_data() {
|
||||
Some(domain::PaymentMethodData::BankTransfer(data)) => match data.deref() {
|
||||
domain::BankTransferData::AchBankTransfer { .. }
|
||||
| domain::BankTransferData::MultibancoBankTransfer { .. }
|
||||
if connector.connector_name == router_types::Connector::Stripe =>
|
||||
{
|
||||
if payment_data
|
||||
.get_payment_attempt()
|
||||
.preprocessing_step_id
|
||||
.is_none()
|
||||
{
|
||||
(
|
||||
router_data.preprocessing_steps(state, connector).await?,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
(router_data, should_continue_payment)
|
||||
}
|
||||
}
|
||||
_ => (router_data, should_continue_payment),
|
||||
},
|
||||
Some(domain::PaymentMethodData::BankTransfer(_)) => (router_data, should_continue_payment),
|
||||
Some(domain::PaymentMethodData::Wallet(_)) => {
|
||||
if is_preprocessing_required_for_wallets(connector.connector_name.to_string()) {
|
||||
(
|
||||
|
||||
@ -632,6 +632,7 @@ default_imp_for_pre_processing_steps!(
|
||||
connector::Plaid,
|
||||
connector::Riskified,
|
||||
connector::Signifyd,
|
||||
connector::Stripe,
|
||||
connector::Threedsecureio,
|
||||
connector::Wellsfargopayout,
|
||||
connector::Wise
|
||||
|
||||
Reference in New Issue
Block a user