From 66563595df6ad397feb607fbca342e4b56183a91 Mon Sep 17 00:00:00 2001 From: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com> Date: Sun, 19 Feb 2023 19:29:22 +0530 Subject: [PATCH] refactor: add payment_issuer and payment_experience in pa (#491) --- Cargo.lock | 48 ++ crates/api_models/src/admin.rs | 4 +- crates/api_models/src/enums.rs | 60 ++ crates/api_models/src/payment_methods.rs | 28 +- crates/api_models/src/payments.rs | 28 +- crates/common_utils/src/custom_serde.rs | 2 +- .../router/src/connector/aci/transformers.rs | 1 - .../src/connector/adyen/transformers.rs | 4 - .../connector/authorizedotnet/transformers.rs | 2 - .../src/connector/braintree/transformers.rs | 1 - .../src/connector/checkout/transformers.rs | 4 - .../src/connector/cybersource/transformers.rs | 2 - .../src/connector/fiserv/transformers.rs | 1 - .../src/connector/globalpay/transformers.rs | 1 - crates/router/src/connector/klarna.rs | 28 +- .../src/connector/klarna/transformers.rs | 1 - .../router/src/connector/payu/transformers.rs | 4 - .../src/connector/rapyd/transformers.rs | 1 - .../src/connector/shift4/transformers.rs | 1 - .../src/connector/stripe/transformers.rs | 285 +++++--- .../src/connector/worldline/transformers.rs | 2 - crates/router/src/connector/worldpay.rs | 3 - .../src/connector/worldpay/transformers.rs | 1 - crates/router/src/core/errors.rs | 7 + crates/router/src/core/errors/utils.rs | 6 + .../router/src/core/payment_methods/cards.rs | 12 +- .../src/core/payment_methods/transformers.rs | 4 +- .../payments/operations/payment_create.rs | 2 + .../payments/operations/payment_response.rs | 2 - .../router/src/core/payments/transformers.rs | 3 +- crates/router/src/db/payment_attempt.rs | 8 +- crates/router/src/openapi.rs | 3 +- crates/router/src/types.rs | 3 +- crates/router/src/types/transformers.rs | 24 +- crates/router/tests/connectors/aci.rs | 2 + crates/router/tests/connectors/adyen.rs | 2 + .../tests/connectors/authorizedotnet.rs | 2 + crates/router/tests/connectors/checkout.rs | 2 + crates/router/tests/connectors/utils.rs | 2 + crates/router/tests/connectors/worldline.rs | 2 + crates/router/tests/payments.rs | 4 + crates/router/tests/payments2.rs | 2 + crates/router_derive/Cargo.toml | 1 + crates/router_derive/src/lib.rs | 48 +- crates/router_derive/src/macros.rs | 4 +- crates/router_derive/src/macros/diesel.rs | 84 ++- crates/storage_models/src/enums.rs | 170 +++-- crates/storage_models/src/payment_attempt.rs | 12 +- crates/storage_models/src/schema.rs | 4 +- .../down.sql | 3 + .../up.sql | 6 + .../down.sql | 15 + .../up.sql | 5 + openapi/generated.json | 635 +++++------------- 54 files changed, 790 insertions(+), 801 deletions(-) create mode 100644 migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/down.sql create mode 100644 migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/up.sql create mode 100644 migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/down.sql create mode 100644 migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/up.sql diff --git a/Cargo.lock b/Cargo.lock index fa1ee72716..607a98aa82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1181,6 +1181,41 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "dashmap" version = "5.4.0" @@ -1893,6 +1928,12 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.3.0" @@ -3094,6 +3135,7 @@ dependencies = [ name = "router_derive" version = "0.1.0" dependencies = [ + "darling", "diesel", "proc-macro2", "quote", @@ -3531,6 +3573,12 @@ dependencies = [ "time", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strum" version = "0.24.1" diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index a7f91bae6d..e4434ad23e 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use super::payments::AddressDetails; -use crate::{enums as api_enums, payment_methods}; +use crate::enums as api_enums; #[derive(Clone, Debug, Deserialize, ToSchema)] #[serde(deny_unknown_fields)] @@ -325,7 +325,7 @@ pub struct PaymentMethods { pub installment_payment_enabled: bool, /// Type of payment experience enabled with the connector #[schema(value_type = Option>,example = json!(["redirect_to_url"]))] - pub payment_experience: Option>, + pub payment_experience: Option>, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index e6c2201145..fbf421d43f 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -343,6 +343,66 @@ pub enum PaymentMethodIssuerCode { JpBacs, } +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + PartialEq, + serde::Deserialize, + serde::Serialize, + frunk::LabelledGeneric, + ToSchema, +)] +#[serde(rename_all = "snake_case")] +pub enum PaymentIssuer { + Klarna, + Affirm, + AfterpayClearpay, + AmericanExpress, + BankOfAmerica, + Barclays, + CapitalOne, + Chase, + Citi, + Discover, + NavyFederalCreditUnion, + PentagonFederalCreditUnion, + SynchronyBank, + WellsFargo, +} + +#[derive( + Eq, + PartialEq, + Hash, + Copy, + Clone, + Debug, + serde::Serialize, + serde::Deserialize, + ToSchema, + Default, + frunk::LabelledGeneric, +)] +#[serde(rename_all = "snake_case")] +pub enum PaymentExperience { + /// The URL to which the customer needs to be redirected for completing the payment. + #[default] + RedirectToUrl, + /// Contains the data for invoking the sdk client for completing the payment. + InvokeSdkClient, + /// The QR code data to be displayed to the customer. + DisplayQrCode, + /// Contains data to finish one click payment. + OneClick, + /// Redirect customer to link wallet + LinkWallet, + /// Contains the data for invoking the sdk client for completing the payment. + InvokePaymentApp, +} + #[derive( Clone, Copy, diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 4d0f484f3b..d768b52f7e 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -122,7 +122,7 @@ pub struct PaymentMethodResponse { /// Type of payment experience enabled with the connector #[schema(value_type = Option>,example = json!(["redirect_to_url"]))] - pub payment_experience: Option>, + pub payment_experience: Option>, /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object. #[schema(value_type = Option,example = json!({ "city": "NY", "unit": "245" }))] @@ -348,8 +348,8 @@ pub struct ListPaymentMethod { pub installment_payment_enabled: bool, /// Type of payment experience enabled with the connector - #[schema(example = json!(["redirect_to_url"]))] - pub payment_experience: Option>, + #[schema(value_type = Option>, example = json!(["redirect_to_url"]))] + pub payment_experience: Option>, } /// We need a custom serializer to only send relevant fields in ListPaymentMethodResponse @@ -447,7 +447,7 @@ pub struct CustomerPaymentMethod { /// Type of payment experience enabled with the connector #[schema(value_type = Option>,example = json!(["redirect_to_url"]))] - pub payment_experience: Option>, + pub payment_experience: Option>, /// Card details from card locker #[schema(example = json!({"last4": "1142","exp_month": "03","exp_year": "2030"}))] @@ -462,26 +462,6 @@ pub struct CustomerPaymentMethod { #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub created: Option, } - -#[derive(Eq, PartialEq, Hash, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] -#[serde(rename_all = "snake_case")] -#[non_exhaustive] -pub enum PaymentExperience { - /// The URL to which the customer needs to be redirected for completing the payment.The URL to - /// which the customer needs to be redirected for completing the payment. - RedirectToUrl, - /// Contains the data for invoking the sdk client for completing the payment. - InvokeSdkClient, - /// The QR code data to be displayed to the customer. - DisplayQrCode, - /// Contains data to finish one click payment. - OneClick, - /// Redirect customer to link wallet - LinkWallet, - /// Contains the data for invoking the sdk client for completing the payment. - InvokePaymentApp, -} - #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct PaymentMethodId { pub payment_method_id: String, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index b28736c980..a4705057be 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -132,6 +132,12 @@ pub struct PaymentsRequest { "java_script_enabled":true }"#)] pub browser_info: Option, + /// Payment Issuser for the current payment + #[schema(value_type = Option, example = "klarna")] + pub payment_issuer: Option, + /// Payment Experience, works in tandem with payment_issuer + #[schema(value_type = Option, example = "redirect_to_url")] + pub payment_experience: Option, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] @@ -342,35 +348,27 @@ pub enum AfterpayClearpayIssuer { pub enum PayLaterData { /// For KlarnaRedirect as PayLater Option KlarnaRedirect { - /// The issuer name of the redirect - issuer_name: KlarnaIssuer, /// The billing email - billing_email: String, + #[schema(value_type = String)] + billing_email: Secret, // The billing country code billing_country: String, }, /// For Klarna Sdk as PayLater Option KlarnaSdk { - /// The issuer name of the sdk - issuer_name: KlarnaIssuer, /// The token for the sdk workflow token: String, }, /// For Affirm redirect as PayLater Option - AffirmRedirect { - /// The issuer name of affirm redirect issuer - issuer_name: AffirmIssuer, - /// The billing email - billing_email: String, - }, + AffirmRedirect {}, /// For AfterpayClearpay redirect as PayLater Option AfterpayClearpayRedirect { - /// The issuer name of afterpayclearpay redirect issuer - issuer_name: AfterpayClearpayIssuer, /// The billing email - billing_email: String, + #[schema(value_type = String)] + billing_email: Secret, /// The billing name - billing_name: String, + #[schema(value_type = String)] + billing_name: Secret, }, } diff --git a/crates/common_utils/src/custom_serde.rs b/crates/common_utils/src/custom_serde.rs index d7bd972150..2d797a5bda 100644 --- a/crates/common_utils/src/custom_serde.rs +++ b/crates/common_utils/src/custom_serde.rs @@ -86,7 +86,7 @@ pub mod iso8601 { } } -/// https://github.com/serde-rs/serde/issues/994#issuecomment-316895860 +/// pub mod json_string { use serde::de::{self, Deserialize, DeserializeOwned, Deserializer}; diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs index 2f0e693f37..2f681a72f7 100644 --- a/crates/router/src/connector/aci/transformers.rs +++ b/crates/router/src/connector/aci/transformers.rs @@ -216,7 +216,6 @@ impl response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index de81160477..03a74af196 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -672,7 +672,6 @@ impl TryFrom> response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.psp_reference), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), @@ -722,7 +721,6 @@ pub fn get_adyen_response( let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.psp_reference), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }; @@ -783,7 +781,6 @@ pub fn get_redirection_response( let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, redirection_data: Some(redirection_data), - redirect: true, mandate_reference: None, connector_metadata: None, }; @@ -876,7 +873,6 @@ impl TryFrom> status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.psp_reference), - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs index 1d0de718a0..027ecd30c9 100644 --- a/crates/router/src/connector/authorizedotnet/transformers.rs +++ b/crates/router/src/connector/authorizedotnet/transformers.rs @@ -329,7 +329,6 @@ impl item.response.transaction_response.transaction_id, ), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: metadata, }), @@ -606,7 +605,6 @@ impl item.response.transaction.transaction_id, ), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/connector/braintree/transformers.rs b/crates/router/src/connector/braintree/transformers.rs index 37dbe67a84..e2ca6ae93f 100644 --- a/crates/router/src/connector/braintree/transformers.rs +++ b/crates/router/src/connector/braintree/transformers.rs @@ -219,7 +219,6 @@ impl item.response.transaction.id, ), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 7a1cf05520..dfb6d152ac 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -246,7 +246,6 @@ impl TryFrom> )), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirect: redirection_data.is_some(), redirection_data, mandate_reference: None, connector_metadata: None, @@ -289,7 +288,6 @@ impl TryFrom> )), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirect: redirection_data.is_some(), redirection_data, mandate_reference: None, connector_metadata: None, @@ -332,7 +330,6 @@ impl TryFrom> Ok(Self { response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.action_id.clone()), - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -404,7 +401,6 @@ impl TryFrom> resource_id: types::ResponseId::ConnectorTransactionId( item.data.request.connector_transaction_id.to_owned(), ), - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index acec267d9f..23f555d364 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -315,7 +315,6 @@ impl _ => Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), @@ -379,7 +378,6 @@ impl response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/connector/fiserv/transformers.rs b/crates/router/src/connector/fiserv/transformers.rs index b998db5d70..6699991b15 100644 --- a/crates/router/src/connector/fiserv/transformers.rs +++ b/crates/router/src/connector/fiserv/transformers.rs @@ -226,7 +226,6 @@ impl gateway_resp.transaction_processing_details.transaction_id, ), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/connector/globalpay/transformers.rs b/crates/router/src/connector/globalpay/transformers.rs index 80adfb4efa..e743ab3403 100644 --- a/crates/router/src/connector/globalpay/transformers.rs +++ b/crates/router/src/connector/globalpay/transformers.rs @@ -165,7 +165,6 @@ fn get_payment_response( _ => Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.id), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index 01a2aee175..aab27644cf 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -13,6 +13,7 @@ use crate::{ types::{ self, api::{self, ConnectorCommon}, + storage::enums as storage_enums, }, utils::{self, BytesExt}, }; @@ -235,12 +236,27 @@ impl match payment_method_data { api_payments::PaymentMethod::PayLater(api_payments::PayLaterData::KlarnaSdk { token, - .. - }) => Ok(format!( - "{}payments/v1/authorizations/{}/order", - self.base_url(connectors), - token - )), + }) => match ( + req.request.payment_issuer.as_ref(), + req.request.payment_experience.as_ref(), + ) { + ( + Some(storage_enums::PaymentIssuer::Klarna), + Some(storage_enums::PaymentExperience::InvokeSdkClient), + ) => Ok(format!( + "{}payments/v1/authorizations/{}/order", + self.base_url(connectors), + token + )), + (None, _) | (_, None) => Err(error_stack::report!( + errors::ConnectorError::MissingRequiredField { + field_name: "payment_issuer and payment_experience" + } + )), + _ => Err(error_stack::report!( + errors::ConnectorError::MismatchedPaymentData + )), + }, _ => Err(error_stack::report!( errors::ConnectorError::NotImplemented( "We only support wallet payments through klarna".to_string(), diff --git a/crates/router/src/connector/klarna/transformers.rs b/crates/router/src/connector/klarna/transformers.rs index 14810ba672..589eeecf19 100644 --- a/crates/router/src/connector/klarna/transformers.rs +++ b/crates/router/src/connector/klarna/transformers.rs @@ -114,7 +114,6 @@ impl TryFrom> Ok(Self { response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.order_id), - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, diff --git a/crates/router/src/connector/payu/transformers.rs b/crates/router/src/connector/payu/transformers.rs index 20a2c6f4bb..3c107ddcb1 100644 --- a/crates/router/src/connector/payu/transformers.rs +++ b/crates/router/src/connector/payu/transformers.rs @@ -207,7 +207,6 @@ impl status: enums::AttemptStatus::from(item.response.status.status_code), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.order_id), - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -258,7 +257,6 @@ impl status: enums::AttemptStatus::from(item.response.status.status_code.clone()), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -337,7 +335,6 @@ impl status: enums::AttemptStatus::from(item.response.status.status_code.clone()), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.order_id), - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -466,7 +463,6 @@ impl status: enums::AttemptStatus::from(order.status.clone()), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(order.order_id.clone()), - redirect: false, redirection_data: None, mandate_reference: None, connector_metadata: None, diff --git a/crates/router/src/connector/rapyd/transformers.rs b/crates/router/src/connector/rapyd/transformers.rs index a0b6df812c..e5f5866890 100644 --- a/crates/router/src/connector/rapyd/transformers.rs +++ b/crates/router/src/connector/rapyd/transformers.rs @@ -414,7 +414,6 @@ impl resource_id: types::ResponseId::ConnectorTransactionId( data.id.to_owned(), ), //transaction_id is also the field but this id is used to initiate a refund - redirect: redirection_data.is_some(), redirection_data, mandate_reference: None, connector_metadata: None, diff --git a/crates/router/src/connector/shift4/transformers.rs b/crates/router/src/connector/shift4/transformers.rs index ea1ebce8c5..bb744fe067 100644 --- a/crates/router/src/connector/shift4/transformers.rs +++ b/crates/router/src/connector/shift4/transformers.rs @@ -154,7 +154,6 @@ impl response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 865d7a243a..b473525a42 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use api_models::{self, payments}; -use common_utils::fp_utils; +use common_utils::{fp_utils, pii::Email}; use error_stack::{IntoReport, ResultExt}; use masking::ExposeInterface; use serde::{Deserialize, Serialize}; @@ -80,12 +80,13 @@ pub struct PaymentIntentRequest { pub metadata_txn_uuid: String, pub return_url: String, pub confirm: bool, - pub off_session: Option, pub mandate: Option, pub description: Option, #[serde(flatten)] pub shipping: StripeShippingAddress, #[serde(flatten)] + pub billing: StripeBillingAddress, + #[serde(flatten)] pub payment_data: Option, pub capture_method: StripeCaptureMethod, } @@ -128,27 +129,19 @@ pub struct StripePayLaterData { pub payment_method_types: StripePaymentMethodType, #[serde(rename = "payment_method_data[type]")] pub payment_method_data_type: StripePaymentMethodType, - #[serde(rename = "payment_method_data[billing_details][email]")] - pub billing_email: String, - #[serde(rename = "payment_method_data[billing_details][address][country]")] - pub billing_country: Option, - #[serde(rename = "payment_method_data[billing_details][name]")] - pub billing_name: Option, } #[derive(Debug, Eq, PartialEq, Serialize)] #[serde(untagged)] pub enum StripePaymentMethodData { Card(StripeCardData), - Klarna(StripePayLaterData), - Affirm(StripePayLaterData), - AfterpayClearpay(StripePayLaterData), + PayLater(StripePayLaterData), Bank, Wallet, Paypal, } -#[derive(Debug, Eq, PartialEq, Serialize)] +#[derive(Debug, Eq, PartialEq, Serialize, Clone)] #[serde(rename_all = "snake_case")] pub enum StripePaymentMethodType { Card, @@ -159,63 +152,165 @@ pub enum StripePaymentMethodType { fn validate_shipping_address_against_payment_method( shipping_address: &StripeShippingAddress, - payment_method: &payments::PaymentMethod, + payment_method: &StripePaymentMethodType, ) -> Result<(), errors::ConnectorError> { - if let payments::PaymentMethod::PayLater(payments::PayLaterData::AfterpayClearpayRedirect { - .. - }) = payment_method - { + if let StripePaymentMethodType::AfterpayClearpay = payment_method { fp_utils::when(shipping_address.name.is_none(), || { Err(errors::ConnectorError::MissingRequiredField { - field_name: "shipping.first_name", + field_name: "shipping.address.first_name", }) })?; fp_utils::when(shipping_address.line1.is_none(), || { Err(errors::ConnectorError::MissingRequiredField { - field_name: "shipping.line1", + field_name: "shipping.address.line1", }) })?; fp_utils::when(shipping_address.country.is_none(), || { Err(errors::ConnectorError::MissingRequiredField { - field_name: "shipping.country", + field_name: "shipping.address.country", }) })?; fp_utils::when(shipping_address.zip.is_none(), || { Err(errors::ConnectorError::MissingRequiredField { - field_name: "shipping.zip", + field_name: "shipping.address.zip", }) })?; } Ok(()) } +fn infer_stripe_pay_later_issuer( + issuer: &enums::PaymentIssuer, + experience: &enums::PaymentExperience, +) -> Result { + if &enums::PaymentExperience::RedirectToUrl == experience { + match issuer { + enums::PaymentIssuer::Klarna => Ok(StripePaymentMethodType::Klarna), + enums::PaymentIssuer::Affirm => Ok(StripePaymentMethodType::Affirm), + enums::PaymentIssuer::AfterpayClearpay => Ok(StripePaymentMethodType::AfterpayClearpay), + _ => Err(errors::ConnectorError::NotSupported { + payment_method: format!("{issuer} payments by {experience}"), + connector: "stripe", + }), + } + } else { + Err(errors::ConnectorError::NotSupported { + payment_method: format!("{issuer} payments by {experience}"), + connector: "stripe", + }) + } +} + +impl TryFrom<(&api_models::payments::PayLaterData, StripePaymentMethodType)> + for StripeBillingAddress +{ + type Error = errors::ConnectorError; + + fn try_from( + (pay_later_data, pm_type): (&api_models::payments::PayLaterData, StripePaymentMethodType), + ) -> Result { + match (pay_later_data, pm_type) { + ( + payments::PayLaterData::KlarnaRedirect { + billing_email, + billing_country, + }, + StripePaymentMethodType::Klarna, + ) => Ok(Self { + email: Some(billing_email.to_owned()), + country: Some(billing_country.to_owned()), + ..Self::default() + }), + (payments::PayLaterData::AffirmRedirect {}, StripePaymentMethodType::Affirm) => { + Ok(Self::default()) + } + ( + payments::PayLaterData::AfterpayClearpayRedirect { + billing_email, + billing_name, + }, + StripePaymentMethodType::AfterpayClearpay, + ) => Ok(Self { + email: Some(billing_email.to_owned()), + name: Some(billing_name.to_owned()), + ..Self::default() + }), + _ => Err(errors::ConnectorError::MismatchedPaymentData), + } + } +} + +fn create_stripe_payment_method( + issuer: Option<&enums::PaymentIssuer>, + experience: Option<&enums::PaymentExperience>, + payment_method: &api_models::payments::PaymentMethod, + auth_type: enums::AuthenticationType, +) -> Result< + ( + StripePaymentMethodData, + StripePaymentMethodType, + StripeBillingAddress, + ), + errors::ConnectorError, +> { + match payment_method { + payments::PaymentMethod::Card(card_details) => { + let payment_method_auth_type = match auth_type { + enums::AuthenticationType::ThreeDs => Auth3ds::Any, + enums::AuthenticationType::NoThreeDs => Auth3ds::Automatic, + }; + Ok(( + StripePaymentMethodData::Card(StripeCardData { + payment_method_types: StripePaymentMethodType::Card, + payment_method_data_type: StripePaymentMethodType::Card, + payment_method_data_card_number: card_details.card_number.clone(), + payment_method_data_card_exp_month: card_details.card_exp_month.clone(), + payment_method_data_card_exp_year: card_details.card_exp_year.clone(), + payment_method_data_card_cvc: card_details.card_cvc.clone(), + payment_method_auth_type, + }), + StripePaymentMethodType::Card, + StripeBillingAddress::default(), + )) + } + payments::PaymentMethod::PayLater(pay_later_data) => { + let pm_issuer = issuer.ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "payment_issuer", + })?; + + let pm_experience = experience.ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "payment_experience", + })?; + + let pm_type = infer_stripe_pay_later_issuer(pm_issuer, pm_experience)?; + + let billing_address = + StripeBillingAddress::try_from((pay_later_data, pm_type.clone()))?; + + Ok(( + StripePaymentMethodData::PayLater(StripePayLaterData { + payment_method_types: pm_type.clone(), + payment_method_data_type: pm_type.clone(), + }), + pm_type, + billing_address, + )) + } + _ => Err(errors::ConnectorError::NotImplemented( + "stripe does not support this payment method".to_string(), + )), + } +} + impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { type Error = errors::ConnectorError; fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { let metadata_order_id = item.payment_id.to_string(); let metadata_txn_id = format!("{}_{}_{}", item.merchant_id, item.payment_id, "1"); let metadata_txn_uuid = Uuid::new_v4().to_string(); //Fetch autogenerated txn_uuid from Database. - // let api::PaymentMethod::Card(a) = item.payment_method_data; - // let api::PaymentMethod::Card(a) = item.payment_method_data; - - let (payment_data, mandate) = { - match item - .request - .mandate_id - .clone() - .and_then(|mandate_ids| mandate_ids.connector_mandate_id) - { - None => { - let payment_method: StripePaymentMethodData = - (item.request.payment_method_data.clone(), item.auth_type).try_into()?; - (Some(payment_method), None) - } - Some(mandate_id) => (None, Some(mandate_id)), - } - }; let shipping_address = match item.address.shipping.clone() { Some(mut shipping) => StripeShippingAddress { @@ -247,15 +342,32 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { None => StripeShippingAddress::default(), }; - validate_shipping_address_against_payment_method( - &shipping_address, - &item.request.payment_method_data, - )?; + let (payment_data, mandate, billing_address) = { + match item + .request + .mandate_id + .clone() + .and_then(|mandate_ids| mandate_ids.connector_mandate_id) + { + None => { + let (payment_method_data, payment_method_type, billing_address) = + create_stripe_payment_method( + item.request.payment_issuer.as_ref(), + item.request.payment_experience.as_ref(), + &item.request.payment_method_data, + item.auth_type, + )?; - let off_session = item - .request - .off_session - .and_then(|value| mandate.as_ref().map(|_| value)); + validate_shipping_address_against_payment_method( + &shipping_address, + &payment_method_type, + )?; + + (Some(payment_method_data), None, billing_address) + } + Some(mandate_id) => (None, Some(mandate_id), StripeBillingAddress::default()), + } + }; Ok(Self { amount: item.request.amount, //hopefully we don't loose some cents here @@ -272,9 +384,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { description: item.description.clone(), shipping: shipping_address, + billing: billing_address, capture_method: StripeCaptureMethod::from(item.request.capture_method), payment_data, - off_session, mandate, }) } @@ -287,8 +399,13 @@ impl TryFrom<&types::VerifyRouterData> for SetupIntentRequest { let metadata_txn_id = format!("{}_{}_{}", item.merchant_id, item.payment_id, "1"); let metadata_txn_uuid = Uuid::new_v4().to_string(); - let payment_data: StripePaymentMethodData = - (item.request.payment_method_data.clone(), item.auth_type).try_into()?; + //Only cards supported for mandates + let pm_type = StripePaymentMethodType::Card; + let payment_data = StripePaymentMethodData::try_from(( + item.request.payment_method_data.clone(), + item.auth_type, + pm_type, + ))?; Ok(Self { confirm: true, @@ -421,7 +538,6 @@ impl // three_ds_form, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirect: redirection_data.is_some(), redirection_data, mandate_reference, connector_metadata: None, @@ -473,7 +589,6 @@ impl status: enums::AttemptStatus::from(item.response.status), response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirect: redirection_data.is_some(), redirection_data, mandate_reference, connector_metadata: None, @@ -649,13 +764,23 @@ pub struct StripeShippingAddress { pub phone: Option>, } +#[derive(Debug, Default, Eq, PartialEq, Serialize)] +pub struct StripeBillingAddress { + #[serde(rename = "payment_method_data[billing_details][email]")] + pub email: Option>, + #[serde(rename = "payment_method_data[billing_details][address][country]")] + pub country: Option, + #[serde(rename = "payment_method_data[billing_details][name]")] + pub name: Option>, +} + #[derive(Debug, Clone, serde::Deserialize, Eq, PartialEq)] pub struct StripeRedirectResponse { pub payment_intent: String, pub payment_intent_client_secret: String, pub source_redirect_slug: Option, pub redirect_status: Option, - pub source_type: Option, + pub source_type: Option>, } #[derive(Debug, Serialize, Clone, Copy)] @@ -792,10 +917,20 @@ pub struct StripeWebhookObjectId { pub data: StripeWebhookDataId, } -impl TryFrom<(api::PaymentMethod, enums::AuthenticationType)> for StripePaymentMethodData { +impl + TryFrom<( + api::PaymentMethod, + enums::AuthenticationType, + StripePaymentMethodType, + )> for StripePaymentMethodData +{ type Error = errors::ConnectorError; fn try_from( - (pm_data, auth_type): (api::PaymentMethod, enums::AuthenticationType), + (pm_data, auth_type, pm_type): ( + api::PaymentMethod, + enums::AuthenticationType, + StripePaymentMethodType, + ), ) -> Result { match pm_data { api::PaymentMethod::Card(ref ccard) => Ok(Self::Card({ @@ -814,42 +949,10 @@ impl TryFrom<(api::PaymentMethod, enums::AuthenticationType)> for StripePaymentM } })), api::PaymentMethod::BankTransfer => Ok(Self::Bank), - api::PaymentMethod::PayLater(pay_later_data) => match pay_later_data { - api_models::payments::PayLaterData::KlarnaRedirect { - billing_email, - billing_country, - .. - } => Ok(Self::Klarna(StripePayLaterData { - payment_method_types: StripePaymentMethodType::Klarna, - payment_method_data_type: StripePaymentMethodType::Klarna, - billing_email, - billing_country: Some(billing_country), - billing_name: None, - })), - api_models::payments::PayLaterData::AffirmRedirect { billing_email, .. } => { - Ok(Self::Affirm(StripePayLaterData { - payment_method_types: StripePaymentMethodType::Affirm, - payment_method_data_type: StripePaymentMethodType::Affirm, - billing_email, - billing_country: None, - billing_name: None, - })) - } - api_models::payments::PayLaterData::AfterpayClearpayRedirect { - billing_email, - billing_name, - .. - } => Ok(Self::AfterpayClearpay(StripePayLaterData { - payment_method_types: StripePaymentMethodType::AfterpayClearpay, - payment_method_data_type: StripePaymentMethodType::AfterpayClearpay, - billing_email, - billing_country: None, - billing_name: Some(billing_name), - })), - _ => Err(errors::ConnectorError::NotImplemented(String::from( - "Stripe does not support payment through provided payment method", - ))), - }, + api::PaymentMethod::PayLater(_) => Ok(Self::PayLater(StripePayLaterData { + payment_method_types: pm_type.clone(), + payment_method_data_type: pm_type, + })), api::PaymentMethod::Wallet(_) => Ok(Self::Wallet), api::PaymentMethod::Paypal => Ok(Self::Paypal), } diff --git a/crates/router/src/connector/worldline/transformers.rs b/crates/router/src/connector/worldline/transformers.rs index f2eefdf8ba..4722a81ed2 100644 --- a/crates/router/src/connector/worldline/transformers.rs +++ b/crates/router/src/connector/worldline/transformers.rs @@ -357,7 +357,6 @@ impl TryFrom TryFrom> response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::try_from(item.response.links)?, redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }), diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index 8bead7d183..c27f2ee65a 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -248,6 +248,11 @@ pub enum ConnectorError { FailedToObtainCertificateKey, #[error("This step has not been implemented for: {0}")] NotImplemented(String), + #[error("{payment_method} is not supported by {connector}")] + NotSupported { + payment_method: String, + connector: &'static str, + }, #[error("Missing connector transaction ID")] MissingConnectorTransactionID, #[error("Missing connector refund ID")] @@ -270,6 +275,8 @@ pub enum ConnectorError { WebhookResourceObjectNotFound, #[error("Invalid Date/time format")] InvalidDateFormat, + #[error("Payment Issuer does not match the Payment Data provided")] + MismatchedPaymentData, } #[derive(Debug, thiserror::Error)] diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs index d146dd0dd6..4371b6bf5a 100644 --- a/crates/router/src/core/errors/utils.rs +++ b/crates/router/src/core/errors/utils.rs @@ -101,6 +101,12 @@ impl ConnectorErrorExt for error_stack::Report { ), } } + errors::ConnectorError::MismatchedPaymentData => { + errors::ApiErrorResponse::InvalidDataValue { + field_name: + "payment_method_data and payment_issuer, payment_experience does not match", + } + } _ => errors::ApiErrorResponse::InternalServerError, }; self.change_context(error) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index ee9a8ea546..e004707a1d 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -85,9 +85,7 @@ pub async fn add_payment_method( payment_method_issuer_code: req.payment_method_issuer_code, recurring_enabled: false, //[#219] installment_payment_enabled: false, //[#219] - payment_experience: Some(vec![ - api_models::payment_methods::PaymentExperience::RedirectToUrl, - ]), //[#219] + payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219] }) } } @@ -635,9 +633,7 @@ pub async fn list_customer_payment_method( .map(ForeignInto::foreign_into), recurring_enabled: false, installment_payment_enabled: false, - payment_experience: Some(vec![ - api_models::payment_methods::PaymentExperience::RedirectToUrl, - ]), + payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), created: Some(pm.created_at), }; vec.push(pma); @@ -880,9 +876,7 @@ pub async fn retrieve_payment_method( .map(ForeignInto::foreign_into), recurring_enabled: false, //[#219] installment_payment_enabled: false, //[#219] - payment_experience: Some(vec![ - api_models::payment_methods::PaymentExperience::RedirectToUrl, - ]), //[#219], + payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219], }, )) } diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs index cedf98e5dc..2144bd7e01 100644 --- a/crates/router/src/core/payment_methods/transformers.rs +++ b/crates/router/src/core/payment_methods/transformers.rs @@ -127,9 +127,7 @@ pub fn mk_add_card_response( payment_method_issuer_code: req.payment_method_issuer_code, recurring_enabled: false, // [#256] installment_payment_enabled: false, // #[#256] - payment_experience: Some(vec![ - api_models::payment_methods::PaymentExperience::RedirectToUrl, - ]), // [#256] + payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), // [#256] } } diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 450572adaa..f8b8f756a3 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -433,6 +433,8 @@ impl PaymentCreate { last_synced, authentication_type: request.authentication_type.map(ForeignInto::foreign_into), browser_info, + payment_experience: request.payment_experience.map(ForeignInto::foreign_into), + payment_issuer: request.payment_issuer.map(ForeignInto::foreign_into), ..storage::PaymentAttemptNew::default() } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 33c0d4fe69..6f8761363e 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -280,7 +280,6 @@ async fn payment_response_update_tracker( types::PaymentsResponseData::TransactionResponse { resource_id, redirection_data, - redirect, connector_metadata, .. } => { @@ -305,7 +304,6 @@ async fn payment_response_update_tracker( connector_transaction_id: connector_transaction_id.clone(), authentication_type: None, payment_method_id: Some(router_data.payment_method_id), - redirect: Some(redirect), mandate_id: payment_data .mandate_id .clone() diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 51c4d35ce1..ee6b62f9e7 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -65,7 +65,6 @@ where .map(|id| types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(id.to_string()), redirection_data: None, - redirect: false, mandate_reference: None, connector_metadata: None, }); @@ -430,6 +429,8 @@ impl TryFrom> for types::PaymentsAuthorizeData { currency: payment_data.currency, browser_info, email: payment_data.email, + payment_experience: payment_data.payment_attempt.payment_experience, + payment_issuer: payment_data.payment_attempt.payment_issuer, order_details, }) } diff --git a/crates/router/src/db/payment_attempt.rs b/crates/router/src/db/payment_attempt.rs index ab8c0027ad..83f4bc9726 100644 --- a/crates/router/src/db/payment_attempt.rs +++ b/crates/router/src/db/payment_attempt.rs @@ -227,8 +227,6 @@ impl PaymentAttemptInterface for MockDb { tax_amount: payment_attempt.tax_amount, payment_method_id: payment_attempt.payment_method_id, payment_method: payment_attempt.payment_method, - payment_flow: payment_attempt.payment_flow, - redirect: payment_attempt.redirect, connector_transaction_id: payment_attempt.connector_transaction_id, capture_method: payment_attempt.capture_method, capture_on: payment_attempt.capture_on, @@ -244,6 +242,8 @@ impl PaymentAttemptInterface for MockDb { payment_token: None, error_code: payment_attempt.error_code, connector_metadata: None, + payment_experience: payment_attempt.payment_experience, + payment_issuer: payment_attempt.payment_issuer, }; payment_attempts.push(payment_attempt.clone()); Ok(payment_attempt) @@ -366,8 +366,6 @@ mod storage { tax_amount: payment_attempt.tax_amount, payment_method_id: payment_attempt.payment_method_id.clone(), payment_method: payment_attempt.payment_method, - payment_flow: payment_attempt.payment_flow, - redirect: payment_attempt.redirect, connector_transaction_id: payment_attempt.connector_transaction_id.clone(), capture_method: payment_attempt.capture_method, capture_on: payment_attempt.capture_on, @@ -383,6 +381,8 @@ mod storage { payment_token: payment_attempt.payment_token.clone(), error_code: payment_attempt.error_code.clone(), connector_metadata: payment_attempt.connector_metadata.clone(), + payment_experience: payment_attempt.payment_experience.clone(), + payment_issuer: payment_attempt.payment_issuer, }; let field = format!("pa_{}", created_attempt.attempt_id); diff --git a/crates/router/src/openapi.rs b/crates/router/src/openapi.rs index d158c5316f..89032a53ea 100644 --- a/crates/router/src/openapi.rs +++ b/crates/router/src/openapi.rs @@ -139,6 +139,8 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::SupportedWallets, api_models::enums::PaymentMethodIssuerCode, api_models::enums::MandateStatus, + api_models::enums::PaymentExperience, + api_models::enums::PaymentIssuer, api_models::admin::PaymentConnectorCreate, api_models::admin::PaymentMethods, api_models::payments::AddressDetails, @@ -163,7 +165,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::CustomerAcceptance, api_models::payments::PaymentsRequest, api_models::payments::PaymentsResponse, - api_models::payment_methods::PaymentExperience, api_models::payments::PaymentsStartRequest, api_models::payments::PaymentRetrieveBody, api_models::payments::PaymentsRetrieveRequest, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 0cc6d6f218..86d2fd67c0 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -115,6 +115,8 @@ pub struct PaymentsAuthorizeData { pub setup_mandate_details: Option, pub browser_info: Option, pub order_details: Option, + pub payment_issuer: Option, + pub payment_experience: Option, } #[derive(Debug, Clone)] @@ -181,7 +183,6 @@ pub enum PaymentsResponseData { TransactionResponse { resource_id: ResponseId, redirection_data: Option, - redirect: bool, mandate_reference: Option, connector_metadata: Option, }, diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 6d4a3511fd..b900c630f9 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -88,18 +88,6 @@ where } } -impl From> for F { - fn from(algo: F) -> Self { - Self(frunk::labelled_convert_from(algo.0)) - } -} - -impl From> for F { - fn from(algo: F) -> Self { - Self(frunk::labelled_convert_from(algo.0)) - } -} - impl From> for F { fn from(conn: F) -> Self { Self(frunk::labelled_convert_from(conn.0)) @@ -158,6 +146,18 @@ impl From> for F> for F { + fn from(issuer: F) -> Self { + Self(frunk::labelled_convert_from(issuer.0)) + } +} + +impl From> for F { + fn from(experience: F) -> Self { + Self(frunk::labelled_convert_from(experience.0)) + } +} + impl From> for F { fn from(status: F) -> Self { Self(frunk::labelled_convert_from(status.0)) diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index 115d4af308..23f9ddfcf8 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -50,6 +50,8 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { browser_info: None, order_details: None, email: None, + payment_experience: None, + payment_issuer: None, }, response: Err(types::ErrorResponse::default()), payment_method_id: None, diff --git a/crates/router/tests/connectors/adyen.rs b/crates/router/tests/connectors/adyen.rs index da0a412784..632d8faf71 100644 --- a/crates/router/tests/connectors/adyen.rs +++ b/crates/router/tests/connectors/adyen.rs @@ -78,6 +78,8 @@ impl AdyenTest { browser_info: None, order_details: None, email: None, + payment_experience: None, + payment_issuer: None, }) } } diff --git a/crates/router/tests/connectors/authorizedotnet.rs b/crates/router/tests/connectors/authorizedotnet.rs index 5068e1d46c..c5fa9ccc58 100644 --- a/crates/router/tests/connectors/authorizedotnet.rs +++ b/crates/router/tests/connectors/authorizedotnet.rs @@ -50,6 +50,8 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { browser_info: None, order_details: None, email: None, + payment_experience: None, + payment_issuer: None, }, payment_method_id: None, response: Err(types::ErrorResponse::default()), diff --git a/crates/router/tests/connectors/checkout.rs b/crates/router/tests/connectors/checkout.rs index a75caff6c1..e9f6b6b1c8 100644 --- a/crates/router/tests/connectors/checkout.rs +++ b/crates/router/tests/connectors/checkout.rs @@ -47,6 +47,8 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { browser_info: None, order_details: None, email: None, + payment_experience: None, + payment_issuer: None, }, response: Err(types::ErrorResponse::default()), payment_method_id: None, diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index 32ab2637bf..e1974180e5 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -469,6 +469,8 @@ impl Default for PaymentAuthorizeType { browser_info: Some(BrowserInfoType::default().0), order_details: None, email: None, + payment_experience: None, + payment_issuer: None, }; Self(data) } diff --git a/crates/router/tests/connectors/worldline.rs b/crates/router/tests/connectors/worldline.rs index 08bcbad43f..f284baf6df 100644 --- a/crates/router/tests/connectors/worldline.rs +++ b/crates/router/tests/connectors/worldline.rs @@ -80,6 +80,8 @@ impl WorldlineTest { browser_info: None, order_details: None, email: None, + payment_experience: None, + payment_issuer: None, }) } } diff --git a/crates/router/tests/payments.rs b/crates/router/tests/payments.rs index b27a100d76..7452ecda85 100644 --- a/crates/router/tests/payments.rs +++ b/crates/router/tests/payments.rs @@ -327,6 +327,8 @@ async fn payments_create_core() { off_session: None, client_secret: None, browser_info: None, + payment_experience: None, + payment_issuer: None, }; let expected_response = api::PaymentsResponse { @@ -482,6 +484,8 @@ async fn payments_create_core_adyen_no_redirect() { off_session: None, client_secret: None, browser_info: None, + payment_experience: None, + payment_issuer: None, }; let expected_response = services::ApplicationResponse::Json(api::PaymentsResponse { diff --git a/crates/router/tests/payments2.rs b/crates/router/tests/payments2.rs index a4e9e498cc..d7c80f560a 100644 --- a/crates/router/tests/payments2.rs +++ b/crates/router/tests/payments2.rs @@ -239,6 +239,8 @@ async fn payments_create_core_adyen_no_redirect() { mandate_id: None, client_secret: None, browser_info: None, + payment_experience: None, + payment_issuer: None, }; let expected_response = services::ApplicationResponse::Json(api::PaymentsResponse { diff --git a/crates/router_derive/Cargo.toml b/crates/router_derive/Cargo.toml index 47a4d8a59d..62540a0f2d 100644 --- a/crates/router_derive/Cargo.toml +++ b/crates/router_derive/Cargo.toml @@ -12,6 +12,7 @@ proc-macro = true doctest = false [dependencies] +darling = "0.14.3" proc-macro2 = "1.0.50" quote = "1.0.23" syn = { version = "1.0.107", features = ["full", "extra-traits"] } # the full feature does not seem to encompass all the features diff --git a/crates/router_derive/src/lib.rs b/crates/router_derive/src/lib.rs index da7c01202f..4fe12da088 100644 --- a/crates/router_derive/src/lib.rs +++ b/crates/router_derive/src/lib.rs @@ -53,13 +53,13 @@ pub fn debug_as_display_derive(input: proc_macro::TokenStream) -> proc_macro::To /// # Example /// /// ``` -/// use router_derive::{DieselEnum, diesel_enum}; +/// use router_derive::diesel_enum; /// /// // Deriving `FromStr` and `ToString` using the `strum` crate, you can also implement it /// // yourself if required. /// #[derive(strum::Display, strum::EnumString)] -/// #[derive(Debug, DieselEnum)] -/// #[diesel_enum] +/// #[derive(Debug)] +/// #[diesel_enum(storage_type = "pg_enum")] /// enum Color { /// Red, /// Green, @@ -69,32 +69,64 @@ pub fn debug_as_display_derive(input: proc_macro::TokenStream) -> proc_macro::To #[proc_macro_derive(DieselEnum)] pub fn diesel_enum_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as syn::DeriveInput); - let tokens = macros::diesel_enum_derive_inner(&ast).unwrap_or_else(|error| error.to_compile_error()); tokens.into() } +/// Similar to [`DieselEnum`] but uses text when storing in the database, this is to avoid +/// making changes to the database when the enum variants are added or modified +/// +/// # Example +/// [DieselEnum]: macro@crate::diesel_enum +/// +/// ``` +/// use router_derive::{diesel_enum}; +/// +/// // Deriving `FromStr` and `ToString` using the `strum` crate, you can also implement it +/// // yourself if required. +/// #[derive(strum::Display, strum::EnumString)] +/// #[derive(Debug)] +/// #[diesel_enum(storage_type = "text")] +/// enum Color { +/// Red, +/// Green, +/// Blue, +/// } +/// ``` +#[proc_macro_derive(DieselEnumText)] +pub fn diesel_enum_derive_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse_macro_input!(input as syn::DeriveInput); + let tokens = macros::diesel_enum_text_derive_inner(&ast) + .unwrap_or_else(|error| error.to_compile_error()); + tokens.into() +} + /// Derives the boilerplate code required for using an enum with `diesel` and a PostgreSQL database. /// -/// Works in tandem with the [`DieselEnum`][DieselEnum] derive macro to achieve the desired results. +/// Storage Type can either be "text" or "pg_enum" +/// Choosing text will store the enum as text in the database, whereas pg_enum will map it to the +/// database enum +/// +/// Works in tandem with the [`DieselEnum`][DieselEnum] and [`DieselEnumText`][DieselEnumText] derive macro to achieve the desired results. /// The enum is required to implement (or derive) the [`ToString`][ToString] and the /// [`FromStr`][FromStr] traits for the [`DieselEnum`][DieselEnum] derive macro to be used. /// /// [DieselEnum]: crate::DieselEnum +/// [DieselEnumText]: crate::DieselEnumText /// [FromStr]: ::core::str::FromStr /// [ToString]: ::std::string::ToString /// /// # Example /// /// ``` -/// use router_derive::{DieselEnum, diesel_enum}; +/// use router_derive::{diesel_enum}; /// /// // Deriving `FromStr` and `ToString` using the `strum` crate, you can also implement it /// // yourself if required. (Required by the DieselEnum derive macro.) /// #[derive(strum::Display, strum::EnumString)] -/// #[derive(Debug, DieselEnum)] -/// #[diesel_enum] +/// #[derive(Debug)] +/// #[diesel_enum(storage_type = "text")] /// enum Color { /// Red, /// Green, diff --git a/crates/router_derive/src/macros.rs b/crates/router_derive/src/macros.rs index db3eb7fc9d..f9dfa3e741 100644 --- a/crates/router_derive/src/macros.rs +++ b/crates/router_derive/src/macros.rs @@ -9,7 +9,9 @@ use syn::DeriveInput; pub(crate) use self::{ api_error::api_error_derive_inner, - diesel::{diesel_enum_attribute_inner, diesel_enum_derive_inner}, + diesel::{ + diesel_enum_attribute_inner, diesel_enum_derive_inner, diesel_enum_text_derive_inner, + }, operation::operation_derive_inner, }; diff --git a/crates/router_derive/src/macros/diesel.rs b/crates/router_derive/src/macros/diesel.rs index b49b9ccc33..3b50fdcf6c 100644 --- a/crates/router_derive/src/macros/diesel.rs +++ b/crates/router_derive/src/macros/diesel.rs @@ -1,9 +1,46 @@ +use darling::FromMeta; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; use syn::{AttributeArgs, Data, DeriveInput, ItemEnum}; use crate::macros::helpers::non_enum_error; +pub(crate) fn diesel_enum_text_derive_inner(ast: &DeriveInput) -> syn::Result { + let name = &ast.ident; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + + match &ast.data { + Data::Enum(_) => (), + _ => return Err(non_enum_error()), + } + + Ok(quote! { + #[automatically_derived] + impl #impl_generics ::diesel::serialize::ToSql<::diesel::sql_types::Text, ::diesel::pg::Pg> for #name #ty_generics + #where_clause + { + fn to_sql<'b>(&'b self, out: &mut ::diesel::serialize::Output<'b, '_, ::diesel::pg::Pg>) -> ::diesel::serialize::Result { + use ::std::io::Write; + + out.write_all(self.to_string().as_bytes())?; + Ok(::diesel::serialize::IsNull::No) + } + } + + #[automatically_derived] + impl #impl_generics ::diesel::deserialize::FromSql<::diesel::sql_types::Text, ::diesel::pg::Pg> for #name #ty_generics + #where_clause + { + fn from_sql(value: ::diesel::pg::PgValue) -> diesel::deserialize::Result { + use ::core::str::FromStr; + + Self::from_str(::core::str::from_utf8(value.as_bytes())?) + .map_err(|_| "Unrecognized enum variant".into()) + } + } + }) +} + pub(crate) fn diesel_enum_derive_inner(ast: &DeriveInput) -> syn::Result { let name = &ast.ident; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); @@ -50,18 +87,41 @@ pub(crate) fn diesel_enum_attribute_inner( args: &AttributeArgs, item: &ItemEnum, ) -> syn::Result { - if !args.is_empty() { - return Err(syn::Error::new( - Span::call_site(), - "This attribute macro does not accept any arguments.", - )); + #[derive(FromMeta, Debug)] + enum StorageType { + PgEnum, + Text, } - let name = &item.ident; - let struct_name = format_ident!("Db{name}"); - Ok(quote! { - #[derive(diesel::AsExpression, diesel::FromSqlRow)] - #[diesel(sql_type = #struct_name)] - #item - }) + #[derive(FromMeta, Debug)] + struct StorageTypeArgs { + storage_type: StorageType, + } + + let storage_type_args = match StorageTypeArgs::from_list(args) { + Ok(v) => v, + Err(_) => { + return Err(syn::Error::new( + Span::call_site(), + "Expected storage_type of text or pg_enum", + )); + } + }; + + match storage_type_args.storage_type { + StorageType::PgEnum => { + let name = &item.ident; + let type_name = format_ident!("Db{name}"); + Ok(quote! { + #[derive(diesel::AsExpression, diesel::FromSqlRow, router_derive::DieselEnum) ] + #[diesel(sql_type = #type_name)] + #item + }) + } + StorageType::Text => Ok(quote! { + #[derive(diesel::AsExpression, diesel::FromSqlRow, router_derive::DieselEnumText) ] + #[diesel(sql_type = ::diesel::sql_types::Text)] + #item + }), + } } diff --git a/crates/storage_models/src/enums.rs b/crates/storage_models/src/enums.rs index eb4d4a200a..89e37f7499 100644 --- a/crates/storage_models/src/enums.rs +++ b/crates/storage_models/src/enums.rs @@ -6,11 +6,11 @@ pub mod diesel_exports { DbEventClass as EventClass, DbEventObjectType as EventObjectType, DbEventType as EventType, DbFutureUsage as FutureUsage, DbIntentStatus as IntentStatus, DbMandateStatus as MandateStatus, DbMandateType as MandateType, - DbMerchantStorageScheme as MerchantStorageScheme, DbPaymentFlow as PaymentFlow, + DbMerchantStorageScheme as MerchantStorageScheme, DbPaymentMethodIssuerCode as PaymentMethodIssuerCode, DbPaymentMethodSubType as PaymentMethodSubType, DbPaymentMethodType as PaymentMethodType, DbProcessTrackerStatus as ProcessTrackerStatus, DbRefundStatus as RefundStatus, - DbRefundType as RefundType, DbRoutingAlgorithm as RoutingAlgorithm, + DbRefundType as RefundType, }; } @@ -25,9 +25,8 @@ pub mod diesel_exports { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum AttemptStatus { @@ -66,10 +65,9 @@ pub enum AttemptStatus { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum AuthenticationType { @@ -89,10 +87,9 @@ pub enum AuthenticationType { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum CaptureMethod { @@ -113,10 +110,9 @@ pub enum CaptureMethod { strum::EnumString, serde::Deserialize, serde::Serialize, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[strum(serialize_all = "snake_case")] #[serde(rename_all = "snake_case")] pub enum ConnectorType { @@ -149,10 +145,9 @@ pub enum ConnectorType { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] pub enum Currency { AED, ALL, @@ -270,9 +265,8 @@ pub enum Currency { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum EventClass { @@ -289,9 +283,8 @@ pub enum EventClass { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum EventObjectType { @@ -308,10 +301,9 @@ pub enum EventObjectType { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum EventType { @@ -329,10 +321,9 @@ pub enum EventType { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum IntentStatus { @@ -358,10 +349,9 @@ pub enum IntentStatus { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum FutureUsage { @@ -381,9 +371,8 @@ pub enum FutureUsage { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum MerchantStorageScheme { @@ -392,30 +381,6 @@ pub enum MerchantStorageScheme { RedisKv, } -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - strum::Display, - strum::EnumString, - serde::Serialize, - serde::Deserialize, - router_derive::DieselEnum, -)] -#[router_derive::diesel_enum] -#[strum(serialize_all = "snake_case")] -pub enum PaymentFlow { - Vsc, - Emi, - Otp, - UpiIntent, - UpiCollect, - UpiScanAndPay, - Sdk, -} - #[derive( Clone, Copy, @@ -427,10 +392,9 @@ pub enum PaymentFlow { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[strum(serialize_all = "snake_case")] #[serde(rename_all = "snake_case")] pub enum PaymentMethodIssuerCode { @@ -457,10 +421,9 @@ pub enum PaymentMethodIssuerCode { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum PaymentMethodSubType { @@ -484,10 +447,9 @@ pub enum PaymentMethodSubType { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum PaymentMethodType { @@ -517,9 +479,8 @@ pub enum PaymentMethodType { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "lowercase")] #[strum(serialize_all = "lowercase")] pub enum WalletIssuer { @@ -537,9 +498,8 @@ pub enum WalletIssuer { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum ProcessTrackerStatus { @@ -566,10 +526,9 @@ pub enum ProcessTrackerStatus { serde::Deserialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[strum(serialize_all = "snake_case")] pub enum RefundStatus { Failure, @@ -591,9 +550,8 @@ pub enum RefundStatus { serde::Deserialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[strum(serialize_all = "snake_case")] pub enum RefundType { InstantRefund, @@ -602,29 +560,6 @@ pub enum RefundType { RetryRefund, } -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, - router_derive::DieselEnum, - frunk::LabelledGeneric, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -#[router_derive::diesel_enum] -pub enum RoutingAlgorithm { - RoundRobin, - MaxConversion, - MinCost, - Custom, -} - // Mandate #[derive( Clone, @@ -637,9 +572,8 @@ pub enum RoutingAlgorithm { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum MandateType { @@ -659,10 +593,9 @@ pub enum MandateType { serde::Serialize, strum::Display, strum::EnumString, - router_derive::DieselEnum, frunk::LabelledGeneric, )] -#[router_derive::diesel_enum] +#[router_derive::diesel_enum(storage_type = "pg_enum")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum MandateStatus { @@ -672,3 +605,62 @@ pub enum MandateStatus { Pending, Revoked, } + +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, + frunk::LabelledGeneric, +)] +#[router_derive::diesel_enum(storage_type = "text")] +#[strum(serialize_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum PaymentIssuer { + Klarna, + Affirm, + AfterpayClearpay, + AmericanExpress, + BankOfAmerica, + Barclays, + CapitalOne, + Chase, + Citi, + Discover, + NavyFederalCreditUnion, + PentagonFederalCreditUnion, + SynchronyBank, + WellsFargo, +} + +#[derive( + Eq, + PartialEq, + Hash, + Clone, + Debug, + serde::Serialize, + serde::Deserialize, + Default, + strum::Display, + strum::EnumString, + frunk::LabelledGeneric, +)] +#[router_derive::diesel_enum(storage_type = "text")] +#[strum(serialize_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum PaymentExperience { + #[default] + RedirectToUrl, + InvokeSdkClient, + DisplayQrCode, + OneClick, + LinkWallet, + InvokePaymentApp, +} diff --git a/crates/storage_models/src/payment_attempt.rs b/crates/storage_models/src/payment_attempt.rs index 93aa1d3c6c..175e625c08 100644 --- a/crates/storage_models/src/payment_attempt.rs +++ b/crates/storage_models/src/payment_attempt.rs @@ -22,8 +22,6 @@ pub struct PaymentAttempt { pub tax_amount: Option, pub payment_method_id: Option, pub payment_method: Option, - pub payment_flow: Option, - pub redirect: Option, pub connector_transaction_id: Option, pub capture_method: Option, pub capture_on: Option, @@ -39,6 +37,8 @@ pub struct PaymentAttempt { pub error_code: Option, pub payment_token: Option, pub connector_metadata: Option, + pub payment_issuer: Option, + pub payment_experience: Option, } #[derive( @@ -61,8 +61,6 @@ pub struct PaymentAttemptNew { pub tax_amount: Option, pub payment_method_id: Option, pub payment_method: Option, - pub payment_flow: Option, - pub redirect: Option, pub connector_transaction_id: Option, pub capture_method: Option, pub capture_on: Option, @@ -78,6 +76,8 @@ pub struct PaymentAttemptNew { pub payment_token: Option, pub error_code: Option, pub connector_metadata: Option, + pub payment_issuer: Option, + pub payment_experience: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -117,7 +117,6 @@ pub enum PaymentAttemptUpdate { connector_transaction_id: Option, authentication_type: Option, payment_method_id: Option>, - redirect: Option, mandate_id: Option, connector_metadata: Option, }, @@ -146,7 +145,6 @@ pub struct PaymentAttemptUpdateInternal { payment_method_id: Option>, cancellation_reason: Option, modified_at: Option, - redirect: Option, mandate_id: Option, browser_info: Option, payment_token: Option, @@ -243,7 +241,6 @@ impl From for PaymentAttemptUpdateInternal { connector_transaction_id, authentication_type, payment_method_id, - redirect, mandate_id, connector_metadata, } => Self { @@ -253,7 +250,6 @@ impl From for PaymentAttemptUpdateInternal { authentication_type, payment_method_id, modified_at: Some(common_utils::date_time::now()), - redirect, mandate_id, connector_metadata, ..Default::default() diff --git a/crates/storage_models/src/schema.rs b/crates/storage_models/src/schema.rs index d2fd26ec38..0cfed2bd42 100644 --- a/crates/storage_models/src/schema.rs +++ b/crates/storage_models/src/schema.rs @@ -219,8 +219,6 @@ diesel::table! { tax_amount -> Nullable, payment_method_id -> Nullable, payment_method -> Nullable, - payment_flow -> Nullable, - redirect -> Nullable, connector_transaction_id -> Nullable, capture_method -> Nullable, capture_on -> Nullable, @@ -236,6 +234,8 @@ diesel::table! { error_code -> Nullable, payment_token -> Nullable, connector_metadata -> Nullable, + payment_issuer -> Nullable, + payment_experience -> Nullable, } } diff --git a/migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/down.sql b/migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/down.sql new file mode 100644 index 0000000000..bc8ba15c7b --- /dev/null +++ b/migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/down.sql @@ -0,0 +1,3 @@ +ALTER TABLE payment_attempt DROP COLUMN IF EXISTS payment_issuer; + +ALTER TABLE payment_attempt DROP COLUMN IF EXISTS payment_experience; diff --git a/migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/up.sql b/migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/up.sql new file mode 100644 index 0000000000..0fd96f21f1 --- /dev/null +++ b/migrations/2023-02-02-055700_add_payment_issuer_and_experience_in_payment_attempt/up.sql @@ -0,0 +1,6 @@ +-- Your SQL goes here +ALTER TABLE payment_attempt +ADD COLUMN IF NOT EXISTS payment_issuer VARCHAR(50); + +ALTER TABLE payment_attempt +ADD COLUMN IF NOT EXISTS payment_experience VARCHAR(50); diff --git a/migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/down.sql b/migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/down.sql new file mode 100644 index 0000000000..67dc64c0f5 --- /dev/null +++ b/migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/down.sql @@ -0,0 +1,15 @@ +CREATE TYPE "PaymentFlow" AS ENUM ( + 'vsc', + 'emi', + 'otp', + 'upi_intent', + 'upi_collect', + 'upi_scan_and_pay', + 'sdk' +); + +ALTER TABLE payment_attempt +ADD COLUMN payment_flow "PaymentFlow"; + +ALTER TABLE payment_attempt +ADD COLUMN redirect BOOLEAN; diff --git a/migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/up.sql b/migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/up.sql new file mode 100644 index 0000000000..e1997e0226 --- /dev/null +++ b/migrations/2023-02-02-062215_remove_redirect_and_payment_flow_from_payment_attempt/up.sql @@ -0,0 +1,5 @@ +ALTER TABLE payment_attempt DROP COLUMN IF EXISTS redirect; + +ALTER TABLE payment_attempt DROP COLUMN IF EXISTS payment_flow; + +DROP TYPE IF EXISTS "PaymentFlow"; diff --git a/openapi/generated.json b/openapi/generated.json index 34ead266ca..28273b8b5b 100644 --- a/openapi/generated.json +++ b/openapi/generated.json @@ -22,9 +22,7 @@ "paths": { "/accounts": { "post": { - "tags": [ - "Merchant Account" - ], + "tags": ["Merchant Account"], "summary": "", "description": "\nCreate a new account for a merchant and the merchant could be a seller or retailer or client who likes to receive and send payments.", "operationId": "Create a Merchant Account", @@ -58,9 +56,7 @@ }, "/accounts/{account_id}": { "get": { - "tags": [ - "Merchant Account" - ], + "tags": ["Merchant Account"], "summary": "", "description": "\nRetrieve a merchant account details.", "operationId": "Retrieve a Merchant Account", @@ -93,9 +89,7 @@ "deprecated": false }, "post": { - "tags": [ - "Merchant Account" - ], + "tags": ["Merchant Account"], "summary": "", "description": "\nTo update an existing merchant account. Helpful in updating merchant details such as email, contact details, or other configuration details like webhook, routing algorithm etc", "operationId": "Update a Merchant Account", @@ -138,9 +132,7 @@ "deprecated": false }, "delete": { - "tags": [ - "Merchant Account" - ], + "tags": ["Merchant Account"], "summary": "", "description": "\nTo delete a merchant account", "operationId": "Delete a Merchant Account", @@ -175,9 +167,7 @@ }, "/accounts/{account_id}/connectors": { "get": { - "tags": [ - "Merchant Connector Account" - ], + "tags": ["Merchant Connector Account"], "summary": "", "description": "\nList Payment Connector Details for the merchant", "operationId": "List all Merchant Connectors", @@ -216,9 +206,7 @@ "deprecated": false }, "post": { - "tags": [ - "Merchant Connector Account" - ], + "tags": ["Merchant Connector Account"], "summary": "", "description": "\nCreate a new Payment Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc.\"", "operationId": "Create a Merchant Connector", @@ -252,9 +240,7 @@ }, "/accounts/{account_id}/connectors/{connector_id}": { "get": { - "tags": [ - "Merchant Connector Account" - ], + "tags": ["Merchant Connector Account"], "summary": "", "description": "\nRetrieve Payment Connector Details", "operationId": "Retrieve a Merchant Connector", @@ -300,9 +286,7 @@ "deprecated": false }, "post": { - "tags": [ - "Merchant Connector Account" - ], + "tags": ["Merchant Connector Account"], "summary": "", "description": "\nTo update an existing Payment Connector. Helpful in enabling / disabling different payment methods and other settings for the connector etc.", "operationId": "Update a Merchant Connector", @@ -358,9 +342,7 @@ "deprecated": false }, "delete": { - "tags": [ - "Merchant Connector Account" - ], + "tags": ["Merchant Connector Account"], "summary": "", "description": "\nDelete or Detach a Payment Connector from Merchant Account", "operationId": "Delete a Merchant Connector", @@ -609,9 +591,7 @@ }, "/customers": { "post": { - "tags": [ - "Customers" - ], + "tags": ["Customers"], "summary": "", "description": "\nCreate a customer object and store the customer details to be reused for future payments. Incase the customer already exists in the system, this API will respond with the customer details.", "operationId": "Create a Customer", @@ -645,9 +625,7 @@ }, "/customers/{customer_id}": { "get": { - "tags": [ - "Customers" - ], + "tags": ["Customers"], "summary": "", "description": "\nRetrieve a customer's details.", "operationId": "Retrieve a Customer", @@ -680,9 +658,7 @@ "deprecated": false }, "post": { - "tags": [ - "Customers" - ], + "tags": ["Customers"], "summary": "", "description": "\nUpdates the customer's details in a customer object.", "operationId": "Update a Customer", @@ -725,9 +701,7 @@ "deprecated": false }, "delete": { - "tags": [ - "Customers" - ], + "tags": ["Customers"], "summary": "", "description": "\nDelete a customer record.", "operationId": "Delete a Customer", @@ -762,9 +736,7 @@ }, "/mandates/revoke/{mandate_id}": { "post": { - "tags": [ - "Mandates" - ], + "tags": ["Mandates"], "summary": "", "description": "\nRevoke a mandate", "operationId": "Revoke a Mandate", @@ -799,9 +771,7 @@ }, "/mandates/{mandate_id}": { "get": { - "tags": [ - "Mandates" - ], + "tags": ["Mandates"], "summary": "", "description": "\nRetrieve a mandate", "operationId": "Retrieve a Mandate", @@ -836,9 +806,7 @@ }, "/payment_methods": { "post": { - "tags": [ - "Payment Methods" - ], + "tags": ["Payment Methods"], "summary": "", "description": "\nTo create a payment method against a customer object. In case of cards, this API could be used only by PCI compliant merchants", "operationId": "Create a Payment Method", @@ -872,9 +840,7 @@ }, "/payment_methods/{account_id}": { "get": { - "tags": [ - "Payment Methods" - ], + "tags": ["Payment Methods"], "summary": "", "description": "\nTo filter and list the applicable payment methods for a particular Merchant ID", "operationId": "List all Payment Methods for a Merchant", @@ -974,9 +940,7 @@ }, "/payment_methods/{customer_id}": { "get": { - "tags": [ - "Payment Methods" - ], + "tags": ["Payment Methods"], "summary": "", "description": "\nTo filter and list the applicable payment methods for a particular Customer ID", "operationId": "List all Payment Methods for a Customer", @@ -1076,9 +1040,7 @@ }, "/payment_methods/{method_id}": { "get": { - "tags": [ - "Payment Methods" - ], + "tags": ["Payment Methods"], "summary": "", "description": "\nTo retrieve a payment method", "operationId": "Retrieve a Payment method", @@ -1111,9 +1073,7 @@ "deprecated": false }, "post": { - "tags": [ - "Payment Methods" - ], + "tags": ["Payment Methods"], "summary": "", "description": "\nTo update an existing payment method attached to a customer object. This API is useful for use cases such as updating the card number for expired cards to prevent discontinuity in recurring payments", "operationId": "Update a Payment method", @@ -1156,9 +1116,7 @@ "deprecated": false }, "delete": { - "tags": [ - "Payment Methods" - ], + "tags": ["Payment Methods"], "summary": "", "description": "\nDelete payment method", "operationId": "Delete a Payment method", @@ -1193,9 +1151,7 @@ }, "/payments": { "post": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nTo process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture", "operationId": "Create a Payment", @@ -1229,9 +1185,7 @@ }, "/payments/list": { "get": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nTo list the payments", "operationId": "List all Payments", @@ -1337,9 +1291,7 @@ }, "/payments/session_tokens": { "post": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nTo create the session object or to get session token for wallets", "operationId": "Create Session tokens for a Payment", @@ -1373,9 +1325,7 @@ }, "/payments/{payment_id}": { "get": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nTo retrieve the properties of a Payment. This may be used to get the status of a previously initiated payment or next action for an ongoing payment", "operationId": "Retrieve a Payment", @@ -1418,9 +1368,7 @@ "deprecated": false }, "post": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nTo update the properties of a PaymentIntent object. This may include attaching a payment method, or attaching customer object or metadata fields after the Payment is created", "operationId": "Update a Payment", @@ -1465,9 +1413,7 @@ }, "/payments/{payment_id}/cancel": { "post": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nA Payment could can be cancelled when it is in one of these statuses: requires_payment_method, requires_capture, requires_confirmation, requires_customer_action", "operationId": "Cancel a Payment", @@ -1505,9 +1451,7 @@ }, "/payments/{payment_id}/capture": { "post": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nTo capture the funds for an uncaptured payment", "operationId": "Capture a Payment", @@ -1552,9 +1496,7 @@ }, "/payments/{payment_id}/confirm": { "post": { - "tags": [ - "Payments" - ], + "tags": ["Payments"], "summary": "", "description": "\nThis API is to confirm the payment request and forward payment to the payment processor. This API provides more granular control upon when the API is forwarded to the payment processor. Alternatively you can confirm the payment within the Payments Create API", "operationId": "Confirm a Payment", @@ -1599,9 +1541,7 @@ }, "/refunds": { "post": { - "tags": [ - "Refunds" - ], + "tags": ["Refunds"], "summary": "", "description": "\nTo create a refund against an already processed payment", "operationId": "Create a Refund", @@ -1635,9 +1575,7 @@ }, "/refunds/list": { "get": { - "tags": [ - "Refunds" - ], + "tags": ["Refunds"], "summary": "", "description": "\nTo list the refunds associated with a payment_id or with the merchant, if payment_id is not provided", "operationId": "List all Refunds", @@ -1732,9 +1670,7 @@ }, "/refunds/{refund_id}": { "get": { - "tags": [ - "Refunds" - ], + "tags": ["Refunds"], "summary": "", "description": "\nTo retrieve the properties of a Refund. This may be used to get the status of a previously initiated payment or next action for an ongoing payment", "operationId": "Retrieve a Refund", @@ -1767,9 +1703,7 @@ "deprecated": false }, "post": { - "tags": [ - "Refunds" - ], + "tags": ["Refunds"], "summary": "", "description": "\nTo update the properties of a Refund object. This may include attaching a reason for the refund or metadata fields", "operationId": "Update a Refund", @@ -1817,10 +1751,7 @@ "schemas": { "AcceptanceType": { "type": "string", - "enum": [ - "online", - "offline" - ] + "enum": ["online", "offline"] }, "Address": { "type": "object", @@ -1894,15 +1825,11 @@ }, "AffirmIssuer": { "type": "string", - "enum": [ - "affirm" - ] + "enum": ["affirm"] }, "AfterpayClearpayIssuer": { "type": "string", - "enum": [ - "afterpay_clearpay" - ] + "enum": ["afterpay_clearpay"] }, "ApiKeyExpiration": { "oneOf": [ @@ -1920,19 +1847,11 @@ }, "AuthenticationType": { "type": "string", - "enum": [ - "three_ds", - "no_three_ds" - ] + "enum": ["three_ds", "no_three_ds"] }, "CaptureMethod": { "type": "string", - "enum": [ - "automatic", - "manual", - "manual_multiple", - "scheduled" - ] + "enum": ["automatic", "manual", "manual_multiple", "scheduled"] }, "Card": { "type": "object", @@ -2144,9 +2063,7 @@ }, "CreateMerchantAccount": { "type": "object", - "required": [ - "merchant_id" - ], + "required": ["merchant_id"], "properties": { "merchant_id": { "type": "string", @@ -2224,9 +2141,7 @@ }, "CreatePaymentMethod": { "type": "object", - "required": [ - "payment_method" - ], + "required": ["payment_method"], "properties": { "payment_method": { "$ref": "#/components/schemas/PaymentMethodType" @@ -2365,9 +2280,7 @@ }, "CustomerAcceptance": { "type": "object", - "required": [ - "acceptance_type" - ], + "required": ["acceptance_type"], "properties": { "acceptance_type": { "$ref": "#/components/schemas/AcceptanceType" @@ -2464,9 +2377,7 @@ "items": { "$ref": "#/components/schemas/PaymentExperience" }, - "example": [ - "redirect_to_url" - ] + "example": ["redirect_to_url"] }, "card": { "$ref": "#/components/schemas/CardDetailFromLocker" @@ -2532,10 +2443,7 @@ }, "CustomerResponse": { "type": "object", - "required": [ - "customer_id", - "created_at" - ], + "required": ["customer_id", "created_at"], "properties": { "customer_id": { "type": "string", @@ -2589,11 +2497,7 @@ }, "DeleteMcaResponse": { "type": "object", - "required": [ - "merchant_id", - "merchant_connector_id", - "deleted" - ], + "required": ["merchant_id", "merchant_connector_id", "deleted"], "properties": { "merchant_id": { "type": "string", @@ -2602,10 +2506,9 @@ "maxLength": 255 }, "merchant_connector_id": { - "type": "integer", - "format": "int32", + "type": "string", "description": "Unique ID of the connector", - "example": 42 + "example": "mca_5apGeP94tMts6rg3U3kR" }, "deleted": { "type": "boolean", @@ -2616,10 +2519,7 @@ }, "DeleteMerchantAccountResponse": { "type": "object", - "required": [ - "merchant_id", - "deleted" - ], + "required": ["merchant_id", "deleted"], "properties": { "merchant_id": { "type": "string", @@ -2636,10 +2536,7 @@ }, "DeletePaymentMethodResponse": { "type": "object", - "required": [ - "payment_method_id", - "deleted" - ], + "required": ["payment_method_id", "deleted"], "properties": { "payment_method_id": { "type": "string", @@ -2655,17 +2552,11 @@ }, "FutureUsage": { "type": "string", - "enum": [ - "off_session", - "on_session" - ] + "enum": ["off_session", "on_session"] }, "GpayAllowedMethodsParameters": { "type": "object", - "required": [ - "allowed_auth_methods", - "allowed_card_networks" - ], + "required": ["allowed_auth_methods", "allowed_card_networks"], "properties": { "allowed_auth_methods": { "type": "array", @@ -2685,11 +2576,7 @@ }, "GpayAllowedPaymentMethods": { "type": "object", - "required": [ - "type", - "parameters", - "tokenization_specification" - ], + "required": ["type", "parameters", "tokenization_specification"], "properties": { "type": { "type": "string", @@ -2705,9 +2592,7 @@ }, "GpayMerchantInfo": { "type": "object", - "required": [ - "merchant_name" - ], + "required": ["merchant_name"], "properties": { "merchant_name": { "type": "string", @@ -2717,10 +2602,7 @@ }, "GpayTokenParameters": { "type": "object", - "required": [ - "gateway", - "gateway_merchant_id" - ], + "required": ["gateway", "gateway_merchant_id"], "properties": { "gateway": { "type": "string", @@ -2734,10 +2616,7 @@ }, "GpayTokenizationSpecification": { "type": "object", - "required": [ - "type", - "parameters" - ], + "required": ["type", "parameters"], "properties": { "type": { "type": "string", @@ -2791,16 +2670,11 @@ }, "KlarnaIssuer": { "type": "string", - "enum": [ - "klarna" - ] + "enum": ["klarna"] }, "ListCustomerPaymentMethodsResponse": { "type": "object", - "required": [ - "enabled_payment_methods", - "customer_payment_methods" - ], + "required": ["enabled_payment_methods", "customer_payment_methods"], "properties": { "enabled_payment_methods": { "type": "array", @@ -2811,10 +2685,7 @@ { "payment_method": "wallet", "payment_experience": null, - "payment_method_issuers": [ - "labore magna ipsum", - "aute" - ] + "payment_method_issuers": ["labore magna ipsum", "aute"] } ] }, @@ -2842,9 +2713,7 @@ "items": { "$ref": "#/components/schemas/PaymentMethodSubType" }, - "example": [ - "credit_card" - ] + "example": ["credit_card"] }, "payment_method_issuers": { "type": "array", @@ -2852,18 +2721,14 @@ "type": "string", "description": "The name of the bank/ provider issuing the payment method to the end user" }, - "example": [ - "Citibank" - ] + "example": ["Citibank"] }, "payment_method_issuer_code": { "type": "array", "items": { "$ref": "#/components/schemas/PaymentMethodIssuerCode" }, - "example": [ - "jp_applepay" - ] + "example": ["jp_applepay"] }, "payment_schemes": { "type": "array", @@ -2871,11 +2736,7 @@ "type": "string", "description": "List of payment schemes accepted or has the processing capabilities of the processor" }, - "example": [ - "MASTER", - "VISA", - "DINERS" - ] + "example": ["MASTER", "VISA", "DINERS"] }, "accepted_countries": { "type": "array", @@ -2883,21 +2744,14 @@ "type": "string", "description": "List of Countries accepted or has the processing capabilities of the processor" }, - "example": [ - "US", - "UK", - "IN" - ] + "example": ["US", "UK", "IN"] }, "accepted_currencies": { "type": "array", "items": { "$ref": "#/components/schemas/Currency" }, - "example": [ - "USD", - "EUR" - ] + "example": ["USD", "EUR"] }, "minimum_amount": { "type": "integer", @@ -2926,17 +2780,13 @@ "items": { "$ref": "#/components/schemas/PaymentExperience" }, - "example": [ - "redirect_to_url" - ] + "example": ["redirect_to_url"] } } }, "ListPaymentMethodResponse": { "type": "object", - "required": [ - "payment_methods" - ], + "required": ["payment_methods"], "properties": { "redirect_url": { "type": "string", @@ -2952,10 +2802,7 @@ { "payment_method": "wallet", "payment_experience": null, - "payment_method_issuers": [ - "labore magna ipsum", - "aute" - ] + "payment_method_issuers": ["labore magna ipsum", "aute"] } ] } @@ -2963,10 +2810,7 @@ }, "MandateAmountData": { "type": "object", - "required": [ - "amount", - "currency" - ], + "required": ["amount", "currency"], "properties": { "amount": { "type": "integer", @@ -3018,10 +2862,7 @@ }, "MandateData": { "type": "object", - "required": [ - "customer_acceptance", - "mandate_type" - ], + "required": ["customer_acceptance", "mandate_type"], "properties": { "customer_acceptance": { "$ref": "#/components/schemas/CustomerAcceptance" @@ -3065,10 +2906,7 @@ }, "MandateRevokedResponse": { "type": "object", - "required": [ - "mandate_id", - "status" - ], + "required": ["mandate_id", "status"], "properties": { "mandate_id": { "type": "string", @@ -3082,20 +2920,13 @@ "MandateStatus": { "type": "string", "description": "The status of the mandate, which indicates whether it can be used to initiate a payment", - "enum": [ - "active", - "inactive", - "pending", - "revoked" - ] + "enum": ["active", "inactive", "pending", "revoked"] }, "MandateType": { "oneOf": [ { "type": "object", - "required": [ - "single_use" - ], + "required": ["single_use"], "properties": { "single_use": { "$ref": "#/components/schemas/MandateAmountData" @@ -3104,9 +2935,7 @@ }, { "type": "object", - "required": [ - "multi_use" - ], + "required": ["multi_use"], "properties": { "multi_use": { "$ref": "#/components/schemas/MandateAmountData" @@ -3201,17 +3030,13 @@ }, "MerchantConnectorId": { "type": "object", - "required": [ - "merchant_id", - "merchant_connector_id" - ], + "required": ["merchant_id", "merchant_connector_id"], "properties": { "merchant_id": { "type": "string" }, "merchant_connector_id": { - "type": "integer", - "format": "int32" + "type": "string" } } }, @@ -3288,9 +3113,7 @@ }, "NextAction": { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "$ref": "#/components/schemas/NextActionType" @@ -3313,10 +3136,7 @@ }, "OnlineMandate": { "type": "object", - "required": [ - "ip_address", - "user_agent" - ], + "required": ["ip_address", "user_agent"], "properties": { "ip_address": { "type": "string", @@ -3331,10 +3151,7 @@ }, "OrderDetails": { "type": "object", - "required": [ - "product_name", - "quantity" - ], + "required": ["product_name", "quantity"], "properties": { "product_name": { "type": "string", @@ -3354,22 +3171,13 @@ "oneOf": [ { "type": "object", - "required": [ - "klarna_redirect" - ], + "required": ["klarna_redirect"], "properties": { "klarna_redirect": { "type": "object", "description": "For KlarnaRedirect as PayLater Option", - "required": [ - "issuer_name", - "billing_email", - "billing_country" - ], + "required": ["billing_email", "billing_country"], "properties": { - "issuer_name": { - "$ref": "#/components/schemas/KlarnaIssuer" - }, "billing_email": { "type": "string", "description": "The billing email" @@ -3383,21 +3191,13 @@ }, { "type": "object", - "required": [ - "klarna_sdk" - ], + "required": ["klarna_sdk"], "properties": { "klarna_sdk": { "type": "object", "description": "For Klarna Sdk as PayLater Option", - "required": [ - "issuer_name", - "token" - ], + "required": ["token"], "properties": { - "issuer_name": { - "$ref": "#/components/schemas/KlarnaIssuer" - }, "token": { "type": "string", "description": "The token for the sdk workflow" @@ -3408,47 +3208,23 @@ }, { "type": "object", - "required": [ - "affirm_redirect" - ], + "required": ["affirm_redirect"], "properties": { "affirm_redirect": { "type": "object", - "description": "For Affirm redirect as PayLater Option", - "required": [ - "issuer_name", - "billing_email" - ], - "properties": { - "issuer_name": { - "$ref": "#/components/schemas/AffirmIssuer" - }, - "billing_email": { - "type": "string", - "description": "The billing email" - } - } + "description": "For Affirm redirect as PayLater Option" } } }, { "type": "object", - "required": [ - "afterpay_clearpay_redirect" - ], + "required": ["afterpay_clearpay_redirect"], "properties": { "afterpay_clearpay_redirect": { "type": "object", "description": "For AfterpayClearpay redirect as PayLater Option", - "required": [ - "issuer_name", - "billing_email", - "billing_name" - ], + "required": ["billing_email", "billing_name"], "properties": { - "issuer_name": { - "$ref": "#/components/schemas/AfterpayClearpayIssuer" - }, "billing_email": { "type": "string", "description": "The billing email" @@ -3466,10 +3242,7 @@ "PaymentConnectorCreate": { "type": "object", "description": "Create a new Payment Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc.\"", - "required": [ - "connector_type", - "connector_name" - ], + "required": ["connector_type", "connector_name"], "properties": { "connector_type": { "$ref": "#/components/schemas/ConnectorType" @@ -3480,10 +3253,9 @@ "example": "stripe" }, "merchant_connector_id": { - "type": "integer", - "format": "int32", + "type": "string", "description": "Unique ID of the connector", - "example": 42 + "example": "mca_5apGeP94tMts6rg3U3kR" }, "connector_account_details": { "type": "object" @@ -3508,26 +3280,11 @@ "example": [ { "payment_method": "wallet", - "payment_method_types": [ - "upi_collect", - "upi_intent" - ], - "payment_method_issuers": [ - "labore magna ipsum", - "aute" - ], - "payment_schemes": [ - "Discover", - "Discover" - ], - "accepted_currencies": [ - "AED", - "AED" - ], - "accepted_countries": [ - "in", - "us" - ], + "payment_method_types": ["upi_collect", "upi_intent"], + "payment_method_issuers": ["labore magna ipsum", "aute"], + "payment_schemes": ["Discover", "Discover"], + "accepted_currencies": ["AED", "AED"], + "accepted_countries": ["in", "us"], "minimum_amount": 1, "maximum_amount": 68607706, "recurring_enabled": true, @@ -3555,9 +3312,7 @@ "oneOf": [ { "type": "object", - "required": [ - "PaymentIntentId" - ], + "required": ["PaymentIntentId"], "properties": { "PaymentIntentId": { "type": "string", @@ -3567,9 +3322,7 @@ }, { "type": "object", - "required": [ - "ConnectorTransactionId" - ], + "required": ["ConnectorTransactionId"], "properties": { "ConnectorTransactionId": { "type": "string", @@ -3579,9 +3332,7 @@ }, { "type": "object", - "required": [ - "PaymentAttemptId" - ], + "required": ["PaymentAttemptId"], "properties": { "PaymentAttemptId": { "type": "string", @@ -3591,6 +3342,25 @@ } ] }, + "PaymentIssuer": { + "type": "string", + "enum": [ + "klarna", + "affirm", + "afterpay_clearpay", + "american_express", + "bank_of_america", + "barclays", + "capital_one", + "chase", + "citi", + "discover", + "navy_federal_credit_union", + "pentagon_federal_credit_union", + "synchrony_bank", + "wells_fargo" + ] + }, "PaymentListConstraints": { "type": "object", "properties": { @@ -3640,10 +3410,7 @@ }, "PaymentListResponse": { "type": "object", - "required": [ - "size", - "data" - ], + "required": ["size", "data"], "properties": { "size": { "type": "integer", @@ -3661,9 +3428,7 @@ "oneOf": [ { "type": "object", - "required": [ - "card" - ], + "required": ["card"], "properties": { "card": { "$ref": "#/components/schemas/Card" @@ -3672,15 +3437,11 @@ }, { "type": "string", - "enum": [ - "bank_transfer" - ] + "enum": ["bank_transfer"] }, { "type": "object", - "required": [ - "wallet" - ], + "required": ["wallet"], "properties": { "wallet": { "$ref": "#/components/schemas/WalletData" @@ -3689,9 +3450,7 @@ }, { "type": "object", - "required": [ - "pay_later" - ], + "required": ["pay_later"], "properties": { "pay_later": { "$ref": "#/components/schemas/PayLaterData" @@ -3700,9 +3459,7 @@ }, { "type": "string", - "enum": [ - "paypal" - ] + "enum": ["paypal"] } ] }, @@ -3778,9 +3535,7 @@ "items": { "$ref": "#/components/schemas/PaymentExperience" }, - "example": [ - "redirect_to_url" - ] + "example": ["redirect_to_url"] }, "metadata": { "type": "object" @@ -3838,9 +3593,7 @@ "items": { "$ref": "#/components/schemas/PaymentMethodSubType" }, - "example": [ - "credit" - ] + "example": ["credit"] }, "payment_method_issuers": { "type": "array", @@ -3848,9 +3601,7 @@ "type": "string", "description": "List of payment method issuers to be enabled for this payment method" }, - "example": [ - "HDFC" - ] + "example": ["HDFC"] }, "payment_schemes": { "type": "array", @@ -3858,22 +3609,14 @@ "type": "string", "description": "List of payment schemes accepted or has the processing capabilities of the processor" }, - "example": [ - "MASTER", - "VISA", - "DINERS" - ] + "example": ["MASTER", "VISA", "DINERS"] }, "accepted_currencies": { "type": "array", "items": { "$ref": "#/components/schemas/Currency" }, - "example": [ - "USD", - "EUR", - "AED" - ] + "example": ["USD", "EUR", "AED"] }, "accepted_countries": { "type": "array", @@ -3881,10 +3624,7 @@ "type": "string", "description": "List of Countries accepted or has the processing capabilities of the processor" }, - "example": [ - "US", - "IN" - ] + "example": ["US", "IN"] }, "minimum_amount": { "type": "integer", @@ -3915,9 +3655,7 @@ "items": { "$ref": "#/components/schemas/PaymentExperience" }, - "example": [ - "redirect_to_url" - ] + "example": ["redirect_to_url"] } } }, @@ -4125,17 +3863,18 @@ }, "browser_info": { "type": "object" + }, + "payment_issuer": { + "$ref": "#/components/schemas/PaymentIssuer" + }, + "payment_experience": { + "$ref": "#/components/schemas/PaymentExperience" } } }, "PaymentsResponse": { "type": "object", - "required": [ - "status", - "amount", - "currency", - "payment_method" - ], + "required": ["status", "amount", "currency", "payment_method"], "properties": { "payment_id": { "type": "string", @@ -4314,10 +4053,7 @@ }, "PaymentsRetrieveRequest": { "type": "object", - "required": [ - "resource_id", - "force_sync" - ], + "required": ["resource_id", "force_sync"], "properties": { "resource_id": { "$ref": "#/components/schemas/PaymentIdType" @@ -4342,11 +4078,7 @@ }, "PaymentsSessionRequest": { "type": "object", - "required": [ - "payment_id", - "client_secret", - "wallets" - ], + "required": ["payment_id", "client_secret", "wallets"], "properties": { "payment_id": { "type": "string", @@ -4366,11 +4098,7 @@ }, "PaymentsSessionResponse": { "type": "object", - "required": [ - "payment_id", - "client_secret", - "session_token" - ], + "required": ["payment_id", "client_secret", "session_token"], "properties": { "payment_id": { "type": "string", @@ -4390,11 +4118,7 @@ }, "PaymentsStartRequest": { "type": "object", - "required": [ - "payment_id", - "merchant_id", - "attempt_id" - ], + "required": ["payment_id", "merchant_id", "attempt_id"], "properties": { "payment_id": { "type": "string", @@ -4466,9 +4190,7 @@ }, "RefundListResponse": { "type": "object", - "required": [ - "data" - ], + "required": ["data"], "properties": { "data": { "type": "array", @@ -4480,9 +4202,7 @@ }, "RefundRequest": { "type": "object", - "required": [ - "payment_id" - ], + "required": ["payment_id"], "properties": { "refund_id": { "type": "string", @@ -4527,13 +4247,7 @@ }, "RefundResponse": { "type": "object", - "required": [ - "refund_id", - "payment_id", - "amount", - "currency", - "status" - ], + "required": ["refund_id", "payment_id", "amount", "currency", "status"], "properties": { "refund_id": { "type": "string", @@ -4585,19 +4299,11 @@ "RefundStatus": { "type": "string", "description": "The status for refunds", - "enum": [ - "succeeded", - "failed", - "pending", - "review" - ] + "enum": ["succeeded", "failed", "pending", "review"] }, "RefundType": { "type": "string", - "enum": [ - "scheduled", - "instant" - ] + "enum": ["scheduled", "instant"] }, "RefundUpdateRequest": { "type": "object", @@ -4689,12 +4395,7 @@ "RoutingAlgorithm": { "type": "string", "description": "The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'", - "enum": [ - "round_robin", - "max_conversion", - "min_cost", - "custom" - ], + "enum": ["round_robin", "max_conversion", "min_cost", "custom"], "example": "custom" }, "SessionToken": { @@ -4723,20 +4424,14 @@ }, "wallet_name": { "type": "string", - "enum": [ - "gpay" - ] + "enum": ["gpay"] } } }, { "type": "object", "description": "The session response structure for Klarna", - "required": [ - "session_token", - "session_id", - "wallet_name" - ], + "required": ["session_token", "session_id", "wallet_name"], "properties": { "session_token": { "type": "string", @@ -4748,19 +4443,14 @@ }, "wallet_name": { "type": "string", - "enum": [ - "klarna" - ] + "enum": ["klarna"] } } }, { "type": "object", "description": "The session response structure for PayPal", - "required": [ - "session_token", - "wallet_name" - ], + "required": ["session_token", "wallet_name"], "properties": { "session_token": { "type": "string", @@ -4768,9 +4458,7 @@ }, "wallet_name": { "type": "string", - "enum": [ - "paypal" - ] + "enum": ["paypal"] } } }, @@ -4841,9 +4529,7 @@ }, "wallet_name": { "type": "string", - "enum": [ - "applepay" - ] + "enum": ["applepay"] } } } @@ -4855,12 +4541,7 @@ "SupportedWallets": { "type": "string", "description": "Wallets which support obtaining session object", - "enum": [ - "paypal", - "apple_pay", - "klarna", - "gpay" - ] + "enum": ["paypal", "apple_pay", "klarna", "gpay"] }, "UpdateApiKeyRequest": { "type": "object", @@ -4896,9 +4577,7 @@ }, "WalletData": { "type": "object", - "required": [ - "issuer_name" - ], + "required": ["issuer_name"], "properties": { "issuer_name": { "$ref": "#/components/schemas/WalletIssuer" @@ -4911,11 +4590,7 @@ }, "WalletIssuer": { "type": "string", - "enum": [ - "googlepay", - "applepay", - "paypal" - ] + "enum": ["googlepay", "applepay", "paypal"] }, "WebhookDetails": { "type": "object", @@ -4996,4 +4671,4 @@ "description": "Create and manage API Keys" } ] -} \ No newline at end of file +}