mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
feat(connector): [STRIPE] Added Connector Tokenization Flow for Cards (#8248)
Co-authored-by: Sayak Bhattacharya <sayak.b@Sayak-Bhattacharya-G092THXJ34.local>
This commit is contained in:
committed by
GitHub
parent
a88eebdec7
commit
8129260238
@ -263,6 +263,23 @@ impl ConnectorIntegration<CreateConnectorCustomer, ConnectorCustomerData, Paymen
|
|||||||
.to_string()
|
.to_string()
|
||||||
.into(),
|
.into(),
|
||||||
)];
|
)];
|
||||||
|
if let Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(
|
||||||
|
stripe_split_payment,
|
||||||
|
)) = &req.request.split_payments
|
||||||
|
{
|
||||||
|
if stripe_split_payment.charge_type
|
||||||
|
== PaymentChargeType::Stripe(StripeChargeType::Direct)
|
||||||
|
{
|
||||||
|
let mut customer_account_header = vec![(
|
||||||
|
STRIPE_COMPATIBLE_CONNECT_ACCOUNT.to_string(),
|
||||||
|
stripe_split_payment
|
||||||
|
.transfer_account_id
|
||||||
|
.clone()
|
||||||
|
.into_masked(),
|
||||||
|
)];
|
||||||
|
header.append(&mut customer_account_header);
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
||||||
header.append(&mut api_key);
|
header.append(&mut api_key);
|
||||||
Ok(header)
|
Ok(header)
|
||||||
@ -389,6 +406,23 @@ impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, Pay
|
|||||||
CONTENT_TYPE.to_string(),
|
CONTENT_TYPE.to_string(),
|
||||||
TokenizationType::get_content_type(self).to_string().into(),
|
TokenizationType::get_content_type(self).to_string().into(),
|
||||||
)];
|
)];
|
||||||
|
if let Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(
|
||||||
|
stripe_split_payment,
|
||||||
|
)) = &req.request.split_payments
|
||||||
|
{
|
||||||
|
if stripe_split_payment.charge_type
|
||||||
|
== PaymentChargeType::Stripe(StripeChargeType::Direct)
|
||||||
|
{
|
||||||
|
let mut customer_account_header = vec![(
|
||||||
|
STRIPE_COMPATIBLE_CONNECT_ACCOUNT.to_string(),
|
||||||
|
stripe_split_payment
|
||||||
|
.transfer_account_id
|
||||||
|
.clone()
|
||||||
|
.into_masked(),
|
||||||
|
)];
|
||||||
|
header.append(&mut customer_account_header);
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
|
||||||
header.append(&mut api_key);
|
header.append(&mut api_key);
|
||||||
Ok(header)
|
Ok(header)
|
||||||
@ -400,9 +434,19 @@ impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, Pay
|
|||||||
|
|
||||||
fn get_url(
|
fn get_url(
|
||||||
&self,
|
&self,
|
||||||
_req: &TokenizationRouterData,
|
req: &TokenizationRouterData,
|
||||||
connectors: &Connectors,
|
connectors: &Connectors,
|
||||||
) -> CustomResult<String, ConnectorError> {
|
) -> CustomResult<String, ConnectorError> {
|
||||||
|
if matches!(
|
||||||
|
req.request.split_payments,
|
||||||
|
Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(_))
|
||||||
|
) {
|
||||||
|
return Ok(format!(
|
||||||
|
"{}{}",
|
||||||
|
self.base_url(connectors),
|
||||||
|
"v1/payment_methods"
|
||||||
|
));
|
||||||
|
}
|
||||||
Ok(format!("{}{}", self.base_url(connectors), "v1/tokens"))
|
Ok(format!("{}{}", self.base_url(connectors), "v1/tokens"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,7 +570,6 @@ impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> fo
|
|||||||
connectors: &Connectors,
|
connectors: &Connectors,
|
||||||
) -> CustomResult<String, ConnectorError> {
|
) -> CustomResult<String, ConnectorError> {
|
||||||
let id = req.request.connector_transaction_id.as_str();
|
let id = req.request.connector_transaction_id.as_str();
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"{}{}/{}/capture",
|
"{}{}/{}/capture",
|
||||||
self.base_url(connectors),
|
self.base_url(connectors),
|
||||||
|
|||||||
@ -37,7 +37,7 @@ use hyperswitch_domain_models::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use hyperswitch_interfaces::{consts, errors::ConnectorError};
|
use hyperswitch_interfaces::{consts, errors::ConnectorError};
|
||||||
use masking::{ExposeInterface, ExposeOptionInterface, Mask, Maskable, PeekInterface, Secret};
|
use masking::{ExposeInterface, Mask, Maskable, PeekInterface, Secret};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use time::PrimitiveDateTime;
|
use time::PrimitiveDateTime;
|
||||||
@ -170,7 +170,7 @@ pub struct PaymentIntentRequest {
|
|||||||
pub meta_data: HashMap<String, String>,
|
pub meta_data: HashMap<String, String>,
|
||||||
pub return_url: String,
|
pub return_url: String,
|
||||||
pub confirm: bool,
|
pub confirm: bool,
|
||||||
pub payment_method: Option<String>,
|
pub payment_method: Option<Secret<String>>,
|
||||||
pub customer: Option<Secret<String>>,
|
pub customer: Option<Secret<String>>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub setup_mandate_details: Option<StripeMandateRequest>,
|
pub setup_mandate_details: Option<StripeMandateRequest>,
|
||||||
@ -486,9 +486,28 @@ pub enum StripePaymentMethodData {
|
|||||||
BankTransfer(StripeBankTransferData),
|
BankTransfer(StripeBankTransferData),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize)]
|
||||||
|
pub struct StripeBillingAddressCardToken {
|
||||||
|
#[serde(rename = "billing_details[name]")]
|
||||||
|
pub name: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "billing_details[email]")]
|
||||||
|
pub email: Option<Email>,
|
||||||
|
#[serde(rename = "billing_details[phone]")]
|
||||||
|
pub phone: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "billing_details[address][line1]")]
|
||||||
|
pub address_line1: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "billing_details[address][line2]")]
|
||||||
|
pub address_line2: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "billing_details[address][state]")]
|
||||||
|
pub state: Option<Secret<String>>,
|
||||||
|
#[serde(rename = "billing_details[address][city]")]
|
||||||
|
pub city: Option<String>,
|
||||||
|
}
|
||||||
// Struct to call the Stripe tokens API to create a PSP token for the card details provided
|
// Struct to call the Stripe tokens API to create a PSP token for the card details provided
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
pub struct StripeCardToken {
|
pub struct StripeCardToken {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub payment_method_type: Option<StripePaymentMethodType>,
|
||||||
#[serde(rename = "card[number]")]
|
#[serde(rename = "card[number]")]
|
||||||
pub token_card_number: cards::CardNumber,
|
pub token_card_number: cards::CardNumber,
|
||||||
#[serde(rename = "card[exp_month]")]
|
#[serde(rename = "card[exp_month]")]
|
||||||
@ -497,6 +516,8 @@ pub struct StripeCardToken {
|
|||||||
pub token_card_exp_year: Secret<String>,
|
pub token_card_exp_year: Secret<String>,
|
||||||
#[serde(rename = "card[cvc]")]
|
#[serde(rename = "card[cvc]")]
|
||||||
pub token_card_cvc: Secret<String>,
|
pub token_card_cvc: Secret<String>,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub billing: StripeBillingAddressCardToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
@ -1642,80 +1663,51 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
type Error = error_stack::Report<ConnectorError>;
|
type Error = error_stack::Report<ConnectorError>;
|
||||||
fn try_from(data: (&PaymentsAuthorizeRouterData, MinorUnit)) -> Result<Self, Self::Error> {
|
fn try_from(data: (&PaymentsAuthorizeRouterData, MinorUnit)) -> Result<Self, Self::Error> {
|
||||||
let item = data.0;
|
let item = data.0;
|
||||||
|
|
||||||
|
let payment_method_token = match &item.request.split_payments {
|
||||||
|
Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(_)) => {
|
||||||
|
match item.payment_method_token.clone() {
|
||||||
|
Some(PaymentMethodToken::Token(secret)) => Some(secret),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let amount = data.1;
|
let amount = data.1;
|
||||||
let order_id = item.connector_request_reference_id.clone();
|
let order_id = item.connector_request_reference_id.clone();
|
||||||
|
|
||||||
let shipping_address = match item.get_optional_shipping() {
|
let shipping_address = if payment_method_token.is_some() {
|
||||||
Some(shipping_details) => {
|
None
|
||||||
let shipping_address = shipping_details.address.as_ref();
|
} else {
|
||||||
shipping_address.and_then(|shipping_detail| {
|
Some(StripeShippingAddress {
|
||||||
shipping_detail
|
city: item.get_optional_shipping_city(),
|
||||||
.first_name
|
country: item.get_optional_shipping_country(),
|
||||||
.as_ref()
|
line1: item.get_optional_shipping_line1(),
|
||||||
.map(|first_name| StripeShippingAddress {
|
line2: item.get_optional_shipping_line2(),
|
||||||
city: shipping_address.and_then(|a| a.city.clone()),
|
zip: item.get_optional_shipping_zip(),
|
||||||
country: shipping_address.and_then(|a| a.country),
|
state: item.get_optional_shipping_state(),
|
||||||
line1: shipping_address.and_then(|a| a.line1.clone()),
|
name: item.get_optional_shipping_full_name(),
|
||||||
line2: shipping_address.and_then(|a| a.line2.clone()),
|
phone: item.get_optional_shipping_phone_number(),
|
||||||
zip: shipping_address.and_then(|a| a.zip.clone()),
|
|
||||||
state: shipping_address.and_then(|a| a.state.clone()),
|
|
||||||
name: format!(
|
|
||||||
"{} {}",
|
|
||||||
first_name.clone().expose(),
|
|
||||||
shipping_detail
|
|
||||||
.last_name
|
|
||||||
.clone()
|
|
||||||
.expose_option()
|
|
||||||
.unwrap_or_default()
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
phone: shipping_details.phone.as_ref().map(|p| {
|
|
||||||
format!(
|
|
||||||
"{}{}",
|
|
||||||
p.country_code.clone().unwrap_or_default(),
|
|
||||||
p.number.clone().expose_option().unwrap_or_default()
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let billing_address = match item.get_optional_billing() {
|
let billing_address = if payment_method_token.is_some() {
|
||||||
Some(billing_details) => {
|
None
|
||||||
let billing_address = billing_details.address.as_ref();
|
} else {
|
||||||
StripeBillingAddress {
|
Some(StripeBillingAddress {
|
||||||
city: billing_address.and_then(|a| a.city.clone()),
|
city: item.get_optional_billing_city(),
|
||||||
country: billing_address.and_then(|a| a.country),
|
country: item.get_optional_billing_country(),
|
||||||
address_line1: billing_address.and_then(|a| a.line1.clone()),
|
address_line1: item.get_optional_billing_line1(),
|
||||||
address_line2: billing_address.and_then(|a| a.line2.clone()),
|
address_line2: item.get_optional_billing_line2(),
|
||||||
zip_code: billing_address.and_then(|a| a.zip.clone()),
|
zip_code: item.get_optional_billing_zip(),
|
||||||
state: billing_address.and_then(|a| a.state.clone()),
|
state: item.get_optional_billing_state(),
|
||||||
name: billing_address.and_then(|a| {
|
name: item.get_optional_billing_full_name(),
|
||||||
a.first_name.as_ref().map(|first_name| {
|
email: item.get_optional_billing_email(),
|
||||||
format!(
|
phone: item.get_optional_billing_phone_number(),
|
||||||
"{} {}",
|
|
||||||
first_name.clone().expose(),
|
|
||||||
a.last_name.clone().expose_option().unwrap_or_default()
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
})
|
||||||
}),
|
|
||||||
email: billing_details.email.clone(),
|
|
||||||
phone: billing_details.phone.as_ref().map(|p| {
|
|
||||||
format!(
|
|
||||||
"{}{}",
|
|
||||||
p.country_code.clone().unwrap_or_default(),
|
|
||||||
p.number.clone().expose_option().unwrap_or_default()
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => StripeBillingAddress::default(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut payment_method_options = None;
|
let mut payment_method_options = None;
|
||||||
|
|
||||||
let (
|
let (
|
||||||
@ -1724,7 +1716,9 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
billing_address,
|
billing_address,
|
||||||
payment_method_types,
|
payment_method_types,
|
||||||
setup_future_usage,
|
setup_future_usage,
|
||||||
) = {
|
) = if payment_method_token.is_some() {
|
||||||
|
(None, None, StripeBillingAddress::default(), None, None)
|
||||||
|
} else {
|
||||||
match item
|
match item
|
||||||
.request
|
.request
|
||||||
.mandate_id
|
.mandate_id
|
||||||
@ -1812,7 +1806,11 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
&item.request,
|
&item.request,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
billing_address,
|
billing_address.ok_or_else(|| {
|
||||||
|
ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "billing_address",
|
||||||
|
}
|
||||||
|
})?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
validate_shipping_address_against_payment_method(
|
validate_shipping_address_against_payment_method(
|
||||||
@ -1831,6 +1829,7 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if payment_method_token.is_none() {
|
||||||
payment_data = match item.request.payment_method_data {
|
payment_data = match item.request.payment_method_data {
|
||||||
PaymentMethodData::Wallet(WalletData::ApplePay(_)) => {
|
PaymentMethodData::Wallet(WalletData::ApplePay(_)) => {
|
||||||
let payment_method_token = item
|
let payment_method_token = item
|
||||||
@ -1863,6 +1862,9 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => payment_data,
|
_ => payment_data,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
payment_data = None
|
||||||
};
|
};
|
||||||
|
|
||||||
let setup_mandate_details = item
|
let setup_mandate_details = item
|
||||||
@ -1932,7 +1934,7 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
|
|
||||||
// We pass browser_info only when payment_data exists.
|
// We pass browser_info only when payment_data exists.
|
||||||
// Hence, we're pass Null during recurring payments as payment_method_data[type] is not passed
|
// Hence, we're pass Null during recurring payments as payment_method_data[type] is not passed
|
||||||
let browser_info = if payment_data.is_some() {
|
let browser_info = if payment_data.is_some() && payment_method_token.is_none() {
|
||||||
item.request
|
item.request
|
||||||
.browser_info
|
.browser_info
|
||||||
.clone()
|
.clone()
|
||||||
@ -1941,11 +1943,10 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let (charges, customer) = match &item.request.split_payments {
|
let charges = match &item.request.split_payments {
|
||||||
Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(
|
Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(
|
||||||
stripe_split_payment,
|
stripe_split_payment,
|
||||||
)) => {
|
)) => match &stripe_split_payment.charge_type {
|
||||||
let charges = match &stripe_split_payment.charge_type {
|
|
||||||
PaymentChargeType::Stripe(charge_type) => match charge_type {
|
PaymentChargeType::Stripe(charge_type) => match charge_type {
|
||||||
StripeChargeType::Direct => Some(IntentCharges {
|
StripeChargeType::Direct => Some(IntentCharges {
|
||||||
application_fee_amount: stripe_split_payment.application_fees,
|
application_fee_amount: stripe_split_payment.application_fees,
|
||||||
@ -1958,14 +1959,24 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
(charges, None)
|
|
||||||
}
|
|
||||||
Some(common_types::payments::SplitPaymentsRequest::AdyenSplitPayment(_))
|
Some(common_types::payments::SplitPaymentsRequest::AdyenSplitPayment(_))
|
||||||
| Some(common_types::payments::SplitPaymentsRequest::XenditSplitPayment(_))
|
| Some(common_types::payments::SplitPaymentsRequest::XenditSplitPayment(_))
|
||||||
| None => (None, item.connector_customer.to_owned().map(Secret::new)),
|
| None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pm = match (payment_method, payment_method_token.clone()) {
|
||||||
|
(Some(method), _) => Some(Secret::new(method)),
|
||||||
|
(None, Some(token)) => Some(token),
|
||||||
|
(None, None) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let customer_id = item.connector_customer.clone().ok_or_else(|| {
|
||||||
|
ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "connector_customer",
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
amount, //hopefully we don't loose some cents here
|
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
|
||||||
@ -1984,8 +1995,8 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
capture_method: StripeCaptureMethod::from(item.request.capture_method),
|
capture_method: StripeCaptureMethod::from(item.request.capture_method),
|
||||||
payment_data,
|
payment_data,
|
||||||
payment_method_options,
|
payment_method_options,
|
||||||
payment_method,
|
payment_method: pm,
|
||||||
customer,
|
customer: Some(Secret::new(customer_id)),
|
||||||
setup_mandate_details,
|
setup_mandate_details,
|
||||||
off_session: item.request.off_session,
|
off_session: item.request.off_session,
|
||||||
setup_future_usage,
|
setup_future_usage,
|
||||||
@ -2076,14 +2087,26 @@ impl TryFrom<&SetupMandateRouterData> for SetupIntentRequest {
|
|||||||
impl TryFrom<&TokenizationRouterData> for TokenRequest {
|
impl TryFrom<&TokenizationRouterData> for TokenRequest {
|
||||||
type Error = error_stack::Report<ConnectorError>;
|
type Error = error_stack::Report<ConnectorError>;
|
||||||
fn try_from(item: &TokenizationRouterData) -> Result<Self, Self::Error> {
|
fn try_from(item: &TokenizationRouterData) -> Result<Self, Self::Error> {
|
||||||
|
let billing_address = StripeBillingAddressCardToken {
|
||||||
|
name: item.get_optional_billing_full_name(),
|
||||||
|
email: item.get_optional_billing_email(),
|
||||||
|
phone: item.get_optional_billing_phone_number(),
|
||||||
|
address_line1: item.get_optional_billing_line1(),
|
||||||
|
address_line2: item.get_optional_billing_line2(),
|
||||||
|
city: item.get_optional_billing_city(),
|
||||||
|
state: item.get_optional_billing_state(),
|
||||||
|
};
|
||||||
|
|
||||||
// Card flow for tokenization is handled separately because of API contact difference
|
// Card flow for tokenization is handled separately because of API contact difference
|
||||||
let request_payment_data = match &item.request.payment_method_data {
|
let request_payment_data = match &item.request.payment_method_data {
|
||||||
PaymentMethodData::Card(card_details) => {
|
PaymentMethodData::Card(card_details) => {
|
||||||
StripePaymentMethodData::CardToken(StripeCardToken {
|
StripePaymentMethodData::CardToken(StripeCardToken {
|
||||||
|
payment_method_type: Some(StripePaymentMethodType::Card),
|
||||||
token_card_number: card_details.card_number.clone(),
|
token_card_number: card_details.card_number.clone(),
|
||||||
token_card_exp_month: card_details.card_exp_month.clone(),
|
token_card_exp_month: card_details.card_exp_month.clone(),
|
||||||
token_card_exp_year: card_details.card_exp_year.clone(),
|
token_card_exp_year: card_details.card_exp_year.clone(),
|
||||||
token_card_cvc: card_details.card_cvc.clone(),
|
token_card_cvc: card_details.card_cvc.clone(),
|
||||||
|
billing: billing_address,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -3327,7 +3350,7 @@ pub struct StripeShippingAddress {
|
|||||||
#[serde(rename = "shipping[address][state]")]
|
#[serde(rename = "shipping[address][state]")]
|
||||||
pub state: Option<Secret<String>>,
|
pub state: Option<Secret<String>>,
|
||||||
#[serde(rename = "shipping[name]")]
|
#[serde(rename = "shipping[name]")]
|
||||||
pub name: Secret<String>,
|
pub name: Option<Secret<String>>,
|
||||||
#[serde(rename = "shipping[phone]")]
|
#[serde(rename = "shipping[phone]")]
|
||||||
pub phone: Option<Secret<String>>,
|
pub phone: Option<Secret<String>>,
|
||||||
}
|
}
|
||||||
@ -3593,10 +3616,9 @@ impl<F, T> TryFrom<ResponseRouterData<F, StripeTokenResponse, T, PaymentsRespons
|
|||||||
fn try_from(
|
fn try_from(
|
||||||
item: ResponseRouterData<F, StripeTokenResponse, T, PaymentsResponseData>,
|
item: ResponseRouterData<F, StripeTokenResponse, T, PaymentsResponseData>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
|
let token = item.response.id.clone().expose();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
response: Ok(PaymentsResponseData::TokenizationResponse {
|
response: Ok(PaymentsResponseData::TokenizationResponse { token }),
|
||||||
token: item.response.id.expose(),
|
|
||||||
}),
|
|
||||||
..item.data
|
..item.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -4392,7 +4414,7 @@ mod test_validate_shipping_address_against_payment_method {
|
|||||||
zip: Option<String>,
|
zip: Option<String>,
|
||||||
) -> StripeShippingAddress {
|
) -> StripeShippingAddress {
|
||||||
StripeShippingAddress {
|
StripeShippingAddress {
|
||||||
name: Secret::new(name),
|
name: Some(Secret::new(name)),
|
||||||
line1: line1.map(Secret::new),
|
line1: line1.map(Secret::new),
|
||||||
country,
|
country,
|
||||||
zip: zip.map(Secret::new),
|
zip: zip.map(Secret::new),
|
||||||
|
|||||||
@ -177,6 +177,7 @@ pub struct ConnectorCustomerData {
|
|||||||
pub name: Option<Secret<String>>,
|
pub name: Option<Secret<String>>,
|
||||||
pub preprocessing_id: Option<String>,
|
pub preprocessing_id: Option<String>,
|
||||||
pub payment_method_data: Option<PaymentMethodData>,
|
pub payment_method_data: Option<PaymentMethodData>,
|
||||||
|
pub split_payments: Option<common_types::payments::SplitPaymentsRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<SetupMandateRequestData> for ConnectorCustomerData {
|
impl TryFrom<SetupMandateRequestData> for ConnectorCustomerData {
|
||||||
@ -189,6 +190,7 @@ impl TryFrom<SetupMandateRequestData> for ConnectorCustomerData {
|
|||||||
phone: None,
|
phone: None,
|
||||||
name: None,
|
name: None,
|
||||||
preprocessing_id: None,
|
preprocessing_id: None,
|
||||||
|
split_payments: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,6 +215,7 @@ impl
|
|||||||
phone: None,
|
phone: None,
|
||||||
name: data.request.customer_name.clone(),
|
name: data.request.customer_name.clone(),
|
||||||
preprocessing_id: data.preprocessing_id.clone(),
|
preprocessing_id: data.preprocessing_id.clone(),
|
||||||
|
split_payments: data.request.split_payments.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,6 +239,7 @@ impl TryFrom<&RouterData<flows::Session, PaymentsSessionData, response_types::Pa
|
|||||||
phone: None,
|
phone: None,
|
||||||
name: data.request.customer_name.clone(),
|
name: data.request.customer_name.clone(),
|
||||||
preprocessing_id: data.preprocessing_id.clone(),
|
preprocessing_id: data.preprocessing_id.clone(),
|
||||||
|
split_payments: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,6 +250,7 @@ pub struct PaymentMethodTokenizationData {
|
|||||||
pub browser_info: Option<BrowserInformation>,
|
pub browser_info: Option<BrowserInformation>,
|
||||||
pub currency: storage_enums::Currency,
|
pub currency: storage_enums::Currency,
|
||||||
pub amount: Option<i64>,
|
pub amount: Option<i64>,
|
||||||
|
pub split_payments: Option<common_types::payments::SplitPaymentsRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<SetupMandateRequestData> for PaymentMethodTokenizationData {
|
impl TryFrom<SetupMandateRequestData> for PaymentMethodTokenizationData {
|
||||||
@ -257,6 +262,7 @@ impl TryFrom<SetupMandateRequestData> for PaymentMethodTokenizationData {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
currency: data.currency,
|
currency: data.currency,
|
||||||
amount: data.amount,
|
amount: data.amount,
|
||||||
|
split_payments: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,6 +277,7 @@ impl<F> From<&RouterData<F, PaymentsAuthorizeData, response_types::PaymentsRespo
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
currency: data.request.currency,
|
currency: data.request.currency,
|
||||||
amount: Some(data.request.amount),
|
amount: Some(data.request.amount),
|
||||||
|
split_payments: data.request.split_payments.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,6 +291,7 @@ impl TryFrom<PaymentsAuthorizeData> for PaymentMethodTokenizationData {
|
|||||||
browser_info: data.browser_info,
|
browser_info: data.browser_info,
|
||||||
currency: data.currency,
|
currency: data.currency,
|
||||||
amount: Some(data.amount),
|
amount: Some(data.amount),
|
||||||
|
split_payments: data.split_payments.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,6 +310,7 @@ impl TryFrom<CompleteAuthorizeData> for PaymentMethodTokenizationData {
|
|||||||
browser_info: data.browser_info,
|
browser_info: data.browser_info,
|
||||||
currency: data.currency,
|
currency: data.currency,
|
||||||
amount: Some(data.amount),
|
amount: Some(data.amount),
|
||||||
|
split_payments: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3227,6 +3227,7 @@ async fn create_single_use_tokenization_flow(
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
currency: api_models::enums::Currency::default(),
|
currency: api_models::enums::Currency::default(),
|
||||||
amount: None,
|
amount: None,
|
||||||
|
split_payments: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let payment_method_session_address = types::PaymentAddress::new(
|
let payment_method_session_address = types::PaymentAddress::new(
|
||||||
|
|||||||
@ -5241,6 +5241,7 @@ async fn decide_payment_method_tokenize_action(
|
|||||||
state: &SessionState,
|
state: &SessionState,
|
||||||
connector_name: &str,
|
connector_name: &str,
|
||||||
payment_method: storage::enums::PaymentMethod,
|
payment_method: storage::enums::PaymentMethod,
|
||||||
|
payment_intent_data: payments::PaymentIntent,
|
||||||
pm_parent_token: Option<&str>,
|
pm_parent_token: Option<&str>,
|
||||||
is_connector_tokenization_enabled: bool,
|
is_connector_tokenization_enabled: bool,
|
||||||
apple_pay_flow: Option<domain::ApplePayFlow>,
|
apple_pay_flow: Option<domain::ApplePayFlow>,
|
||||||
@ -5276,6 +5277,11 @@ async fn decide_payment_method_tokenize_action(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if matches!(
|
||||||
|
payment_intent_data.split_payments,
|
||||||
|
Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(_))
|
||||||
|
) {
|
||||||
|
Ok(TokenizationAction::TokenizeInConnector)
|
||||||
} else {
|
} else {
|
||||||
match pm_parent_token {
|
match pm_parent_token {
|
||||||
None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) {
|
None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) {
|
||||||
@ -5445,6 +5451,7 @@ where
|
|||||||
state,
|
state,
|
||||||
&connector,
|
&connector,
|
||||||
payment_method,
|
payment_method,
|
||||||
|
payment_data.get_payment_intent().clone(),
|
||||||
payment_data.get_token(),
|
payment_data.get_token(),
|
||||||
is_connector_tokenization_enabled,
|
is_connector_tokenization_enabled,
|
||||||
apple_pay_flow,
|
apple_pay_flow,
|
||||||
|
|||||||
@ -67,6 +67,7 @@ fn token_details() -> Option<types::PaymentMethodTokenizationData> {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,6 +441,7 @@ async fn should_fail_payment_for_incorrect_cvc() {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
}),
|
}),
|
||||||
get_default_payment_info(None),
|
get_default_payment_info(None),
|
||||||
)
|
)
|
||||||
@ -471,6 +473,7 @@ async fn should_fail_payment_for_invalid_exp_month() {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
}),
|
}),
|
||||||
get_default_payment_info(None),
|
get_default_payment_info(None),
|
||||||
)
|
)
|
||||||
@ -502,6 +505,7 @@ async fn should_fail_payment_for_incorrect_expiry_year() {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
}),
|
}),
|
||||||
get_default_payment_info(None),
|
get_default_payment_info(None),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -72,6 +72,7 @@ fn token_details() -> Option<types::PaymentMethodTokenizationData> {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,6 +483,7 @@ async fn should_fail_payment_for_incorrect_cvc() {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
}),
|
}),
|
||||||
get_default_payment_info(connector_customer_id, None),
|
get_default_payment_info(connector_customer_id, None),
|
||||||
)
|
)
|
||||||
@ -520,6 +522,7 @@ async fn should_fail_payment_for_invalid_exp_month() {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
}),
|
}),
|
||||||
get_default_payment_info(connector_customer_id, None),
|
get_default_payment_info(connector_customer_id, None),
|
||||||
)
|
)
|
||||||
@ -558,6 +561,7 @@ async fn should_fail_payment_for_incorrect_expiry_year() {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: None,
|
amount: None,
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
}),
|
}),
|
||||||
get_default_payment_info(connector_customer_id, None),
|
get_default_payment_info(connector_customer_id, None),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1107,6 +1107,7 @@ impl Default for CustomerType {
|
|||||||
phone: None,
|
phone: None,
|
||||||
name: None,
|
name: None,
|
||||||
preprocessing_id: None,
|
preprocessing_id: None,
|
||||||
|
split_payments: None,
|
||||||
};
|
};
|
||||||
Self(data)
|
Self(data)
|
||||||
}
|
}
|
||||||
@ -1119,6 +1120,7 @@ impl Default for TokenType {
|
|||||||
browser_info: None,
|
browser_info: None,
|
||||||
amount: Some(100),
|
amount: Some(100),
|
||||||
currency: enums::Currency::USD,
|
currency: enums::Currency::USD,
|
||||||
|
split_payments: None,
|
||||||
};
|
};
|
||||||
Self(data)
|
Self(data)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user