diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index de8af66214..e06b264cef 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -1,15 +1,21 @@ use std::str::FromStr; use api_models::payments; -use common_utils::{crypto::Encryptable, date_time, ext_traits::StringExt, pii as secret}; +use common_utils::{ + crypto::Encryptable, + date_time, + ext_traits::StringExt, + pii::{IpAddress, SecretSerdeValue}, +}; use error_stack::{IntoReport, ResultExt}; use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; use crate::{ compatibility::stripe::refunds::types as stripe_refunds, consts, core::errors, - pii::{self, Email, PeekInterface}, + pii::{Email, PeekInterface}, types::{ api::{admin, enums as api_enums}, transformers::{ForeignFrom, ForeignTryFrom}, @@ -21,7 +27,7 @@ pub struct StripeBillingDetails { pub address: Option, pub email: Option, pub name: Option, - pub phone: Option>, + pub phone: Option>, } impl From for payments::Address { @@ -42,10 +48,10 @@ impl From for payments::Address { #[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone, Debug)] pub struct StripeCard { pub number: cards::CardNumber, - pub exp_month: pii::Secret, - pub exp_year: pii::Secret, - pub cvc: pii::Secret, - pub holder_name: Option>, + pub exp_month: masking::Secret, + pub exp_year: masking::Secret, + pub cvc: masking::Secret, + pub holder_name: Option>, } #[derive(Serialize, PartialEq, Eq, Deserialize, Clone)] @@ -78,7 +84,7 @@ pub struct StripePaymentMethodData { pub billing_details: Option, #[serde(flatten)] pub payment_method_details: Option, // enum - pub metadata: Option, + pub metadata: Option, } #[derive(PartialEq, Eq, Deserialize, Clone)] @@ -127,11 +133,21 @@ impl From for payments::PaymentMethodData { #[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)] pub struct Shipping { - pub address: Option, - pub name: Option, + pub address: AddressDetails, + pub name: Option>, pub carrier: Option, - pub phone: Option>, - pub tracking_number: Option>, + pub phone: Option>, + pub tracking_number: Option>, +} + +#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)] +pub struct AddressDetails { + pub city: Option, + pub country: Option, + pub line1: Option>, + pub line2: Option>, + pub postal_code: Option>, + pub state: Option>, } impl From for payments::Address { @@ -139,19 +155,61 @@ impl From for payments::Address { Self { phone: Some(payments::PhoneDetails { number: details.phone, - country_code: details.address.as_ref().and_then(|address| { - address.country.as_ref().map(|country| country.to_string()) - }), + country_code: details.address.country.map(|country| country.to_string()), + }), + address: Some(payments::AddressDetails { + city: details.address.city, + country: details.address.country, + line1: details.address.line1, + line2: details.address.line2, + zip: details.address.postal_code, + state: details.address.state, + first_name: details.name, + line3: None, + last_name: None, }), - address: details.address, } } } +#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)] +pub struct MandateData { + pub customer_acceptance: CustomerAcceptance, + pub mandate_type: Option, + pub amount: Option, + #[serde(default, with = "common_utils::custom_serde::timestamp::option")] + pub start_date: Option, + #[serde(default, with = "common_utils::custom_serde::timestamp::option")] + pub end_date: Option, +} + +#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)] +pub struct CustomerAcceptance { + #[serde(rename = "type")] + pub acceptance_type: Option, + pub accepted_at: Option, + pub online: Option, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq, Clone)] +#[serde(rename_all = "lowercase")] +pub enum AcceptanceType { + Online, + #[default] + Offline, +} + +#[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct OnlineMandate { + pub ip_address: masking::Secret, + pub user_agent: String, +} + #[derive(Deserialize, Clone)] pub struct StripePaymentIntentRequest { pub id: Option, - pub amount: Option, //amount in cents, hence passed as integer + pub amount: Option, // amount in cents, hence passed as integer pub connector: Option>, pub currency: Option, #[serde(rename = "amount_to_capture")] @@ -167,39 +225,26 @@ pub struct StripePaymentIntentRequest { pub shipping: Option, pub statement_descriptor: Option, pub statement_descriptor_suffix: Option, - pub metadata: Option, - pub client_secret: Option>, + pub metadata: Option, + pub client_secret: Option>, pub payment_method_options: Option, pub merchant_connector_details: Option, - pub mandate_id: Option, + pub mandate: Option, pub off_session: Option, - pub payment_method_type: Option, + pub payment_method_types: Option, pub receipt_ipaddress: Option, pub user_agent: Option, + pub mandate_data: Option, + pub automatic_payment_methods: Option, // not used + pub payment_method: Option, // not used + pub confirmation_method: Option, // not used + pub error_on_requires_action: Option, // not used + pub radar_options: Option, // not used } impl TryFrom for payments::PaymentsRequest { type Error = error_stack::Report; fn try_from(item: StripePaymentIntentRequest) -> errors::RouterResult { - let (mandate_options, authentication_type) = match item.payment_method_options { - Some(pmo) => { - let StripePaymentMethodOptions::Card { - request_three_d_secure, - mandate_options, - }: StripePaymentMethodOptions = pmo; - ( - Option::::foreign_try_from(( - mandate_options, - item.currency.to_owned(), - ))?, - Some(api_enums::AuthenticationType::foreign_from( - request_three_d_secure, - )), - ) - } - None => (None, None), - }; - let routable_connector: Option = item.connector.and_then(|v| v.into_iter().next()); @@ -262,13 +307,26 @@ impl TryFrom for payments::PaymentsRequest { statement_descriptor_suffix: item.statement_descriptor_suffix, metadata: item.metadata, client_secret: item.client_secret.map(|s| s.peek().clone()), - authentication_type, - mandate_data: mandate_options, + authentication_type: match item.payment_method_options { + Some(pmo) => { + let StripePaymentMethodOptions::Card { + request_three_d_secure, + }: StripePaymentMethodOptions = pmo; + Some(api_enums::AuthenticationType::foreign_from( + request_three_d_secure, + )) + } + None => None, + }, + mandate_data: ForeignTryFrom::foreign_try_from(( + item.mandate_data, + item.currency.to_owned(), + ))?, merchant_connector_details: item.merchant_connector_details, setup_future_usage: item.setup_future_usage, - mandate_id: item.mandate_id, + mandate_id: item.mandate, off_session: item.off_session, - payment_method_type: item.payment_method_type, + payment_method_type: item.payment_method_types, routing, browser_info: Some( serde_json::to_value(crate::types::BrowserInformation { @@ -280,6 +338,7 @@ impl TryFrom for payments::PaymentsRequest { .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("convert to browser info failed")?, ), + ..Self::default() }); request @@ -334,6 +393,7 @@ impl ToString for CancellationReason { }) } } + #[derive(Debug, Deserialize, Serialize, Copy, Clone)] pub struct StripePaymentCancelRequest { cancellation_reason: Option, @@ -348,11 +408,6 @@ impl From for payments::PaymentsCancelRequest { } } -#[derive(Default, PartialEq, Eq, Deserialize, Clone)] -pub struct StripeCaptureRequest { - pub amount_to_capture: Option, -} - #[derive(Default, Eq, PartialEq, Serialize, Debug)] pub struct StripePaymentIntentResponse { pub id: Option, @@ -366,8 +421,8 @@ pub struct StripePaymentIntentResponse { pub created: Option, pub customer: Option, pub refunds: Option>, - pub mandate_id: Option, - pub metadata: Option, + pub mandate: Option, + pub metadata: Option, pub charges: Charges, pub connector: Option, pub description: Option, @@ -382,7 +437,7 @@ pub struct StripePaymentIntentResponse { pub shipping: Option, pub billing: Option, #[serde(with = "common_utils::custom_serde::iso8601::option")] - pub capture_on: Option, + pub capture_on: Option, pub payment_token: Option, pub email: Option, pub phone: Option>, @@ -423,7 +478,7 @@ impl From for StripePaymentIntentResponse { refunds: resp .refunds .map(|a| a.into_iter().map(Into::into).collect()), - mandate_id: resp.mandate_id, + mandate: resp.mandate_id, mandate_data: resp.mandate_data, setup_future_usage: resp.setup_future_usage, off_session: resp.off_session, @@ -543,7 +598,7 @@ impl TryFrom for payments::PaymentListConstraints #[inline] fn from_timestamp_to_datetime( time: Option, -) -> Result, errors::ApiErrorResponse> { +) -> Result, errors::ApiErrorResponse> { if let Some(time) = time { let time = time::OffsetDateTime::from_unix_timestamp(time).map_err(|_| { errors::ApiErrorResponse::InvalidRequestData { @@ -581,7 +636,6 @@ impl From for StripePaymentIntentListResponse { pub enum StripePaymentMethodOptions { Card { request_three_d_secure: Option, - mandate_options: Option, }, } @@ -595,21 +649,21 @@ pub enum StripeMandateType { #[derive(PartialEq, Eq, Clone, Default, Deserialize, Serialize, Debug)] pub struct MandateOption { #[serde(default, with = "common_utils::custom_serde::timestamp::option")] - pub accepted_at: Option, + pub accepted_at: Option, pub user_agent: Option, - pub ip_address: Option>, + pub ip_address: Option>, pub mandate_type: Option, pub amount: Option, #[serde(default, with = "common_utils::custom_serde::timestamp::option")] - pub start_date: Option, + pub start_date: Option, #[serde(default, with = "common_utils::custom_serde::timestamp::option")] - pub end_date: Option, + pub end_date: Option, } -impl ForeignTryFrom<(Option, Option)> for Option { +impl ForeignTryFrom<(Option, Option)> for Option { type Error = error_stack::Report; fn foreign_try_from( - (mandate_options, currency): (Option, Option), + (mandate_data, currency): (Option, Option), ) -> errors::RouterResult { let currency = currency .ok_or(errors::ApiErrorResponse::MissingRequiredField { @@ -623,7 +677,7 @@ impl ForeignTryFrom<(Option, Option)> for Option match item { StripeMandateType::SingleUse => Some(payments::MandateType::SingleUse( @@ -641,11 +695,14 @@ impl ForeignTryFrom<(Option, Option)> for Option, pub receipt_ipaddress: Option, pub user_agent: Option, + pub mandate_data: Option, } impl TryFrom for payments::PaymentsRequest { type Error = error_stack::Report; fn try_from(item: StripeSetupIntentRequest) -> errors::RouterResult { - let (mandate_options, authentication_type) = match item.payment_method_options { - Some(pmo) => { - let payment_intent::StripePaymentMethodOptions::Card { - request_three_d_secure, - mandate_options, - }: payment_intent::StripePaymentMethodOptions = pmo; - ( - Option::::foreign_try_from(( - mandate_options, - item.currency.to_owned(), - ))?, - Some(api_enums::AuthenticationType::foreign_from( - request_three_d_secure, - )), - ) - } - None => (None, None), - }; let routable_connector: Option = item.connector.and_then(|v| v.into_iter().next()); @@ -243,9 +226,22 @@ impl TryFrom for payments::PaymentsRequest { client_secret: item.client_secret.map(|s| s.peek().clone()), setup_future_usage: item.setup_future_usage, merchant_connector_details: item.merchant_connector_details, - authentication_type, routing, - mandate_data: mandate_options, + authentication_type: match item.payment_method_options { + Some(pmo) => { + let payment_intent::StripePaymentMethodOptions::Card { + request_three_d_secure, + }: payment_intent::StripePaymentMethodOptions = pmo; + Some(api_enums::AuthenticationType::foreign_from( + request_three_d_secure, + )) + } + None => None, + }, + mandate_data: ForeignTryFrom::foreign_try_from(( + item.mandate_data, + item.currency.to_owned(), + ))?, browser_info: Some( serde_json::to_value(crate::types::BrowserInformation { ip_address,