mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +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 common_enums::{enums, AttemptStatus, PaymentChargeType, StripeChargeType};
|
||||
use common_types::payments::{AcceptanceType, SplitPaymentsRequest};
|
||||
use common_types::{
|
||||
payments::{AcceptanceType, SplitPaymentsRequest},
|
||||
primitive_wrappers,
|
||||
};
|
||||
use common_utils::{
|
||||
collect_missing_value_keys,
|
||||
errors::CustomResult,
|
||||
@ -19,7 +22,7 @@ use hyperswitch_domain_models::{
|
||||
},
|
||||
router_data::{
|
||||
AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
|
||||
PaymentMethodToken, RouterData,
|
||||
ExtendedAuthorizationResponseData, PaymentMethodToken, RouterData,
|
||||
},
|
||||
router_flow_types::{Execute, RSync},
|
||||
router_request_types::{
|
||||
@ -287,6 +290,9 @@ pub struct StripeCardData {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "payment_method_options[card][request_incremental_authorization]")]
|
||||
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)]
|
||||
@ -296,6 +302,12 @@ pub enum StripeRequestIncrementalAuthorization {
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum StripeRequestExtendedAuthorization {
|
||||
IfAvailable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct StripePayLaterData {
|
||||
#[serde(rename = "payment_method_data[type]")]
|
||||
@ -1260,6 +1272,7 @@ fn create_stripe_payment_method(
|
||||
is_customer_initiated_mandate_payment: Option<bool>,
|
||||
billing_address: StripeBillingAddress,
|
||||
request_incremental_authorization: bool,
|
||||
request_extended_authorization: Option<primitive_wrappers::RequestExtendedAuthorizationBool>,
|
||||
) -> Result<
|
||||
(
|
||||
StripePaymentMethodData,
|
||||
@ -1279,6 +1292,7 @@ fn create_stripe_payment_method(
|
||||
card_details,
|
||||
payment_method_auth_type,
|
||||
request_incremental_authorization,
|
||||
request_extended_authorization,
|
||||
))?,
|
||||
Some(StripePaymentMethodType::Card),
|
||||
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;
|
||||
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> {
|
||||
Ok(Self::Card(StripeCardData {
|
||||
payment_method_data_type: StripePaymentMethodType::Card,
|
||||
@ -1518,6 +1549,14 @@ impl TryFrom<(&Card, Auth3ds, bool)> for StripePaymentMethodData {
|
||||
} else {
|
||||
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()
|
||||
.and_then(get_stripe_card_network),
|
||||
request_incremental_authorization: None,
|
||||
request_extended_authorization: None,
|
||||
}),
|
||||
PaymentMethodData::CardRedirect(_)
|
||||
| PaymentMethodData::Wallet(_)
|
||||
@ -1917,6 +1957,7 @@ impl TryFrom<(&PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest
|
||||
}
|
||||
})?,
|
||||
item.request.request_incremental_authorization,
|
||||
item.request.request_extended_authorization,
|
||||
)?;
|
||||
|
||||
validate_shipping_address_against_payment_method(
|
||||
@ -2243,6 +2284,7 @@ impl TryFrom<&TokenizationRouterData> for TokenRequest {
|
||||
None,
|
||||
StripeBillingAddress::default(),
|
||||
false,
|
||||
None,
|
||||
)?
|
||||
.0
|
||||
}
|
||||
@ -2537,6 +2579,21 @@ pub struct StripeAdditionalCardDetails {
|
||||
checks: Option<Value>,
|
||||
three_d_secure: Option<Value>,
|
||||
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)]
|
||||
@ -2586,25 +2643,45 @@ pub enum StripePaymentMethodDetailsResponse {
|
||||
pub struct AdditionalPaymentMethodDetails {
|
||||
pub payment_checks: Option<Value>,
|
||||
pub authentication_details: Option<Value>,
|
||||
pub extended_authorization: Option<StripeExtendedAuthorizationResponse>,
|
||||
pub capture_before: Option<PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
impl From<AdditionalPaymentMethodDetails> for AdditionalPaymentMethodConnectorResponse {
|
||||
fn from(item: AdditionalPaymentMethodDetails) -> Self {
|
||||
impl From<&AdditionalPaymentMethodDetails> for AdditionalPaymentMethodConnectorResponse {
|
||||
fn from(item: &AdditionalPaymentMethodDetails) -> Self {
|
||||
Self::Card {
|
||||
authentication_data: item.authentication_details,
|
||||
payment_checks: item.payment_checks,
|
||||
authentication_data: item.authentication_details.clone(),
|
||||
payment_checks: item.payment_checks.clone(),
|
||||
card_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 {
|
||||
pub fn get_additional_payment_method_data(&self) -> Option<AdditionalPaymentMethodDetails> {
|
||||
match self {
|
||||
Self::Card { card } => Some(AdditionalPaymentMethodDetails {
|
||||
payment_checks: card.checks.clone(),
|
||||
authentication_details: card.three_d_secure.clone(),
|
||||
extended_authorization: card.extended_authorization.clone(),
|
||||
capture_before: card.capture_before,
|
||||
}),
|
||||
Self::Ideal { .. }
|
||||
| Self::Bancontact { .. }
|
||||
@ -2694,16 +2771,31 @@ pub struct SetupIntentResponse {
|
||||
fn extract_payment_method_connector_response_from_latest_charge(
|
||||
stripe_charge_enum: &StripeChargeEnum,
|
||||
) -> Option<ConnectorResponseData> {
|
||||
if let StripeChargeEnum::ChargeObject(charge_object) = stripe_charge_enum {
|
||||
charge_object
|
||||
.payment_method_details
|
||||
.as_ref()
|
||||
.and_then(StripePaymentMethodDetailsResponse::get_additional_payment_method_data)
|
||||
let additional_payment_method_details =
|
||||
if let StripeChargeEnum::ChargeObject(charge_object) = stripe_charge_enum {
|
||||
charge_object
|
||||
.payment_method_details
|
||||
.as_ref()
|
||||
.and_then(StripePaymentMethodDetailsResponse::get_additional_payment_method_data)
|
||||
} else {
|
||||
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(
|
||||
@ -2717,6 +2809,7 @@ fn extract_payment_method_connector_response_from_latest_attempt(
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.as_ref()
|
||||
.map(AdditionalPaymentMethodConnectorResponse::from)
|
||||
.map(ConnectorResponseData::with_additional_payment_method_data)
|
||||
}
|
||||
@ -4166,6 +4259,7 @@ impl
|
||||
ccard,
|
||||
payment_method_auth_type,
|
||||
item.request.request_incremental_authorization,
|
||||
None,
|
||||
))?)
|
||||
}
|
||||
PaymentMethodData::PayLater(_) => Ok(Self::PayLater(StripePayLaterData {
|
||||
|
||||
@ -474,6 +474,16 @@ impl ConnectorResponseData {
|
||||
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(
|
||||
&self,
|
||||
) -> Option<&ExtendedAuthorizationResponseData> {
|
||||
|
||||
Reference in New Issue
Block a user