mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(connectors): [Stripe] add extended authorization for cards (#9084)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -2,7 +2,10 @@ use std::{collections::HashMap, fmt::Debug, ops::Deref};
|
|||||||
|
|
||||||
use api_models::{self, enums as api_enums, payments};
|
use api_models::{self, enums as api_enums, payments};
|
||||||
use common_enums::{enums, AttemptStatus, PaymentChargeType, StripeChargeType};
|
use common_enums::{enums, AttemptStatus, PaymentChargeType, StripeChargeType};
|
||||||
use common_types::payments::{AcceptanceType, SplitPaymentsRequest};
|
use common_types::{
|
||||||
|
payments::{AcceptanceType, SplitPaymentsRequest},
|
||||||
|
primitive_wrappers,
|
||||||
|
};
|
||||||
use common_utils::{
|
use common_utils::{
|
||||||
collect_missing_value_keys,
|
collect_missing_value_keys,
|
||||||
errors::CustomResult,
|
errors::CustomResult,
|
||||||
@ -19,7 +22,7 @@ use hyperswitch_domain_models::{
|
|||||||
},
|
},
|
||||||
router_data::{
|
router_data::{
|
||||||
AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
|
AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
|
||||||
PaymentMethodToken, RouterData,
|
ExtendedAuthorizationResponseData, PaymentMethodToken, RouterData,
|
||||||
},
|
},
|
||||||
router_flow_types::{Execute, RSync},
|
router_flow_types::{Execute, RSync},
|
||||||
router_request_types::{
|
router_request_types::{
|
||||||
@ -287,6 +290,9 @@ pub struct StripeCardData {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
#[serde(rename = "payment_method_options[card][request_incremental_authorization]")]
|
#[serde(rename = "payment_method_options[card][request_incremental_authorization]")]
|
||||||
pub request_incremental_authorization: Option<StripeRequestIncrementalAuthorization>,
|
pub request_incremental_authorization: Option<StripeRequestIncrementalAuthorization>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde(rename = "payment_method_options[card][request_extended_authorization]")]
|
||||||
|
request_extended_authorization: Option<StripeRequestExtendedAuthorization>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
@ -296,6 +302,12 @@ pub enum StripeRequestIncrementalAuthorization {
|
|||||||
Never,
|
Never,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum StripeRequestExtendedAuthorization {
|
||||||
|
IfAvailable,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||||
pub struct StripePayLaterData {
|
pub struct StripePayLaterData {
|
||||||
#[serde(rename = "payment_method_data[type]")]
|
#[serde(rename = "payment_method_data[type]")]
|
||||||
@ -1260,6 +1272,7 @@ fn create_stripe_payment_method(
|
|||||||
is_customer_initiated_mandate_payment: Option<bool>,
|
is_customer_initiated_mandate_payment: Option<bool>,
|
||||||
billing_address: StripeBillingAddress,
|
billing_address: StripeBillingAddress,
|
||||||
request_incremental_authorization: bool,
|
request_incremental_authorization: bool,
|
||||||
|
request_extended_authorization: Option<primitive_wrappers::RequestExtendedAuthorizationBool>,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
StripePaymentMethodData,
|
StripePaymentMethodData,
|
||||||
@ -1279,6 +1292,7 @@ fn create_stripe_payment_method(
|
|||||||
card_details,
|
card_details,
|
||||||
payment_method_auth_type,
|
payment_method_auth_type,
|
||||||
request_incremental_authorization,
|
request_incremental_authorization,
|
||||||
|
request_extended_authorization,
|
||||||
))?,
|
))?,
|
||||||
Some(StripePaymentMethodType::Card),
|
Some(StripePaymentMethodType::Card),
|
||||||
billing_address,
|
billing_address,
|
||||||
@ -1497,10 +1511,27 @@ fn get_stripe_card_network(card_network: common_enums::CardNetwork) -> Option<St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<(&Card, Auth3ds, bool)> for StripePaymentMethodData {
|
impl
|
||||||
|
TryFrom<(
|
||||||
|
&Card,
|
||||||
|
Auth3ds,
|
||||||
|
bool,
|
||||||
|
Option<primitive_wrappers::RequestExtendedAuthorizationBool>,
|
||||||
|
)> for StripePaymentMethodData
|
||||||
|
{
|
||||||
type Error = ConnectorError;
|
type Error = ConnectorError;
|
||||||
fn try_from(
|
fn try_from(
|
||||||
(card, payment_method_auth_type, request_incremental_authorization): (&Card, Auth3ds, bool),
|
(
|
||||||
|
card,
|
||||||
|
payment_method_auth_type,
|
||||||
|
request_incremental_authorization,
|
||||||
|
request_extended_authorization,
|
||||||
|
): (
|
||||||
|
&Card,
|
||||||
|
Auth3ds,
|
||||||
|
bool,
|
||||||
|
Option<primitive_wrappers::RequestExtendedAuthorizationBool>,
|
||||||
|
),
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
Ok(Self::Card(StripeCardData {
|
Ok(Self::Card(StripeCardData {
|
||||||
payment_method_data_type: StripePaymentMethodType::Card,
|
payment_method_data_type: StripePaymentMethodType::Card,
|
||||||
@ -1518,6 +1549,14 @@ impl TryFrom<(&Card, Auth3ds, bool)> for StripePaymentMethodData {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
request_extended_authorization: if request_extended_authorization
|
||||||
|
.map(|request_extended_authorization| request_extended_authorization.is_true())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
Some(StripeRequestExtendedAuthorization::IfAvailable)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1868,6 +1907,7 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
.clone()
|
.clone()
|
||||||
.and_then(get_stripe_card_network),
|
.and_then(get_stripe_card_network),
|
||||||
request_incremental_authorization: None,
|
request_incremental_authorization: None,
|
||||||
|
request_extended_authorization: None,
|
||||||
}),
|
}),
|
||||||
PaymentMethodData::CardRedirect(_)
|
PaymentMethodData::CardRedirect(_)
|
||||||
| PaymentMethodData::Wallet(_)
|
| PaymentMethodData::Wallet(_)
|
||||||
@ -1917,6 +1957,7 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
|||||||
}
|
}
|
||||||
})?,
|
})?,
|
||||||
item.request.request_incremental_authorization,
|
item.request.request_incremental_authorization,
|
||||||
|
item.request.request_extended_authorization,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
validate_shipping_address_against_payment_method(
|
validate_shipping_address_against_payment_method(
|
||||||
@ -2243,6 +2284,7 @@ impl TryFrom<&TokenizationRouterData> for TokenRequest {
|
|||||||
None,
|
None,
|
||||||
StripeBillingAddress::default(),
|
StripeBillingAddress::default(),
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
)?
|
)?
|
||||||
.0
|
.0
|
||||||
}
|
}
|
||||||
@ -2537,6 +2579,21 @@ pub struct StripeAdditionalCardDetails {
|
|||||||
checks: Option<Value>,
|
checks: Option<Value>,
|
||||||
three_d_secure: Option<Value>,
|
three_d_secure: Option<Value>,
|
||||||
network_transaction_id: Option<String>,
|
network_transaction_id: Option<String>,
|
||||||
|
extended_authorization: Option<StripeExtendedAuthorizationResponse>,
|
||||||
|
#[serde(default, with = "common_utils::custom_serde::timestamp::option")]
|
||||||
|
pub capture_before: Option<PrimitiveDateTime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Serialize)]
|
||||||
|
pub struct StripeExtendedAuthorizationResponse {
|
||||||
|
status: Option<StripeExtendedAuthorizationStatus>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Serialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum StripeExtendedAuthorizationStatus {
|
||||||
|
Disabled,
|
||||||
|
Enabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Serialize)]
|
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Serialize)]
|
||||||
@ -2586,25 +2643,45 @@ pub enum StripePaymentMethodDetailsResponse {
|
|||||||
pub struct AdditionalPaymentMethodDetails {
|
pub struct AdditionalPaymentMethodDetails {
|
||||||
pub payment_checks: Option<Value>,
|
pub payment_checks: Option<Value>,
|
||||||
pub authentication_details: Option<Value>,
|
pub authentication_details: Option<Value>,
|
||||||
|
pub extended_authorization: Option<StripeExtendedAuthorizationResponse>,
|
||||||
|
pub capture_before: Option<PrimitiveDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AdditionalPaymentMethodDetails> for AdditionalPaymentMethodConnectorResponse {
|
impl From<&AdditionalPaymentMethodDetails> for AdditionalPaymentMethodConnectorResponse {
|
||||||
fn from(item: AdditionalPaymentMethodDetails) -> Self {
|
fn from(item: &AdditionalPaymentMethodDetails) -> Self {
|
||||||
Self::Card {
|
Self::Card {
|
||||||
authentication_data: item.authentication_details,
|
authentication_data: item.authentication_details.clone(),
|
||||||
payment_checks: item.payment_checks,
|
payment_checks: item.payment_checks.clone(),
|
||||||
card_network: None,
|
card_network: None,
|
||||||
domestic_network: None,
|
domestic_network: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&AdditionalPaymentMethodDetails> for ExtendedAuthorizationResponseData {
|
||||||
|
fn from(item: &AdditionalPaymentMethodDetails) -> Self {
|
||||||
|
Self {
|
||||||
|
extended_authentication_applied: item.extended_authorization.as_ref().map(
|
||||||
|
|extended_authorization| {
|
||||||
|
primitive_wrappers::ExtendedAuthorizationAppliedBool::from(matches!(
|
||||||
|
extended_authorization.status,
|
||||||
|
Some(StripeExtendedAuthorizationStatus::Enabled)
|
||||||
|
))
|
||||||
|
},
|
||||||
|
),
|
||||||
|
capture_before: item.capture_before,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl StripePaymentMethodDetailsResponse {
|
impl StripePaymentMethodDetailsResponse {
|
||||||
pub fn get_additional_payment_method_data(&self) -> Option<AdditionalPaymentMethodDetails> {
|
pub fn get_additional_payment_method_data(&self) -> Option<AdditionalPaymentMethodDetails> {
|
||||||
match self {
|
match self {
|
||||||
Self::Card { card } => Some(AdditionalPaymentMethodDetails {
|
Self::Card { card } => Some(AdditionalPaymentMethodDetails {
|
||||||
payment_checks: card.checks.clone(),
|
payment_checks: card.checks.clone(),
|
||||||
authentication_details: card.three_d_secure.clone(),
|
authentication_details: card.three_d_secure.clone(),
|
||||||
|
extended_authorization: card.extended_authorization.clone(),
|
||||||
|
capture_before: card.capture_before,
|
||||||
}),
|
}),
|
||||||
Self::Ideal { .. }
|
Self::Ideal { .. }
|
||||||
| Self::Bancontact { .. }
|
| Self::Bancontact { .. }
|
||||||
@ -2694,6 +2771,7 @@ pub struct SetupIntentResponse {
|
|||||||
fn extract_payment_method_connector_response_from_latest_charge(
|
fn extract_payment_method_connector_response_from_latest_charge(
|
||||||
stripe_charge_enum: &StripeChargeEnum,
|
stripe_charge_enum: &StripeChargeEnum,
|
||||||
) -> Option<ConnectorResponseData> {
|
) -> Option<ConnectorResponseData> {
|
||||||
|
let additional_payment_method_details =
|
||||||
if let StripeChargeEnum::ChargeObject(charge_object) = stripe_charge_enum {
|
if let StripeChargeEnum::ChargeObject(charge_object) = stripe_charge_enum {
|
||||||
charge_object
|
charge_object
|
||||||
.payment_method_details
|
.payment_method_details
|
||||||
@ -2701,9 +2779,23 @@ fn extract_payment_method_connector_response_from_latest_charge(
|
|||||||
.and_then(StripePaymentMethodDetailsResponse::get_additional_payment_method_data)
|
.and_then(StripePaymentMethodDetailsResponse::get_additional_payment_method_data)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let additional_payment_method_data = additional_payment_method_details
|
||||||
|
.as_ref()
|
||||||
|
.map(AdditionalPaymentMethodConnectorResponse::from);
|
||||||
|
let extended_authorization_data = additional_payment_method_details
|
||||||
|
.as_ref()
|
||||||
|
.map(ExtendedAuthorizationResponseData::from);
|
||||||
|
|
||||||
|
if additional_payment_method_data.is_some() || extended_authorization_data.is_some() {
|
||||||
|
Some(ConnectorResponseData::new(
|
||||||
|
additional_payment_method_data,
|
||||||
|
extended_authorization_data,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
.map(AdditionalPaymentMethodConnectorResponse::from)
|
|
||||||
.map(ConnectorResponseData::with_additional_payment_method_data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_payment_method_connector_response_from_latest_attempt(
|
fn extract_payment_method_connector_response_from_latest_attempt(
|
||||||
@ -2717,6 +2809,7 @@ fn extract_payment_method_connector_response_from_latest_attempt(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
.as_ref()
|
||||||
.map(AdditionalPaymentMethodConnectorResponse::from)
|
.map(AdditionalPaymentMethodConnectorResponse::from)
|
||||||
.map(ConnectorResponseData::with_additional_payment_method_data)
|
.map(ConnectorResponseData::with_additional_payment_method_data)
|
||||||
}
|
}
|
||||||
@ -4166,6 +4259,7 @@ impl
|
|||||||
ccard,
|
ccard,
|
||||||
payment_method_auth_type,
|
payment_method_auth_type,
|
||||||
item.request.request_incremental_authorization,
|
item.request.request_incremental_authorization,
|
||||||
|
None,
|
||||||
))?)
|
))?)
|
||||||
}
|
}
|
||||||
PaymentMethodData::PayLater(_) => Ok(Self::PayLater(StripePayLaterData {
|
PaymentMethodData::PayLater(_) => Ok(Self::PayLater(StripePayLaterData {
|
||||||
|
|||||||
@ -474,6 +474,16 @@ impl ConnectorResponseData {
|
|||||||
extended_authorization_response_data: None,
|
extended_authorization_response_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn new(
|
||||||
|
additional_payment_method_data: Option<AdditionalPaymentMethodConnectorResponse>,
|
||||||
|
extended_authorization_response_data: Option<ExtendedAuthorizationResponseData>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
additional_payment_method_data,
|
||||||
|
extended_authorization_response_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_extended_authorization_response_data(
|
pub fn get_extended_authorization_response_data(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<&ExtendedAuthorizationResponseData> {
|
) -> Option<&ExtendedAuthorizationResponseData> {
|
||||||
|
|||||||
Reference in New Issue
Block a user