From 110a04107b2e1194dd56028c4388e152f7b22031 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 29 Oct 2024 15:18:33 +0530 Subject: [PATCH 01/24] feat: implement payments retrieve for v2 --- crates/api_models/src/events/payment.rs | 10 + crates/api_models/src/payments.rs | 82 +++ crates/diesel_models/src/kv.rs | 11 + crates/diesel_models/src/payment_intent.rs | 21 +- .../src/query/payment_attempt.rs | 5 +- .../diesel_models/src/query/payment_intent.rs | 4 +- .../hyperswitch_domain_models/src/payments.rs | 15 +- .../src/payments/payment_attempt.rs | 2 +- .../src/payments/payment_intent.rs | 73 ++- .../router/src/core/authentication/utils.rs | 1 + .../core/fraud_check/flows/checkout_flow.rs | 2 +- .../core/fraud_check/flows/record_return.rs | 2 +- .../src/core/fraud_check/flows/sale_flow.rs | 2 +- .../fraud_check/flows/transaction_flow.rs | 2 +- crates/router/src/core/payments.rs | 553 ++++++++++++++---- crates/router/src/core/payments/flows.rs | 6 +- .../src/core/payments/flows/approve_flow.rs | 16 + .../src/core/payments/flows/authorize_flow.rs | 2 +- .../src/core/payments/flows/cancel_flow.rs | 16 + .../src/core/payments/flows/capture_flow.rs | 16 + .../payments/flows/complete_authorize_flow.rs | 22 + .../flows/incremental_authorization_flow.rs | 16 + .../flows/post_session_tokens_flow.rs | 18 +- .../src/core/payments/flows/psync_flow.rs | 46 ++ .../src/core/payments/flows/reject_flow.rs | 16 + .../src/core/payments/flows/session_flow.rs | 16 + .../payments/flows/session_update_flow.rs | 16 + .../core/payments/flows/setup_mandate_flow.rs | 16 + crates/router/src/core/payments/operations.rs | 106 +++- .../operations/payment_confirm_intent.rs | 50 +- .../operations/payment_create_intent.rs | 16 +- .../core/payments/operations/payment_get.rs | 307 ++++++++++ .../payments/operations/payment_response.rs | 189 +++++- crates/router/src/core/payments/retry.rs | 1 + .../router/src/core/payments/transformers.rs | 270 ++++++++- crates/router/src/core/payouts.rs | 11 + crates/router/src/db/kafka_store.rs | 2 +- crates/router/src/routes/app.rs | 3 +- crates/router/src/routes/payments.rs | 77 ++- crates/router/src/types/api.rs | 2 + .../src/mock_db/payment_attempt.rs | 4 +- .../src/mock_db/payment_intent.rs | 15 + .../src/payments/payment_attempt.rs | 8 +- .../src/payments/payment_intent.rs | 3 +- .../down.sql | 12 +- .../up.sql | 20 +- 46 files changed, 1886 insertions(+), 217 deletions(-) create mode 100644 crates/router/src/core/payments/operations/payment_get.rs diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs index 000343864b20..cf04b8dbec69 100644 --- a/crates/api_models/src/events/payment.rs +++ b/crates/api_models/src/events/payment.rs @@ -3,6 +3,7 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; #[cfg(feature = "v2")] use super::{ PaymentsConfirmIntentResponse, PaymentsCreateIntentRequest, PaymentsCreateIntentResponse, + PaymentsRetrieveResponse, }; #[cfg(all( any(feature = "v2", feature = "v1"), @@ -167,6 +168,15 @@ impl ApiEventMetric for PaymentsConfirmIntentResponse { } } +#[cfg(feature = "v2")] +impl ApiEventMetric for PaymentsRetrieveResponse { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Payment { + payment_id: self.id.clone(), + }) + } +} + #[cfg(feature = "v1")] impl ApiEventMetric for PaymentsResponse { fn get_api_event_type(&self) -> Option { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 61c7911170a3..acbafac4f8d8 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -295,6 +295,10 @@ pub struct PaymentsCreateIntentResponse { #[schema(value_type = String)] pub id: id_type::GlobalPaymentId, + /// The status of the payment + #[schema(value_type = IntentStatus, example = "succeeded")] + pub status: common_enums::IntentStatus, + /// The amount details for the payment pub amount_details: AmountDetailsResponse, @@ -4468,6 +4472,19 @@ pub struct PaymentsConfirmIntentRequest { pub browser_info: Option, } +// Serialize is implemented because, this will be serialized in the api events. +// Usually request types should not have serialize implemented. +// +/// Request for Payment Status +#[cfg(feature = "v2")] +#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct PaymentsStatusRequest { + /// A boolean used to indicate if the payment status should be fetched from the connector + /// If this is set to true, the status will be fetched from the connector + #[serde(default)] + pub force_sync: bool, +} + /// Error details for the payment #[cfg(feature = "v2")] #[derive(Debug, serde::Serialize, ToSchema)] @@ -4549,6 +4566,71 @@ pub struct PaymentsConfirmIntentResponse { pub error: Option, } +/// Response for Payment Intent Confirm +#[cfg(feature = "v2")] +#[derive(Debug, serde::Serialize, ToSchema)] +pub struct PaymentsRetrieveResponse { + /// Unique identifier for the payment. This ensures idempotency for multiple payments + /// that have been done by a single merchant. + #[schema( + min_length = 32, + max_length = 64, + example = "12345_pay_01926c58bc6e77c09e809964e72af8c8", + value_type = String, + )] + pub id: id_type::GlobalPaymentId, + + #[schema(value_type = IntentStatus, example = "success")] + pub status: api_enums::IntentStatus, + + /// Amount related information for this payment and attempt + pub amount: ConfirmIntentAmountDetailsResponse, + + /// The connector used for the payment + #[schema(example = "stripe")] + pub connector: Option, + + /// It's a token used for client side verification. + #[schema(value_type = String)] + pub client_secret: common_utils::types::ClientSecret, + + /// Time when the payment was created + #[schema(example = "2022-09-10T10:11:12Z")] + #[serde(with = "common_utils::custom_serde::iso8601")] + pub created: PrimitiveDateTime, + + /// The payment method information provided for making a payment + #[schema(value_type = Option)] + #[serde(serialize_with = "serialize_payment_method_data_response")] + pub payment_method_data: Option, + + /// The payment method type for this payment attempt + #[schema(value_type = Option, example = "wallet")] + pub payment_method_type: Option, + + #[schema(value_type = Option, example = "apple_pay")] + pub payment_method_subtype: Option, + + /// A unique identifier for a payment provided by the connector + #[schema(value_type = Option, example = "993672945374576J")] + pub connector_transaction_id: Option, + + /// reference(Identifier) to the payment at connector side + #[schema(value_type = Option, example = "993672945374576J")] + pub connector_reference_id: Option, + + /// Identifier of the connector ( merchant connector account ) which was chosen to make the payment + #[schema(value_type = Option)] + pub merchant_connector_id: Option, + + /// The browser information used for this payment + #[schema(value_type = Option)] + pub browser_info: Option, + + /// Error details for the payment if any + pub error: Option, +} + /// Fee information to be charged on the payment being collected #[derive(Setter, Clone, Default, Debug, PartialEq, serde::Serialize, ToSchema)] pub struct PaymentChargeResponse { diff --git a/crates/diesel_models/src/kv.rs b/crates/diesel_models/src/kv.rs index 0bfa1434f69a..68dae0689460 100644 --- a/crates/diesel_models/src/kv.rs +++ b/crates/diesel_models/src/kv.rs @@ -3,6 +3,10 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "v2")] use crate::payment_attempt::PaymentAttemptUpdateInternal; + +#[cfg(feature = "v2")] +use crate::payment_intent::PaymentIntentUpdateInternal; + use crate::{ address::{Address, AddressNew, AddressUpdateInternal}, customers::{Customer, CustomerNew, CustomerUpdateInternal}, @@ -108,9 +112,16 @@ impl DBOperation { Insertable::Mandate(m) => DBResult::Mandate(Box::new(m.insert(conn).await?)), }, Self::Update { updatable } => match *updatable { + #[cfg(feature = "v1")] Updateable::PaymentIntentUpdate(a) => { DBResult::PaymentIntent(Box::new(a.orig.update(conn, a.update_data).await?)) } + #[cfg(feature = "v2")] + Updateable::PaymentIntentUpdate(a) => DBResult::PaymentIntent(Box::new( + a.orig + .update(conn, PaymentIntentUpdateInternal::from(a.update_data)) + .await?, + )), #[cfg(feature = "v1")] Updateable::PaymentAttemptUpdate(a) => DBResult::PaymentAttempt(Box::new( a.orig.update_with_attempt_id(conn, a.update_data).await?, diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index 210b12b7aadc..eaf4497959e4 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -31,7 +31,7 @@ pub struct PaymentIntent { pub last_synced: Option, pub setup_future_usage: Option, pub client_secret: common_utils::types::ClientSecret, - pub active_attempt_id: Option, + pub active_attempt_id: Option, #[diesel(deserialize_as = super::OptionalDieselArray)] pub order_details: Option>, pub allowed_payment_method_types: Option, @@ -205,7 +205,7 @@ impl TaxDetails { } /// Get the default tax amount - fn get_default_tax_amount(&self) -> Option { + pub fn get_default_tax_amount(&self) -> Option { self.default .as_ref() .map(|default_tax_details| default_tax_details.order_tax_amount) @@ -248,7 +248,7 @@ pub struct PaymentIntentNew { pub last_synced: Option, pub setup_future_usage: Option, pub client_secret: common_utils::types::ClientSecret, - pub active_attempt_id: Option, + pub active_attempt_id: Option, #[diesel(deserialize_as = super::OptionalDieselArray)] pub order_details: Option>, pub allowed_payment_method_types: Option, @@ -356,6 +356,7 @@ pub enum PaymentIntentUpdate { /// Update the payment intent details on payment intent confirmation, before calling the connector ConfirmIntent { status: storage_enums::IntentStatus, + active_attempt_id: common_utils::id_type::GlobalAttemptId, updated_by: String, }, /// Update the payment intent details on payment intent confirmation, after calling the connector @@ -518,7 +519,7 @@ pub struct PaymentIntentUpdateInternal { // pub setup_future_usage: Option, // pub metadata: Option, pub modified_at: PrimitiveDateTime, - // pub active_attempt_id: Option, + pub active_attempt_id: Option, // pub description: Option, // pub statement_descriptor: Option, // #[diesel(deserialize_as = super::OptionalDieselArray)] @@ -592,7 +593,7 @@ impl PaymentIntentUpdate { // setup_future_usage, // metadata, modified_at: _, - // active_attempt_id, + active_attempt_id, // description, // statement_descriptor, // order_details, @@ -618,7 +619,7 @@ impl PaymentIntentUpdate { // setup_future_usage: setup_future_usage.or(source.setup_future_usage), // metadata: metadata.or(source.metadata), modified_at: common_utils::date_time::now(), - // active_attempt_id: active_attempt_id.unwrap_or(source.active_attempt_id), + active_attempt_id: active_attempt_id.or(source.active_attempt_id), // description: description.or(source.description), // statement_descriptor: statement_descriptor.or(source.statement_descriptor), // order_details: order_details.or(source.order_details), @@ -733,13 +734,19 @@ impl PaymentIntentUpdate { impl From for PaymentIntentUpdateInternal { fn from(payment_intent_update: PaymentIntentUpdate) -> Self { match payment_intent_update { - PaymentIntentUpdate::ConfirmIntent { status, updated_by } => Self { + PaymentIntentUpdate::ConfirmIntent { + status, + active_attempt_id, + updated_by, + } => Self { status: Some(status), + active_attempt_id: Some(active_attempt_id), modified_at: common_utils::date_time::now(), updated_by, }, PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => Self { status: Some(status), + active_attempt_id: None, modified_at: common_utils::date_time::now(), updated_by, }, diff --git a/crates/diesel_models/src/query/payment_attempt.rs b/crates/diesel_models/src/query/payment_attempt.rs index 7141675c880a..b52e3e2d3300 100644 --- a/crates/diesel_models/src/query/payment_attempt.rs +++ b/crates/diesel_models/src/query/payment_attempt.rs @@ -204,7 +204,10 @@ impl PaymentAttempt { } #[cfg(feature = "v2")] - pub async fn find_by_id(conn: &PgPooledConn, id: &str) -> StorageResult { + pub async fn find_by_id( + conn: &PgPooledConn, + id: &common_utils::id_type::GlobalAttemptId, + ) -> StorageResult { generics::generic_find_one::<::Table, _, _>( conn, dsl::id.eq(id.to_owned()), diff --git a/crates/diesel_models/src/query/payment_intent.rs b/crates/diesel_models/src/query/payment_intent.rs index fb23fc60107d..84984aeb52ef 100644 --- a/crates/diesel_models/src/query/payment_intent.rs +++ b/crates/diesel_models/src/query/payment_intent.rs @@ -24,12 +24,12 @@ impl PaymentIntent { pub async fn update( self, conn: &PgPooledConn, - payment_intent: PaymentIntentUpdate, + payment_intent_update: PaymentIntentUpdateInternal, ) -> StorageResult { match generics::generic_update_by_id::<::Table, _, _, _>( conn, self.id.to_owned(), - PaymentIntentUpdateInternal::from(payment_intent), + payment_intent_update, ) .await { diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 933c13416f20..72d0ec694f8e 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -260,7 +260,7 @@ pub struct PaymentIntent { /// The client secret that is generated for the payment. This is used to authenticate the payment from client facing apis. pub client_secret: common_utils::types::ClientSecret, /// The active attempt for the payment intent. This is the payment attempt that is currently active for the payment intent. - pub active_attempt: Option>, + pub active_attempt_id: Option, /// The order details for the payment. pub order_details: Option>>, /// This is the list of payment method types that are allowed for the payment intent. @@ -409,7 +409,7 @@ impl PaymentIntent { last_synced: None, setup_future_usage: request.setup_future_usage.unwrap_or_default(), client_secret, - active_attempt: None, + active_attempt_id: None, order_details, allowed_payment_method_types, connector_metadata, @@ -511,3 +511,14 @@ where pub payment_attempt: PaymentAttempt, pub payment_method_data: Option, } + +#[cfg(feature = "v2")] +#[derive(Clone)] +pub struct PaymentStatusData +where + F: Clone, +{ + pub flow: PhantomData, + pub payment_intent: PaymentIntent, + pub payment_attempt: Option, +} diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 4b3fd1f8cf9f..ee90126a2d84 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -122,7 +122,7 @@ pub trait PaymentAttemptInterface { &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, - attempt_id: &str, + attempt_id: &id_type::GlobalAttemptId, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index f1e4de499e68..ace326d4c776 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -271,6 +271,7 @@ pub enum PaymentIntentUpdate { pub enum PaymentIntentUpdate { ConfirmIntent { status: storage_enums::IntentStatus, + active_attempt_id: id_type::GlobalAttemptId, updated_by: String, }, ConfirmIntentPostUpdate { @@ -356,13 +357,43 @@ pub struct PaymentIntentUpdateInternal { pub tax_details: Option, } -// TODO: convert directly to diesel_models::PaymentIntentUpdateInternal +// This conversion is used in the `update_payment_intent` function +#[cfg(feature = "v2")] +impl From for diesel_models::PaymentIntentUpdateInternal { + fn from(payment_intent_update: PaymentIntentUpdate) -> Self { + match payment_intent_update { + PaymentIntentUpdate::ConfirmIntent { + status, + active_attempt_id, + updated_by, + } => Self { + status: Some(status), + active_attempt_id: Some(active_attempt_id), + modified_at: common_utils::date_time::now(), + updated_by, + }, + PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => Self { + status: Some(status), + active_attempt_id: None, + modified_at: common_utils::date_time::now(), + updated_by, + }, + } + } +} + +// This conversion is required for the `apply_changeset` function used for mockdb #[cfg(feature = "v2")] impl From for PaymentIntentUpdateInternal { fn from(payment_intent_update: PaymentIntentUpdate) -> Self { match payment_intent_update { - PaymentIntentUpdate::ConfirmIntent { status, updated_by } => Self { + PaymentIntentUpdate::ConfirmIntent { + status, + active_attempt_id, + updated_by, + } => Self { status: Some(status), + active_attempt_id: Some(active_attempt_id), updated_by, ..Default::default() }, @@ -576,19 +607,21 @@ use diesel_models::{ PaymentIntentUpdate as DieselPaymentIntentUpdate, PaymentIntentUpdateFields as DieselPaymentIntentUpdateFields, }; -#[cfg(feature = "v2")] -impl From for DieselPaymentIntentUpdate { - fn from(value: PaymentIntentUpdate) -> Self { - match value { - PaymentIntentUpdate::ConfirmIntent { status, updated_by } => { - Self::ConfirmIntent { status, updated_by } - } - PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => { - Self::ConfirmIntentPostUpdate { status, updated_by } - } - } - } -} + +// TODO: check where this conversion is used +// #[cfg(feature = "v2")] +// impl From for DieselPaymentIntentUpdate { +// fn from(value: PaymentIntentUpdate) -> Self { +// match value { +// PaymentIntentUpdate::ConfirmIntent { status, updated_by } => { +// Self::ConfirmIntent { status, updated_by } +// } +// PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => { +// Self::ConfirmIntentPostUpdate { status, updated_by } +// } +// } +// } +// } #[cfg(feature = "v1")] impl From for DieselPaymentIntentUpdate { @@ -1132,7 +1165,7 @@ impl behaviour::Conversion for PaymentIntent { last_synced, setup_future_usage, client_secret, - active_attempt, + active_attempt_id, order_details, allowed_payment_method_types, connector_metadata, @@ -1180,7 +1213,7 @@ impl behaviour::Conversion for PaymentIntent { last_synced, setup_future_usage: Some(setup_future_usage), client_secret, - active_attempt_id: active_attempt.map(|attempt| attempt.get_id()), + active_attempt_id, order_details: order_details .map(|order_details| { order_details @@ -1307,9 +1340,7 @@ impl behaviour::Conversion for PaymentIntent { last_synced: storage_model.last_synced, setup_future_usage: storage_model.setup_future_usage.unwrap_or_default(), client_secret: storage_model.client_secret, - active_attempt: storage_model - .active_attempt_id - .map(RemoteStorageObject::ForeignID), + active_attempt_id: storage_model.active_attempt_id, order_details: storage_model .order_details .map(|order_details| { @@ -1389,7 +1420,7 @@ impl behaviour::Conversion for PaymentIntent { last_synced: self.last_synced, setup_future_usage: Some(self.setup_future_usage), client_secret: self.client_secret, - active_attempt_id: self.active_attempt.map(|attempt| attempt.get_id()), + active_attempt_id: self.active_attempt_id, order_details: self .order_details .map(|order_details| { diff --git a/crates/router/src/core/authentication/utils.rs b/crates/router/src/core/authentication/utils.rs index e1e5dc9f6248..01cc6a89562d 100644 --- a/crates/router/src/core/authentication/utils.rs +++ b/crates/router/src/core/authentication/utils.rs @@ -17,6 +17,7 @@ use crate::{ utils::OptionExt, }; +#[cfg(feature = "v1")] pub fn get_connector_data_if_separate_authn_supported( connector_call_type: &api::ConnectorCallType, ) -> Option { diff --git a/crates/router/src/core/fraud_check/flows/checkout_flow.rs b/crates/router/src/core/fraud_check/flows/checkout_flow.rs index 87e76b2c5fb8..b21b4003b149 100644 --- a/crates/router/src/core/fraud_check/flows/checkout_flow.rs +++ b/crates/router/src/core/fraud_check/flows/checkout_flow.rs @@ -36,7 +36,7 @@ impl ConstructFlowSpecificData, - _merchant_connector_account: &helpers::MerchantConnectorAccountType, + _merchant_connector_account: &domain::MerchantConnectorAccount, _merchant_recipient_data: Option, _header_payload: Option, ) -> RouterResult> diff --git a/crates/router/src/core/fraud_check/flows/record_return.rs b/crates/router/src/core/fraud_check/flows/record_return.rs index f80f604daa40..9358c65ffcf5 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -34,7 +34,7 @@ impl ConstructFlowSpecificData, - _merchant_connector_account: &helpers::MerchantConnectorAccountType, + _merchant_connector_account: &domain::MerchantConnectorAccount, _merchant_recipient_data: Option, _header_payload: Option, ) -> RouterResult> diff --git a/crates/router/src/core/fraud_check/flows/sale_flow.rs b/crates/router/src/core/fraud_check/flows/sale_flow.rs index 23c0e05fd509..c69e1fd40af9 100644 --- a/crates/router/src/core/fraud_check/flows/sale_flow.rs +++ b/crates/router/src/core/fraud_check/flows/sale_flow.rs @@ -32,7 +32,7 @@ impl ConstructFlowSpecificData, - _merchant_connector_account: &helpers::MerchantConnectorAccountType, + _merchant_connector_account: &domain::MerchantConnectorAccount, _merchant_recipient_data: Option, _header_payload: Option, ) -> RouterResult> { diff --git a/crates/router/src/core/fraud_check/flows/transaction_flow.rs b/crates/router/src/core/fraud_check/flows/transaction_flow.rs index d1c26a32f98f..524c95e836a4 100644 --- a/crates/router/src/core/fraud_check/flows/transaction_flow.rs +++ b/crates/router/src/core/fraud_check/flows/transaction_flow.rs @@ -37,7 +37,7 @@ impl _merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, _customer: &Option, - _merchant_connector_account: &helpers::MerchantConnectorAccountType, + _merchant_connector_account: &domain::MerchantConnectorAccount, _merchant_recipient_data: Option, _header_payload: Option, ) -> RouterResult< diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index a76e24af0c26..c6108c0818e5 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -36,7 +36,9 @@ use events::EventInfo; use futures::future::join_all; use helpers::{decrypt_paze_token, ApplePayData}; #[cfg(feature = "v2")] -use hyperswitch_domain_models::payments::{PaymentConfirmData, PaymentIntentData}; +use hyperswitch_domain_models::payments::{ + PaymentConfirmData, PaymentIntentData, PaymentStatusData, +}; pub use hyperswitch_domain_models::{ mandates::{CustomerAcceptance, MandateData}, payment_address::PaymentAddress, @@ -141,10 +143,12 @@ where { let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation); + // Validate the request fields let (operation, validate_result) = operation .to_validate_request()? .validate_request(&req, &merchant_account)?; + // Get the trackers related to track the state of the payment let operations::GetTrackerResponse { operation, mut payment_data, @@ -173,68 +177,62 @@ where .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound) .attach_printable("Failed while fetching/creating customer")?; - let connector = get_connector_choice( - &operation, - state, - &req, - &merchant_account, - &profile, - &key_store, - &mut payment_data, - None, - None, - ) - .await?; + let connector = operation + .to_domain()? + .perform_routing( + &merchant_account, + &profile, + state, + &mut payment_data, + &key_store, + ) + .await?; + + let payment_data = match connector { + ConnectorCallType::PreDetermined(connector_data) => { + let router_data = call_connector_service( + state, + req_state.clone(), + &merchant_account, + &key_store, + connector_data.clone(), + &operation, + &mut payment_data, + &customer, + call_connector_action.clone(), + &validate_result, + None, + header_payload.clone(), + #[cfg(feature = "frm")] + None, + #[cfg(not(feature = "frm"))] + None, + &profile, + false, + ) + .await?; - // TODO: do not use if let - let payment_data = if let Some(connector_call_type) = connector { - match connector_call_type { - ConnectorCallType::PreDetermined(connector_data) => { - let (router_data, mca) = call_connector_service( + let payments_response_operation = Box::new(PaymentResponse); + + payments_response_operation + .to_post_update_tracker()? + .update_tracker( state, - req_state.clone(), - &merchant_account, + payment_data, + router_data, &key_store, - connector_data.clone(), - &operation, - &mut payment_data, - &customer, - call_connector_action.clone(), - &validate_result, - None, - header_payload.clone(), - #[cfg(feature = "frm")] - None, - #[cfg(not(feature = "frm"))] - None, - &profile, - false, + merchant_account.storage_scheme, + &header_payload.locale, + #[cfg(all(feature = "dynamic_routing", feature = "v1"))] + routable_connectors, + #[cfg(all(feature = "dynamic_routing", feature = "v1"))] + &business_profile, ) - .await?; - - let payments_response_operation = Box::new(PaymentResponse); - - payments_response_operation - .to_post_update_tracker()? - .update_tracker( - state, - payment_data, - router_data, - &key_store, - merchant_account.storage_scheme, - &header_payload.locale, - #[cfg(all(feature = "dynamic_routing", feature = "v1"))] - routable_connectors, - #[cfg(all(feature = "dynamic_routing", feature = "v1"))] - &business_profile, - ) - .await? - } - ConnectorCallType::Retryable(vec) => todo!(), - ConnectorCallType::SessionMultiple(vec) => todo!(), + .await? } - } else { - todo!() + ConnectorCallType::Retryable(vec) => todo!(), + ConnectorCallType::SessionMultiple(vec) => todo!(), + ConnectorCallType::Skip => payment_data, }; Ok((payment_data, req, customer, None, None)) @@ -2137,6 +2135,7 @@ impl PaymentRedirectFlow for PaymentAuthenticateCompleteAuthorize { } } +#[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub async fn call_connector_service( @@ -2184,6 +2183,7 @@ where ) .await?; + #[cfg(feature = "v1")] if payment_data .get_payment_attempt() .merchant_connector_id @@ -2388,6 +2388,157 @@ where Ok((router_data, merchant_connector_account)) } +#[cfg(feature = "v2")] +#[allow(clippy::too_many_arguments)] +#[instrument(skip_all)] +pub async fn call_connector_service( + state: &SessionState, + req_state: ReqState, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + connector: api::ConnectorData, + operation: &BoxedOperation<'_, F, ApiRequest, D>, + payment_data: &mut D, + customer: &Option, + call_connector_action: CallConnectorAction, + validate_result: &operations::ValidateResult, + schedule_time: Option, + header_payload: HeaderPayload, + frm_suggestion: Option, + business_profile: &domain::Profile, + is_retry_payment: bool, +) -> RouterResult> +where + F: Send + Clone + Sync, + RouterDReq: Send + Sync, + + // To create connector flow specific interface data + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, + D: ConstructFlowSpecificData, + RouterData: Feature + Send, + // To construct connector flow specific api + dyn api::Connector: + services::api::ConnectorIntegration, +{ + let stime_connector = Instant::now(); + + let merchant_connector_id = connector + .merchant_connector_id + .as_ref() + .get_required_value("merchant_connector_id") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("connector id is not set")?; + + let merchant_connector_account = state + .store + .find_merchant_connector_account_by_id(&state.into(), merchant_connector_id, key_store) + .await + .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound { + id: merchant_connector_id.get_string_repr().to_owned(), + })?; + + let mut router_data = payment_data + .construct_router_data( + state, + connector.connector.id(), + merchant_account, + key_store, + customer, + &merchant_connector_account, + None, + None, + ) + .await?; + + let add_access_token_result = router_data + .add_access_token( + state, + &connector, + merchant_account, + payment_data.get_creds_identifier(), + ) + .await?; + + router_data = router_data.add_session_token(state, &connector).await?; + + let should_continue_further = access_token::update_router_data_with_access_token_result( + &add_access_token_result, + &mut router_data, + &call_connector_action, + ); + + // In case of authorize flow, pre-task and post-tasks are being called in build request + // if we do not want to proceed further, then the function will return Ok(None, false) + let (connector_request, should_continue_further) = if should_continue_further { + // Check if the actual flow specific request can be built with available data + router_data + .build_flow_specific_connector_request(state, &connector, call_connector_action.clone()) + .await? + } else { + (None, false) + }; + + if should_add_task_to_process_tracker(payment_data) { + operation + .to_domain()? + .add_task_to_process_tracker( + state, + payment_data.get_payment_attempt(), + validate_result.requeue, + schedule_time, + ) + .await + .map_err(|error| logger::error!(process_tracker_error=?error)) + .ok(); + } + + // Update the payment trackers just before calling the connector + // Since the request is already built in the previous step, + // there should be no error in request construction from hyperswitch end + (_, *payment_data) = operation + .to_update_tracker()? + .update_trackers( + state, + req_state, + payment_data.clone(), + customer.clone(), + merchant_account.storage_scheme, + // TODO: update the customer with connector customer id + None, + key_store, + frm_suggestion, + header_payload.clone(), + ) + .await?; + + let router_data = if should_continue_further { + // The status of payment_attempt and intent will be updated in the previous step + // update this in router_data. + // This is added because few connector integrations do not update the status, + // and rely on previous status set in router_data + router_data.status = payment_data.get_payment_attempt().status; + router_data + .decide_flows( + state, + &connector, + call_connector_action, + connector_request, + business_profile, + header_payload.clone(), + ) + .await + } else { + Ok(router_data) + }?; + + let etime_connector = Instant::now(); + let duration_connector = etime_connector.saturating_duration_since(stime_connector); + tracing::info!(duration = format!("Duration taken: {}", duration_connector.as_millis())); + + Ok(router_data) +} + +#[cfg(feature = "v1")] // This function does not perform the tokenization action, as the payment method is not saved in this flow. #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] @@ -2712,7 +2863,7 @@ where F: Send + Clone + Sync, D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { - let merchant_id = &payment_data.get_payment_attempt().merchant_id; + let merchant_id = merchant_account.get_id(); let blocklist_enabled_key = merchant_id.get_blocklist_guard_key(); let blocklist_guard_enabled = state .store @@ -2741,6 +2892,7 @@ where } } +#[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] pub async fn call_multiple_connectors_service( state: &SessionState, @@ -2866,6 +3018,7 @@ where Ok(payment_data) } +#[cfg(feature = "v1")] pub async fn call_create_connector_customer_if_required( state: &SessionState, customer: &Option, @@ -3131,6 +3284,7 @@ where Ok(router_data_and_should_continue_payment) } +#[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] async fn complete_postprocessing_steps_if_required( state: &SessionState, @@ -3863,6 +4017,7 @@ where } } +#[cfg(feature = "v1")] pub fn should_call_connector(operation: &Op, payment_data: &D) -> bool where D: OperationSessionGetters + Send + Sync + Clone, @@ -4311,53 +4466,6 @@ where Ok(()) } -#[cfg(feature = "v2")] -#[allow(clippy::too_many_arguments)] -pub async fn get_connector_choice( - operation: &BoxedOperation<'_, F, Req, D>, - state: &SessionState, - req: &Req, - merchant_account: &domain::MerchantAccount, - business_profile: &domain::Profile, - key_store: &domain::MerchantKeyStore, - payment_data: &mut D, - eligible_connectors: Option>, - mandate_type: Option, -) -> RouterResult> -where - F: Send + Clone, - D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, -{ - // Currently rule based routing and other routing features are not implemented for v2 - // So we are using the default fallback connector for now - // Eligibility analysis is not yet implemented - - let fallback_config = super::admin::ProfileWrapper::new(business_profile.clone()) - .get_default_fallback_list_of_connector_under_profile() - .change_context(errors::RoutingError::FallbackConfigFetchFailed) - .change_context(errors::ApiErrorResponse::InternalServerError)?; - - let first_chosen_connector = fallback_config - .first() - .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?; - - let connector_name = first_chosen_connector.connector.to_string(); - let merchant_connector_id = first_chosen_connector - .merchant_connector_id - .clone() - .get_required_value("merchant_connector_id")?; - - payment_data.set_connector_in_payment_attempt(Some(connector_name.to_string())); - let connector_data = api::ConnectorData::get_connector_by_name( - &state.conf.connectors, - &connector_name, - api::GetToken::Connector, - Some(merchant_connector_id), - )?; - - Ok(Some(ConnectorCallType::PreDetermined(connector_data))) -} - #[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] pub async fn get_connector_choice( @@ -6142,6 +6250,9 @@ pub trait OperationSessionGetters { fn get_mandate_connector(&self) -> Option<&MandateConnectorDetails>; fn get_force_sync(&self) -> Option; fn get_capture_method(&self) -> Option; + + #[cfg(feature = "v2")] + fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt>; } pub trait OperationSessionSetters { @@ -6319,6 +6430,11 @@ impl OperationSessionGetters for PaymentData { fn get_capture_method(&self) -> Option { Some(self.payment_intent.capture_method) } + + #[cfg(feature = "v2")] + fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt> { + todo!(); + } } #[cfg(feature = "v1")] @@ -6550,6 +6666,11 @@ impl OperationSessionGetters for PaymentIntentData { fn get_capture_method(&self) -> Option { todo!() } + + #[cfg(feature = "v2")] + fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt> { + todo!(); + } } #[cfg(feature = "v2")] @@ -6759,6 +6880,11 @@ impl OperationSessionGetters for PaymentConfirmData { fn get_capture_method(&self) -> Option { todo!() } + + #[cfg(feature = "v2")] + fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt> { + todo!(); + } } #[cfg(feature = "v2")] @@ -6846,3 +6972,218 @@ impl OperationSessionSetters for PaymentConfirmData { self.payment_attempt.connector = connector; } } + +#[cfg(feature = "v2")] +impl OperationSessionGetters for PaymentStatusData { + #[track_caller] + fn get_payment_attempt(&self) -> &storage::PaymentAttempt { + todo!() + } + + fn get_payment_intent(&self) -> &storage::PaymentIntent { + &self.payment_intent + } + + fn get_payment_method_info(&self) -> Option<&domain::PaymentMethod> { + todo!() + } + + fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> { + todo!() + } + + // what is this address find out and not required remove this + fn get_address(&self) -> &PaymentAddress { + todo!() + } + + fn get_creds_identifier(&self) -> Option<&str> { + None + } + + fn get_token(&self) -> Option<&str> { + todo!() + } + + fn get_multiple_capture_data(&self) -> Option<&types::MultipleCaptureData> { + todo!() + } + + fn get_payment_link_data(&self) -> Option { + todo!() + } + + fn get_ephemeral_key(&self) -> Option { + todo!() + } + + fn get_setup_mandate(&self) -> Option<&MandateData> { + todo!() + } + + fn get_poll_config(&self) -> Option { + todo!() + } + + fn get_authentication(&self) -> Option<&storage::Authentication> { + todo!() + } + + fn get_frm_message(&self) -> Option { + todo!() + } + + fn get_refunds(&self) -> Vec { + todo!() + } + + fn get_disputes(&self) -> Vec { + todo!() + } + + fn get_authorizations(&self) -> Vec { + todo!() + } + + fn get_attempts(&self) -> Option> { + todo!() + } + + fn get_recurring_details(&self) -> Option<&RecurringDetails> { + todo!() + } + + fn get_payment_intent_profile_id(&self) -> Option<&id_type::ProfileId> { + Some(&self.payment_intent.profile_id) + } + + fn get_currency(&self) -> storage_enums::Currency { + self.payment_intent.amount_details.currency + } + + fn get_amount(&self) -> api::Amount { + todo!() + } + + fn get_payment_attempt_connector(&self) -> Option<&str> { + todo!() + } + + fn get_billing_address(&self) -> Option { + todo!() + } + + fn get_payment_method_data(&self) -> Option<&domain::PaymentMethodData> { + todo!() + } + + fn get_sessions_token(&self) -> Vec { + todo!() + } + + fn get_token_data(&self) -> Option<&storage::PaymentTokenData> { + todo!() + } + + fn get_mandate_connector(&self) -> Option<&MandateConnectorDetails> { + todo!() + } + + fn get_force_sync(&self) -> Option { + todo!() + } + + fn get_capture_method(&self) -> Option { + todo!() + } + + #[cfg(feature = "v2")] + fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt> { + self.payment_attempt.as_ref() + } +} + +#[cfg(feature = "v2")] +impl OperationSessionSetters for PaymentStatusData { + fn set_payment_intent(&mut self, payment_intent: storage::PaymentIntent) { + self.payment_intent = payment_intent; + } + + fn set_payment_attempt(&mut self, payment_attempt: storage::PaymentAttempt) { + self.payment_attempt = Some(payment_attempt); + } + + fn set_payment_method_data(&mut self, _payment_method_data: Option) { + todo!() + } + + fn set_payment_method_id_in_attempt(&mut self, _payment_method_id: Option) { + todo!() + } + + fn set_email_if_not_present(&mut self, _email: pii::Email) { + todo!() + } + + fn set_pm_token(&mut self, _token: String) { + todo!() + } + + fn set_connector_customer_id(&mut self, _customer_id: Option) { + // TODO: handle this case. Should we add connector_customer_id in paymentConfirmData? + } + + fn push_sessions_token(&mut self, _token: api::SessionToken) { + todo!() + } + + fn set_surcharge_details(&mut self, _surcharge_details: Option) { + todo!() + } + + #[track_caller] + fn set_merchant_connector_id_in_attempt( + &mut self, + merchant_connector_id: Option, + ) { + todo!() + } + + fn set_frm_message(&mut self, _frm_message: FraudCheck) { + todo!() + } + + fn set_payment_intent_status(&mut self, status: storage_enums::IntentStatus) { + self.payment_intent.status = status; + } + + fn set_authentication_type_in_attempt( + &mut self, + _authentication_type: Option, + ) { + todo!() + } + + fn set_recurring_mandate_payment_data( + &mut self, + _recurring_mandate_payment_data: + hyperswitch_domain_models::router_data::RecurringMandatePaymentData, + ) { + todo!() + } + + fn set_mandate_id(&mut self, _mandate_id: api_models::payments::MandateIds) { + todo!() + } + + fn set_setup_future_usage_in_payment_intent( + &mut self, + setup_future_usage: storage_enums::FutureUsage, + ) { + self.payment_intent.setup_future_usage = setup_future_usage; + } + + fn set_connector_in_payment_attempt(&mut self, connector: Option) { + todo!() + } +} diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 8c84f7ab9a6c..3c54d939c9d4 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -29,7 +29,7 @@ use crate::{ #[async_trait] #[allow(clippy::too_many_arguments)] pub trait ConstructFlowSpecificData { - #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -42,7 +42,7 @@ pub trait ConstructFlowSpecificData { header_payload: Option, ) -> RouterResult>; - #[cfg(all(feature = "v2", feature = "customer_v2"))] + #[cfg(feature = "v2")] async fn construct_router_data<'a>( &self, _state: &SessionState, @@ -50,7 +50,7 @@ pub trait ConstructFlowSpecificData { _merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, _customer: &Option, - _merchant_connector_account: &helpers::MerchantConnectorAccountType, + _merchant_connector_account: &domain::MerchantConnectorAccount, _merchant_recipient_data: Option, _header_payload: Option, ) -> RouterResult>; diff --git a/crates/router/src/core/payments/flows/approve_flow.rs b/crates/router/src/core/payments/flows/approve_flow.rs index 98d204d52643..c35f096fbd3d 100644 --- a/crates/router/src/core/payments/flows/approve_flow.rs +++ b/crates/router/src/core/payments/flows/approve_flow.rs @@ -16,6 +16,22 @@ impl ConstructFlowSpecificData for PaymentData { + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult { + todo!() + } + + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index 09a6fb519248..bc624082055c 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -38,7 +38,7 @@ impl merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, customer: &Option, - merchant_connector_account: &helpers::MerchantConnectorAccountType, + merchant_connector_account: &domain::MerchantConnectorAccount, merchant_recipient_data: Option, header_payload: Option, ) -> RouterResult< diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs index 9c5bc84a6218..e9c3f63c7920 100644 --- a/crates/router/src/core/payments/flows/cancel_flow.rs +++ b/crates/router/src/core/payments/flows/cancel_flow.rs @@ -16,6 +16,22 @@ use crate::{ impl ConstructFlowSpecificData for PaymentData { + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + _state: &SessionState, + _connector_id: &str, + _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, + _customer: &Option, + _merchant_connector_account: &domain::MerchantConnectorAccount, + _merchant_recipient_data: Option, + _header_payload: Option, + ) -> RouterResult { + todo!() + } + + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, diff --git a/crates/router/src/core/payments/flows/capture_flow.rs b/crates/router/src/core/payments/flows/capture_flow.rs index aaa245a341f0..8b6fa24fbfd7 100644 --- a/crates/router/src/core/payments/flows/capture_flow.rs +++ b/crates/router/src/core/payments/flows/capture_flow.rs @@ -16,6 +16,7 @@ impl ConstructFlowSpecificData for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -44,6 +45,21 @@ impl .await } + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/flows/complete_authorize_flow.rs b/crates/router/src/core/payments/flows/complete_authorize_flow.rs index 24f6d8d07545..f3cfb45f188f 100644 --- a/crates/router/src/core/payments/flows/complete_authorize_flow.rs +++ b/crates/router/src/core/payments/flows/complete_authorize_flow.rs @@ -20,6 +20,7 @@ impl types::PaymentsResponseData, > for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -54,6 +55,27 @@ impl .await } + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult< + types::RouterData< + api::CompleteAuthorize, + types::CompleteAuthorizeData, + types::PaymentsResponseData, + >, + > { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs index a187146903e7..982fbc4c99a1 100644 --- a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs +++ b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs @@ -19,6 +19,7 @@ impl types::PaymentsResponseData, > for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -47,6 +48,21 @@ impl .await } + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/flows/post_session_tokens_flow.rs b/crates/router/src/core/payments/flows/post_session_tokens_flow.rs index 13738480c907..19dc356f1483 100644 --- a/crates/router/src/core/payments/flows/post_session_tokens_flow.rs +++ b/crates/router/src/core/payments/flows/post_session_tokens_flow.rs @@ -19,6 +19,7 @@ impl types::PaymentsResponseData, > for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -26,7 +27,7 @@ impl merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, customer: &Option, - merchant_connector_account: &helpers::MerchantConnectorAccountType, + merchant_connector_account: &domain::MerchantConnectorAccount, merchant_recipient_data: Option, header_payload: Option, ) -> RouterResult { @@ -47,6 +48,21 @@ impl .await } + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs index 34ebfdf4bad0..d468514da87a 100644 --- a/crates/router/src/core/payments/flows/psync_flow.rs +++ b/crates/router/src/core/payments/flows/psync_flow.rs @@ -13,6 +13,8 @@ use crate::{ services::{self, api::ConnectorValidation, logger}, types::{self, api, domain}, }; + +#[cfg(feature = "v1")] #[async_trait] impl ConstructFlowSpecificData for PaymentData @@ -59,6 +61,50 @@ impl ConstructFlowSpecificData + for hyperswitch_domain_models::payments::PaymentStatusData +{ + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult< + types::RouterData, + > { + Box::pin(transformers::construct_router_data_for_psync( + state, + self.clone(), + connector_id, + merchant_account, + key_store, + customer, + merchant_connector_account, + merchant_recipient_data, + header_payload, + )) + .await + } + + async fn get_merchant_recipient_data<'a>( + &self, + _state: &SessionState, + _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, + _merchant_connector_account: &helpers::MerchantConnectorAccountType, + _connector: &api::ConnectorData, + ) -> RouterResult> { + Ok(None) + } +} + #[async_trait] impl Feature for types::RouterData diff --git a/crates/router/src/core/payments/flows/reject_flow.rs b/crates/router/src/core/payments/flows/reject_flow.rs index 43163c1374b8..66337a49e7c1 100644 --- a/crates/router/src/core/payments/flows/reject_flow.rs +++ b/crates/router/src/core/payments/flows/reject_flow.rs @@ -15,6 +15,7 @@ use crate::{ impl ConstructFlowSpecificData for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -43,6 +44,21 @@ impl ConstructFlowSpecificData( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 736ffdd7b8b4..8aa068d86d25 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -31,6 +31,7 @@ impl ConstructFlowSpecificData for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &routes::SessionState, @@ -59,6 +60,21 @@ impl .await } + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &routes::SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &routes::SessionState, diff --git a/crates/router/src/core/payments/flows/session_update_flow.rs b/crates/router/src/core/payments/flows/session_update_flow.rs index e48f90d1bb6a..8f4457b36f58 100644 --- a/crates/router/src/core/payments/flows/session_update_flow.rs +++ b/crates/router/src/core/payments/flows/session_update_flow.rs @@ -19,6 +19,7 @@ impl types::PaymentsResponseData, > for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -47,6 +48,21 @@ impl .await } + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + _merchant_recipient_data: Option, + _header_payload: Option, + ) -> RouterResult { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs index 2cee81115d64..ee8ff78bdab1 100644 --- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs +++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs @@ -23,6 +23,7 @@ impl types::PaymentsResponseData, > for PaymentData { + #[cfg(feature = "v1")] async fn construct_router_data<'a>( &self, state: &SessionState, @@ -51,6 +52,21 @@ impl .await } + #[cfg(feature = "v2")] + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult { + todo!() + } + async fn get_merchant_recipient_data<'a>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 6546638a62ed..20d966a105fe 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -34,6 +34,9 @@ pub mod payment_create_intent; #[cfg(feature = "v2")] pub mod payment_confirm_intent; +#[cfg(feature = "v2")] +pub mod payment_get; + use api_models::enums::FrmSuggestion; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] use api_models::routing::RoutableConnectorChoice; @@ -42,9 +45,11 @@ use error_stack::{report, ResultExt}; use router_env::{instrument, tracing}; #[cfg(feature = "v2")] -pub use self::payment_confirm_intent::PaymentIntentConfirm; -#[cfg(feature = "v2")] -pub use self::payment_create_intent::PaymentIntentCreate; +pub use self::{ + payment_confirm_intent::PaymentIntentConfirm, payment_create_intent::PaymentIntentCreate, + payment_get::PaymentGet, +}; + pub use self::payment_response::PaymentResponse; #[cfg(feature = "v1")] pub use self::{ @@ -80,20 +85,24 @@ pub trait Operation: Send + std::fmt::Debug { Err(report!(errors::ApiErrorResponse::InternalServerError)) .attach_printable_lazy(|| format!("validate request interface not found for {self:?}")) } + fn to_get_tracker(&self) -> RouterResult<&(dyn GetTracker + Send + Sync)> { Err(report!(errors::ApiErrorResponse::InternalServerError)) .attach_printable_lazy(|| format!("get tracker interface not found for {self:?}")) } + fn to_domain(&self) -> RouterResult<&dyn Domain> { Err(report!(errors::ApiErrorResponse::InternalServerError)) .attach_printable_lazy(|| format!("domain interface not found for {self:?}")) } + fn to_update_tracker( &self, ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> { Err(report!(errors::ApiErrorResponse::InternalServerError)) .attach_printable_lazy(|| format!("update tracker interface not found for {self:?}")) } + fn to_post_update_tracker( &self, ) -> RouterResult<&(dyn PostUpdateTracker + Send + Sync)> { @@ -235,6 +244,7 @@ pub trait Domain: Send + Sync { Ok(()) } + #[cfg(feature = "v1")] async fn get_connector<'a>( &'a self, merchant_account: &domain::MerchantAccount, @@ -244,6 +254,17 @@ pub trait Domain: Send + Sync { mechant_key_store: &domain::MerchantKeyStore, ) -> CustomResult; + #[cfg(feature = "v2")] + async fn perform_routing<'a>( + &'a self, + merchant_account: &domain::MerchantAccount, + business_profile: &domain::Profile, + state: &SessionState, + // TODO: do not take the whole payment data here + payment_data: &mut D, + mechant_key_store: &domain::MerchantKeyStore, + ) -> CustomResult; + async fn populate_payment_data<'a>( &'a self, _state: &SessionState, @@ -300,11 +321,36 @@ pub trait Domain: Send + Sync { ) -> CustomResult<(), errors::ApiErrorResponse> { Ok(()) } + + // #[cfg(feature = "v2")] + // async fn call_connector<'a, RouterDataReq>( + // &'a self, + // _state: &SessionState, + // _req_state: ReqState, + // _merchant_account: &domain::MerchantAccount, + // _key_store: &domain::MerchantKeyStore, + // _business_profile: &domain::Profile, + // _payment_method_data: Option<&domain::PaymentMethodData>, + // _connector: api::ConnectorData, + // _customer: &Option, + // _payment_data: &mut D, + // _call_connector_action: common_enums::CallConnectorAction, + // ) -> CustomResult< + // hyperswitch_domain_models::router_data::RouterData, + // errors::ApiErrorResponse, + // > { + // // TODO: raise an error here + // todo!(); + // } } #[async_trait] #[allow(clippy::too_many_arguments)] pub trait UpdateTracker: Send { + /// Update the tracker information with the new data from request or calculated by the operations performed after get trackers + /// This will persist the SessionData ( PaymentData ) in the database + /// + /// In case we are calling a processor / connector, we persist all the data in the database and then call the connector async fn update_trackers<'b>( &'b self, db: &'b SessionState, @@ -321,9 +367,32 @@ pub trait UpdateTracker: Send { F: 'b + Send; } +#[cfg(feature = "v2")] +#[async_trait] +#[allow(clippy::too_many_arguments)] +pub trait CallConnector: Send { + async fn call_connector<'b>( + &'b self, + db: &'b SessionState, + req_state: ReqState, + payment_data: D, + key_store: &domain::MerchantKeyStore, + call_connector_action: common_enums::CallConnectorAction, + connector_data: api::ConnectorData, + storage_scheme: enums::MerchantStorageScheme, + ) -> RouterResult> + where + F: 'b + Send + Sync, + D: super::flows::ConstructFlowSpecificData, + types::RouterData: + super::flows::Feature + Send; +} + #[async_trait] #[allow(clippy::too_many_arguments)] pub trait PostUpdateTracker: Send { + /// Update the tracker information with the response from the connector + /// The response from routerdata is used to update paymentdata and also persist this in the database async fn update_tracker<'b>( &'b self, db: &'b SessionState, @@ -356,6 +425,7 @@ pub trait PostUpdateTracker: Send { } } +#[cfg(feature = "v1")] #[async_trait] impl< D, @@ -406,24 +476,6 @@ where Ok((Box::new(self), customer)) } - #[instrument(skip_all)] - #[cfg(feature = "v2")] - async fn get_customer_details<'a>( - &'a self, - _state: &SessionState, - _payment_data: &mut D, - _merchant_key_store: &domain::MerchantKeyStore, - _storage_scheme: enums::MerchantStorageScheme, - ) -> CustomResult< - ( - BoxedOperation<'a, F, api::PaymentsRetrieveRequest, D>, - Option, - ), - errors::StorageError, - > { - todo!() - } - async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, @@ -464,6 +516,7 @@ where } } +#[cfg(feature = "v1")] #[async_trait] impl> Domain for Op @@ -568,6 +621,7 @@ where } } +#[cfg(feature = "v1")] #[async_trait] impl> Domain for Op @@ -672,6 +726,7 @@ where } } +#[cfg(feature = "v1")] #[async_trait] impl> Domain for Op @@ -762,3 +817,12 @@ pub trait ValidateStatusForOperation { intent_status: common_enums::IntentStatus, ) -> Result<(), errors::ApiErrorResponse>; } + +/// Should the connector be called for this operation +pub trait ShouldCallConnector { + fn should_call_connector( + &self, + intent_status: common_enums::IntentStatus, + force_sync: Option, + ) -> bool; +} diff --git a/crates/router/src/core/payments/operations/payment_confirm_intent.rs b/crates/router/src/core/payments/operations/payment_confirm_intent.rs index 083bb5adca28..c89f0bdc5c1c 100644 --- a/crates/router/src/core/payments/operations/payment_confirm_intent.rs +++ b/crates/router/src/core/payments/operations/payment_confirm_intent.rs @@ -5,16 +5,14 @@ use api_models::{ }; use async_trait::async_trait; use error_stack::ResultExt; -use hyperswitch_domain_models::payments::{ - payment_attempt::PaymentAttempt, PaymentConfirmData, PaymentIntent, -}; +use hyperswitch_domain_models::payments::PaymentConfirmData; use router_env::{instrument, tracing}; use tracing_futures::Instrument; use super::{Domain, GetTracker, Operation, UpdateTracker, ValidateRequest}; use crate::{ core::{ - authentication, + admin, errors::{self, CustomResult, RouterResult, StorageErrorExt}, payments::{ self, helpers, @@ -270,15 +268,44 @@ impl Domain( + #[cfg(feature = "v2")] + async fn perform_routing<'a>( &'a self, - _merchant_account: &domain::MerchantAccount, + merchant_account: &domain::MerchantAccount, + business_profile: &domain::Profile, state: &SessionState, - request: &PaymentsConfirmIntentRequest, - _payment_intent: &storage::PaymentIntent, - _key_store: &domain::MerchantKeyStore, - ) -> CustomResult { - todo!() + // TODO: do not take the whole payment data here + payment_data: &mut PaymentConfirmData, + mechant_key_store: &domain::MerchantKeyStore, + ) -> CustomResult { + use crate::core::payments::OperationSessionSetters; + + let fallback_config = admin::ProfileWrapper::new(business_profile.clone()) + .get_default_fallback_list_of_connector_under_profile() + .change_context(errors::RoutingError::FallbackConfigFetchFailed) + .change_context(errors::ApiErrorResponse::InternalServerError)?; + + let first_chosen_connector = fallback_config + .first() + .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?; + + let connector_name = first_chosen_connector.connector.to_string(); + let merchant_connector_id = first_chosen_connector + .merchant_connector_id + .clone() + .get_required_value("merchant_connector_id")?; + + payment_data.set_connector_in_payment_attempt(Some(connector_name.to_string())); + payment_data.set_merchant_connector_id_in_attempt(Some(merchant_connector_id.clone())); + + let connector_data = api::ConnectorData::get_connector_by_name( + &state.conf.connectors, + &connector_name, + api::GetToken::Connector, + Some(merchant_connector_id), + )?; + + Ok(ConnectorCallType::PreDetermined(connector_data)) } } @@ -328,6 +355,7 @@ impl UpdateTracker, PaymentsConfirmIntentRequ hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntent { status: intent_status, updated_by: storage_scheme.to_string(), + active_attempt_id: payment_data.payment_attempt.id.clone(), }; let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntent { diff --git a/crates/router/src/core/payments/operations/payment_create_intent.rs b/crates/router/src/core/payments/operations/payment_create_intent.rs index bd82a67e6270..d57d24e3edd1 100644 --- a/crates/router/src/core/payments/operations/payment_create_intent.rs +++ b/crates/router/src/core/payments/operations/payment_create_intent.rs @@ -287,15 +287,17 @@ impl Domain( + #[instrument(skip_all)] + async fn perform_routing<'a>( &'a self, - _merchant_account: &domain::MerchantAccount, + merchant_account: &domain::MerchantAccount, + business_profile: &domain::Profile, state: &SessionState, - _request: &PaymentsCreateIntentRequest, - _payment_intent: &storage::PaymentIntent, - _merchant_key_store: &domain::MerchantKeyStore, - ) -> CustomResult { - helpers::get_connector_default(state, None).await + // TODO: do not take the whole payment data here + payment_data: &mut payments::PaymentIntentData, + mechant_key_store: &domain::MerchantKeyStore, + ) -> CustomResult { + Ok(api::ConnectorCallType::Skip) } #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs new file mode 100644 index 000000000000..19c846a5990f --- /dev/null +++ b/crates/router/src/core/payments/operations/payment_get.rs @@ -0,0 +1,307 @@ +use api_models::{ + admin::ExtendedCardInfoConfig, + enums::FrmSuggestion, + payments::{ExtendedCardInfo, GetAddressFromPaymentMethodData, PaymentsStatusRequest}, +}; +use async_trait::async_trait; +use common_utils::ext_traits::AsyncExt; +use error_stack::ResultExt; +use hyperswitch_domain_models::payments::{ + payment_attempt::PaymentAttempt, PaymentIntent, PaymentStatusData, +}; +use router_env::{instrument, tracing}; +use tracing_futures::Instrument; + +use super::{Domain, GetTracker, Operation, UpdateTracker, ValidateRequest}; +use crate::{ + core::{ + authentication, + errors::{self, CustomResult, RouterResult, StorageErrorExt}, + payments::{ + self, helpers, + operations::{self, ValidateStatusForOperation}, + populate_surcharge_details, CustomerDetails, PaymentAddress, PaymentData, + }, + utils as core_utils, + }, + routes::{app::ReqState, SessionState}, + services, + types::{ + self, + api::{self, ConnectorCallType, PaymentIdTypeExt}, + domain::{self}, + storage::{self, enums as storage_enums}, + }, + utils::{self, OptionExt}, +}; + +#[derive(Debug, Clone, Copy)] +pub struct PaymentGet; + +impl ValidateStatusForOperation for PaymentGet { + /// Validate if the current operation can be performed on the current status of the payment intent + fn validate_status_for_operation( + &self, + intent_status: common_enums::IntentStatus, + ) -> Result<(), errors::ApiErrorResponse> { + match intent_status { + common_enums::IntentStatus::RequiresPaymentMethod + | common_enums::IntentStatus::Succeeded + | common_enums::IntentStatus::Failed + | common_enums::IntentStatus::Cancelled + | common_enums::IntentStatus::Processing + | common_enums::IntentStatus::RequiresCustomerAction + | common_enums::IntentStatus::RequiresMerchantAction + | common_enums::IntentStatus::RequiresCapture + | common_enums::IntentStatus::PartiallyCaptured + | common_enums::IntentStatus::RequiresConfirmation + | common_enums::IntentStatus::PartiallyCapturedAndCapturable => Ok(()), + } + } +} + +type BoxedConfirmOperation<'b, F> = + super::BoxedOperation<'b, F, PaymentsStatusRequest, PaymentStatusData>; + +// TODO: change the macro to include changes for v2 +// TODO: PaymentData in the macro should be an input +impl Operation for &PaymentGet { + type Data = PaymentStatusData; + fn to_validate_request( + &self, + ) -> RouterResult<&(dyn ValidateRequest + Send + Sync)> + { + Ok(*self) + } + fn to_get_tracker( + &self, + ) -> RouterResult<&(dyn GetTracker + Send + Sync)> { + Ok(*self) + } + fn to_domain(&self) -> RouterResult<&(dyn Domain)> { + Ok(*self) + } + fn to_update_tracker( + &self, + ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> + { + Ok(*self) + } +} +#[automatically_derived] +impl Operation for PaymentGet { + type Data = PaymentStatusData; + fn to_validate_request( + &self, + ) -> RouterResult<&(dyn ValidateRequest + Send + Sync)> + { + Ok(self) + } + fn to_get_tracker( + &self, + ) -> RouterResult<&(dyn GetTracker + Send + Sync)> { + Ok(self) + } + fn to_domain(&self) -> RouterResult<&dyn Domain> { + Ok(self) + } + fn to_update_tracker( + &self, + ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> + { + Ok(self) + } +} + +impl ValidateRequest> + for PaymentGet +{ + #[instrument(skip_all)] + fn validate_request<'a, 'b>( + &'b self, + request: &PaymentsStatusRequest, + merchant_account: &'a domain::MerchantAccount, + ) -> RouterResult<(BoxedConfirmOperation<'b, F>, operations::ValidateResult)> { + let validate_result = operations::ValidateResult { + merchant_id: merchant_account.get_id().to_owned(), + storage_scheme: merchant_account.storage_scheme, + requeue: false, + }; + + Ok((Box::new(self), validate_result)) + } +} + +#[async_trait] +impl GetTracker, PaymentsStatusRequest> for PaymentGet { + #[instrument(skip_all)] + async fn get_trackers<'a>( + &'a self, + state: &'a SessionState, + payment_id: &common_utils::id_type::GlobalPaymentId, + request: &PaymentsStatusRequest, + merchant_account: &domain::MerchantAccount, + _profile: &domain::Profile, + key_store: &domain::MerchantKeyStore, + header_payload: &hyperswitch_domain_models::payments::HeaderPayload, + ) -> RouterResult< + operations::GetTrackerResponse<'a, F, PaymentsStatusRequest, PaymentStatusData>, + > { + let db = &*state.store; + let key_manager_state = &state.into(); + + let storage_scheme = merchant_account.storage_scheme; + + let payment_intent = db + .find_payment_intent_by_id(key_manager_state, payment_id, key_store, storage_scheme) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; + + self.validate_status_for_operation(payment_intent.status)?; + let client_secret = header_payload + .client_secret + .as_ref() + .get_required_value("client_secret header")?; + payment_intent.validate_client_secret(client_secret)?; + + let payment_attempt = payment_intent + .active_attempt_id + .as_ref() + .async_map(|active_attempt| async { + db.find_payment_attempt_by_id( + key_manager_state, + key_store, + active_attempt, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Could not find payment attempt given the attempt id") + }) + .await + .transpose()?; + + let payment_data = PaymentStatusData { + flow: std::marker::PhantomData, + payment_intent, + payment_attempt, + }; + + let get_trackers_response = operations::GetTrackerResponse { + operation: Box::new(self), + payment_data, + }; + + Ok(get_trackers_response) + } +} + +#[async_trait] +impl Domain> for PaymentGet { + async fn get_customer_details<'a>( + &'a self, + state: &SessionState, + payment_data: &mut PaymentStatusData, + merchant_key_store: &domain::MerchantKeyStore, + storage_scheme: storage_enums::MerchantStorageScheme, + ) -> CustomResult<(BoxedConfirmOperation<'a, F>, Option), errors::StorageError> + { + match payment_data.payment_intent.customer_id.clone() { + Some(id) => { + let customer = state + .store + .find_customer_by_global_id( + &state.into(), + id.get_string_repr(), + &payment_data.payment_intent.merchant_id, + merchant_key_store, + storage_scheme, + ) + .await?; + + Ok((Box::new(self), Some(customer))) + } + None => Ok((Box::new(self), None)), + } + } + + #[instrument(skip_all)] + async fn make_pm_data<'a>( + &'a self, + state: &'a SessionState, + payment_data: &mut PaymentStatusData, + storage_scheme: storage_enums::MerchantStorageScheme, + key_store: &domain::MerchantKeyStore, + customer: &Option, + business_profile: &domain::Profile, + ) -> RouterResult<( + BoxedConfirmOperation<'a, F>, + Option, + Option, + )> { + Ok((Box::new(self), None, None)) + } + + #[instrument(skip_all)] + async fn perform_routing<'a>( + &'a self, + merchant_account: &domain::MerchantAccount, + business_profile: &domain::Profile, + state: &SessionState, + // TODO: do not take the whole payment data here + payment_data: &mut PaymentStatusData, + mechant_key_store: &domain::MerchantKeyStore, + ) -> CustomResult { + match &payment_data.payment_attempt { + Some(payment_attempt) => { + let connector = payment_attempt + .connector + .as_ref() + .get_required_value("connector") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Connector is none when constructing response")?; + + let merchant_connector_id = payment_attempt + .merchant_connector_id + .as_ref() + .get_required_value("merchant_connector_id") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Merchant connector id is none when constructing response")?; + + let connector_data = api::ConnectorData::get_connector_by_name( + &state.conf.connectors, + connector, + api::GetToken::Connector, + Some(merchant_connector_id.to_owned()), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Invalid connector name received")?; + + Ok(ConnectorCallType::PreDetermined(connector_data)) + } + None => Ok(ConnectorCallType::Skip), + } + } +} + +#[async_trait] +impl UpdateTracker, PaymentsStatusRequest> for PaymentGet { + #[instrument(skip_all)] + async fn update_trackers<'b>( + &'b self, + state: &'b SessionState, + req_state: ReqState, + mut payment_data: PaymentStatusData, + customer: Option, + storage_scheme: storage_enums::MerchantStorageScheme, + updated_customer: Option, + key_store: &domain::MerchantKeyStore, + frm_suggestion: Option, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, + ) -> RouterResult<(BoxedConfirmOperation<'b, F>, PaymentStatusData)> + where + F: 'b + Send, + { + Ok((Box::new(self), payment_data)) + } +} diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 7aa67a9b50f6..b22a64158429 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -13,7 +13,7 @@ use error_stack::{report, ResultExt}; use futures::FutureExt; use hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt; #[cfg(feature = "v2")] -use hyperswitch_domain_models::payments::PaymentConfirmData; +use hyperswitch_domain_models::payments::{PaymentConfirmData, PaymentStatusData}; use router_derive; use router_env::{instrument, logger, metrics::add_attributes, tracing}; use storage_impl::DataModelExt; @@ -27,8 +27,8 @@ use crate::{ consts, core::{ errors::{self, CustomResult, RouterResult, StorageErrorExt}, - mandate, payment_methods, - payment_methods::cards::create_encrypted_data, + mandate, + payment_methods::{self, cards::create_encrypted_data}, payments::{ helpers::{ self as payments_helpers, @@ -2288,6 +2288,189 @@ impl PostUpdateTracker, types::PaymentsAuthor } } +#[cfg(feature = "v2")] +impl Operation for PaymentResponse { + type Data = PaymentStatusData; + fn to_post_update_tracker( + &self, + ) -> RouterResult<&(dyn PostUpdateTracker + Send + Sync)> + { + Ok(self) + } +} + +#[cfg(feature = "v2")] +#[async_trait] +impl PostUpdateTracker, types::PaymentsSyncData> + for PaymentResponse +{ + async fn update_tracker<'b>( + &'b self, + state: &'b SessionState, + mut payment_data: PaymentStatusData, + response: types::RouterData, + key_store: &domain::MerchantKeyStore, + storage_scheme: enums::MerchantStorageScheme, + locale: &Option, + #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec< + RoutableConnectorChoice, + >, + #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile, + ) -> RouterResult> + where + F: 'b + Send + Sync, + { + use common_utils::ext_traits::OptionExt; + + let db = &*state.store; + let key_manager_state = &state.into(); + + let response_router_data = response; + let payment_attempt = payment_data + .payment_attempt + .clone() + .get_required_value("payment_attempt") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("payment attempt is not set in payment data")?; + + match response_router_data.response { + Ok(response) => match response { + types::PaymentsResponseData::TransactionResponse { + resource_id, + redirection_data, + mandate_reference, + connector_metadata, + network_txn_id, + connector_response_reference_id, + incremental_authorization_allowed, + charge_id, + } => { + let attempt_status = response_router_data.status; + let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); + let connector_payment_id = match resource_id { + types::ResponseId::NoResponseId => None, + types::ResponseId::ConnectorTransactionId(id) + | types::ResponseId::EncodedData(id) => Some(id), + }; + + let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; + let updated_payment_intent = db + .update_payment_intent( + key_manager_state, + payment_data.payment_intent, + payment_intent_update, + key_store, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment intent")?; + payment_data.payment_intent = updated_payment_intent; + + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentResponse { status: attempt_status, connector_payment_id, updated_by: storage_scheme.to_string() }; + let updated_payment_attempt = db + .update_payment_attempt( + key_manager_state, + key_store, + payment_attempt, + payment_attempt_update, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment attempt")?; + payment_data.payment_attempt = Some(updated_payment_attempt); + } + types::PaymentsResponseData::MultipleCaptureResponse { + capture_sync_response_list, + } => todo!(), + types::PaymentsResponseData::SessionResponse { session_token } => todo!(), + types::PaymentsResponseData::SessionTokenResponse { session_token } => todo!(), + types::PaymentsResponseData::TransactionUnresolvedResponse { + resource_id, + reason, + connector_response_reference_id, + } => todo!(), + types::PaymentsResponseData::TokenizationResponse { token } => todo!(), + types::PaymentsResponseData::ConnectorCustomerResponse { + connector_customer_id, + } => todo!(), + types::PaymentsResponseData::ThreeDSEnrollmentResponse { + enrolled_v2, + related_transaction_id, + } => todo!(), + types::PaymentsResponseData::PreProcessingResponse { + pre_processing_id, + connector_metadata, + session_token, + connector_response_reference_id, + } => todo!(), + types::PaymentsResponseData::IncrementalAuthorizationResponse { + status, + connector_authorization_id, + error_code, + error_message, + } => todo!(), + types::PaymentsResponseData::PostProcessingResponse { session_token } => todo!(), + types::PaymentsResponseData::SessionUpdateResponse { status } => todo!(), + }, + Err(ErrorResponse { + code, + message, + reason, + status_code, + attempt_status, + connector_transaction_id, + }) => { + let attempt_status = common_enums::AttemptStatus::Failure; + let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); + let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; + + let updated_payment_intent = db + .update_payment_intent( + key_manager_state, + payment_data.payment_intent, + payment_intent_update, + key_store, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment intent")?; + + payment_data.payment_intent = updated_payment_intent; + + // TODO: populate unified code and message and translation by calling gsm and translation table + let error_details = + hyperswitch_domain_models::payments::payment_attempt::ErrorDetails { + code, + message, + reason, + unified_code: None, + unified_message: None, + }; + + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentError { status: attempt_status, error: error_details,updated_by: storage_scheme.to_string() }; + let updated_payment_attempt = db + .update_payment_attempt( + key_manager_state, + key_store, + payment_attempt, + payment_attempt_update, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment attempt")?; + + payment_data.payment_attempt = Some(updated_payment_attempt); + } + } + // TODO: Implement this + Ok(payment_data) + } +} + #[cfg(feature = "v1")] fn update_connector_mandate_details_for_the_flow( connector_mandate_id: Option, diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 7fdccf9c60fa..fed28b680110 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -291,6 +291,7 @@ fn get_flow_name() -> RouterResult { .to_string()) } +#[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub async fn do_retry( diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 66e5c996d34b..72e3d752ad0b 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -173,19 +173,21 @@ pub async fn construct_payment_router_data_for_authorize<'a>( merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, customer: &'a Option, - merchant_connector_account: &helpers::MerchantConnectorAccountType, + merchant_connector_account: &domain::MerchantConnectorAccount, _merchant_recipient_data: Option, header_payload: Option, ) -> RouterResult { use masking::ExposeOptionInterface; - fp_utils::when(merchant_connector_account.is_disabled(), || { + fp_utils::when(merchant_connector_account.disabled.unwrap_or(false), || { Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled) })?; - let auth_type: types::ConnectorAuthType = merchant_connector_account - .get_connector_account_details() - .parse_value("ConnectorAuthType") + let auth_type = merchant_connector_account + .connector_account_details + .clone() + .into_inner() + .parse_value::("ConnectorAuthType") .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while parsing value for ConnectorAuthType")?; @@ -359,6 +361,151 @@ pub async fn construct_payment_router_data_for_authorize<'a>( Ok(router_data) } +#[cfg(feature = "v2")] +#[instrument(skip_all)] +#[allow(clippy::too_many_arguments)] +pub async fn construct_router_data_for_psync<'a>( + state: &'a SessionState, + payment_data: hyperswitch_domain_models::payments::PaymentStatusData, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, + customer: &'a Option, + merchant_connector_account: &domain::MerchantConnectorAccount, + _merchant_recipient_data: Option, + header_payload: Option, +) -> RouterResult { + use masking::ExposeOptionInterface; + + fp_utils::when(merchant_connector_account.disabled.unwrap_or(false), || { + Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled) + })?; + + // TODO: Take Globalid and convert to connector reference id + let customer_id = customer + .to_owned() + .map(|customer| customer.id.clone()) + .map(std::borrow::Cow::Owned) + .map(common_utils::id_type::CustomerId::try_from) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "Invalid global customer generated, not able to convert to reference id", + )?; + + let payment_intent = payment_data.payment_intent; + + let auth_type: types::ConnectorAuthType = merchant_connector_account + .connector_account_details + .clone() + .into_inner() + .parse_value("ConnectorAuthType") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while parsing value for ConnectorAuthType")?; + + let router_base_url = &state.base_url; + let attempt = &payment_data + .payment_attempt + .get_required_value("attempt") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Payment Attempt is not available in payment data")?; + + let connector_request_reference_id = payment_intent + .merchant_reference_id + .map(|id| id.get_string_repr().to_owned()) + .unwrap_or(attempt.id.get_string_repr().to_owned()); + + let request = types::PaymentsSyncData { + amount: attempt.amount_details.net_amount, + integrity_object: None, + // TODO: How do we provide this in v2 + mandate_id: None, + connector_transaction_id: match attempt.get_connector_payment_id() { + Some(connector_txn_id) => { + types::ResponseId::ConnectorTransactionId(connector_txn_id.to_owned()) + } + None => types::ResponseId::NoResponseId, + }, + encoded_data: attempt.encoded_data.clone().expose_option(), + capture_method: Some(payment_intent.capture_method), + connector_meta: attempt.connector_metadata.clone().expose_option(), + sync_type: types::SyncRequestType::SinglePaymentSync, + payment_method_type: Some(attempt.payment_method_subtype), + currency: payment_intent.amount_details.currency, + // TODO: Get the charges object from + charges: None, + payment_experience: None, + }; + + // TODO: evaluate the fields in router data, if they are required or not + let router_data = types::RouterData { + flow: PhantomData, + merchant_id: merchant_account.get_id().clone(), + // TODO: evaluate why we need customer id at the connector level. We already have connector customer id. + customer_id, + connector: connector_id.to_owned(), + // TODO: evaluate why we need payment id at the connector level. We already have connector reference id + payment_id: payment_intent.id.get_string_repr().to_owned(), + // TODO: evaluate why we need attempt id at the connector level. We already have connector reference id + attempt_id: attempt.get_id().get_string_repr().to_owned(), + status: attempt.status, + payment_method: attempt.payment_method_type, + connector_auth_type: auth_type, + description: payment_intent + .description + .as_ref() + .map(|description| description.get_string_repr()) + .map(ToOwned::to_owned), + // TODO: evaluate why we need to send merchant's return url here + // This should be the return url of application, since application takes care of the redirection + return_url: payment_intent + .return_url + .as_ref() + .map(|description| description.get_string_repr()) + .map(ToOwned::to_owned), + // TODO: Create unified address + address: hyperswitch_domain_models::payment_address::PaymentAddress::default(), + auth_type: attempt.authentication_type, + connector_meta_data: None, + connector_wallets_details: None, + request, + response: Err(hyperswitch_domain_models::router_data::ErrorResponse::default()), + amount_captured: None, + minor_amount_captured: None, + access_token: None, + session_token: None, + reference_id: None, + payment_method_status: None, + payment_method_token: None, + connector_customer: None, + recurring_mandate_payment_data: None, + // TODO: This has to be generated as the reference id based on the connector configuration + // Some connectros might not accept accept the global id. This has to be done when generating the reference id + connector_request_reference_id, + preprocessing_id: attempt.preprocessing_step_id.clone(), + #[cfg(feature = "payouts")] + payout_method_data: None, + #[cfg(feature = "payouts")] + quote_id: None, + // TODO: take this based on the env + test_mode: Some(true), + payment_method_balance: None, + connector_api_version: None, + connector_http_status_code: None, + external_latency: None, + apple_pay_flow: None, + frm_metadata: None, + refund_id: None, + dispute_id: None, + connector_response: None, + integrity_check: Ok(()), + additional_merchant_data: None, + header_payload, + }; + + Ok(router_data) +} + #[cfg(feature = "v2")] #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] @@ -775,6 +922,7 @@ where Ok(services::ApplicationResponse::JsonWithHeaders(( Self { id: payment_intent.id.clone(), + status: payment_intent.status, amount_details: api_models::payments::AmountDetailsResponse::foreign_from( payment_intent.amount_details.clone(), ), @@ -894,6 +1042,67 @@ where } } +#[cfg(feature = "v2")] +impl ToResponse for api_models::payments::PaymentsRetrieveResponse +where + F: Clone, + Op: Debug, + D: OperationSessionGetters, +{ + #[allow(clippy::too_many_arguments)] + fn generate_response( + payment_data: D, + _customer: Option, + _base_url: &str, + operation: Op, + _connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, + _connector_http_status_code: Option, + _external_latency: Option, + _is_latency_header_enabled: Option, + ) -> RouterResponse { + let payment_intent = payment_data.get_payment_intent(); + let payment_attempt = payment_data.get_optional_payment_attempt(); + + let amount = api_models::payments::ConfirmIntentAmountDetailsResponse::foreign_from(( + &payment_intent.amount_details, + payment_attempt.map(|payment_attempt| &payment_attempt.amount_details), + )); + + let connector = + payment_attempt.and_then(|payment_attempt| payment_attempt.connector.clone()); + + let merchant_connector_id = payment_attempt + .and_then(|payment_attempt| payment_attempt.merchant_connector_id.clone()); + + let error = payment_attempt + .and_then(|payment_attempt| payment_attempt.error.clone()) + .map(api_models::payments::ErrorDetails::foreign_from); + + let response = Self { + id: payment_intent.id.clone(), + status: payment_intent.status, + amount, + connector, + client_secret: payment_intent.client_secret.clone(), + created: payment_intent.created_at, + payment_method_data: None, + payment_method_type: payment_attempt.map(|attempt| attempt.payment_method_type), + payment_method_subtype: payment_attempt.map(|attempt| attempt.payment_method_subtype), + connector_transaction_id: payment_attempt + .and_then(|attempt| attempt.connector_payment_id.clone()), + connector_reference_id: None, + merchant_connector_id, + browser_info: None, + error, + }; + + Ok(services::ApplicationResponse::JsonWithHeaders(( + response, + vec![], + ))) + } +} + #[cfg(feature = "v1")] impl ToResponse for api::PaymentsPostSessionTokensResponse where @@ -3054,6 +3263,57 @@ impl } } +/// The response amount details in the confirm intent response will have the combined fields from +/// intent amount details and attempt amount details. +#[cfg(feature = "v2")] +impl + ForeignFrom<( + &hyperswitch_domain_models::payments::AmountDetails, + Option<&hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails>, + )> for api_models::payments::ConfirmIntentAmountDetailsResponse +{ + fn foreign_from( + (intent_amount_details, attempt_amount_details): ( + &hyperswitch_domain_models::payments::AmountDetails, + Option<&hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails>, + ), + ) -> Self { + Self { + order_amount: intent_amount_details.order_amount, + currency: intent_amount_details.currency, + shipping_cost: attempt_amount_details + .and_then(|attempt_amount| attempt_amount.shipping_cost) + .or(intent_amount_details.shipping_cost), + order_tax_amount: attempt_amount_details + .and_then(|attempt_amount| attempt_amount.order_tax_amount) + .or(intent_amount_details + .tax_details + .as_ref() + .and_then(|tax_details| tax_details.get_default_tax_amount())), + skip_external_tax_calculation: common_enums::TaxCalculationOverride::foreign_from( + intent_amount_details.skip_external_tax_calculation, + ), + skip_surcharge_calculation: common_enums::SurchargeCalculationOverride::foreign_from( + intent_amount_details.skip_surcharge_calculation, + ), + surcharge_amount: attempt_amount_details + .and_then(|attempt| attempt.surcharge_amount) + .or(intent_amount_details.surcharge_amount), + tax_on_surcharge: attempt_amount_details + .and_then(|attempt| attempt.tax_on_surcharge) + .or(intent_amount_details.tax_on_surcharge), + net_amount: attempt_amount_details + .map(|attempt| attempt.net_amount) + .unwrap_or(intent_amount_details.calculate_net_amount()), + amount_to_capture: attempt_amount_details.and_then(|attempt| attempt.amount_to_capture), + amount_capturable: attempt_amount_details + .map(|attempt| attempt.amount_capturable) + .unwrap_or(MinorUnit::zero()), + amount_captured: intent_amount_details.amount_captured, + } + } +} + #[cfg(feature = "v2")] impl ForeignFrom for api_models::payments::ErrorDetails diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 02c619b68d9d..adf3c51fd80b 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -1762,6 +1762,7 @@ async fn complete_payout_quote_steps_if_required( Ok(()) } +#[cfg(feature = "v1")] pub async fn complete_payout_retrieve( state: &SessionState, merchant_account: &domain::MerchantAccount, @@ -1783,6 +1784,16 @@ pub async fn complete_payout_retrieve( Ok(()) } +#[cfg(feature = "v2")] +pub async fn complete_payout_retrieve( + state: &SessionState, + merchant_account: &domain::MerchantAccount, + connector_call_type: api::ConnectorCallType, + payout_data: &mut PayoutData, +) -> RouterResult<()> { + todo!() +} + pub async fn create_payout_retrieve( state: &SessionState, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 8ca0b2937666..6a66c4391cf2 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1515,7 +1515,7 @@ impl PaymentAttemptInterface for KafkaStore { &self, key_manager_state: &KeyManagerState, merchant_key_store: &domain::MerchantKeyStore, - attempt_id: &str, + attempt_id: &id_type::GlobalAttemptId, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { self.diesel_store diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 33699ed266a4..7ac882bdcce2 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -530,7 +530,8 @@ impl Payments { .service( web::resource("/create-external-sdk-tokens") .route(web::post().to(payments::payments_connector_session)), - ), + ) + .service(web::resource("").route(web::post().to(payments::payment_status))), ); route diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index bca7bd37cccb..a277a454404e 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -2038,13 +2038,6 @@ pub async fn payment_confirm_intent( } }; - // TODO: handle client secret auth - // let (auth_type, auth_flow) = - // match auth::check_client_secret_and_get_auth(req.headers(), &payload) { - // Ok(auth) => auth, - // Err(e) => return api::log_and_return_error_response(e), - // }; - let locking_action = internal_payload.get_locking_input(flow.clone()); Box::pin(api::server_wrap( @@ -2084,3 +2077,73 @@ pub async fn payment_confirm_intent( )) .await } + +#[cfg(feature = "v2")] +#[instrument(skip(state, req), fields(flow, payment_id))] +pub async fn payment_status( + state: web::Data, + req: actix_web::HttpRequest, + payload: web::Query, + path: web::Path, +) -> impl Responder { + use hyperswitch_domain_models::payments::PaymentStatusData; + + let flow = match payload.force_sync { + true => Flow::PaymentsRetrieveForceSync, + false => Flow::PaymentsRetrieve, + }; + + let global_payment_id = path.into_inner(); + tracing::Span::current().record("payment_id", global_payment_id.get_string_repr()); + + let internal_payload = internal_payload_types::PaymentsGenericRequestWithResourceId { + global_payment_id, + payload: payload.into_inner(), + }; + + let header_payload = match HeaderPayload::foreign_try_from(req.headers()) { + Ok(headers) => headers, + Err(err) => { + return api::log_and_return_error_response(err); + } + }; + + let locking_action = internal_payload.get_locking_input(flow.clone()); + + Box::pin(api::server_wrap( + flow, + state, + &req, + internal_payload, + |state, auth: auth::AuthenticationDataV2, req, req_state| async { + let payment_id = req.global_payment_id; + let request = req.payload; + + let operation = payments::operations::PaymentGet; + + Box::pin(payments::payments_core::< + api_types::PSync, + api_models::payments::PaymentsRetrieveResponse, + _, + _, + _, + PaymentStatusData, + >( + state, + req_state, + auth.merchant_account, + auth.profile, + auth.key_store, + operation, + request, + payment_id, + payments::CallConnectorAction::Trigger, + header_payload.clone(), + )) + .await + }, + &auth::PublishableKeyAuth, + locking_action, + )) + .await +} diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 434352fa1174..db9c7e6acb5b 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -76,6 +76,8 @@ pub enum ConnectorCallType { PreDetermined(ConnectorData), Retryable(Vec), SessionMultiple(Vec), + #[cfg(feature = "v2")] + Skip, } pub trait ConnectorTransactionId: ConnectorCommon + Sync { diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs index 8adeb7006425..ae4a9e659a6f 100644 --- a/crates/storage_impl/src/mock_db/payment_attempt.rs +++ b/crates/storage_impl/src/mock_db/payment_attempt.rs @@ -1,6 +1,6 @@ use common_utils::errors::CustomResult; #[cfg(feature = "v2")] -use common_utils::types::keymanager::KeyManagerState; +use common_utils::{id_type, types::keymanager::KeyManagerState}; use diesel_models::enums as storage_enums; #[cfg(feature = "v2")] use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore; @@ -74,7 +74,7 @@ impl PaymentAttemptInterface for MockDb { &self, _key_manager_state: &KeyManagerState, _merchant_key_store: &MerchantKeyStore, - _attempt_id: &str, + _attempt_id: &id_type::GlobalAttemptId, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result { // [#172]: Implement function for `MockDb` diff --git a/crates/storage_impl/src/mock_db/payment_intent.rs b/crates/storage_impl/src/mock_db/payment_intent.rs index 22160d901f49..3a564d958e9f 100644 --- a/crates/storage_impl/src/mock_db/payment_intent.rs +++ b/crates/storage_impl/src/mock_db/payment_intent.rs @@ -95,6 +95,7 @@ impl PaymentIntentInterface for MockDb { Ok(new) } + #[cfg(feature = "v1")] // safety: only used for testing #[allow(clippy::unwrap_used)] async fn update_payment_intent( @@ -130,6 +131,20 @@ impl PaymentIntentInterface for MockDb { Ok(payment_intent.clone()) } + #[cfg(feature = "v2")] + // safety: only used for testing + #[allow(clippy::unwrap_used)] + async fn update_payment_intent( + &self, + state: &KeyManagerState, + this: PaymentIntent, + update: PaymentIntentUpdate, + key_store: &MerchantKeyStore, + _storage_scheme: storage_enums::MerchantStorageScheme, + ) -> CustomResult { + todo!() + } + #[cfg(feature = "v1")] // safety: only used for testing #[allow(clippy::unwrap_used)] diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 899ba08244b3..13d7202eb404 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -1,10 +1,10 @@ -#[cfg(feature = "v2")] -use common_utils::types::keymanager::KeyManagerState; use common_utils::{ errors::CustomResult, fallback_reverse_lookup_not_found, types::{ConnectorTransactionId, ConnectorTransactionIdTrait}, }; +#[cfg(feature = "v2")] +use common_utils::{id_type, types::keymanager::KeyManagerState}; use diesel_models::{ enums::{ MandateAmountData as DieselMandateAmountData, MandateDataType as DieselMandateType, @@ -375,7 +375,7 @@ impl PaymentAttemptInterface for RouterStore { &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, - attempt_id: &str, + attempt_id: &id_type::GlobalAttemptId, _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let conn = pg_connection_read(self).await?; @@ -1132,7 +1132,7 @@ impl PaymentAttemptInterface for KVRouterStore { &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, - attempt_id: &str, + attempt_id: &id_type::GlobalAttemptId, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { // Ignoring storage scheme for v2 implementation diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index 3fcd30f1e890..e4ab66878559 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -505,7 +505,8 @@ impl PaymentIntentInterface for crate::RouterStore { _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let conn = pg_connection_write(self).await?; - let diesel_payment_intent_update = DieselPaymentIntentUpdate::from(payment_intent); + let diesel_payment_intent_update = + diesel_models::PaymentIntentUpdateInternal::from(payment_intent); let diesel_payment_intent = this .convert() diff --git a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql index 359d5ce6359c..3585a4551836 100644 --- a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql +++ b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql @@ -86,8 +86,13 @@ ALTER TABLE payment_intent ALTER COLUMN currency DROP NOT NULL, ALTER COLUMN client_secret DROP NOT NULL, ALTER COLUMN profile_id DROP NOT NULL; -ALTER TABLE payment_intent ALTER COLUMN active_attempt_id SET NOT NULL; -ALTER TABLE payment_intent ALTER COLUMN session_expiry DROP NOT NULL; + +ALTER TABLE payment_intent +ALTER COLUMN active_attempt_id +SET NOT NULL; + +ALTER TABLE payment_intent +ALTER COLUMN session_expiry DROP NOT NULL; ------------------------ Payment Attempt ----------------------- ALTER TABLE payment_attempt DROP CONSTRAINT payment_attempt_pkey; @@ -101,3 +106,6 @@ ALTER COLUMN net_amount DROP NOT NULL; ALTER TABLE payment_attempt ADD PRIMARY KEY (attempt_id, merchant_id); + +ALTER TABLE payment_attempt +SET DEFAULT 'xxx'; diff --git a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql index d4a1e7879b6b..2494bc3c63d1 100644 --- a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql +++ b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql @@ -88,12 +88,21 @@ ADD PRIMARY KEY (id); ------------------------ Payment Intent ----------------------- ALTER TABLE payment_intent DROP CONSTRAINT payment_intent_pkey; +-- To work around database constraints +UPDATE payment_intent +SET id = payment_id +WHERE id IS NULL; + ALTER TABLE payment_intent ADD PRIMARY KEY (id); ------------------------ Payment Attempt ----------------------- ALTER TABLE payment_attempt DROP CONSTRAINT payment_attempt_pkey; +UPDATE payment_attempt +SET id = attempt_id +WHERE id IS NULL; + ALTER TABLE payment_attempt ADD PRIMARY KEY (id); @@ -125,9 +134,14 @@ SET NOT NULL, SET NOT NULL, ALTER COLUMN payment_method_subtype SET NOT NULL; -ALTER TABLE payment_intent ALTER COLUMN session_expiry SET NOT NULL; --- This migration is to make fields optional in payment_intent table -ALTER TABLE payment_intent ALTER COLUMN active_attempt_id DROP NOT NULL; +ALTER TABLE payment_intent +ALTER COLUMN session_expiry +SET NOT NULL; +-- This migration is to make fields optional in payment_intent table +ALTER TABLE payment_intent +ALTER COLUMN active_attempt_id DROP NOT NULL; +ALTER TABLE payment_intent +ALTER COLUMN active_attempt_id DROP DEFAULT; From d09862918995e98ab3e07c1aa4276e79a1f2562e Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 29 Oct 2024 18:21:00 +0530 Subject: [PATCH 02/24] refactor: remove direct attempt access in call_connector_service --- crates/router/src/core/payments.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 843069ceb640..080f9e6778fc 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2478,20 +2478,6 @@ where (None, false) }; - if should_add_task_to_process_tracker(payment_data) { - operation - .to_domain()? - .add_task_to_process_tracker( - state, - payment_data.get_payment_attempt(), - validate_result.requeue, - schedule_time, - ) - .await - .map_err(|error| logger::error!(process_tracker_error=?error)) - .ok(); - } - // Update the payment trackers just before calling the connector // Since the request is already built in the previous step, // there should be no error in request construction from hyperswitch end @@ -2516,7 +2502,8 @@ where // update this in router_data. // This is added because few connector integrations do not update the status, // and rely on previous status set in router_data - router_data.status = payment_data.get_payment_attempt().status; + // TODO: status is already set when constructing payment data, why should this be done again? + // router_data.status = payment_data.get_payment_attempt().status; router_data .decide_flows( state, From 186136c82c6918adb13f8192c867a3c844c4a431 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:46:21 +0000 Subject: [PATCH 03/24] chore: run formatter --- crates/diesel_models/src/kv.rs | 2 -- crates/router/src/core/payments/operations.rs | 11 +++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/diesel_models/src/kv.rs b/crates/diesel_models/src/kv.rs index 68dae0689460..7c5c3a8de178 100644 --- a/crates/diesel_models/src/kv.rs +++ b/crates/diesel_models/src/kv.rs @@ -3,10 +3,8 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "v2")] use crate::payment_attempt::PaymentAttemptUpdateInternal; - #[cfg(feature = "v2")] use crate::payment_intent::PaymentIntentUpdateInternal; - use crate::{ address::{Address, AddressNew, AddressUpdateInternal}, customers::{Customer, CustomerNew, CustomerUpdateInternal}, diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 20d966a105fe..df8a0a5e7327 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -44,12 +44,6 @@ use async_trait::async_trait; use error_stack::{report, ResultExt}; use router_env::{instrument, tracing}; -#[cfg(feature = "v2")] -pub use self::{ - payment_confirm_intent::PaymentIntentConfirm, payment_create_intent::PaymentIntentCreate, - payment_get::PaymentGet, -}; - pub use self::payment_response::PaymentResponse; #[cfg(feature = "v1")] pub use self::{ @@ -61,6 +55,11 @@ pub use self::{ payments_incremental_authorization::PaymentIncrementalAuthorization, tax_calculation::PaymentSessionUpdate, }; +#[cfg(feature = "v2")] +pub use self::{ + payment_confirm_intent::PaymentIntentConfirm, payment_create_intent::PaymentIntentCreate, + payment_get::PaymentGet, +}; use super::{helpers, CustomerDetails, OperationSessionGetters, OperationSessionSetters}; use crate::{ core::errors::{self, CustomResult, RouterResult}, From a5d0526871213a39bb60233a8220ea0e1477711b Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:49:37 +0000 Subject: [PATCH 04/24] docs(openapi): re-generate OpenAPI specification --- api-reference-v2/openapi_spec.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 06bbf125dfbf..85b718a7f8ff 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -13572,6 +13572,7 @@ "type": "object", "required": [ "id", + "status", "amount_details", "client_secret", "capture_method", @@ -13589,6 +13590,9 @@ "type": "string", "description": "Global Payment Id for the payment" }, + "status": { + "$ref": "#/components/schemas/IntentStatus" + }, "amount_details": { "$ref": "#/components/schemas/AmountDetailsResponse" }, From d040fbc3407bdd69a5b76994a20697faf7069eee Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Wed, 30 Oct 2024 06:11:48 +0530 Subject: [PATCH 05/24] chore: rename PaymentStatusRequest to PaymentRetrieveRequest --- crates/api_models/src/payments.rs | 3 +- crates/common_enums/src/enums.rs | 20 ++++++++ .../hyperswitch_domain_models/src/payments.rs | 3 ++ .../core/payments/operations/payment_get.rs | 46 ++++++++++--------- crates/router/src/routes/payments.rs | 2 +- 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index ca08210d2ab7..ccb99dc6a536 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -4479,7 +4479,7 @@ pub struct PaymentsConfirmIntentRequest { /// Request for Payment Status #[cfg(feature = "v2")] #[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)] -pub struct PaymentsStatusRequest { +pub struct PaymentsRetrieveRequest { /// A boolean used to indicate if the payment status should be fetched from the connector /// If this is set to true, the status will be fetched from the connector #[serde(default)] @@ -5129,6 +5129,7 @@ pub struct PaymentsResponseForm { pub order_id: String, } +#[cfg(feature = "v1")] #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] pub struct PaymentsRetrieveRequest { /// The type of ID (ex: payment intent id, payment attempt id or connector txn id) diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index c103153eec80..98e588de8e25 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1419,6 +1419,26 @@ pub enum IntentStatus { PartiallyCapturedAndCapturable, } +impl IntentStatus { + pub fn should_force_sync_with_connector(&self) -> bool { + match self { + // Confirm has not happened yet + Self::RequiresConfirmation + | Self::RequiresPaymentMethod + // Once the status is success, failed or cancelled need not force sync with the connector + | Self::Succeeded + | Self::Failed + | Self::Cancelled + | Self::PartiallyCaptured + | Self::PartiallyCapturedAndCapturable => false, + Self::Processing + | Self::RequiresCustomerAction + | Self::RequiresMerchantAction + | Self::RequiresCapture => true, + } + } +} + /// Indicates that you intend to make future payments with the payment methods used for this Payment. Providing this parameter will attach the payment method to the Customer, if present, after the Payment is confirmed and any required actions from the user are complete. /// - On_session - Payment method saved only at hyperswitch when consent is provided by the user. CVV will asked during the returning user payment /// - Off_session - Payment method saved at both hyperswitch and Processor when consent is provided by the user. No input is required during the returning user payment. diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 72d0ec694f8e..44d5e3c43d0a 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -521,4 +521,7 @@ where pub flow: PhantomData, pub payment_intent: PaymentIntent, pub payment_attempt: Option, + /// Should the payment status be synced with connector + /// This will depend on the payment status + pub should_sync_with_connector: bool, } diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs index 19c846a5990f..0fba1607efb1 100644 --- a/crates/router/src/core/payments/operations/payment_get.rs +++ b/crates/router/src/core/payments/operations/payment_get.rs @@ -1,7 +1,7 @@ use api_models::{ admin::ExtendedCardInfoConfig, enums::FrmSuggestion, - payments::{ExtendedCardInfo, GetAddressFromPaymentMethodData, PaymentsStatusRequest}, + payments::{ExtendedCardInfo, GetAddressFromPaymentMethodData, PaymentsRetrieveRequest}, }; use async_trait::async_trait; use common_utils::ext_traits::AsyncExt; @@ -61,65 +61,65 @@ impl ValidateStatusForOperation for PaymentGet { } type BoxedConfirmOperation<'b, F> = - super::BoxedOperation<'b, F, PaymentsStatusRequest, PaymentStatusData>; + super::BoxedOperation<'b, F, PaymentsRetrieveRequest, PaymentStatusData>; // TODO: change the macro to include changes for v2 // TODO: PaymentData in the macro should be an input -impl Operation for &PaymentGet { +impl Operation for &PaymentGet { type Data = PaymentStatusData; fn to_validate_request( &self, - ) -> RouterResult<&(dyn ValidateRequest + Send + Sync)> + ) -> RouterResult<&(dyn ValidateRequest + Send + Sync)> { Ok(*self) } fn to_get_tracker( &self, - ) -> RouterResult<&(dyn GetTracker + Send + Sync)> { + ) -> RouterResult<&(dyn GetTracker + Send + Sync)> { Ok(*self) } - fn to_domain(&self) -> RouterResult<&(dyn Domain)> { + fn to_domain(&self) -> RouterResult<&(dyn Domain)> { Ok(*self) } fn to_update_tracker( &self, - ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> + ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> { Ok(*self) } } #[automatically_derived] -impl Operation for PaymentGet { +impl Operation for PaymentGet { type Data = PaymentStatusData; fn to_validate_request( &self, - ) -> RouterResult<&(dyn ValidateRequest + Send + Sync)> + ) -> RouterResult<&(dyn ValidateRequest + Send + Sync)> { Ok(self) } fn to_get_tracker( &self, - ) -> RouterResult<&(dyn GetTracker + Send + Sync)> { + ) -> RouterResult<&(dyn GetTracker + Send + Sync)> { Ok(self) } - fn to_domain(&self) -> RouterResult<&dyn Domain> { + fn to_domain(&self) -> RouterResult<&dyn Domain> { Ok(self) } fn to_update_tracker( &self, - ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> + ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> { Ok(self) } } -impl ValidateRequest> +impl ValidateRequest> for PaymentGet { #[instrument(skip_all)] fn validate_request<'a, 'b>( &'b self, - request: &PaymentsStatusRequest, + request: &PaymentsRetrieveRequest, merchant_account: &'a domain::MerchantAccount, ) -> RouterResult<(BoxedConfirmOperation<'b, F>, operations::ValidateResult)> { let validate_result = operations::ValidateResult { @@ -133,19 +133,19 @@ impl ValidateRequest GetTracker, PaymentsStatusRequest> for PaymentGet { +impl GetTracker, PaymentsRetrieveRequest> for PaymentGet { #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, state: &'a SessionState, payment_id: &common_utils::id_type::GlobalPaymentId, - request: &PaymentsStatusRequest, + request: &PaymentsRetrieveRequest, merchant_account: &domain::MerchantAccount, _profile: &domain::Profile, key_store: &domain::MerchantKeyStore, header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< - operations::GetTrackerResponse<'a, F, PaymentsStatusRequest, PaymentStatusData>, + operations::GetTrackerResponse<'a, F, PaymentsRetrieveRequest, PaymentStatusData>, > { let db = &*state.store; let key_manager_state = &state.into(); @@ -181,10 +181,14 @@ impl GetTracker, PaymentsStatusRequest> .await .transpose()?; + let should_sync_with_connector = + request.force_sync && payment_intent.status.should_force_sync_with_connector(); + let payment_data = PaymentStatusData { flow: std::marker::PhantomData, payment_intent, payment_attempt, + should_sync_with_connector, }; let get_trackers_response = operations::GetTrackerResponse { @@ -197,7 +201,7 @@ impl GetTracker, PaymentsStatusRequest> } #[async_trait] -impl Domain> for PaymentGet { +impl Domain> for PaymentGet { async fn get_customer_details<'a>( &'a self, state: &SessionState, @@ -253,7 +257,7 @@ impl Domain> for mechant_key_store: &domain::MerchantKeyStore, ) -> CustomResult { match &payment_data.payment_attempt { - Some(payment_attempt) => { + Some(payment_attempt) if payment_data.should_sync_with_connector => { let connector = payment_attempt .connector .as_ref() @@ -279,13 +283,13 @@ impl Domain> for Ok(ConnectorCallType::PreDetermined(connector_data)) } - None => Ok(ConnectorCallType::Skip), + None | Some(_) => Ok(ConnectorCallType::Skip), } } } #[async_trait] -impl UpdateTracker, PaymentsStatusRequest> for PaymentGet { +impl UpdateTracker, PaymentsRetrieveRequest> for PaymentGet { #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index a277a454404e..b57451d03299 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -2083,7 +2083,7 @@ pub async fn payment_confirm_intent( pub async fn payment_status( state: web::Data, req: actix_web::HttpRequest, - payload: web::Query, + payload: web::Query, path: web::Path, ) -> impl Responder { use hyperswitch_domain_models::payments::PaymentStatusData; From c5e4df2ff48702567e63ea1fc68a18f33a2363fa Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:44:54 +0000 Subject: [PATCH 06/24] docs(openapi): re-generate OpenAPI specification --- api-reference-v2/openapi_spec.json | 49 ++---------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 85b718a7f8ff..a9e46c206fe3 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -15004,56 +15004,11 @@ }, "PaymentsRetrieveRequest": { "type": "object", - "required": [ - "resource_id", - "force_sync" - ], + "description": "Request for Payment Status", "properties": { - "resource_id": { - "type": "string", - "description": "The type of ID (ex: payment intent id, payment attempt id or connector txn id)" - }, - "merchant_id": { - "type": "string", - "description": "The identifier for the Merchant Account.", - "nullable": true - }, "force_sync": { "type": "boolean", - "description": "Decider to enable or disable the connector call for retrieve request" - }, - "param": { - "type": "string", - "description": "The parameters passed to a retrieve request", - "nullable": true - }, - "connector": { - "type": "string", - "description": "The name of the connector", - "nullable": true - }, - "merchant_connector_details": { - "allOf": [ - { - "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" - } - ], - "nullable": true - }, - "client_secret": { - "type": "string", - "description": "This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK", - "nullable": true - }, - "expand_captures": { - "type": "boolean", - "description": "If enabled provides list of captures linked to latest attempt", - "nullable": true - }, - "expand_attempts": { - "type": "boolean", - "description": "If enabled provides list of attempts linked to payment intent", - "nullable": true + "description": "A boolean used to indicate if the payment status should be fetched from the connector\nIf this is set to true, the status will be fetched from the connector" } } }, From ef71de36546f96598523e070c0872110d2b2d06a Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Wed, 30 Oct 2024 13:00:58 +0530 Subject: [PATCH 07/24] chore: cargo clippy --- .../diesel_models/src/query/payment_intent.rs | 10 +++--- .../flows/post_session_tokens_flow.rs | 2 +- crates/router/src/services/authentication.rs | 6 ---- .../src/payments/payment_attempt.rs | 8 ++--- .../src/payments/payment_intent.rs | 35 +++++++++++++++++++ 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/crates/diesel_models/src/query/payment_intent.rs b/crates/diesel_models/src/query/payment_intent.rs index 84984aeb52ef..4f4099eca015 100644 --- a/crates/diesel_models/src/query/payment_intent.rs +++ b/crates/diesel_models/src/query/payment_intent.rs @@ -7,9 +7,7 @@ use crate::schema::payment_intent::dsl; use crate::schema_v2::payment_intent::dsl; use crate::{ errors, - payment_intent::{ - PaymentIntent, PaymentIntentNew, PaymentIntentUpdate, PaymentIntentUpdateInternal, - }, + payment_intent::{self, PaymentIntent, PaymentIntentNew}, PgPooledConn, StorageResult, }; @@ -24,7 +22,7 @@ impl PaymentIntent { pub async fn update( self, conn: &PgPooledConn, - payment_intent_update: PaymentIntentUpdateInternal, + payment_intent_update: payment_intent::PaymentIntentUpdateInternal, ) -> StorageResult { match generics::generic_update_by_id::<::Table, _, _, _>( conn, @@ -53,14 +51,14 @@ impl PaymentIntent { pub async fn update( self, conn: &PgPooledConn, - payment_intent: PaymentIntentUpdate, + payment_intent: payment_intent::PaymentIntentUpdate, ) -> StorageResult { match generics::generic_update_with_results::<::Table, _, _, _>( conn, dsl::payment_id .eq(self.payment_id.to_owned()) .and(dsl::merchant_id.eq(self.merchant_id.to_owned())), - PaymentIntentUpdateInternal::from(payment_intent), + payment_intent::PaymentIntentUpdateInternal::from(payment_intent), ) .await { diff --git a/crates/router/src/core/payments/flows/post_session_tokens_flow.rs b/crates/router/src/core/payments/flows/post_session_tokens_flow.rs index 19dc356f1483..deb876660e9c 100644 --- a/crates/router/src/core/payments/flows/post_session_tokens_flow.rs +++ b/crates/router/src/core/payments/flows/post_session_tokens_flow.rs @@ -27,7 +27,7 @@ impl merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, customer: &Option, - merchant_connector_account: &domain::MerchantConnectorAccount, + merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, header_payload: Option, ) -> RouterResult { diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index a3cc54de34f9..346fea41033a 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -2109,12 +2109,6 @@ impl ClientSecretFetch for api_models::cards_info::CardsInfoRequest { } } -impl ClientSecretFetch for payments::PaymentsRetrieveRequest { - fn get_client_secret(&self) -> Option<&String> { - self.client_secret.as_ref() - } -} - impl ClientSecretFetch for payments::RetrievePaymentLinkRequest { fn get_client_secret(&self) -> Option<&String> { self.client_secret.as_ref() diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 13d7202eb404..7bc9bcc8a92e 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -1,10 +1,10 @@ +#[cfg(feature = "v2")] +use common_utils::types::keymanager::KeyManagerState; use common_utils::{ errors::CustomResult, fallback_reverse_lookup_not_found, types::{ConnectorTransactionId, ConnectorTransactionIdTrait}, }; -#[cfg(feature = "v2")] -use common_utils::{id_type, types::keymanager::KeyManagerState}; use diesel_models::{ enums::{ MandateAmountData as DieselMandateAmountData, MandateDataType as DieselMandateType, @@ -375,7 +375,7 @@ impl PaymentAttemptInterface for RouterStore { &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, - attempt_id: &id_type::GlobalAttemptId, + attempt_id: &common_utils::id_type::GlobalAttemptId, _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let conn = pg_connection_read(self).await?; @@ -1132,7 +1132,7 @@ impl PaymentAttemptInterface for KVRouterStore { &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, - attempt_id: &id_type::GlobalAttemptId, + attempt_id: &common_utils::id_type::GlobalAttemptId, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { // Ignoring storage scheme for v2 implementation diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index e4ab66878559..f26cf876ade8 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -495,6 +495,41 @@ impl PaymentIntentInterface for crate::RouterStore { .change_context(StorageError::DecryptionError) } + #[cfg(feature = "v1")] + #[instrument(skip_all)] + async fn update_payment_intent( + &self, + state: &KeyManagerState, + this: PaymentIntent, + payment_intent: PaymentIntentUpdate, + merchant_key_store: &MerchantKeyStore, + _storage_scheme: MerchantStorageScheme, + ) -> error_stack::Result { + let conn = pg_connection_write(self).await?; + let diesel_payment_intent_update = DieselPaymentIntentUpdate::from(payment_intent); + + let diesel_payment_intent = this + .convert() + .await + .change_context(StorageError::EncryptionError)? + .update(&conn, diesel_payment_intent_update) + .await + .map_err(|er| { + let new_err = diesel_error_to_data_error(er.current_context()); + er.change_context(new_err) + })?; + + PaymentIntent::convert_back( + state, + diesel_payment_intent, + merchant_key_store.key.get_inner(), + merchant_key_store.merchant_id.clone().into(), + ) + .await + .change_context(StorageError::DecryptionError) + } + + #[cfg(feature = "v2")] #[instrument(skip_all)] async fn update_payment_intent( &self, From e50a0716cc2b454d75645767b1863c2bbc980c4b Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Wed, 30 Oct 2024 14:40:10 +0530 Subject: [PATCH 08/24] refactor: use separate update enums for sync update --- .../src/payments/payment_attempt.rs | 28 ++++++++++++++++--- .../src/payments/payment_intent.rs | 15 ++++++++++ .../payments/operations/payment_response.rs | 8 +++--- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index ee90126a2d84..a47feaa1b51e 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -1277,7 +1277,6 @@ impl PaymentAttemptUpdate { } } -// TODO: Add fields as necessary #[cfg(feature = "v2")] #[derive(Debug, Clone, Serialize)] pub enum PaymentAttemptUpdate { @@ -1294,11 +1293,17 @@ pub enum PaymentAttemptUpdate { connector_payment_id: Option, updated_by: String, }, + /// Update the payment attempt after force syncing with the connector + SyncUpdate { + status: storage_enums::AttemptStatus, + updated_by: String, + }, /// Update the payment attempt on confirming the intent, after calling the connector on error response - ConfirmIntentError { + ErrorUpdate { status: storage_enums::AttemptStatus, error: ErrorDetails, updated_by: String, + connector_payment_id: Option, }, } @@ -1921,9 +1926,10 @@ impl From for diesel_models::PaymentAttemptUpdateInternal connector_payment_id: None, connector: Some(connector), }, - PaymentAttemptUpdate::ConfirmIntentError { + PaymentAttemptUpdate::ErrorUpdate { status, error, + connector_payment_id, updated_by, } => Self { status: Some(status), @@ -1936,7 +1942,7 @@ impl From for diesel_models::PaymentAttemptUpdateInternal merchant_connector_id: None, unified_code: None, unified_message: None, - connector_payment_id: None, + connector_payment_id, connector: None, }, PaymentAttemptUpdate::ConfirmIntentResponse { @@ -1957,6 +1963,20 @@ impl From for diesel_models::PaymentAttemptUpdateInternal connector_payment_id, connector: None, }, + PaymentAttemptUpdate::SyncUpdate { status, updated_by } => Self { + status: Some(status), + error_message: None, + error_code: None, + modified_at: common_utils::date_time::now(), + browser_info: None, + error_reason: None, + updated_by, + merchant_connector_id: None, + unified_code: None, + unified_message: None, + connector_payment_id: None, + connector: None, + }, } } } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index ace326d4c776..f3027081094b 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -278,6 +278,10 @@ pub enum PaymentIntentUpdate { status: storage_enums::IntentStatus, updated_by: String, }, + SyncUpdate { + status: storage_enums::IntentStatus, + updated_by: String, + }, } #[cfg(feature = "v2")] @@ -378,6 +382,12 @@ impl From for diesel_models::PaymentIntentUpdateInternal { modified_at: common_utils::date_time::now(), updated_by, }, + PaymentIntentUpdate::SyncUpdate { status, updated_by } => Self { + status: Some(status), + active_attempt_id: None, + modified_at: common_utils::date_time::now(), + updated_by, + }, } } } @@ -402,6 +412,11 @@ impl From for PaymentIntentUpdateInternal { updated_by, ..Default::default() }, + PaymentIntentUpdate::SyncUpdate { status, updated_by } => Self { + status: Some(status), + updated_by, + ..Default::default() + }, } } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index cf78c8fb0c4c..522486f8ac30 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -2293,7 +2293,7 @@ impl PostUpdateTracker, types::PaymentsAuthor unified_message: None, }; - let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentError { status: attempt_status, error: error_details,updated_by: storage_scheme.to_string() }; + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ErrorUpdate { status: attempt_status, error: error_details, connector_payment_id: connector_transaction_id, updated_by: storage_scheme.to_string() }; let updated_payment_attempt = db .update_payment_attempt( key_manager_state, @@ -2379,7 +2379,7 @@ impl PostUpdateTracker, types::PaymentsSyncDat | types::ResponseId::EncodedData(id) => Some(id), }; - let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; + let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::SyncUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; let updated_payment_intent = db .update_payment_intent( key_manager_state, @@ -2393,7 +2393,7 @@ impl PostUpdateTracker, types::PaymentsSyncDat .attach_printable("Unable to update payment intent")?; payment_data.payment_intent = updated_payment_intent; - let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentResponse { status: attempt_status, connector_payment_id, updated_by: storage_scheme.to_string() }; + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::SyncUpdate { status: attempt_status, updated_by: storage_scheme.to_string() }; let updated_payment_attempt = db .update_payment_attempt( key_manager_state, @@ -2476,7 +2476,7 @@ impl PostUpdateTracker, types::PaymentsSyncDat unified_message: None, }; - let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentError { status: attempt_status, error: error_details,updated_by: storage_scheme.to_string() }; + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ErrorUpdate { status: attempt_status, error: error_details, connector_payment_id: connector_transaction_id, updated_by: storage_scheme.to_string() }; let updated_payment_attempt = db .update_payment_attempt( key_manager_state, From 575ef181405a5df0f5ab8addc167c19998638664 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 08:08:18 +0000 Subject: [PATCH 09/24] chore: run formatter --- crates/router/src/core/payments/operations.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index a5d70e565616..539407bf1c1d 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -51,7 +51,6 @@ pub use self::payment_confirm_intent::PaymentIntentConfirm; pub use self::payment_create_intent::PaymentIntentCreate; #[cfg(feature = "v2")] pub use self::payment_get_intent::PaymentGetIntent; - pub use self::payment_response::PaymentResponse; #[cfg(feature = "v1")] pub use self::{ From 0e93355e01755631614596054aa69424438c5c47 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 08:11:34 +0000 Subject: [PATCH 10/24] docs(openapi): re-generate OpenAPI specification --- api-reference-v2/openapi_spec.json | 2938 ++++++++++++++++++++++------ 1 file changed, 2288 insertions(+), 650 deletions(-) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index fe956fde5c01..e725126460fa 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -22,7 +22,9 @@ "paths": { "/v2/organization": { "post": { - "tags": ["Organization"], + "tags": [ + "Organization" + ], "summary": "Organization - Create", "description": "Create a new organization", "operationId": "Create an Organization", @@ -67,7 +69,9 @@ }, "/v2/organization/{id}": { "get": { - "tags": ["Organization"], + "tags": [ + "Organization" + ], "summary": "Organization - Retrieve", "description": "Retrieve an existing organization", "operationId": "Retrieve an Organization", @@ -104,7 +108,9 @@ ] }, "put": { - "tags": ["Organization"], + "tags": [ + "Organization" + ], "summary": "Organization - Update", "description": "Create a new organization for .", "operationId": "Update an Organization", @@ -160,7 +166,9 @@ }, "/v2/organization/{id}/merchant_accounts": { "get": { - "tags": ["Organization"], + "tags": [ + "Organization" + ], "summary": "Organization - Merchant Account - List", "description": "List merchant accounts for an Organization", "operationId": "List Merchant Accounts", @@ -202,7 +210,9 @@ }, "/v2/connector_accounts": { "post": { - "tags": ["Merchant Connector Account"], + "tags": [ + "Merchant Connector Account" + ], "summary": "Merchant Connector - Create", "description": "Creates a new Merchant Connector for the merchant account. The connector could be a payment processor/facilitator/acquirer or a provider of specialized services like Fraud/Accounting etc.", "operationId": "Create a Merchant Connector", @@ -277,7 +287,9 @@ }, "/v2/connector_accounts/{id}": { "get": { - "tags": ["Merchant Connector Account"], + "tags": [ + "Merchant Connector Account" + ], "summary": "Merchant Connector - Retrieve", "description": "Retrieves details of a Connector account", "operationId": "Retrieve a Merchant Connector", @@ -318,7 +330,9 @@ ] }, "put": { - "tags": ["Merchant Connector Account"], + "tags": [ + "Merchant Connector Account" + ], "summary": "Merchant Connector - Update", "description": "To update an existing Merchant Connector account. Helpful in enabling/disabling different payment methods and other settings for the connector", "operationId": "Update a Merchant Connector", @@ -388,7 +402,9 @@ ] }, "delete": { - "tags": ["Merchant Connector Account"], + "tags": [ + "Merchant Connector Account" + ], "summary": "Merchant Connector - Delete", "description": "Delete or Detach a Merchant Connector from Merchant Account", "operationId": "Delete a Merchant Connector", @@ -431,7 +447,9 @@ }, "/v2/merchant_accounts": { "post": { - "tags": ["Merchant Account"], + "tags": [ + "Merchant Account" + ], "summary": "Merchant Account - Create", "description": "Create a new account for a *merchant* and the *merchant* could be a seller or retailer or client who likes to receive and send payments.\n\nBefore creating the merchant account, it is mandatory to create an organization.", "operationId": "Create a Merchant Account", @@ -508,7 +526,9 @@ }, "/v2/merchant_accounts/{id}": { "get": { - "tags": ["Merchant Account"], + "tags": [ + "Merchant Account" + ], "summary": "Merchant Account - Retrieve", "description": "Retrieve a *merchant* account details.", "operationId": "Retrieve a Merchant Account", @@ -545,7 +565,9 @@ ] }, "put": { - "tags": ["Merchant Account"], + "tags": [ + "Merchant Account" + ], "summary": "Merchant Account - Update", "description": "Updates details of 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", @@ -610,7 +632,9 @@ }, "/v2/merchant_accounts/{account_id}/profiles": { "get": { - "tags": ["Merchant Account"], + "tags": [ + "Merchant Account" + ], "summary": "Profile - List", "description": "List profiles for an Merchant", "operationId": "List Profiles", @@ -652,7 +676,9 @@ }, "/v2/payments/{payment_id}/create-external-sdk-tokens": { "post": { - "tags": ["Payments"], + "tags": [ + "Payments" + ], "summary": "Payments - Session token", "description": "Creates a session object or a session token for wallets like Apple Pay, Google Pay, etc. These tokens are used by Hyperswitch's SDK to initiate these wallets' SDK.", "operationId": "Create Session tokens for a Payment", @@ -690,7 +716,9 @@ }, "/v2/profiles": { "post": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Create", "description": "Creates a new *profile* for a merchant", "operationId": "Create A Profile", @@ -749,7 +777,9 @@ }, "/v2/profiles/{profile_id}": { "get": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Retrieve", "description": "Retrieve existing *profile*", "operationId": "Retrieve a Profile", @@ -798,7 +828,9 @@ ] }, "put": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Update", "description": "Update the *profile*", "operationId": "Update a Profile", @@ -866,7 +898,9 @@ }, "/v2/profiles/{profile_id}/connector_accounts": { "get": { - "tags": ["Business Profile"], + "tags": [ + "Business Profile" + ], "summary": "Merchant Connector - List", "description": "List Merchant Connector Details for the business profile", "operationId": "List all Merchant Connectors", @@ -923,7 +957,9 @@ }, "/v2/profiles/{profile_id}/activate_routing_algorithm": { "patch": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Activate routing algorithm", "description": "Activates a routing algorithm under a profile", "operationId": "Activates a routing algorithm under a profile", @@ -988,7 +1024,9 @@ }, "/v2/profiles/{profile_id}/deactivate_routing_algorithm": { "patch": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Deactivate routing algorithm", "description": "Deactivates a routing algorithm under a profile", "operationId": " Deactivates a routing algorithm under a profile", @@ -1039,7 +1077,9 @@ }, "/v2/profiles/{profile_id}/fallback_routing": { "patch": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Update Default Fallback Routing Algorithm", "description": "Update the default fallback routing algorithm for the profile", "operationId": "Update the default fallback routing algorithm for the profile", @@ -1101,7 +1141,9 @@ ] }, "get": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Retrieve Default Fallback Routing Algorithm", "description": "Retrieve the default fallback routing algorithm for the profile", "operationId": "Retrieve the default fallback routing algorithm for the profile", @@ -1146,7 +1188,9 @@ }, "/v2/profiles/{profile_id}/routing_algorithm": { "get": { - "tags": ["Profile"], + "tags": [ + "Profile" + ], "summary": "Profile - Retrieve Active Routing Algorithm", "description": "Retrieve active routing algorithm under the profile", "operationId": "Retrieve the active routing algorithm under the profile", @@ -1218,7 +1262,9 @@ }, "/v2/routing_algorithm": { "post": { - "tags": ["Routing"], + "tags": [ + "Routing" + ], "summary": "Routing - Create", "description": "Create a routing algorithm", "operationId": "Create a routing algprithm", @@ -1271,7 +1317,9 @@ }, "/v2/routing_algorithm/{routing_algorithm_id}": { "get": { - "tags": ["Routing"], + "tags": [ + "Routing" + ], "summary": "Routing - Retrieve", "description": "Retrieve a routing algorithm with its algorithm id", "operationId": "Retrieve a routing algorithm with its algorithm id", @@ -1319,7 +1367,9 @@ }, "/v2/api_keys": { "post": { - "tags": ["API Key"], + "tags": [ + "API Key" + ], "summary": "API Key - Create", "description": "Create a new API Key for accessing our APIs from your servers. The plaintext API Key will be\ndisplayed only once on creation, so ensure you store it securely.", "operationId": "Create an API Key", @@ -1357,7 +1407,9 @@ }, "/v2/api_keys/{key_id}": { "get": { - "tags": ["API Key"], + "tags": [ + "API Key" + ], "summary": "API Key - Retrieve", "description": "Retrieve information about the specified API Key.", "operationId": "Retrieve an API Key", @@ -1394,7 +1446,9 @@ ] }, "put": { - "tags": ["API Key"], + "tags": [ + "API Key" + ], "summary": "API Key - Update", "description": "Update information for the specified API Key.", "operationId": "Update an API Key", @@ -1441,7 +1495,9 @@ ] }, "delete": { - "tags": ["API Key"], + "tags": [ + "API Key" + ], "summary": "API Key - Revoke", "description": "Revoke the specified API Key. Once revoked, the API Key can no longer be used for\nauthenticating with our APIs.", "operationId": "Revoke an API Key", @@ -1480,7 +1536,9 @@ }, "/v2/api_keys/list": { "get": { - "tags": ["API Key"], + "tags": [ + "API Key" + ], "summary": "API Key - List", "description": "List all the API Keys associated to a merchant account.", "operationId": "List all API Keys associated with a merchant account", @@ -1532,7 +1590,9 @@ }, "/v2/customers": { "post": { - "tags": ["Customers"], + "tags": [ + "Customers" + ], "summary": "Customers - Create", "description": "Creates a customer object and stores the customer details to be reused for future payments.\nIncase the customer already exists in the system, this API will respond with the customer details.", "operationId": "Create a Customer", @@ -1578,7 +1638,9 @@ }, "/v2/customers/{id}": { "get": { - "tags": ["Customers"], + "tags": [ + "Customers" + ], "summary": "Customers - Retrieve", "description": "Retrieves a customer's details.", "operationId": "Retrieve a Customer", @@ -1618,7 +1680,9 @@ ] }, "post": { - "tags": ["Customers"], + "tags": [ + "Customers" + ], "summary": "Customers - Update", "description": "Updates the customer's details in a customer object.", "operationId": "Update a Customer", @@ -1673,7 +1737,9 @@ ] }, "delete": { - "tags": ["Customers"], + "tags": [ + "Customers" + ], "summary": "Customers - Delete", "description": "Delete a customer record.", "operationId": "Delete a Customer", @@ -1712,7 +1778,9 @@ }, "/v2/customers/list": { "get": { - "tags": ["Customers"], + "tags": [ + "Customers" + ], "summary": "Customers - List", "description": "Lists all the customers for a particular merchant id.", "operationId": "List all Customers for a Merchant", @@ -1743,7 +1811,9 @@ }, "/v2/payments/create-intent": { "post": { - "tags": ["Payments"], + "tags": [ + "Payments" + ], "summary": "Payments - Create Intent", "description": "**Creates a payment intent object when amount_details are passed.**\n\nYou will require the 'API - Key' from the Hyperswitch dashboard to make the first call, and use the 'client secret' returned in this API along with your 'publishable key' to make subsequent API calls from your client.", "operationId": "Create a Payment Intent", @@ -1791,7 +1861,9 @@ }, "/v2/payments/{id}/get-intent": { "get": { - "tags": ["Payments"], + "tags": [ + "Payments" + ], "summary": "Payments - Get Intent", "description": "**Get a payment intent object when id is passed in path**\n\nYou will require the 'API - Key' from the Hyperswitch dashboard to make the call.", "operationId": "Get the Payment Intent details", @@ -1830,7 +1902,9 @@ }, "/v2/payments/{id}/confirm-intent": { "post": { - "tags": ["Payments"], + "tags": [ + "Payments" + ], "summary": "Payments - Confirm Intent", "description": "**Confirms a payment intent object with the payment method data**\n\n.", "operationId": "Confirm Payment Intent", @@ -1884,7 +1958,9 @@ }, "/v2/refunds": { "post": { - "tags": ["Refunds"], + "tags": [ + "Refunds" + ], "summary": "Refunds - Create", "description": "Creates a refund against an already processed payment. In case of some processors, you can even opt to refund only a partial amount multiple times until the original charge amount has been refunded", "operationId": "Create a Refund", @@ -1952,17 +2028,25 @@ "AcceptanceType": { "type": "string", "description": "This is used to indicate if the mandate was accepted online or offline", - "enum": ["online", "offline"] + "enum": [ + "online", + "offline" + ] }, "AcceptedCountries": { "oneOf": [ { "type": "object", - "required": ["type", "list"], + "required": [ + "type", + "list" + ], "properties": { "type": { "type": "string", - "enum": ["enable_only"] + "enum": [ + "enable_only" + ] }, "list": { "type": "array", @@ -1974,11 +2058,16 @@ }, { "type": "object", - "required": ["type", "list"], + "required": [ + "type", + "list" + ], "properties": { "type": { "type": "string", - "enum": ["disable_only"] + "enum": [ + "disable_only" + ] }, "list": { "type": "array", @@ -1990,11 +2079,15 @@ }, { "type": "object", - "required": ["type"], + "required": [ + "type" + ], "properties": { "type": { "type": "string", - "enum": ["all_accepted"] + "enum": [ + "all_accepted" + ] } } } @@ -2008,11 +2101,16 @@ "oneOf": [ { "type": "object", - "required": ["type", "list"], + "required": [ + "type", + "list" + ], "properties": { "type": { "type": "string", - "enum": ["enable_only"] + "enum": [ + "enable_only" + ] }, "list": { "type": "array", @@ -2024,11 +2122,16 @@ }, { "type": "object", - "required": ["type", "list"], + "required": [ + "type", + "list" + ], "properties": { "type": { "type": "string", - "enum": ["disable_only"] + "enum": [ + "disable_only" + ] }, "list": { "type": "array", @@ -2040,11 +2143,15 @@ }, { "type": "object", - "required": ["type"], + "required": [ + "type" + ], "properties": { "type": { "type": "string", - "enum": ["all_accepted"] + "enum": [ + "all_accepted" + ] } } } @@ -2055,7 +2162,10 @@ }, "AchBankDebitAdditionalData": { "type": "object", - "required": ["account_number", "routing_number"], + "required": [ + "account_number", + "routing_number" + ], "properties": { "account_number": { "type": "string", @@ -2107,7 +2217,10 @@ }, "AchBankTransfer": { "type": "object", - "required": ["bank_account_number", "bank_routing_number"], + "required": [ + "bank_account_number", + "bank_routing_number" + ], "properties": { "bank_name": { "type": "string", @@ -2144,7 +2257,10 @@ "AchBankTransferAdditionalData": { "type": "object", "description": "Masked payout method details for ach bank transfer payout method", - "required": ["bank_account_number", "bank_routing_number"], + "required": [ + "bank_account_number", + "bank_routing_number" + ], "properties": { "bank_account_number": { "type": "string", @@ -2221,7 +2337,9 @@ "oneOf": [ { "type": "object", - "required": ["open_banking_recipient_data"], + "required": [ + "open_banking_recipient_data" + ], "properties": { "open_banking_recipient_data": { "$ref": "#/components/schemas/MerchantRecipientData" @@ -2234,7 +2352,9 @@ "oneOf": [ { "type": "object", - "required": ["Card"], + "required": [ + "Card" + ], "properties": { "Card": { "$ref": "#/components/schemas/CardAdditionalData" @@ -2243,7 +2363,9 @@ }, { "type": "object", - "required": ["Bank"], + "required": [ + "Bank" + ], "properties": { "Bank": { "$ref": "#/components/schemas/BankAdditionalData" @@ -2252,7 +2374,9 @@ }, { "type": "object", - "required": ["Wallet"], + "required": [ + "Wallet" + ], "properties": { "Wallet": { "$ref": "#/components/schemas/WalletAdditionalData" @@ -2402,7 +2526,9 @@ }, "AmountDetails": { "type": "object", - "required": ["currency"], + "required": [ + "currency" + ], "properties": { "order_amount": { "type": "integer", @@ -2532,7 +2658,10 @@ }, "AmountInfo": { "type": "object", - "required": ["label", "amount"], + "required": [ + "label", + "amount" + ], "properties": { "label": { "type": "string", @@ -2554,7 +2683,9 @@ "oneOf": [ { "type": "string", - "enum": ["never"] + "enum": [ + "never" + ] }, { "type": "string", @@ -2564,7 +2695,11 @@ }, "ApplePayAddressParameters": { "type": "string", - "enum": ["postalAddress", "phone", "email"] + "enum": [ + "postalAddress", + "phone", + "email" + ] }, "ApplePayBillingContactFields": { "type": "array", @@ -2574,7 +2709,11 @@ }, "ApplePayPaymentRequest": { "type": "object", - "required": ["country_code", "currency_code", "total"], + "required": [ + "country_code", + "currency_code", + "total" + ], "properties": { "country_code": { "$ref": "#/components/schemas/CountryAlpha2" @@ -2686,11 +2825,18 @@ }, "ApplepayInitiative": { "type": "string", - "enum": ["web", "ios"] + "enum": [ + "web", + "ios" + ] }, "ApplepayPaymentMethod": { "type": "object", - "required": ["display_name", "network", "type"], + "required": [ + "display_name", + "network", + "type" + ], "properties": { "display_name": { "type": "string", @@ -2708,7 +2854,11 @@ }, "ApplepaySessionTokenResponse": { "type": "object", - "required": ["connector", "delayed_session_token", "sdk_next_action"], + "required": [ + "connector", + "delayed_session_token", + "sdk_next_action" + ], "properties": { "session_token_data": { "allOf": [ @@ -2786,7 +2936,10 @@ }, "AuthenticationConnectorDetails": { "type": "object", - "required": ["authentication_connectors", "three_ds_requestor_url"], + "required": [ + "authentication_connectors", + "three_ds_requestor_url" + ], "properties": { "authentication_connectors": { "type": "array", @@ -2803,24 +2956,44 @@ }, "AuthenticationConnectors": { "type": "string", - "enum": ["threedsecureio", "netcetera", "gpayments"] + "enum": [ + "threedsecureio", + "netcetera", + "gpayments" + ] }, "AuthenticationStatus": { "type": "string", - "enum": ["started", "pending", "success", "failed"] + "enum": [ + "started", + "pending", + "success", + "failed" + ] }, "AuthenticationType": { "type": "string", "description": "Pass this parameter to force 3DS or non 3DS auth for this payment. Some connectors will still force 3DS auth even in case of passing 'no_three_ds' here and vice versa. Default value is 'no_three_ds' if not set", - "enum": ["three_ds", "no_three_ds"] + "enum": [ + "three_ds", + "no_three_ds" + ] }, "AuthorizationStatus": { "type": "string", - "enum": ["success", "failure", "processing", "unresolved"] + "enum": [ + "success", + "failure", + "processing", + "unresolved" + ] }, "BacsBankDebitAdditionalData": { "type": "object", - "required": ["account_number", "sort_code"], + "required": [ + "account_number", + "sort_code" + ], "properties": { "account_number": { "type": "string", @@ -2842,7 +3015,10 @@ }, "BacsBankTransfer": { "type": "object", - "required": ["bank_account_number", "bank_sort_code"], + "required": [ + "bank_account_number", + "bank_sort_code" + ], "properties": { "bank_name": { "type": "string", @@ -2879,7 +3055,10 @@ "BacsBankTransferAdditionalData": { "type": "object", "description": "Masked payout method details for bacs bank transfer payout method", - "required": ["bank_sort_code", "bank_account_number"], + "required": [ + "bank_sort_code", + "bank_account_number" + ], "properties": { "bank_sort_code": { "type": "string", @@ -2915,7 +3094,11 @@ }, "BacsBankTransferInstructions": { "type": "object", - "required": ["account_holder_name", "account_number", "sort_code"], + "required": [ + "account_holder_name", + "account_number", + "sort_code" + ], "properties": { "account_holder_name": { "type": "string", @@ -2997,7 +3180,9 @@ "oneOf": [ { "type": "object", - "required": ["ach"], + "required": [ + "ach" + ], "properties": { "ach": { "$ref": "#/components/schemas/AchBankDebitAdditionalData" @@ -3006,7 +3191,9 @@ }, { "type": "object", - "required": ["bacs"], + "required": [ + "bacs" + ], "properties": { "bacs": { "$ref": "#/components/schemas/BacsBankDebitAdditionalData" @@ -3015,7 +3202,9 @@ }, { "type": "object", - "required": ["becs"], + "required": [ + "becs" + ], "properties": { "becs": { "$ref": "#/components/schemas/BecsBankDebitAdditionalData" @@ -3024,7 +3213,9 @@ }, { "type": "object", - "required": ["sepa"], + "required": [ + "sepa" + ], "properties": { "sepa": { "$ref": "#/components/schemas/SepaBankDebitAdditionalData" @@ -3062,7 +3253,9 @@ "oneOf": [ { "type": "object", - "required": ["ach_bank_debit"], + "required": [ + "ach_bank_debit" + ], "properties": { "ach_bank_debit": { "type": "object", @@ -3121,11 +3314,16 @@ }, { "type": "object", - "required": ["sepa_bank_debit"], + "required": [ + "sepa_bank_debit" + ], "properties": { "sepa_bank_debit": { "type": "object", - "required": ["iban", "bank_account_holder_name"], + "required": [ + "iban", + "bank_account_holder_name" + ], "properties": { "billing_details": { "allOf": [ @@ -3151,11 +3349,16 @@ }, { "type": "object", - "required": ["becs_bank_debit"], + "required": [ + "becs_bank_debit" + ], "properties": { "becs_bank_debit": { "type": "object", - "required": ["account_number", "bsb_number"], + "required": [ + "account_number", + "bsb_number" + ], "properties": { "billing_details": { "allOf": [ @@ -3187,7 +3390,9 @@ }, { "type": "object", - "required": ["bacs_bank_debit"], + "required": [ + "bacs_bank_debit" + ], "properties": { "bacs_bank_debit": { "type": "object", @@ -3243,7 +3448,10 @@ }, "BankHolderType": { "type": "string", - "enum": ["personal", "business"] + "enum": [ + "personal", + "business" + ] }, "BankNames": { "type": "string", @@ -3399,7 +3607,10 @@ }, "BankRedirectBilling": { "type": "object", - "required": ["billing_name", "email"], + "required": [ + "billing_name", + "email" + ], "properties": { "billing_name": { "type": "string", @@ -3417,7 +3628,9 @@ "oneOf": [ { "type": "object", - "required": ["bancontact_card"], + "required": [ + "bancontact_card" + ], "properties": { "bancontact_card": { "type": "object", @@ -3462,7 +3675,9 @@ }, { "type": "object", - "required": ["bizum"], + "required": [ + "bizum" + ], "properties": { "bizum": { "type": "object" @@ -3471,7 +3686,9 @@ }, { "type": "object", - "required": ["blik"], + "required": [ + "blik" + ], "properties": { "blik": { "type": "object", @@ -3486,11 +3703,16 @@ }, { "type": "object", - "required": ["eps"], + "required": [ + "eps" + ], "properties": { "eps": { "type": "object", - "required": ["bank_name", "country"], + "required": [ + "bank_name", + "country" + ], "properties": { "billing_details": { "allOf": [ @@ -3512,11 +3734,15 @@ }, { "type": "object", - "required": ["giropay"], + "required": [ + "giropay" + ], "properties": { "giropay": { "type": "object", - "required": ["country"], + "required": [ + "country" + ], "properties": { "billing_details": { "allOf": [ @@ -3545,11 +3771,16 @@ }, { "type": "object", - "required": ["ideal"], + "required": [ + "ideal" + ], "properties": { "ideal": { "type": "object", - "required": ["bank_name", "country"], + "required": [ + "bank_name", + "country" + ], "properties": { "billing_details": { "allOf": [ @@ -3571,7 +3802,9 @@ }, { "type": "object", - "required": ["interac"], + "required": [ + "interac" + ], "properties": { "interac": { "type": "object", @@ -3595,11 +3828,15 @@ }, { "type": "object", - "required": ["online_banking_czech_republic"], + "required": [ + "online_banking_czech_republic" + ], "properties": { "online_banking_czech_republic": { "type": "object", - "required": ["issuer"], + "required": [ + "issuer" + ], "properties": { "issuer": { "$ref": "#/components/schemas/BankNames" @@ -3610,7 +3847,9 @@ }, { "type": "object", - "required": ["online_banking_finland"], + "required": [ + "online_banking_finland" + ], "properties": { "online_banking_finland": { "type": "object", @@ -3625,11 +3864,15 @@ }, { "type": "object", - "required": ["online_banking_poland"], + "required": [ + "online_banking_poland" + ], "properties": { "online_banking_poland": { "type": "object", - "required": ["issuer"], + "required": [ + "issuer" + ], "properties": { "issuer": { "$ref": "#/components/schemas/BankNames" @@ -3640,11 +3883,15 @@ }, { "type": "object", - "required": ["online_banking_slovakia"], + "required": [ + "online_banking_slovakia" + ], "properties": { "online_banking_slovakia": { "type": "object", - "required": ["issuer"], + "required": [ + "issuer" + ], "properties": { "issuer": { "$ref": "#/components/schemas/BankNames" @@ -3655,11 +3902,16 @@ }, { "type": "object", - "required": ["open_banking_uk"], + "required": [ + "open_banking_uk" + ], "properties": { "open_banking_uk": { "type": "object", - "required": ["issuer", "country"], + "required": [ + "issuer", + "country" + ], "properties": { "issuer": { "$ref": "#/components/schemas/BankNames" @@ -3673,7 +3925,9 @@ }, { "type": "object", - "required": ["przelewy24"], + "required": [ + "przelewy24" + ], "properties": { "przelewy24": { "type": "object", @@ -3700,11 +3954,15 @@ }, { "type": "object", - "required": ["sofort"], + "required": [ + "sofort" + ], "properties": { "sofort": { "type": "object", - "required": ["country"], + "required": [ + "country" + ], "properties": { "billing_details": { "allOf": [ @@ -3729,11 +3987,15 @@ }, { "type": "object", - "required": ["trustly"], + "required": [ + "trustly" + ], "properties": { "trustly": { "type": "object", - "required": ["country"], + "required": [ + "country" + ], "properties": { "country": { "$ref": "#/components/schemas/CountryAlpha2" @@ -3744,11 +4006,15 @@ }, { "type": "object", - "required": ["online_banking_fpx"], + "required": [ + "online_banking_fpx" + ], "properties": { "online_banking_fpx": { "type": "object", - "required": ["issuer"], + "required": [ + "issuer" + ], "properties": { "issuer": { "$ref": "#/components/schemas/BankNames" @@ -3759,11 +4025,15 @@ }, { "type": "object", - "required": ["online_banking_thailand"], + "required": [ + "online_banking_thailand" + ], "properties": { "online_banking_thailand": { "type": "object", - "required": ["issuer"], + "required": [ + "issuer" + ], "properties": { "issuer": { "$ref": "#/components/schemas/BankNames" @@ -3774,7 +4044,9 @@ }, { "type": "object", - "required": ["local_bank_redirect"], + "required": [ + "local_bank_redirect" + ], "properties": { "local_bank_redirect": { "type": "object" @@ -3787,7 +4059,9 @@ "oneOf": [ { "type": "object", - "required": ["BancontactCard"], + "required": [ + "BancontactCard" + ], "properties": { "BancontactCard": { "$ref": "#/components/schemas/BancontactBankRedirectAdditionalData" @@ -3796,7 +4070,9 @@ }, { "type": "object", - "required": ["Blik"], + "required": [ + "Blik" + ], "properties": { "Blik": { "$ref": "#/components/schemas/BlikBankRedirectAdditionalData" @@ -3805,7 +4081,9 @@ }, { "type": "object", - "required": ["Giropay"], + "required": [ + "Giropay" + ], "properties": { "Giropay": { "$ref": "#/components/schemas/GiropayBankRedirectAdditionalData" @@ -3843,7 +4121,9 @@ "oneOf": [ { "type": "object", - "required": ["ach"], + "required": [ + "ach" + ], "properties": { "ach": { "type": "object" @@ -3852,7 +4132,9 @@ }, { "type": "object", - "required": ["sepa"], + "required": [ + "sepa" + ], "properties": { "sepa": { "type": "object" @@ -3861,7 +4143,9 @@ }, { "type": "object", - "required": ["bacs"], + "required": [ + "bacs" + ], "properties": { "bacs": { "type": "object" @@ -3870,7 +4154,9 @@ }, { "type": "object", - "required": ["multibanco"], + "required": [ + "multibanco" + ], "properties": { "multibanco": { "type": "object" @@ -3879,7 +4165,9 @@ }, { "type": "object", - "required": ["permata"], + "required": [ + "permata" + ], "properties": { "permata": { "type": "object" @@ -3888,7 +4176,9 @@ }, { "type": "object", - "required": ["bca"], + "required": [ + "bca" + ], "properties": { "bca": { "type": "object" @@ -3897,7 +4187,9 @@ }, { "type": "object", - "required": ["bni_va"], + "required": [ + "bni_va" + ], "properties": { "bni_va": { "type": "object" @@ -3906,7 +4198,9 @@ }, { "type": "object", - "required": ["bri_va"], + "required": [ + "bri_va" + ], "properties": { "bri_va": { "type": "object" @@ -3915,7 +4209,9 @@ }, { "type": "object", - "required": ["cimb_va"], + "required": [ + "cimb_va" + ], "properties": { "cimb_va": { "type": "object" @@ -3924,7 +4220,9 @@ }, { "type": "object", - "required": ["danamon_va"], + "required": [ + "danamon_va" + ], "properties": { "danamon_va": { "type": "object" @@ -3933,7 +4231,9 @@ }, { "type": "object", - "required": ["mandiri_va"], + "required": [ + "mandiri_va" + ], "properties": { "mandiri_va": { "type": "object" @@ -3942,7 +4242,9 @@ }, { "type": "object", - "required": ["pix"], + "required": [ + "pix" + ], "properties": { "pix": { "$ref": "#/components/schemas/PixBankTransferAdditionalData" @@ -3951,7 +4253,9 @@ }, { "type": "object", - "required": ["pse"], + "required": [ + "pse" + ], "properties": { "pse": { "type": "object" @@ -3960,7 +4264,9 @@ }, { "type": "object", - "required": ["local_bank_transfer"], + "required": [ + "local_bank_transfer" + ], "properties": { "local_bank_transfer": { "$ref": "#/components/schemas/LocalBankTransferAdditionalData" @@ -3973,7 +4279,9 @@ "oneOf": [ { "type": "object", - "required": ["ach_bank_transfer"], + "required": [ + "ach_bank_transfer" + ], "properties": { "ach_bank_transfer": { "type": "object", @@ -3992,11 +4300,15 @@ }, { "type": "object", - "required": ["sepa_bank_transfer"], + "required": [ + "sepa_bank_transfer" + ], "properties": { "sepa_bank_transfer": { "type": "object", - "required": ["country"], + "required": [ + "country" + ], "properties": { "billing_details": { "allOf": [ @@ -4015,7 +4327,9 @@ }, { "type": "object", - "required": ["bacs_bank_transfer"], + "required": [ + "bacs_bank_transfer" + ], "properties": { "bacs_bank_transfer": { "type": "object", @@ -4034,7 +4348,9 @@ }, { "type": "object", - "required": ["multibanco_bank_transfer"], + "required": [ + "multibanco_bank_transfer" + ], "properties": { "multibanco_bank_transfer": { "type": "object", @@ -4053,7 +4369,9 @@ }, { "type": "object", - "required": ["permata_bank_transfer"], + "required": [ + "permata_bank_transfer" + ], "properties": { "permata_bank_transfer": { "type": "object", @@ -4072,8 +4390,10 @@ }, { "type": "object", - "required": ["bca_bank_transfer"], - "properties": { + "required": [ + "bca_bank_transfer" + ], + "properties": { "bca_bank_transfer": { "type": "object", "properties": { @@ -4091,7 +4411,9 @@ }, { "type": "object", - "required": ["bni_va_bank_transfer"], + "required": [ + "bni_va_bank_transfer" + ], "properties": { "bni_va_bank_transfer": { "type": "object", @@ -4110,7 +4432,9 @@ }, { "type": "object", - "required": ["bri_va_bank_transfer"], + "required": [ + "bri_va_bank_transfer" + ], "properties": { "bri_va_bank_transfer": { "type": "object", @@ -4129,7 +4453,9 @@ }, { "type": "object", - "required": ["cimb_va_bank_transfer"], + "required": [ + "cimb_va_bank_transfer" + ], "properties": { "cimb_va_bank_transfer": { "type": "object", @@ -4148,7 +4474,9 @@ }, { "type": "object", - "required": ["danamon_va_bank_transfer"], + "required": [ + "danamon_va_bank_transfer" + ], "properties": { "danamon_va_bank_transfer": { "type": "object", @@ -4167,7 +4495,9 @@ }, { "type": "object", - "required": ["mandiri_va_bank_transfer"], + "required": [ + "mandiri_va_bank_transfer" + ], "properties": { "mandiri_va_bank_transfer": { "type": "object", @@ -4186,7 +4516,9 @@ }, { "type": "object", - "required": ["pix"], + "required": [ + "pix" + ], "properties": { "pix": { "type": "object", @@ -4215,7 +4547,9 @@ }, { "type": "object", - "required": ["pse"], + "required": [ + "pse" + ], "properties": { "pse": { "type": "object" @@ -4224,7 +4558,9 @@ }, { "type": "object", - "required": ["local_bank_transfer"], + "required": [ + "local_bank_transfer" + ], "properties": { "local_bank_transfer": { "type": "object", @@ -4243,7 +4579,9 @@ "oneOf": [ { "type": "object", - "required": ["doku_bank_transfer_instructions"], + "required": [ + "doku_bank_transfer_instructions" + ], "properties": { "doku_bank_transfer_instructions": { "$ref": "#/components/schemas/DokuBankTransferInstructions" @@ -4252,7 +4590,9 @@ }, { "type": "object", - "required": ["ach_credit_transfer"], + "required": [ + "ach_credit_transfer" + ], "properties": { "ach_credit_transfer": { "$ref": "#/components/schemas/AchTransfer" @@ -4261,7 +4601,9 @@ }, { "type": "object", - "required": ["sepa_bank_instructions"], + "required": [ + "sepa_bank_instructions" + ], "properties": { "sepa_bank_instructions": { "$ref": "#/components/schemas/SepaBankTransferInstructions" @@ -4270,7 +4612,9 @@ }, { "type": "object", - "required": ["bacs_bank_instructions"], + "required": [ + "bacs_bank_instructions" + ], "properties": { "bacs_bank_instructions": { "$ref": "#/components/schemas/BacsBankTransferInstructions" @@ -4279,7 +4623,9 @@ }, { "type": "object", - "required": ["multibanco"], + "required": [ + "multibanco" + ], "properties": { "multibanco": { "$ref": "#/components/schemas/MultibancoTransferInstructions" @@ -4325,11 +4671,17 @@ }, "BankType": { "type": "string", - "enum": ["checking", "savings"] + "enum": [ + "checking", + "savings" + ] }, "BecsBankDebitAdditionalData": { "type": "object", - "required": ["account_number", "bsb_number"], + "required": [ + "account_number", + "bsb_number" + ], "properties": { "account_number": { "type": "string", @@ -4361,17 +4713,26 @@ }, "BlocklistDataKind": { "type": "string", - "enum": ["payment_method", "card_bin", "extended_card_bin"] + "enum": [ + "payment_method", + "card_bin", + "extended_card_bin" + ] }, "BlocklistRequest": { "oneOf": [ { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["card_bin"] + "enum": [ + "card_bin" + ] }, "data": { "type": "string" @@ -4380,11 +4741,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["fingerprint"] + "enum": [ + "fingerprint" + ] }, "data": { "type": "string" @@ -4393,11 +4759,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["extended_card_bin"] + "enum": [ + "extended_card_bin" + ] }, "data": { "type": "string" @@ -4411,7 +4782,11 @@ }, "BlocklistResponse": { "type": "object", - "required": ["fingerprint_id", "data_kind", "created_at"], + "required": [ + "fingerprint_id", + "data_kind", + "created_at" + ], "properties": { "fingerprint_id": { "type": "string" @@ -4506,7 +4881,9 @@ }, { "type": "object", - "required": ["enabled_payment_methods"], + "required": [ + "enabled_payment_methods" + ], "properties": { "enabled_payment_methods": { "type": "array", @@ -4527,7 +4904,9 @@ }, { "type": "object", - "required": ["allowed_domains"], + "required": [ + "allowed_domains" + ], "properties": { "domain_name": { "type": "string", @@ -4609,7 +4988,12 @@ "CaptureMethod": { "type": "string", "description": "Default value if not passed is set to 'automatic' which results in Auth and Capture in one single API request. Pass 'manual' or 'manual_multiple' in case you want do a separate Auth and Capture by first authorizing and placing a hold on your customer's funds so that you can use the Payments/Capture endpoint later to capture the authorized amount. Pass 'manual' if you want to only capture the amount later once or 'manual_multiple' if you want to capture the funds multiple times later. Both 'manual' and 'manual_multiple' are only supported by a specific list of processors", - "enum": ["automatic", "manual", "manual_multiple", "scheduled"] + "enum": [ + "automatic", + "manual", + "manual_multiple", + "scheduled" + ] }, "CaptureResponse": { "type": "object", @@ -4685,7 +5069,12 @@ }, "CaptureStatus": { "type": "string", - "enum": ["started", "charged", "pending", "failed"] + "enum": [ + "started", + "charged", + "pending", + "failed" + ] }, "Card": { "type": "object", @@ -4762,7 +5151,11 @@ "CardAdditionalData": { "type": "object", "description": "Masked payout method details for card payout method", - "required": ["card_exp_month", "card_exp_year", "card_holder_name"], + "required": [ + "card_exp_month", + "card_exp_year", + "card_holder_name" + ], "properties": { "card_issuer": { "type": "string", @@ -4887,7 +5280,9 @@ }, "CardDetailFromLocker": { "type": "object", - "required": ["saved_to_locker"], + "required": [ + "saved_to_locker" + ], "properties": { "scheme": { "type": "string", @@ -4952,7 +5347,11 @@ }, "CardDetailUpdate": { "type": "object", - "required": ["card_exp_month", "card_exp_year", "card_holder_name"], + "required": [ + "card_exp_month", + "card_exp_year", + "card_holder_name" + ], "properties": { "card_exp_month": { "type": "string", @@ -5028,7 +5427,9 @@ "oneOf": [ { "type": "object", - "required": ["knet"], + "required": [ + "knet" + ], "properties": { "knet": { "type": "object" @@ -5037,7 +5438,9 @@ }, { "type": "object", - "required": ["benefit"], + "required": [ + "benefit" + ], "properties": { "benefit": { "type": "object" @@ -5046,7 +5449,9 @@ }, { "type": "object", - "required": ["momo_atm"], + "required": [ + "momo_atm" + ], "properties": { "momo_atm": { "type": "object" @@ -5055,7 +5460,9 @@ }, { "type": "object", - "required": ["card_redirect"], + "required": [ + "card_redirect" + ], "properties": { "card_redirect": { "type": "object" @@ -5136,7 +5543,9 @@ }, "CardToken": { "type": "object", - "required": ["card_holder_name"], + "required": [ + "card_holder_name" + ], "properties": { "card_holder_name": { "type": "string", @@ -5152,7 +5561,9 @@ }, "CardTokenAdditionalData": { "type": "object", - "required": ["card_holder_name"], + "required": [ + "card_holder_name" + ], "properties": { "card_holder_name": { "type": "string", @@ -5182,7 +5593,9 @@ "ChargeRefunds": { "type": "object", "description": "Charge specific fields for controlling the revert of funds from either platform or connected account. Check sub-fields for more details.", - "required": ["charge_id"], + "required": [ + "charge_id" + ], "properties": { "charge_id": { "type": "string", @@ -5203,7 +5616,12 @@ "Comparison": { "type": "object", "description": "Represents a single comparison condition.", - "required": ["lhs", "comparison", "value", "metadata"], + "required": [ + "lhs", + "comparison", + "value", + "metadata" + ], "properties": { "lhs": { "type": "string", @@ -5436,11 +5854,16 @@ "oneOf": [ { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["priority"] + "enum": [ + "priority" + ] }, "data": { "type": "array", @@ -5452,11 +5875,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["volume_split"] + "enum": [ + "volume_split" + ] }, "data": { "type": "array", @@ -5473,7 +5901,10 @@ }, "ConnectorStatus": { "type": "string", - "enum": ["inactive", "active"] + "enum": [ + "inactive", + "active" + ] }, "ConnectorType": { "type": "string", @@ -5494,7 +5925,10 @@ }, "ConnectorVolumeSplit": { "type": "object", - "required": ["connector", "split"], + "required": [ + "connector", + "split" + ], "properties": { "connector": { "$ref": "#/components/schemas/RoutableConnectorChoice" @@ -5789,7 +6223,10 @@ "CreateApiKeyRequest": { "type": "object", "description": "The request body for creating an API Key.", - "required": ["name", "expiration"], + "required": [ + "name", + "expiration" + ], "properties": { "name": { "type": "string", @@ -6057,7 +6494,9 @@ "CustomerAcceptance": { "type": "object", "description": "This \"CustomerAcceptance\" object is passed during Payments-Confirm request, it enlists the type, time, and mode of acceptance properties related to an acceptance done by the customer. The customer_acceptance sub object is usually passed by the SDK or client.", - "required": ["acceptance_type"], + "required": [ + "acceptance_type" + ], "properties": { "acceptance_type": { "$ref": "#/components/schemas/AcceptanceType" @@ -6082,7 +6521,10 @@ }, "CustomerDefaultPaymentMethodResponse": { "type": "object", - "required": ["customer_id", "payment_method"], + "required": [ + "customer_id", + "payment_method" + ], "properties": { "default_payment_method_id": { "type": "string", @@ -6150,7 +6592,9 @@ "CustomerDetails": { "type": "object", "description": "Passing this object creates a new customer or attaches an existing customer to the payment", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string", @@ -6302,7 +6746,9 @@ "$ref": "#/components/schemas/PaymentExperience" }, "description": "Type of payment experience enabled with the connector", - "example": ["redirect_to_url"], + "example": [ + "redirect_to_url" + ], "nullable": true }, "card": { @@ -6378,7 +6824,9 @@ }, "CustomerPaymentMethodsListResponse": { "type": "object", - "required": ["customer_payment_methods"], + "required": [ + "customer_payment_methods" + ], "properties": { "customer_payment_methods": { "type": "array", @@ -6397,7 +6845,10 @@ "CustomerRequest": { "type": "object", "description": "The customer details", - "required": ["name", "email"], + "required": [ + "name", + "email" + ], "properties": { "merchant_reference_id": { "type": "string", @@ -6465,7 +6916,11 @@ }, "CustomerResponse": { "type": "object", - "required": ["merchant_reference_id", "created_at", "id"], + "required": [ + "merchant_reference_id", + "created_at", + "id" + ], "properties": { "merchant_reference_id": { "type": "string", @@ -6551,11 +7006,17 @@ }, "DecoupledAuthenticationType": { "type": "string", - "enum": ["challenge", "frictionless"] + "enum": [ + "challenge", + "frictionless" + ] }, "DefaultPaymentMethod": { "type": "object", - "required": ["customer_id", "payment_method_id"], + "required": [ + "customer_id", + "payment_method_id" + ], "properties": { "customer_id": { "type": "string", @@ -6571,11 +7032,18 @@ "DeviceChannel": { "type": "string", "description": "Device Channel indicating whether request is coming from App or Browser", - "enum": ["APP", "BRW"] + "enum": [ + "APP", + "BRW" + ] }, "DisplayAmountOnSdk": { "type": "object", - "required": ["net_amount", "order_tax_amount", "shipping_cost"], + "required": [ + "net_amount", + "order_tax_amount", + "shipping_cost" + ], "properties": { "net_amount": { "type": "string", @@ -6757,7 +7225,11 @@ "DisputeStage": { "type": "string", "description": "Stage of the dispute", - "enum": ["pre_dispute", "dispute", "pre_arbitration"] + "enum": [ + "pre_dispute", + "dispute", + "pre_arbitration" + ] }, "DisputeStatus": { "type": "string", @@ -6774,7 +7246,11 @@ }, "DokuBankTransferInstructions": { "type": "object", - "required": ["expires_at", "reference", "instructions_url"], + "required": [ + "expires_at", + "reference", + "instructions_url" + ], "properties": { "expires_at": { "type": "string", @@ -6815,12 +7291,18 @@ "EnablePaymentLinkRequest": { "type": "string", "description": "Whether payment link is requested to be enabled or not for this transaction", - "enum": ["Enable", "Skip"] + "enum": [ + "Enable", + "Skip" + ] }, "EnabledPaymentMethod": { "type": "object", "description": "Object for EnabledPaymentMethod", - "required": ["payment_method", "payment_method_types"], + "required": [ + "payment_method", + "payment_method_types" + ], "properties": { "payment_method": { "$ref": "#/components/schemas/PaymentMethod" @@ -6838,7 +7320,12 @@ "EphemeralKeyCreateResponse": { "type": "object", "description": "ephemeral_key for the customer_id mentioned", - "required": ["customer_id", "created_at", "expires", "secret"], + "required": [ + "customer_id", + "created_at", + "expires", + "secret" + ], "properties": { "customer_id": { "type": "string", @@ -6866,7 +7353,10 @@ "ErrorDetails": { "type": "object", "description": "Error details for the payment", - "required": ["code", "message"], + "required": [ + "code", + "message" + ], "properties": { "code": { "type": "string", @@ -6890,7 +7380,13 @@ }, "EventClass": { "type": "string", - "enum": ["payments", "refunds", "disputes", "mandates", "payouts"] + "enum": [ + "payments", + "refunds", + "disputes", + "mandates", + "payouts" + ] }, "EventListItemResponse": { "type": "object", @@ -6962,7 +7458,10 @@ }, { "type": "object", - "required": ["request", "response"], + "required": [ + "request", + "response" + ], "properties": { "request": { "$ref": "#/components/schemas/OutgoingWebhookRequestContent" @@ -7081,7 +7580,9 @@ }, "ExtendedCardInfoConfig": { "type": "object", - "required": ["public_key"], + "required": [ + "public_key" + ], "properties": { "public_key": { "type": "string", @@ -7099,7 +7600,9 @@ }, "ExtendedCardInfoResponse": { "type": "object", - "required": ["payload"], + "required": [ + "payload" + ], "properties": { "payload": { "type": "string" @@ -7109,12 +7612,17 @@ "External3dsAuthenticationRequest": { "type": "string", "description": "Whether 3ds authentication is requested or not", - "enum": ["Enable", "Skip"] + "enum": [ + "Enable", + "Skip" + ] }, "ExternalAuthenticationDetailsResponse": { "type": "object", "description": "Details of external authentication", - "required": ["status"], + "required": [ + "status" + ], "properties": { "authentication_flow": { "allOf": [ @@ -7180,43 +7688,63 @@ "oneOf": [ { "type": "string", - "enum": ["user_card_number"] + "enum": [ + "user_card_number" + ] }, { "type": "string", - "enum": ["user_card_expiry_month"] + "enum": [ + "user_card_expiry_month" + ] }, { "type": "string", - "enum": ["user_card_expiry_year"] + "enum": [ + "user_card_expiry_year" + ] }, { "type": "string", - "enum": ["user_card_cvc"] + "enum": [ + "user_card_cvc" + ] }, { "type": "string", - "enum": ["user_full_name"] + "enum": [ + "user_full_name" + ] }, { "type": "string", - "enum": ["user_email_address"] + "enum": [ + "user_email_address" + ] }, { "type": "string", - "enum": ["user_phone_number"] + "enum": [ + "user_phone_number" + ] }, { "type": "string", - "enum": ["user_phone_number_country_code"] + "enum": [ + "user_phone_number_country_code" + ] }, { "type": "object", - "required": ["user_country"], + "required": [ + "user_country" + ], "properties": { "user_country": { "type": "object", - "required": ["options"], + "required": [ + "options" + ], "properties": { "options": { "type": "array", @@ -7230,11 +7758,15 @@ }, { "type": "object", - "required": ["user_currency"], + "required": [ + "user_currency" + ], "properties": { "user_currency": { "type": "object", - "required": ["options"], + "required": [ + "options" + ], "properties": { "options": { "type": "array", @@ -7248,39 +7780,57 @@ }, { "type": "string", - "enum": ["user_crypto_currency_network"] + "enum": [ + "user_crypto_currency_network" + ] }, { "type": "string", - "enum": ["user_billing_name"] + "enum": [ + "user_billing_name" + ] }, { "type": "string", - "enum": ["user_address_line1"] + "enum": [ + "user_address_line1" + ] }, { "type": "string", - "enum": ["user_address_line2"] + "enum": [ + "user_address_line2" + ] }, { "type": "string", - "enum": ["user_address_city"] + "enum": [ + "user_address_city" + ] }, { "type": "string", - "enum": ["user_address_pincode"] + "enum": [ + "user_address_pincode" + ] }, { "type": "string", - "enum": ["user_address_state"] + "enum": [ + "user_address_state" + ] }, { "type": "object", - "required": ["user_address_country"], + "required": [ + "user_address_country" + ], "properties": { "user_address_country": { "type": "object", - "required": ["options"], + "required": [ + "options" + ], "properties": { "options": { "type": "array", @@ -7294,35 +7844,51 @@ }, { "type": "string", - "enum": ["user_shipping_name"] + "enum": [ + "user_shipping_name" + ] }, { "type": "string", - "enum": ["user_shipping_address_line1"] + "enum": [ + "user_shipping_address_line1" + ] }, { "type": "string", - "enum": ["user_shipping_address_line2"] + "enum": [ + "user_shipping_address_line2" + ] }, { "type": "string", - "enum": ["user_shipping_address_city"] + "enum": [ + "user_shipping_address_city" + ] }, { "type": "string", - "enum": ["user_shipping_address_pincode"] + "enum": [ + "user_shipping_address_pincode" + ] }, { "type": "string", - "enum": ["user_shipping_address_state"] + "enum": [ + "user_shipping_address_state" + ] }, { "type": "object", - "required": ["user_shipping_address_country"], + "required": [ + "user_shipping_address_country" + ], "properties": { "user_shipping_address_country": { "type": "object", - "required": ["options"], + "required": [ + "options" + ], "properties": { "options": { "type": "array", @@ -7336,27 +7902,39 @@ }, { "type": "string", - "enum": ["user_blik_code"] + "enum": [ + "user_blik_code" + ] }, { "type": "string", - "enum": ["user_bank"] + "enum": [ + "user_bank" + ] }, { "type": "string", - "enum": ["user_bank_account_number"] + "enum": [ + "user_bank_account_number" + ] }, { "type": "string", - "enum": ["text"] + "enum": [ + "text" + ] }, { "type": "object", - "required": ["drop_down"], + "required": [ + "drop_down" + ], "properties": { "drop_down": { "type": "object", - "required": ["options"], + "required": [ + "options" + ], "properties": { "options": { "type": "array", @@ -7370,19 +7948,27 @@ }, { "type": "string", - "enum": ["user_date_of_birth"] + "enum": [ + "user_date_of_birth" + ] }, { "type": "string", - "enum": ["user_vpa_id"] + "enum": [ + "user_vpa_id" + ] }, { "type": "object", - "required": ["language_preference"], + "required": [ + "language_preference" + ], "properties": { "language_preference": { "type": "object", - "required": ["options"], + "required": [ + "options" + ], "properties": { "options": { "type": "array", @@ -7396,39 +7982,58 @@ }, { "type": "string", - "enum": ["user_pix_key"] + "enum": [ + "user_pix_key" + ] }, { "type": "string", - "enum": ["user_cpf"] + "enum": [ + "user_cpf" + ] }, { "type": "string", - "enum": ["user_cnpj"] + "enum": [ + "user_cnpj" + ] }, { "type": "string", - "enum": ["user_iban"] + "enum": [ + "user_iban" + ] }, { "type": "string", - "enum": ["browser_language"] + "enum": [ + "browser_language" + ] }, { "type": "string", - "enum": ["browser_ip"] + "enum": [ + "browser_ip" + ] } ], "description": "Possible field type of required fields in payment_method_data" }, "FrmAction": { "type": "string", - "enum": ["cancel_txn", "auto_refund", "manual_review"] + "enum": [ + "cancel_txn", + "auto_refund", + "manual_review" + ] }, "FrmConfigs": { "type": "object", "description": "Details of FrmConfigs are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", - "required": ["gateway", "payment_methods"], + "required": [ + "gateway", + "payment_methods" + ], "properties": { "gateway": { "$ref": "#/components/schemas/ConnectorType" @@ -7446,7 +8051,9 @@ "FrmMessage": { "type": "object", "description": "frm message is an object sent inside the payments response...when frm is invoked, its value is Some(...), else its None", - "required": ["frm_name"], + "required": [ + "frm_name" + ], "properties": { "frm_name": { "type": "string" @@ -7480,7 +8087,9 @@ "FrmPaymentMethod": { "type": "object", "description": "Details of FrmPaymentMethod are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", - "required": ["payment_method"], + "required": [ + "payment_method" + ], "properties": { "payment_method": { "$ref": "#/components/schemas/PaymentMethod" @@ -7507,7 +8116,12 @@ "FrmPaymentMethodType": { "type": "object", "description": "Details of FrmPaymentMethodType are mentioned here... it should be passed in payment connector create api call, and stored in merchant_connector_table", - "required": ["payment_method_type", "card_networks", "flow", "action"], + "required": [ + "payment_method_type", + "card_networks", + "flow", + "action" + ], "properties": { "payment_method_type": { "$ref": "#/components/schemas/PaymentMethodType" @@ -7526,12 +8140,18 @@ }, "FrmPreferredFlowTypes": { "type": "string", - "enum": ["pre", "post"] + "enum": [ + "pre", + "post" + ] }, "FutureUsage": { "type": "string", "description": "Indicates that you intend to make future payments with the payment methods used for this Payment. Providing this parameter will attach the payment method to the Customer, if present, after the Payment is confirmed and any required actions from the user are complete.\n- On_session - Payment method saved only at hyperswitch when consent is provided by the user. CVV will asked during the returning user payment\n- Off_session - Payment method saved at both hyperswitch and Processor when consent is provided by the user. No input is required during the returning user payment.", - "enum": ["off_session", "on_session"] + "enum": [ + "off_session", + "on_session" + ] }, "GcashRedirection": { "type": "object" @@ -7567,7 +8187,9 @@ "oneOf": [ { "type": "object", - "required": ["givex"], + "required": [ + "givex" + ], "properties": { "givex": { "$ref": "#/components/schemas/GivexGiftCardAdditionalData" @@ -7576,7 +8198,9 @@ }, { "type": "object", - "required": ["pay_safe_card"], + "required": [ + "pay_safe_card" + ], "properties": { "pay_safe_card": { "type": "object" @@ -7589,7 +8213,9 @@ "oneOf": [ { "type": "object", - "required": ["givex"], + "required": [ + "givex" + ], "properties": { "givex": { "$ref": "#/components/schemas/GiftCardDetails" @@ -7598,7 +8224,9 @@ }, { "type": "object", - "required": ["pay_safe_card"], + "required": [ + "pay_safe_card" + ], "properties": { "pay_safe_card": { "type": "object" @@ -7609,7 +8237,10 @@ }, "GiftCardDetails": { "type": "object", - "required": ["number", "cvc"], + "required": [ + "number", + "cvc" + ], "properties": { "number": { "type": "string", @@ -7661,7 +8292,9 @@ }, "GivexGiftCardAdditionalData": { "type": "object", - "required": ["last4"], + "required": [ + "last4" + ], "properties": { "last4": { "type": "string", @@ -7675,7 +8308,10 @@ }, "GooglePayAssuranceDetails": { "type": "object", - "required": ["card_holder_authenticated", "account_verified"], + "required": [ + "card_holder_authenticated", + "account_verified" + ], "properties": { "card_holder_authenticated": { "type": "boolean", @@ -7689,7 +8325,10 @@ }, "GooglePayPaymentMethodInfo": { "type": "object", - "required": ["card_network", "card_details"], + "required": [ + "card_network", + "card_details" + ], "properties": { "card_network": { "type": "string", @@ -7773,7 +8412,11 @@ }, "GooglePayThirdPartySdk": { "type": "object", - "required": ["delayed_session_token", "connector", "sdk_next_action"], + "required": [ + "delayed_session_token", + "connector", + "sdk_next_action" + ], "properties": { "delayed_session_token": { "type": "boolean", @@ -7793,7 +8436,12 @@ }, "GooglePayWalletData": { "type": "object", - "required": ["type", "description", "info", "tokenization_data"], + "required": [ + "type", + "description", + "info", + "tokenization_data" + ], "properties": { "type": { "type": "string", @@ -7813,7 +8461,10 @@ }, "GpayAllowedMethodsParameters": { "type": "object", - "required": ["allowed_auth_methods", "allowed_card_networks"], + "required": [ + "allowed_auth_methods", + "allowed_card_networks" + ], "properties": { "allowed_auth_methods": { "type": "array", @@ -7851,7 +8502,11 @@ }, "GpayAllowedPaymentMethods": { "type": "object", - "required": ["type", "parameters", "tokenization_specification"], + "required": [ + "type", + "parameters", + "tokenization_specification" + ], "properties": { "type": { "type": "string", @@ -7867,11 +8522,17 @@ }, "GpayBillingAddressFormat": { "type": "string", - "enum": ["FULL", "MIN"] + "enum": [ + "FULL", + "MIN" + ] }, "GpayBillingAddressParameters": { "type": "object", - "required": ["phone_number_required", "format"], + "required": [ + "phone_number_required", + "format" + ], "properties": { "phone_number_required": { "type": "boolean", @@ -7884,7 +8545,9 @@ }, "GpayMerchantInfo": { "type": "object", - "required": ["merchant_name"], + "required": [ + "merchant_name" + ], "properties": { "merchant_id": { "type": "string", @@ -7909,7 +8572,9 @@ }, "GpayShippingAddressParameters": { "type": "object", - "required": ["phone_number_required"], + "required": [ + "phone_number_required" + ], "properties": { "phone_number_required": { "type": "boolean", @@ -7919,7 +8584,9 @@ }, "GpayTokenParameters": { "type": "object", - "required": ["gateway"], + "required": [ + "gateway" + ], "properties": { "gateway": { "type": "string", @@ -7942,7 +8609,10 @@ }, "GpayTokenizationData": { "type": "object", - "required": ["type", "token"], + "required": [ + "type", + "token" + ], "properties": { "type": { "type": "string", @@ -7956,7 +8626,10 @@ }, "GpayTokenizationSpecification": { "type": "object", - "required": ["type", "parameters"], + "required": [ + "type", + "parameters" + ], "properties": { "type": { "type": "string", @@ -8055,11 +8728,21 @@ }, "GsmDecision": { "type": "string", - "enum": ["retry", "requeue", "do_default"] + "enum": [ + "retry", + "requeue", + "do_default" + ] }, "GsmDeleteRequest": { "type": "object", - "required": ["connector", "flow", "sub_flow", "code", "message"], + "required": [ + "connector", + "flow", + "sub_flow", + "code", + "message" + ], "properties": { "connector": { "type": "string", @@ -8178,7 +8861,13 @@ }, "GsmRetrieveRequest": { "type": "object", - "required": ["connector", "flow", "sub_flow", "code", "message"], + "required": [ + "connector", + "flow", + "sub_flow", + "code", + "message" + ], "properties": { "connector": { "$ref": "#/components/schemas/Connector" @@ -8203,7 +8892,13 @@ }, "GsmUpdateRequest": { "type": "object", - "required": ["connector", "flow", "sub_flow", "code", "message"], + "required": [ + "connector", + "flow", + "sub_flow", + "code", + "message" + ], "properties": { "connector": { "type": "string", @@ -8263,7 +8958,9 @@ "IfStatement": { "type": "object", "description": "Represents an IF statement with conditions and optional nested IF statements\n\n```text\npayment.method = card {\npayment.method.cardtype = (credit, debit) {\npayment.method.network = (amex, rupay, diners)\n}\n}\n```", - "required": ["condition"], + "required": [ + "condition" + ], "properties": { "condition": { "type": "array", @@ -8400,7 +9097,10 @@ }, "KlarnaSessionTokenResponse": { "type": "object", - "required": ["session_token", "session_id"], + "required": [ + "session_token", + "session_id" + ], "properties": { "session_token": { "type": "string", @@ -8427,7 +9127,9 @@ }, "ListBlocklistQuery": { "type": "object", - "required": ["data_kind"], + "required": [ + "data_kind" + ], "properties": { "data_kind": { "$ref": "#/components/schemas/BlocklistDataKind" @@ -8457,7 +9159,10 @@ }, "MandateAmountData": { "type": "object", - "required": ["amount", "currency"], + "required": [ + "amount", + "currency" + ], "properties": { "amount": { "type": "integer", @@ -8639,7 +9344,10 @@ }, "MandateRevokedResponse": { "type": "object", - "required": ["mandate_id", "status"], + "required": [ + "mandate_id", + "status" + ], "properties": { "mandate_id": { "type": "string", @@ -8665,13 +9373,20 @@ "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" @@ -8680,7 +9395,9 @@ }, { "type": "object", - "required": ["multi_use"], + "required": [ + "multi_use" + ], "properties": { "multi_use": { "allOf": [ @@ -8696,7 +9413,9 @@ }, "MaskedBankDetails": { "type": "object", - "required": ["mask"], + "required": [ + "mask" + ], "properties": { "mask": { "type": "string" @@ -8705,7 +9424,9 @@ }, "MbWayRedirection": { "type": "object", - "required": ["telephone_number"], + "required": [ + "telephone_number" + ], "properties": { "telephone_number": { "type": "string", @@ -8715,7 +9436,9 @@ }, "MerchantAccountCreate": { "type": "object", - "required": ["merchant_name"], + "required": [ + "merchant_name" + ], "properties": { "merchant_name": { "type": "string", @@ -8743,11 +9466,16 @@ "oneOf": [ { "type": "object", - "required": ["iban"], + "required": [ + "iban" + ], "properties": { "iban": { "type": "object", - "required": ["iban", "name"], + "required": [ + "iban", + "name" + ], "properties": { "iban": { "type": "string" @@ -8765,11 +9493,17 @@ }, { "type": "object", - "required": ["bacs"], + "required": [ + "bacs" + ], "properties": { "bacs": { "type": "object", - "required": ["account_number", "sort_code", "name"], + "required": [ + "account_number", + "sort_code", + "name" + ], "properties": { "account_number": { "type": "string" @@ -8792,7 +9526,10 @@ }, "MerchantAccountDeleteResponse": { "type": "object", - "required": ["merchant_id", "deleted"], + "required": [ + "merchant_id", + "deleted" + ], "properties": { "merchant_id": { "type": "string", @@ -8886,7 +9623,11 @@ "MerchantConnectorCreate": { "type": "object", "description": "Create a new Merchant 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", "profile_id"], + "required": [ + "connector_type", + "connector_name", + "profile_id" + ], "properties": { "connector_type": { "$ref": "#/components/schemas/ConnectorType" @@ -8922,20 +9663,36 @@ "example": [ { "accepted_countries": { - "list": ["FR", "DE", "IN"], + "list": [ + "FR", + "DE", + "IN" + ], "type": "disable_only" }, "accepted_currencies": { - "list": ["USD", "EUR"], + "list": [ + "USD", + "EUR" + ], "type": "enable_only" }, "installment_payment_enabled": true, "maximum_amount": 68607706, "minimum_amount": 1, "payment_method": "wallet", - "payment_method_issuers": ["labore magna ipsum", "aute"], - "payment_method_types": ["upi_collect", "upi_intent"], - "payment_schemes": ["Discover", "Discover"], + "payment_method_issuers": [ + "labore magna ipsum", + "aute" + ], + "payment_method_types": [ + "upi_collect", + "upi_intent" + ], + "payment_schemes": [ + "Discover", + "Discover" + ], "recurring_enabled": true } ], @@ -9004,7 +9761,11 @@ }, "MerchantConnectorDeleteResponse": { "type": "object", - "required": ["merchant_id", "id", "deleted"], + "required": [ + "merchant_id", + "id", + "deleted" + ], "properties": { "merchant_id": { "type": "string", @@ -9042,7 +9803,9 @@ "MerchantConnectorDetailsWrap": { "type": "object", "description": "Merchant connector details used to make payments.", - "required": ["creds_identifier"], + "required": [ + "creds_identifier" + ], "properties": { "creds_identifier": { "type": "string", @@ -9060,7 +9823,9 @@ }, "MerchantConnectorId": { "type": "object", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string" @@ -9108,20 +9873,36 @@ "example": [ { "accepted_countries": { - "list": ["FR", "DE", "IN"], + "list": [ + "FR", + "DE", + "IN" + ], "type": "disable_only" }, "accepted_currencies": { - "list": ["USD", "EUR"], + "list": [ + "USD", + "EUR" + ], "type": "enable_only" }, "installment_payment_enabled": true, "maximum_amount": 68607706, "minimum_amount": 1, "payment_method": "wallet", - "payment_method_issuers": ["labore magna ipsum", "aute"], - "payment_method_types": ["upi_collect", "upi_intent"], - "payment_schemes": ["Discover", "Discover"], + "payment_method_issuers": [ + "labore magna ipsum", + "aute" + ], + "payment_method_types": [ + "upi_collect", + "upi_intent" + ], + "payment_schemes": [ + "Discover", + "Discover" + ], "recurring_enabled": true } ], @@ -9232,20 +10013,36 @@ "example": [ { "accepted_countries": { - "list": ["FR", "DE", "IN"], + "list": [ + "FR", + "DE", + "IN" + ], "type": "disable_only" }, "accepted_currencies": { - "list": ["USD", "EUR"], + "list": [ + "USD", + "EUR" + ], "type": "enable_only" }, "installment_payment_enabled": true, "maximum_amount": 68607706, "minimum_amount": 1, "payment_method": "wallet", - "payment_method_issuers": ["labore magna ipsum", "aute"], - "payment_method_types": ["upi_collect", "upi_intent"], - "payment_schemes": ["Discover", "Discover"], + "payment_method_issuers": [ + "labore magna ipsum", + "aute" + ], + "payment_method_types": [ + "upi_collect", + "upi_intent" + ], + "payment_schemes": [ + "Discover", + "Discover" + ], "recurring_enabled": true } ], @@ -9318,7 +10115,11 @@ "MerchantConnectorUpdate": { "type": "object", "description": "Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc.\"", - "required": ["connector_type", "status", "merchant_id"], + "required": [ + "connector_type", + "status", + "merchant_id" + ], "properties": { "connector_type": { "$ref": "#/components/schemas/ConnectorType" @@ -9346,20 +10147,36 @@ "example": [ { "accepted_countries": { - "list": ["FR", "DE", "IN"], + "list": [ + "FR", + "DE", + "IN" + ], "type": "disable_only" }, "accepted_currencies": { - "list": ["USD", "EUR"], + "list": [ + "USD", + "EUR" + ], "type": "enable_only" }, "installment_payment_enabled": true, "maximum_amount": 68607706, "minimum_amount": 1, "payment_method": "wallet", - "payment_method_issuers": ["labore magna ipsum", "aute"], - "payment_method_types": ["upi_collect", "upi_intent"], - "payment_schemes": ["Discover", "Discover"], + "payment_method_issuers": [ + "labore magna ipsum", + "aute" + ], + "payment_method_types": [ + "upi_collect", + "upi_intent" + ], + "payment_schemes": [ + "Discover", + "Discover" + ], "recurring_enabled": true } ], @@ -9430,7 +10247,10 @@ }, "MerchantConnectorWebhookDetails": { "type": "object", - "required": ["merchant_secret", "additional_secret"], + "required": [ + "merchant_secret", + "additional_secret" + ], "properties": { "merchant_secret": { "type": "string", @@ -9517,7 +10337,9 @@ "oneOf": [ { "type": "object", - "required": ["connector_recipient_id"], + "required": [ + "connector_recipient_id" + ], "properties": { "connector_recipient_id": { "type": "string", @@ -9527,7 +10349,9 @@ }, { "type": "object", - "required": ["wallet_id"], + "required": [ + "wallet_id" + ], "properties": { "wallet_id": { "type": "string", @@ -9537,7 +10361,9 @@ }, { "type": "object", - "required": ["account_data"], + "required": [ + "account_data" + ], "properties": { "account_data": { "$ref": "#/components/schemas/MerchantAccountData" @@ -9590,7 +10416,10 @@ }, "MetadataValue": { "type": "object", - "required": ["key", "value"], + "required": [ + "key", + "value" + ], "properties": { "key": { "type": "string" @@ -9602,7 +10431,9 @@ }, "MifinityData": { "type": "object", - "required": ["date_of_birth"], + "required": [ + "date_of_birth" + ], "properties": { "date_of_birth": { "type": "string", @@ -9621,7 +10452,10 @@ }, "MitExemptionRequest": { "type": "string", - "enum": ["Apply", "Skip"] + "enum": [ + "Apply", + "Skip" + ] }, "MobilePayRedirection": { "type": "object" @@ -9641,7 +10475,10 @@ }, "MultibancoTransferInstructions": { "type": "object", - "required": ["reference", "entity"], + "required": [ + "reference", + "entity" + ], "properties": { "reference": { "type": "string", @@ -9726,42 +10563,59 @@ }, "NextActionCall": { "type": "string", - "enum": ["post_session_tokens", "confirm", "sync", "complete_authorize"] + "enum": [ + "post_session_tokens", + "confirm", + "sync", + "complete_authorize" + ] }, "NextActionData": { "oneOf": [ { "type": "object", "description": "Contains the url for redirection flow", - "required": ["redirect_to_url", "type"], + "required": [ + "redirect_to_url", + "type" + ], "properties": { "redirect_to_url": { "type": "string" }, "type": { "type": "string", - "enum": ["redirect_to_url"] + "enum": [ + "redirect_to_url" + ] } } }, { "type": "object", "description": "Informs the next steps for bank transfer and also contains the charges details (ex: amount received, amount charged etc)", - "required": ["bank_transfer_steps_and_charges_details", "type"], + "required": [ + "bank_transfer_steps_and_charges_details", + "type" + ], "properties": { "bank_transfer_steps_and_charges_details": { "$ref": "#/components/schemas/BankTransferNextStepsData" }, "type": { "type": "string", - "enum": ["display_bank_transfer_information"] + "enum": [ + "display_bank_transfer_information" + ] } } }, { "type": "object", "description": "Contains third party sdk session token response", - "required": ["type"], + "required": [ + "type" + ], "properties": { "session_token": { "allOf": [ @@ -9773,14 +10627,20 @@ }, "type": { "type": "string", - "enum": ["third_party_sdk_session_token"] + "enum": [ + "third_party_sdk_session_token" + ] } } }, { "type": "object", "description": "Contains url for Qr code image, this qr code has to be shown in sdk", - "required": ["image_data_url", "qr_code_url", "type"], + "required": [ + "image_data_url", + "qr_code_url", + "type" + ], "properties": { "image_data_url": { "type": "string", @@ -9797,42 +10657,57 @@ }, "type": { "type": "string", - "enum": ["qr_code_information"] + "enum": [ + "qr_code_information" + ] } } }, { "type": "object", "description": "Contains url to fetch Qr code data", - "required": ["qr_code_fetch_url", "type"], + "required": [ + "qr_code_fetch_url", + "type" + ], "properties": { "qr_code_fetch_url": { "type": "string" }, "type": { "type": "string", - "enum": ["fetch_qr_code_information"] + "enum": [ + "fetch_qr_code_information" + ] } } }, { "type": "object", "description": "Contains the download url and the reference number for transaction", - "required": ["voucher_details", "type"], + "required": [ + "voucher_details", + "type" + ], "properties": { "voucher_details": { "type": "string" }, "type": { "type": "string", - "enum": ["display_voucher_information"] + "enum": [ + "display_voucher_information" + ] } } }, { "type": "object", "description": "Contains duration for displaying a wait screen, wait screen with timer is displayed by sdk", - "required": ["display_from_timestamp", "type"], + "required": [ + "display_from_timestamp", + "type" + ], "properties": { "display_from_timestamp": { "type": "integer" @@ -9843,34 +10718,46 @@ }, "type": { "type": "string", - "enum": ["wait_screen_information"] + "enum": [ + "wait_screen_information" + ] } } }, { "type": "object", "description": "Contains the information regarding three_ds_method_data submission, three_ds authentication, and authorization flows", - "required": ["three_ds_data", "type"], + "required": [ + "three_ds_data", + "type" + ], "properties": { "three_ds_data": { "$ref": "#/components/schemas/ThreeDsData" }, "type": { "type": "string", - "enum": ["three_ds_invoke"] + "enum": [ + "three_ds_invoke" + ] } } }, { "type": "object", - "required": ["next_action_data", "type"], + "required": [ + "next_action_data", + "type" + ], "properties": { "next_action_data": { "$ref": "#/components/schemas/SdkNextActionData" }, "type": { "type": "string", - "enum": ["invoke_sdk_client"] + "enum": [ + "invoke_sdk_client" + ] } } } @@ -9971,7 +10858,10 @@ "NumberComparison": { "type": "object", "description": "Represents a number comparison for \"NumberComparisonArrayValue\"", - "required": ["comparisonType", "number"], + "required": [ + "comparisonType", + "number" + ], "properties": { "comparisonType": { "$ref": "#/components/schemas/ComparisonType" @@ -9983,7 +10873,10 @@ }, "OnlineMandate": { "type": "object", - "required": ["ip_address", "user_agent"], + "required": [ + "ip_address", + "user_agent" + ], "properties": { "ip_address": { "type": "string", @@ -10001,7 +10894,9 @@ "oneOf": [ { "type": "object", - "required": ["open_banking_pis"], + "required": [ + "open_banking_pis" + ], "properties": { "open_banking_pis": { "type": "object" @@ -10027,7 +10922,9 @@ }, "OpenBankingSessionToken": { "type": "object", - "required": ["open_banking_session_token"], + "required": [ + "open_banking_session_token" + ], "properties": { "open_banking_session_token": { "type": "string", @@ -10037,7 +10934,10 @@ }, "OrderDetails": { "type": "object", - "required": ["product_name", "quantity"], + "required": [ + "product_name", + "quantity" + ], "properties": { "product_name": { "type": "string", @@ -10098,7 +10998,11 @@ }, "OrderDetailsWithAmount": { "type": "object", - "required": ["product_name", "quantity", "amount"], + "required": [ + "product_name", + "quantity", + "amount" + ], "properties": { "product_name": { "type": "string", @@ -10162,11 +11066,16 @@ }, "OrderFulfillmentTimeOrigin": { "type": "string", - "enum": ["create", "confirm"] + "enum": [ + "create", + "confirm" + ] }, "OrganizationCreateRequest": { "type": "object", - "required": ["organization_name"], + "required": [ + "organization_name" + ], "properties": { "organization_name": { "type": "string" @@ -10184,7 +11093,11 @@ }, "OrganizationResponse": { "type": "object", - "required": ["organization_id", "modified_at", "created_at"], + "required": [ + "organization_id", + "modified_at", + "created_at" + ], "properties": { "organization_id": { "type": "string", @@ -10234,7 +11147,12 @@ }, "OutgoingWebhook": { "type": "object", - "required": ["merchant_id", "event_id", "event_type", "content"], + "required": [ + "merchant_id", + "event_id", + "event_type", + "content" + ], "properties": { "merchant_id": { "type": "string", @@ -10262,11 +11180,16 @@ { "type": "object", "title": "PaymentsResponse", - "required": ["type", "object"], + "required": [ + "type", + "object" + ], "properties": { "type": { "type": "string", - "enum": ["payment_details"] + "enum": [ + "payment_details" + ] }, "object": { "$ref": "#/components/schemas/PaymentsResponse" @@ -10276,11 +11199,16 @@ { "type": "object", "title": "RefundResponse", - "required": ["type", "object"], + "required": [ + "type", + "object" + ], "properties": { "type": { "type": "string", - "enum": ["refund_details"] + "enum": [ + "refund_details" + ] }, "object": { "$ref": "#/components/schemas/RefundResponse" @@ -10290,11 +11218,16 @@ { "type": "object", "title": "DisputeResponse", - "required": ["type", "object"], + "required": [ + "type", + "object" + ], "properties": { "type": { "type": "string", - "enum": ["dispute_details"] + "enum": [ + "dispute_details" + ] }, "object": { "$ref": "#/components/schemas/DisputeResponse" @@ -10304,11 +11237,16 @@ { "type": "object", "title": "MandateResponse", - "required": ["type", "object"], + "required": [ + "type", + "object" + ], "properties": { "type": { "type": "string", - "enum": ["mandate_details"] + "enum": [ + "mandate_details" + ] }, "object": { "$ref": "#/components/schemas/MandateResponse" @@ -10318,11 +11256,16 @@ { "type": "object", "title": "PayoutCreateResponse", - "required": ["type", "object"], + "required": [ + "type", + "object" + ], "properties": { "type": { "type": "string", - "enum": ["payout_details"] + "enum": [ + "payout_details" + ] }, "object": { "$ref": "#/components/schemas/PayoutCreateResponse" @@ -10337,7 +11280,10 @@ "OutgoingWebhookRequestContent": { "type": "object", "description": "The request information (headers and body) sent in the webhook.", - "required": ["body", "headers"], + "required": [ + "body", + "headers" + ], "properties": { "body": { "type": "string", @@ -10360,8 +11306,14 @@ }, "description": "The request headers sent in the webhook.", "example": [ - ["content-type", "application/json"], - ["content-length", "1024"] + [ + "content-type", + "application/json" + ], + [ + "content-length", + "1024" + ] ] } } @@ -10392,8 +11344,14 @@ }, "description": "The response headers received for the webhook sent.", "example": [ - ["content-type", "application/json"], - ["content-length", "1024"] + [ + "content-type", + "application/json" + ], + [ + "content-length", + "1024" + ] ], "nullable": true }, @@ -10417,7 +11375,9 @@ "oneOf": [ { "type": "object", - "required": ["klarna_redirect"], + "required": [ + "klarna_redirect" + ], "properties": { "klarna_redirect": { "type": "object", @@ -10442,12 +11402,16 @@ }, { "type": "object", - "required": ["klarna_sdk"], + "required": [ + "klarna_sdk" + ], "properties": { "klarna_sdk": { "type": "object", "description": "For Klarna Sdk as PayLater Option", - "required": ["token"], + "required": [ + "token" + ], "properties": { "token": { "type": "string", @@ -10459,7 +11423,9 @@ }, { "type": "object", - "required": ["affirm_redirect"], + "required": [ + "affirm_redirect" + ], "properties": { "affirm_redirect": { "type": "object", @@ -10469,7 +11435,9 @@ }, { "type": "object", - "required": ["afterpay_clearpay_redirect"], + "required": [ + "afterpay_clearpay_redirect" + ], "properties": { "afterpay_clearpay_redirect": { "type": "object", @@ -10491,7 +11459,9 @@ }, { "type": "object", - "required": ["pay_bright_redirect"], + "required": [ + "pay_bright_redirect" + ], "properties": { "pay_bright_redirect": { "type": "object", @@ -10501,7 +11471,9 @@ }, { "type": "object", - "required": ["walley_redirect"], + "required": [ + "walley_redirect" + ], "properties": { "walley_redirect": { "type": "object", @@ -10511,7 +11483,9 @@ }, { "type": "object", - "required": ["alma_redirect"], + "required": [ + "alma_redirect" + ], "properties": { "alma_redirect": { "type": "object", @@ -10521,7 +11495,9 @@ }, { "type": "object", - "required": ["atome_redirect"], + "required": [ + "atome_redirect" + ], "properties": { "atome_redirect": { "type": "object" @@ -10532,7 +11508,9 @@ }, "PayPalWalletData": { "type": "object", - "required": ["token"], + "required": [ + "token" + ], "properties": { "token": { "type": "string", @@ -10707,7 +11685,11 @@ "PaymentChargeRequest": { "type": "object", "description": "Fee information to be charged on the payment being collected", - "required": ["charge_type", "fees", "transfer_account_id"], + "required": [ + "charge_type", + "fees", + "transfer_account_id" + ], "properties": { "charge_type": { "$ref": "#/components/schemas/PaymentChargeType" @@ -10727,7 +11709,11 @@ "PaymentChargeResponse": { "type": "object", "description": "Fee information to be charged on the payment being collected", - "required": ["charge_type", "application_fees", "transfer_account_id"], + "required": [ + "charge_type", + "application_fees", + "transfer_account_id" + ], "properties": { "charge_id": { "type": "string", @@ -10753,7 +11739,9 @@ "oneOf": [ { "type": "object", - "required": ["Stripe"], + "required": [ + "Stripe" + ], "properties": { "Stripe": { "$ref": "#/components/schemas/StripeChargeType" @@ -10902,7 +11890,10 @@ }, "PaymentLinkInitiateRequest": { "type": "object", - "required": ["merchant_id", "payment_id"], + "required": [ + "merchant_id", + "payment_id" + ], "properties": { "merchant_id": { "type": "string" @@ -10914,7 +11905,10 @@ }, "PaymentLinkResponse": { "type": "object", - "required": ["link", "payment_link_id"], + "required": [ + "link", + "payment_link_id" + ], "properties": { "link": { "type": "string", @@ -10934,11 +11928,17 @@ "PaymentLinkStatus": { "type": "string", "description": "Status Of the Payment Link", - "enum": ["active", "expired"] + "enum": [ + "active", + "expired" + ] }, "PaymentLinkTransactionDetails": { "type": "object", - "required": ["key", "value"], + "required": [ + "key", + "value" + ], "properties": { "key": { "type": "string", @@ -11033,7 +12033,10 @@ }, "PaymentListResponse": { "type": "object", - "required": ["size", "data"], + "required": [ + "size", + "data" + ], "properties": { "size": { "type": "integer", @@ -11080,7 +12083,9 @@ }, { "type": "object", - "required": ["customer_id"], + "required": [ + "customer_id" + ], "properties": { "pm_collect_link_id": { "type": "string", @@ -11127,7 +12132,12 @@ }, { "type": "object", - "required": ["pm_collect_link_id", "customer_id", "expiry", "link"], + "required": [ + "pm_collect_link_id", + "customer_id", + "expiry", + "link" + ], "properties": { "pm_collect_link_id": { "type": "string", @@ -11171,7 +12181,9 @@ }, "PaymentMethodCreate": { "type": "object", - "required": ["payment_method"], + "required": [ + "payment_method" + ], "properties": { "payment_method": { "$ref": "#/components/schemas/PaymentMethod" @@ -11269,7 +12281,9 @@ "oneOf": [ { "type": "object", - "required": ["card"], + "required": [ + "card" + ], "properties": { "card": { "$ref": "#/components/schemas/CardDetail" @@ -11283,7 +12297,9 @@ { "type": "object", "title": "Card", - "required": ["card"], + "required": [ + "card" + ], "properties": { "card": { "$ref": "#/components/schemas/Card" @@ -11293,7 +12309,9 @@ { "type": "object", "title": "CardRedirect", - "required": ["card_redirect"], + "required": [ + "card_redirect" + ], "properties": { "card_redirect": { "$ref": "#/components/schemas/CardRedirectData" @@ -11303,7 +12321,9 @@ { "type": "object", "title": "Wallet", - "required": ["wallet"], + "required": [ + "wallet" + ], "properties": { "wallet": { "$ref": "#/components/schemas/WalletData" @@ -11313,8 +12333,10 @@ { "type": "object", "title": "PayLater", - "required": ["pay_later"], - "properties": { + "required": [ + "pay_later" + ], + "properties": { "pay_later": { "$ref": "#/components/schemas/PayLaterData" } @@ -11323,7 +12345,9 @@ { "type": "object", "title": "BankRedirect", - "required": ["bank_redirect"], + "required": [ + "bank_redirect" + ], "properties": { "bank_redirect": { "$ref": "#/components/schemas/BankRedirectData" @@ -11333,7 +12357,9 @@ { "type": "object", "title": "BankDebit", - "required": ["bank_debit"], + "required": [ + "bank_debit" + ], "properties": { "bank_debit": { "$ref": "#/components/schemas/BankDebitData" @@ -11343,7 +12369,9 @@ { "type": "object", "title": "BankTransfer", - "required": ["bank_transfer"], + "required": [ + "bank_transfer" + ], "properties": { "bank_transfer": { "$ref": "#/components/schemas/BankTransferData" @@ -11353,7 +12381,9 @@ { "type": "object", "title": "RealTimePayment", - "required": ["real_time_payment"], + "required": [ + "real_time_payment" + ], "properties": { "real_time_payment": { "$ref": "#/components/schemas/RealTimePaymentData" @@ -11363,7 +12393,9 @@ { "type": "object", "title": "Crypto", - "required": ["crypto"], + "required": [ + "crypto" + ], "properties": { "crypto": { "$ref": "#/components/schemas/CryptoData" @@ -11373,17 +12405,23 @@ { "type": "string", "title": "MandatePayment", - "enum": ["mandate_payment"] + "enum": [ + "mandate_payment" + ] }, { "type": "string", "title": "Reward", - "enum": ["reward"] + "enum": [ + "reward" + ] }, { "type": "object", "title": "Upi", - "required": ["upi"], + "required": [ + "upi" + ], "properties": { "upi": { "$ref": "#/components/schemas/UpiData" @@ -11393,7 +12431,9 @@ { "type": "object", "title": "Voucher", - "required": ["voucher"], + "required": [ + "voucher" + ], "properties": { "voucher": { "$ref": "#/components/schemas/VoucherData" @@ -11403,7 +12443,9 @@ { "type": "object", "title": "GiftCard", - "required": ["gift_card"], + "required": [ + "gift_card" + ], "properties": { "gift_card": { "$ref": "#/components/schemas/GiftCardData" @@ -11413,7 +12455,9 @@ { "type": "object", "title": "CardToken", - "required": ["card_token"], + "required": [ + "card_token" + ], "properties": { "card_token": { "$ref": "#/components/schemas/CardToken" @@ -11423,7 +12467,9 @@ { "type": "object", "title": "OpenBanking", - "required": ["open_banking"], + "required": [ + "open_banking" + ], "properties": { "open_banking": { "$ref": "#/components/schemas/OpenBankingData" @@ -11462,7 +12508,9 @@ "oneOf": [ { "type": "object", - "required": ["card"], + "required": [ + "card" + ], "properties": { "card": { "$ref": "#/components/schemas/CardResponse" @@ -11471,7 +12519,9 @@ }, { "type": "object", - "required": ["bank_transfer"], + "required": [ + "bank_transfer" + ], "properties": { "bank_transfer": { "$ref": "#/components/schemas/BankTransferResponse" @@ -11480,7 +12530,9 @@ }, { "type": "object", - "required": ["wallet"], + "required": [ + "wallet" + ], "properties": { "wallet": { "$ref": "#/components/schemas/WalletResponse" @@ -11489,7 +12541,9 @@ }, { "type": "object", - "required": ["pay_later"], + "required": [ + "pay_later" + ], "properties": { "pay_later": { "$ref": "#/components/schemas/PaylaterResponse" @@ -11498,7 +12552,9 @@ }, { "type": "object", - "required": ["bank_redirect"], + "required": [ + "bank_redirect" + ], "properties": { "bank_redirect": { "$ref": "#/components/schemas/BankRedirectResponse" @@ -11507,7 +12563,9 @@ }, { "type": "object", - "required": ["crypto"], + "required": [ + "crypto" + ], "properties": { "crypto": { "$ref": "#/components/schemas/CryptoResponse" @@ -11516,7 +12574,9 @@ }, { "type": "object", - "required": ["bank_debit"], + "required": [ + "bank_debit" + ], "properties": { "bank_debit": { "$ref": "#/components/schemas/BankDebitResponse" @@ -11525,7 +12585,9 @@ }, { "type": "object", - "required": ["mandate_payment"], + "required": [ + "mandate_payment" + ], "properties": { "mandate_payment": { "type": "object" @@ -11534,7 +12596,9 @@ }, { "type": "object", - "required": ["reward"], + "required": [ + "reward" + ], "properties": { "reward": { "type": "object" @@ -11543,7 +12607,9 @@ }, { "type": "object", - "required": ["real_time_payment"], + "required": [ + "real_time_payment" + ], "properties": { "real_time_payment": { "$ref": "#/components/schemas/RealTimePaymentDataResponse" @@ -11552,7 +12618,9 @@ }, { "type": "object", - "required": ["upi"], + "required": [ + "upi" + ], "properties": { "upi": { "$ref": "#/components/schemas/UpiResponse" @@ -11561,7 +12629,9 @@ }, { "type": "object", - "required": ["voucher"], + "required": [ + "voucher" + ], "properties": { "voucher": { "$ref": "#/components/schemas/VoucherResponse" @@ -11570,7 +12640,9 @@ }, { "type": "object", - "required": ["gift_card"], + "required": [ + "gift_card" + ], "properties": { "gift_card": { "$ref": "#/components/schemas/GiftCardResponse" @@ -11579,7 +12651,9 @@ }, { "type": "object", - "required": ["card_redirect"], + "required": [ + "card_redirect" + ], "properties": { "card_redirect": { "$ref": "#/components/schemas/CardRedirectResponse" @@ -11588,7 +12662,9 @@ }, { "type": "object", - "required": ["card_token"], + "required": [ + "card_token" + ], "properties": { "card_token": { "$ref": "#/components/schemas/CardTokenResponse" @@ -11597,7 +12673,9 @@ }, { "type": "object", - "required": ["open_banking"], + "required": [ + "open_banking" + ], "properties": { "open_banking": { "$ref": "#/components/schemas/OpenBankingResponse" @@ -11633,7 +12711,10 @@ }, "PaymentMethodDeleteResponse": { "type": "object", - "required": ["payment_method_id", "deleted"], + "required": [ + "payment_method_id", + "deleted" + ], "properties": { "payment_method_id": { "type": "string", @@ -11664,7 +12745,9 @@ }, "PaymentMethodList": { "type": "object", - "required": ["payment_method"], + "required": [ + "payment_method" + ], "properties": { "payment_method": { "$ref": "#/components/schemas/PaymentMethod" @@ -11675,7 +12758,9 @@ "$ref": "#/components/schemas/PaymentMethodType" }, "description": "This is a sub-category of payment method.", - "example": ["credit"], + "example": [ + "credit" + ], "nullable": true } } @@ -11710,7 +12795,10 @@ { "payment_experience": null, "payment_method": "wallet", - "payment_method_issuers": ["labore magna ipsum", "aute"] + "payment_method_issuers": [ + "labore magna ipsum", + "aute" + ] } ] }, @@ -11817,7 +12905,9 @@ "$ref": "#/components/schemas/PaymentExperience" }, "description": "Type of payment experience enabled with the connector", - "example": ["redirect_to_url"], + "example": [ + "redirect_to_url" + ], "nullable": true }, "metadata": { @@ -11856,7 +12946,12 @@ "PaymentMethodStatus": { "type": "string", "description": "Payment Method Status", - "enum": ["active", "inactive", "processing", "awaiting_data"] + "enum": [ + "active", + "inactive", + "processing", + "awaiting_data" + ] }, "PaymentMethodType": { "type": "string", @@ -11983,7 +13078,9 @@ "PaymentMethodsEnabled": { "type": "object", "description": "Details of all the payment methods enabled for the connector for the given merchant account", - "required": ["payment_method"], + "required": [ + "payment_method" + ], "properties": { "payment_method": { "$ref": "#/components/schemas/PaymentMethod" @@ -11994,7 +13091,9 @@ "$ref": "#/components/schemas/RequestPaymentMethodTypes" }, "description": "Subtype of payment method", - "example": ["credit"], + "example": [ + "credit" + ], "nullable": true } }, @@ -12024,11 +13123,15 @@ }, { "type": "object", - "required": ["payment_processing_details_at"], + "required": [ + "payment_processing_details_at" + ], "properties": { "payment_processing_details_at": { "type": "string", - "enum": ["Hyperswitch"] + "enum": [ + "Hyperswitch" + ] } } } @@ -12036,11 +13139,15 @@ }, { "type": "object", - "required": ["payment_processing_details_at"], + "required": [ + "payment_processing_details_at" + ], "properties": { "payment_processing_details_at": { "type": "string", - "enum": ["Connector"] + "enum": [ + "Connector" + ] } } } @@ -12082,7 +13189,12 @@ "PaymentType": { "type": "string", "description": "The type of the payment that differentiates between normal and various types of mandate payments. Use 'setup_mandate' in case of zero auth flow.", - "enum": ["normal", "new_mandate", "setup_mandate", "recurring_mandate"] + "enum": [ + "normal", + "new_mandate", + "setup_mandate", + "recurring_mandate" + ] }, "PaymentsCancelRequest": { "type": "object", @@ -12104,7 +13216,9 @@ }, "PaymentsCaptureRequest": { "type": "object", - "required": ["amount_to_capture"], + "required": [ + "amount_to_capture" + ], "properties": { "merchant_id": { "type": "string", @@ -12144,7 +13258,9 @@ }, "PaymentsCompleteAuthorizeRequest": { "type": "object", - "required": ["client_secret"], + "required": [ + "client_secret" + ], "properties": { "shipping": { "allOf": [ @@ -12303,7 +13419,9 @@ }, "PaymentsCreateIntentRequest": { "type": "object", - "required": ["amount_details"], + "required": [ + "amount_details" + ], "properties": { "amount_details": { "$ref": "#/components/schemas/AmountDetails" @@ -13032,7 +14150,11 @@ }, "PaymentsDynamicTaxCalculationRequest": { "type": "object", - "required": ["shipping", "client_secret", "payment_method_type"], + "required": [ + "shipping", + "client_secret", + "payment_method_type" + ], "properties": { "shipping": { "$ref": "#/components/schemas/Address" @@ -13053,7 +14175,11 @@ }, "PaymentsDynamicTaxCalculationResponse": { "type": "object", - "required": ["payment_id", "net_amount", "display_amount"], + "required": [ + "payment_id", + "net_amount", + "display_amount" + ], "properties": { "payment_id": { "type": "string", @@ -13113,7 +14239,10 @@ }, "PaymentsExternalAuthenticationResponse": { "type": "object", - "required": ["trans_status", "three_ds_requestor_url"], + "required": [ + "trans_status", + "three_ds_requestor_url" + ], "properties": { "trans_status": { "$ref": "#/components/schemas/TransactionStatus" @@ -13156,7 +14285,9 @@ }, "PaymentsIncrementalAuthorizationRequest": { "type": "object", - "required": ["amount"], + "required": [ + "amount" + ], "properties": { "amount": { "type": "integer", @@ -13175,6 +14306,7 @@ "type": "object", "required": [ "id", + "status", "amount_details", "client_secret", "capture_method", @@ -13192,6 +14324,9 @@ "type": "string", "description": "Global Payment Id for the payment" }, + "status": { + "$ref": "#/components/schemas/IntentStatus" + }, "amount_details": { "$ref": "#/components/schemas/AmountDetailsResponse" }, @@ -13923,7 +15058,11 @@ }, "PaymentsSessionResponse": { "type": "object", - "required": ["payment_id", "client_secret", "session_token"], + "required": [ + "payment_id", + "client_secret", + "session_token" + ], "properties": { "payment_id": { "type": "string", @@ -13947,7 +15086,11 @@ }, "PayoutAttemptResponse": { "type": "object", - "required": ["attempt_id", "status", "amount"], + "required": [ + "attempt_id", + "status", + "amount" + ], "properties": { "attempt_id": { "type": "string", @@ -14135,7 +15278,10 @@ "$ref": "#/components/schemas/PayoutConnectors" }, "description": "This field allows the merchant to manually select a connector with which the payout can go through.", - "example": ["wise", "adyen"], + "example": [ + "wise", + "adyen" + ], "nullable": true }, "confirm": { @@ -14575,7 +15721,10 @@ }, "PayoutLinkInitiateRequest": { "type": "object", - "required": ["merchant_id", "payout_id"], + "required": [ + "merchant_id", + "payout_id" + ], "properties": { "merchant_id": { "type": "string" @@ -14587,7 +15736,10 @@ }, "PayoutLinkResponse": { "type": "object", - "required": ["payout_link_id", "link"], + "required": [ + "payout_link_id", + "link" + ], "properties": { "payout_link_id": { "type": "string" @@ -14659,7 +15811,10 @@ }, { "type": "object", - "required": ["currency", "entity_type"], + "required": [ + "currency", + "entity_type" + ], "properties": { "payout_id": { "type": "string", @@ -14699,7 +15854,10 @@ "$ref": "#/components/schemas/PayoutConnectors" }, "description": "The list of connectors to filter payouts list", - "example": ["wise", "adyen"], + "example": [ + "wise", + "adyen" + ], "nullable": true }, "currency": { @@ -14711,7 +15869,10 @@ "$ref": "#/components/schemas/PayoutStatus" }, "description": "The list of payout status to filter payouts list", - "example": ["pending", "failed"], + "example": [ + "pending", + "failed" + ], "nullable": true }, "payout_method": { @@ -14720,7 +15881,10 @@ "$ref": "#/components/schemas/PayoutType" }, "description": "The list of payout methods to filter payouts list", - "example": ["bank", "card"], + "example": [ + "bank", + "card" + ], "nullable": true }, "entity_type": { @@ -14732,7 +15896,10 @@ }, "PayoutListResponse": { "type": "object", - "required": ["size", "data"], + "required": [ + "size", + "data" + ], "properties": { "size": { "type": "integer", @@ -14758,7 +15925,9 @@ "oneOf": [ { "type": "object", - "required": ["card"], + "required": [ + "card" + ], "properties": { "card": { "$ref": "#/components/schemas/CardPayout" @@ -14767,7 +15936,9 @@ }, { "type": "object", - "required": ["bank"], + "required": [ + "bank" + ], "properties": { "bank": { "$ref": "#/components/schemas/Bank" @@ -14776,7 +15947,9 @@ }, { "type": "object", - "required": ["wallet"], + "required": [ + "wallet" + ], "properties": { "wallet": { "$ref": "#/components/schemas/Wallet" @@ -14790,7 +15963,9 @@ "oneOf": [ { "type": "object", - "required": ["card"], + "required": [ + "card" + ], "properties": { "card": { "$ref": "#/components/schemas/CardAdditionalData" @@ -14799,7 +15974,9 @@ }, { "type": "object", - "required": ["bank"], + "required": [ + "bank" + ], "properties": { "bank": { "$ref": "#/components/schemas/BankAdditionalData" @@ -14808,7 +15985,9 @@ }, { "type": "object", - "required": ["wallet"], + "required": [ + "wallet" + ], "properties": { "wallet": { "$ref": "#/components/schemas/WalletAdditionalData" @@ -14822,7 +16001,9 @@ "oneOf": [ { "type": "object", - "required": ["PayoutActionRequest"], + "required": [ + "PayoutActionRequest" + ], "properties": { "PayoutActionRequest": { "$ref": "#/components/schemas/PayoutActionRequest" @@ -14831,7 +16012,9 @@ }, { "type": "object", - "required": ["PayoutCreateRequest"], + "required": [ + "PayoutCreateRequest" + ], "properties": { "PayoutCreateRequest": { "$ref": "#/components/schemas/PayoutCreateRequest" @@ -14840,7 +16023,9 @@ }, { "type": "object", - "required": ["PayoutRetrieveRequest"], + "required": [ + "PayoutRetrieveRequest" + ], "properties": { "PayoutRetrieveRequest": { "$ref": "#/components/schemas/PayoutRetrieveRequest" @@ -14864,7 +16049,9 @@ }, "PayoutRetrieveRequest": { "type": "object", - "required": ["payout_id"], + "required": [ + "payout_id" + ], "properties": { "payout_id": { "type": "string", @@ -14920,11 +16107,19 @@ "PayoutType": { "type": "string", "description": "The payout_type of the payout request is a mandatory field for confirming the payouts. It should be specified in the Create request. If not provided, it must be updated in the Payout Update request before it can be confirmed.", - "enum": ["card", "bank", "wallet"] + "enum": [ + "card", + "bank", + "wallet" + ] }, "Paypal": { "type": "object", - "required": ["email", "telephone_number", "paypal_id"], + "required": [ + "email", + "telephone_number", + "paypal_id" + ], "properties": { "email": { "type": "string", @@ -14981,7 +16176,11 @@ }, "PaypalSessionTokenResponse": { "type": "object", - "required": ["connector", "session_token", "sdk_next_action"], + "required": [ + "connector", + "session_token", + "sdk_next_action" + ], "properties": { "connector": { "type": "string", @@ -15037,7 +16236,9 @@ }, "PazeWalletData": { "type": "object", - "required": ["complete_response"], + "required": [ + "complete_response" + ], "properties": { "complete_response": { "type": "string" @@ -15063,7 +16264,10 @@ }, "PixBankTransfer": { "type": "object", - "required": ["bank_account_number", "pix_key"], + "required": [ + "bank_account_number", + "pix_key" + ], "properties": { "bank_name": { "type": "string", @@ -15120,7 +16324,11 @@ }, "PollConfigResponse": { "type": "object", - "required": ["poll_id", "delay_in_secs", "frequency"], + "required": [ + "poll_id", + "delay_in_secs", + "frequency" + ], "properties": { "poll_id": { "type": "string", @@ -15140,7 +16348,10 @@ }, "PollResponse": { "type": "object", - "required": ["poll_id", "status"], + "required": [ + "poll_id", + "status" + ], "properties": { "poll_id": { "type": "string", @@ -15153,16 +16364,26 @@ }, "PollStatus": { "type": "string", - "enum": ["pending", "completed", "not_found"] + "enum": [ + "pending", + "completed", + "not_found" + ] }, "PresenceOfCustomerDuringPayment": { "type": "string", "description": "Set to true to indicate that the customer is in your checkout flow during this payment, and therefore is able to authenticate. This parameter should be false when merchant's doing merchant initiated payments and customer is not present while doing the payment.", - "enum": ["Present", "Absent"] + "enum": [ + "Present", + "Absent" + ] }, "PrimaryBusinessDetails": { "type": "object", - "required": ["country", "business"], + "required": [ + "country", + "business" + ], "properties": { "country": { "$ref": "#/components/schemas/CountryAlpha2" @@ -15177,7 +16398,9 @@ "ProcessorPaymentToken": { "type": "object", "description": "Processor payment token for MIT payments where payment_method_data is not available", - "required": ["processor_payment_token"], + "required": [ + "processor_payment_token" + ], "properties": { "processor_payment_token": { "type": "string" @@ -15201,7 +16424,9 @@ }, "ProfileCreate": { "type": "object", - "required": ["profile_name"], + "required": [ + "profile_name" + ], "properties": { "profile_name": { "type": "string", @@ -15364,7 +16589,10 @@ }, "ProfileDefaultRoutingConfig": { "type": "object", - "required": ["profile_id", "connectors"], + "required": [ + "profile_id", + "connectors" + ], "properties": { "profile_id": { "type": "string" @@ -15568,7 +16796,11 @@ "ProgramConnectorSelection": { "type": "object", "description": "The program, having a default connector selection and\na bunch of rules. Also can hold arbitrary metadata.", - "required": ["defaultSelection", "rules", "metadata"], + "required": [ + "defaultSelection", + "rules", + "metadata" + ], "properties": { "defaultSelection": { "$ref": "#/components/schemas/ConnectorSelection" @@ -15586,7 +16818,9 @@ "oneOf": [ { "type": "object", - "required": ["fps"], + "required": [ + "fps" + ], "properties": { "fps": { "type": "object" @@ -15595,7 +16829,9 @@ }, { "type": "object", - "required": ["duit_now"], + "required": [ + "duit_now" + ], "properties": { "duit_now": { "type": "object" @@ -15604,7 +16840,9 @@ }, { "type": "object", - "required": ["prompt_pay"], + "required": [ + "prompt_pay" + ], "properties": { "prompt_pay": { "type": "object" @@ -15613,7 +16851,9 @@ }, { "type": "object", - "required": ["viet_qr"], + "required": [ + "viet_qr" + ], "properties": { "viet_qr": { "type": "object" @@ -15639,7 +16879,9 @@ }, "ReceiverDetails": { "type": "object", - "required": ["amount_received"], + "required": [ + "amount_received" + ], "properties": { "amount_received": { "type": "integer", @@ -15662,17 +16904,27 @@ }, "ReconStatus": { "type": "string", - "enum": ["not_requested", "requested", "active", "disabled"] + "enum": [ + "not_requested", + "requested", + "active", + "disabled" + ] }, "RecurringDetails": { "oneOf": [ { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["mandate_id"] + "enum": [ + "mandate_id" + ] }, "data": { "type": "string" @@ -15681,11 +16933,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["payment_method_id"] + "enum": [ + "payment_method_id" + ] }, "data": { "type": "string" @@ -15694,11 +16951,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["processor_payment_token"] + "enum": [ + "processor_payment_token" + ] }, "data": { "$ref": "#/components/schemas/ProcessorPaymentToken" @@ -15707,11 +16969,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["network_transaction_id_and_card_details"] + "enum": [ + "network_transaction_id_and_card_details" + ] }, "data": { "$ref": "#/components/schemas/NetworkTransactionIdAndCardDetails" @@ -15739,7 +17006,9 @@ }, "RefundAggregateResponse": { "type": "object", - "required": ["status_with_count"], + "required": [ + "status_with_count" + ], "properties": { "status_with_count": { "type": "object", @@ -15753,7 +17022,10 @@ }, "RefundErrorDetails": { "type": "object", - "required": ["code", "message"], + "required": [ + "code", + "message" + ], "properties": { "code": { "type": "string" @@ -15849,7 +17121,11 @@ }, "RefundListResponse": { "type": "object", - "required": ["count", "total_count", "data"], + "required": [ + "count", + "total_count", + "data" + ], "properties": { "count": { "type": "integer", @@ -15872,7 +17148,9 @@ }, "RefundRequest": { "type": "object", - "required": ["payment_id"], + "required": [ + "payment_id" + ], "properties": { "payment_id": { "type": "string", @@ -16037,12 +17315,20 @@ "RefundStatus": { "type": "string", "description": "The status for refunds", - "enum": ["succeeded", "failed", "pending", "review"] + "enum": [ + "succeeded", + "failed", + "pending", + "review" + ] }, "RefundType": { "type": "string", "description": "To indicate whether to refund needs to be instant or scheduled", - "enum": ["scheduled", "instant"] + "enum": [ + "scheduled", + "instant" + ] }, "RefundUpdateRequest": { "type": "object", @@ -16064,7 +17350,9 @@ }, "RefundsCreateRequest": { "type": "object", - "required": ["payment_id"], + "required": [ + "payment_id" + ], "properties": { "payment_id": { "type": "string", @@ -16115,7 +17403,11 @@ }, "RequestIncrementalAuthorization": { "type": "string", - "enum": ["true", "false", "default"] + "enum": [ + "true", + "false", + "default" + ] }, "RequestPaymentMethodTypes": { "type": "object", @@ -16192,7 +17484,9 @@ "RequestSurchargeDetails": { "type": "object", "description": "Details of surcharge applied on this payment, if applicable", - "required": ["surcharge_amount"], + "required": [ + "surcharge_amount" + ], "properties": { "surcharge_amount": { "type": "integer", @@ -16212,7 +17506,11 @@ "RequiredFieldInfo": { "type": "object", "description": "Required fields info used while listing the payment_method_data", - "required": ["required_field", "display_name", "field_type"], + "required": [ + "required_field", + "display_name", + "field_type" + ], "properties": { "required_field": { "type": "string", @@ -16360,12 +17658,19 @@ "RetryAction": { "type": "string", "description": "Denotes the retry action", - "enum": ["manual_retry", "requeue"] + "enum": [ + "manual_retry", + "requeue" + ] }, "RevokeApiKeyResponse": { "type": "object", "description": "The response body for revoking an API Key.", - "required": ["merchant_id", "key_id", "revoked"], + "required": [ + "merchant_id", + "key_id", + "revoked" + ], "properties": { "merchant_id": { "type": "string", @@ -16388,7 +17693,9 @@ }, "RewardData": { "type": "object", - "required": ["merchant_id"], + "required": [ + "merchant_id" + ], "properties": { "merchant_id": { "type": "string", @@ -16398,12 +17705,17 @@ }, "RoutableChoiceKind": { "type": "string", - "enum": ["OnlyConnector", "FullStruct"] + "enum": [ + "OnlyConnector", + "FullStruct" + ] }, "RoutableConnectorChoice": { "type": "object", "description": "Routable Connector chosen for a payment", - "required": ["connector"], + "required": [ + "connector" + ], "properties": { "connector": { "$ref": "#/components/schemas/RoutableConnectors" @@ -16500,11 +17812,16 @@ "oneOf": [ { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["single"] + "enum": [ + "single" + ] }, "data": { "$ref": "#/components/schemas/RoutableConnectorChoice" @@ -16513,11 +17830,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["priority"] + "enum": [ + "priority" + ] }, "data": { "type": "array", @@ -16529,11 +17851,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["volume_split"] + "enum": [ + "volume_split" + ] }, "data": { "type": "array", @@ -16545,11 +17872,16 @@ }, { "type": "object", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["advanced"] + "enum": [ + "advanced" + ] }, "data": { "$ref": "#/components/schemas/ProgramConnectorSelection" @@ -16564,7 +17896,9 @@ }, "RoutingAlgorithmId": { "type": "object", - "required": ["routing_algorithm_id"], + "required": [ + "routing_algorithm_id" + ], "properties": { "routing_algorithm_id": { "type": "string" @@ -16573,11 +17907,22 @@ }, "RoutingAlgorithmKind": { "type": "string", - "enum": ["single", "priority", "volume_split", "advanced", "dynamic"] + "enum": [ + "single", + "priority", + "volume_split", + "advanced", + "dynamic" + ] }, "RoutingConfigRequest": { "type": "object", - "required": ["name", "description", "algorithm", "profile_id"], + "required": [ + "name", + "description", + "algorithm", + "profile_id" + ], "properties": { "name": { "type": "string" @@ -16595,7 +17940,10 @@ }, "RoutingDictionary": { "type": "object", - "required": ["merchant_id", "records"], + "required": [ + "merchant_id", + "records" + ], "properties": { "merchant_id": { "type": "string" @@ -16687,7 +18035,11 @@ "RuleConnectorSelection": { "type": "object", "description": "Represents a rule\n\n```text\nrule_name: [stripe, adyen, checkout]\n{\npayment.method = card {\npayment.method.cardtype = (credit, debit) {\npayment.method.network = (amex, rupay, diners)\n}\n\npayment.method.cardtype = credit\n}\n}\n```", - "required": ["name", "connectorSelection", "statements"], + "required": [ + "name", + "connectorSelection", + "statements" + ], "properties": { "name": { "type": "string" @@ -16705,7 +18057,11 @@ }, "SamsungPayAmountDetails": { "type": "object", - "required": ["option", "currency_code", "total"], + "required": [ + "option", + "currency_code", + "total" + ], "properties": { "option": { "$ref": "#/components/schemas/SamsungPayAmountFormat" @@ -16722,7 +18078,10 @@ }, "SamsungPayAmountFormat": { "type": "string", - "enum": ["FORMAT_TOTAL_PRICE_ONLY", "FORMAT_TOTAL_ESTIMATED_AMOUNT"] + "enum": [ + "FORMAT_TOTAL_PRICE_ONLY", + "FORMAT_TOTAL_ESTIMATED_AMOUNT" + ] }, "SamsungPayAppWalletData": { "type": "object", @@ -16771,11 +18130,20 @@ }, "SamsungPayCardBrand": { "type": "string", - "enum": ["visa", "mastercard", "amex", "discover", "unknown"] + "enum": [ + "visa", + "mastercard", + "amex", + "discover", + "unknown" + ] }, "SamsungPayMerchantPaymentInformation": { "type": "object", - "required": ["name", "country_code"], + "required": [ + "name", + "country_code" + ], "properties": { "name": { "type": "string", @@ -16793,7 +18161,9 @@ }, "SamsungPayProtocolType": { "type": "string", - "enum": ["PROTOCOL3DS"] + "enum": [ + "PROTOCOL3DS" + ] }, "SamsungPaySessionTokenResponse": { "type": "object", @@ -16839,7 +18209,10 @@ }, "SamsungPayTokenData": { "type": "object", - "required": ["version", "data"], + "required": [ + "version", + "data" + ], "properties": { "type": { "type": "string", @@ -16868,7 +18241,9 @@ }, "SamsungPayWalletData": { "type": "object", - "required": ["payment_credential"], + "required": [ + "payment_credential" + ], "properties": { "payment_credential": { "$ref": "#/components/schemas/SamsungPayWalletCredentials" @@ -16877,7 +18252,11 @@ }, "SamsungPayWebWalletData": { "type": "object", - "required": ["card_brand", "card_last4digits", "3_d_s"], + "required": [ + "card_brand", + "card_last4digits", + "3_d_s" + ], "properties": { "method": { "type": "string", @@ -16946,7 +18325,9 @@ }, "SdkNextAction": { "type": "object", - "required": ["next_action"], + "required": [ + "next_action" + ], "properties": { "next_action": { "$ref": "#/components/schemas/NextActionCall" @@ -16955,7 +18336,9 @@ }, "SdkNextActionData": { "type": "object", - "required": ["next_action"], + "required": [ + "next_action" + ], "properties": { "next_action": { "$ref": "#/components/schemas/NextActionCall" @@ -16968,7 +18351,10 @@ }, "SecretInfoToInitiateSdk": { "type": "object", - "required": ["display", "payment"], + "required": [ + "display", + "payment" + ], "properties": { "display": { "type": "string" @@ -16997,7 +18383,9 @@ }, "SepaBankDebitAdditionalData": { "type": "object", - "required": ["iban"], + "required": [ + "iban" + ], "properties": { "iban": { "type": "string", @@ -17014,7 +18402,10 @@ }, "SepaBankTransfer": { "type": "object", - "required": ["iban", "bic"], + "required": [ + "iban", + "bic" + ], "properties": { "bank_name": { "type": "string", @@ -17051,7 +18442,9 @@ "SepaBankTransferAdditionalData": { "type": "object", "description": "Masked payout method details for sepa bank transfer payout method", - "required": ["iban"], + "required": [ + "iban" + ], "properties": { "iban": { "type": "string", @@ -17126,11 +18519,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["google_pay"] + "enum": [ + "google_pay" + ] } } } @@ -17143,11 +18540,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["samsung_pay"] + "enum": [ + "samsung_pay" + ] } } } @@ -17160,11 +18561,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["klarna"] + "enum": [ + "klarna" + ] } } } @@ -17177,11 +18582,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["paypal"] + "enum": [ + "paypal" + ] } } } @@ -17194,11 +18603,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["apple_pay"] + "enum": [ + "apple_pay" + ] } } } @@ -17211,11 +18624,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["open_banking"] + "enum": [ + "open_banking" + ] } } } @@ -17228,11 +18645,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["paze"] + "enum": [ + "paze" + ] } } } @@ -17240,11 +18661,15 @@ }, { "type": "object", - "required": ["wallet_name"], + "required": [ + "wallet_name" + ], "properties": { "wallet_name": { "type": "string", - "enum": ["no_session_token_received"] + "enum": [ + "no_session_token_received" + ] } } } @@ -17309,11 +18734,16 @@ { "type": "object", "title": "Single", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["single"] + "enum": [ + "single" + ] }, "data": { "$ref": "#/components/schemas/RoutableConnectorChoice" @@ -17323,11 +18753,16 @@ { "type": "object", "title": "Priority", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["priority"] + "enum": [ + "priority" + ] }, "data": { "type": "array", @@ -17340,11 +18775,16 @@ { "type": "object", "title": "VolumeSplit", - "required": ["type", "data"], + "required": [ + "type", + "data" + ], "properties": { "type": { "type": "string", - "enum": ["volume_split"] + "enum": [ + "volume_split" + ] }, "data": { "type": "array", @@ -17361,11 +18801,17 @@ }, "StripeChargeType": { "type": "string", - "enum": ["direct", "destination"] + "enum": [ + "direct", + "destination" + ] }, "SurchargeCalculationOverride": { "type": "string", - "enum": ["Skip", "Calculate"] + "enum": [ + "Skip", + "Calculate" + ] }, "SurchargeDetailsResponse": { "type": "object", @@ -17406,7 +18852,9 @@ }, "SurchargePercentage": { "type": "object", - "required": ["percentage"], + "required": [ + "percentage" + ], "properties": { "percentage": { "type": "number", @@ -17418,11 +18866,16 @@ "oneOf": [ { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["fixed"] + "enum": [ + "fixed" + ] }, "value": { "$ref": "#/components/schemas/MinorUnit" @@ -17431,11 +18884,16 @@ }, { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["rate"] + "enum": [ + "rate" + ] }, "value": { "$ref": "#/components/schemas/SurchargePercentage" @@ -17452,11 +18910,16 @@ }, "TaxCalculationOverride": { "type": "string", - "enum": ["Skip", "Calculate"] + "enum": [ + "Skip", + "Calculate" + ] }, "ThirdPartySdkSessionResponse": { "type": "object", - "required": ["secrets"], + "required": [ + "secrets" + ], "properties": { "secrets": { "$ref": "#/components/schemas/SecretInfoToInitiateSdk" @@ -17465,7 +18928,11 @@ }, "ThreeDsCompletionIndicator": { "type": "string", - "enum": ["Y", "N", "U"] + "enum": [ + "Y", + "N", + "U" + ] }, "ThreeDsData": { "type": "object", @@ -17527,7 +18994,9 @@ }, "three_ds_method_key": { "type": "string", - "enum": ["threeDSMethodData"] + "enum": [ + "threeDSMethodData" + ] } } } @@ -17539,7 +19008,9 @@ "TimeRange": { "type": "object", "description": "A type representing a range of time for filtering, including a mandatory start time and an optional end time.", - "required": ["start_time"], + "required": [ + "start_time" + ], "properties": { "start_time": { "type": "string", @@ -17556,7 +19027,9 @@ }, "ToggleBlocklistResponse": { "type": "object", - "required": ["blocklist_guard_status"], + "required": [ + "blocklist_guard_status" + ], "properties": { "blocklist_guard_status": { "type": "string" @@ -17565,7 +19038,9 @@ }, "ToggleKVRequest": { "type": "object", - "required": ["kv_enabled"], + "required": [ + "kv_enabled" + ], "properties": { "kv_enabled": { "type": "boolean", @@ -17576,7 +19051,10 @@ }, "ToggleKVResponse": { "type": "object", - "required": ["merchant_id", "kv_enabled"], + "required": [ + "merchant_id", + "kv_enabled" + ], "properties": { "merchant_id": { "type": "string", @@ -17623,15 +19101,30 @@ "TransactionStatus": { "type": "string", "description": "Indicates the transaction status", - "enum": ["Y", "N", "U", "A", "R", "C", "D", "I"] + "enum": [ + "Y", + "N", + "U", + "A", + "R", + "C", + "D", + "I" + ] }, "TransactionType": { "type": "string", - "enum": ["payment", "payout"] + "enum": [ + "payment", + "payout" + ] }, "UIWidgetFormLayout": { "type": "string", - "enum": ["tabs", "journey"] + "enum": [ + "tabs", + "journey" + ] }, "UpdateApiKeyRequest": { "type": "object", @@ -17666,7 +19159,9 @@ "oneOf": [ { "type": "object", - "required": ["upi_collect"], + "required": [ + "upi_collect" + ], "properties": { "upi_collect": { "$ref": "#/components/schemas/UpiCollectAdditionalData" @@ -17675,7 +19170,9 @@ }, { "type": "object", - "required": ["upi_intent"], + "required": [ + "upi_intent" + ], "properties": { "upi_intent": { "$ref": "#/components/schemas/UpiIntentData" @@ -17709,7 +19206,9 @@ "oneOf": [ { "type": "object", - "required": ["upi_collect"], + "required": [ + "upi_collect" + ], "properties": { "upi_collect": { "$ref": "#/components/schemas/UpiCollectData" @@ -17718,7 +19217,9 @@ }, { "type": "object", - "required": ["upi_intent"], + "required": [ + "upi_intent" + ], "properties": { "upi_intent": { "$ref": "#/components/schemas/UpiIntentData" @@ -17749,11 +19250,16 @@ "oneOf": [ { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["number"] + "enum": [ + "number" + ] }, "value": { "$ref": "#/components/schemas/MinorUnit" @@ -17762,11 +19268,16 @@ }, { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["enum_variant"] + "enum": [ + "enum_variant" + ] }, "value": { "type": "string", @@ -17776,11 +19287,16 @@ }, { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["metadata_variant"] + "enum": [ + "metadata_variant" + ] }, "value": { "$ref": "#/components/schemas/MetadataValue" @@ -17789,11 +19305,16 @@ }, { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["str_value"] + "enum": [ + "str_value" + ] }, "value": { "type": "string", @@ -17803,11 +19324,16 @@ }, { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["number_array"] + "enum": [ + "number_array" + ] }, "value": { "type": "array", @@ -17820,11 +19346,16 @@ }, { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["enum_variant_array"] + "enum": [ + "enum_variant_array" + ] }, "value": { "type": "array", @@ -17837,11 +19368,16 @@ }, { "type": "object", - "required": ["type", "value"], + "required": [ + "type", + "value" + ], "properties": { "type": { "type": "string", - "enum": ["number_comparison_array"] + "enum": [ + "number_comparison_array" + ] }, "value": { "type": "array", @@ -17860,7 +19396,9 @@ }, "Venmo": { "type": "object", - "required": ["telephone_number"], + "required": [ + "telephone_number" + ], "properties": { "telephone_number": { "type": "string", @@ -17885,7 +19423,9 @@ "oneOf": [ { "type": "object", - "required": ["boleto"], + "required": [ + "boleto" + ], "properties": { "boleto": { "$ref": "#/components/schemas/BoletoVoucherData" @@ -17894,23 +19434,33 @@ }, { "type": "string", - "enum": ["efecty"] + "enum": [ + "efecty" + ] }, { "type": "string", - "enum": ["pago_efectivo"] + "enum": [ + "pago_efectivo" + ] }, { "type": "string", - "enum": ["red_compra"] + "enum": [ + "red_compra" + ] }, { "type": "string", - "enum": ["red_pagos"] + "enum": [ + "red_pagos" + ] }, { "type": "object", - "required": ["alfamart"], + "required": [ + "alfamart" + ], "properties": { "alfamart": { "$ref": "#/components/schemas/AlfamartVoucherData" @@ -17919,7 +19469,9 @@ }, { "type": "object", - "required": ["indomaret"], + "required": [ + "indomaret" + ], "properties": { "indomaret": { "$ref": "#/components/schemas/IndomaretVoucherData" @@ -17928,11 +19480,15 @@ }, { "type": "string", - "enum": ["oxxo"] + "enum": [ + "oxxo" + ] }, { "type": "object", - "required": ["seven_eleven"], + "required": [ + "seven_eleven" + ], "properties": { "seven_eleven": { "$ref": "#/components/schemas/JCSVoucherData" @@ -17941,7 +19497,9 @@ }, { "type": "object", - "required": ["lawson"], + "required": [ + "lawson" + ], "properties": { "lawson": { "$ref": "#/components/schemas/JCSVoucherData" @@ -17950,7 +19508,9 @@ }, { "type": "object", - "required": ["mini_stop"], + "required": [ + "mini_stop" + ], "properties": { "mini_stop": { "$ref": "#/components/schemas/JCSVoucherData" @@ -17959,7 +19519,9 @@ }, { "type": "object", - "required": ["family_mart"], + "required": [ + "family_mart" + ], "properties": { "family_mart": { "$ref": "#/components/schemas/JCSVoucherData" @@ -17968,7 +19530,9 @@ }, { "type": "object", - "required": ["seicomart"], + "required": [ + "seicomart" + ], "properties": { "seicomart": { "$ref": "#/components/schemas/JCSVoucherData" @@ -17977,7 +19541,9 @@ }, { "type": "object", - "required": ["pay_easy"], + "required": [ + "pay_easy" + ], "properties": { "pay_easy": { "$ref": "#/components/schemas/JCSVoucherData" @@ -18005,7 +19571,9 @@ "oneOf": [ { "type": "object", - "required": ["paypal"], + "required": [ + "paypal" + ], "properties": { "paypal": { "$ref": "#/components/schemas/Paypal" @@ -18014,7 +19582,9 @@ }, { "type": "object", - "required": ["venmo"], + "required": [ + "venmo" + ], "properties": { "venmo": { "$ref": "#/components/schemas/Venmo" @@ -18036,7 +19606,11 @@ }, "WalletAdditionalDataForCard": { "type": "object", - "required": ["last4", "card_network", "type"], + "required": [ + "last4", + "card_network", + "type" + ], "properties": { "last4": { "type": "string", @@ -18056,7 +19630,9 @@ "oneOf": [ { "type": "object", - "required": ["ali_pay_qr"], + "required": [ + "ali_pay_qr" + ], "properties": { "ali_pay_qr": { "$ref": "#/components/schemas/AliPayQr" @@ -18065,7 +19641,9 @@ }, { "type": "object", - "required": ["ali_pay_redirect"], + "required": [ + "ali_pay_redirect" + ], "properties": { "ali_pay_redirect": { "$ref": "#/components/schemas/AliPayRedirection" @@ -18074,7 +19652,9 @@ }, { "type": "object", - "required": ["ali_pay_hk_redirect"], + "required": [ + "ali_pay_hk_redirect" + ], "properties": { "ali_pay_hk_redirect": { "$ref": "#/components/schemas/AliPayHkRedirection" @@ -18083,7 +19663,9 @@ }, { "type": "object", - "required": ["momo_redirect"], + "required": [ + "momo_redirect" + ], "properties": { "momo_redirect": { "$ref": "#/components/schemas/MomoRedirection" @@ -18092,7 +19674,9 @@ }, { "type": "object", - "required": ["kakao_pay_redirect"], + "required": [ + "kakao_pay_redirect" + ], "properties": { "kakao_pay_redirect": { "$ref": "#/components/schemas/KakaoPayRedirection" @@ -18101,7 +19685,9 @@ }, { "type": "object", - "required": ["go_pay_redirect"], + "required": [ + "go_pay_redirect" + ], "properties": { "go_pay_redirect": { "$ref": "#/components/schemas/GoPayRedirection" @@ -18110,7 +19696,9 @@ }, { "type": "object", - "required": ["gcash_redirect"], + "required": [ + "gcash_redirect" + ], "properties": { "gcash_redirect": { "$ref": "#/components/schemas/GcashRedirection" @@ -18119,7 +19707,9 @@ }, { "type": "object", - "required": ["apple_pay"], + "required": [ + "apple_pay" + ], "properties": { "apple_pay": { "$ref": "#/components/schemas/ApplePayWalletData" @@ -18128,7 +19718,9 @@ }, { "type": "object", - "required": ["apple_pay_redirect"], + "required": [ + "apple_pay_redirect" + ], "properties": { "apple_pay_redirect": { "$ref": "#/components/schemas/ApplePayRedirectData" @@ -18137,7 +19729,9 @@ }, { "type": "object", - "required": ["apple_pay_third_party_sdk"], + "required": [ + "apple_pay_third_party_sdk" + ], "properties": { "apple_pay_third_party_sdk": { "$ref": "#/components/schemas/ApplePayThirdPartySdkData" @@ -18146,7 +19740,9 @@ }, { "type": "object", - "required": ["dana_redirect"], + "required": [ + "dana_redirect" + ], "properties": { "dana_redirect": { "type": "object", @@ -18156,7 +19752,9 @@ }, { "type": "object", - "required": ["google_pay"], + "required": [ + "google_pay" + ], "properties": { "google_pay": { "$ref": "#/components/schemas/GooglePayWalletData" @@ -18165,7 +19763,9 @@ }, { "type": "object", - "required": ["google_pay_redirect"], + "required": [ + "google_pay_redirect" + ], "properties": { "google_pay_redirect": { "$ref": "#/components/schemas/GooglePayRedirectData" @@ -18174,7 +19774,9 @@ }, { "type": "object", - "required": ["google_pay_third_party_sdk"], + "required": [ + "google_pay_third_party_sdk" + ], "properties": { "google_pay_third_party_sdk": { "$ref": "#/components/schemas/GooglePayThirdPartySdkData" @@ -18183,7 +19785,9 @@ }, { "type": "object", - "required": ["mb_way_redirect"], + "required": [ + "mb_way_redirect" + ], "properties": { "mb_way_redirect": { "$ref": "#/components/schemas/MbWayRedirection" @@ -18192,7 +19796,9 @@ }, { "type": "object", - "required": ["mobile_pay_redirect"], + "required": [ + "mobile_pay_redirect" + ], "properties": { "mobile_pay_redirect": { "$ref": "#/components/schemas/MobilePayRedirection" @@ -18201,7 +19807,9 @@ }, { "type": "object", - "required": ["paypal_redirect"], + "required": [ + "paypal_redirect" + ], "properties": { "paypal_redirect": { "$ref": "#/components/schemas/PaypalRedirection" @@ -18210,7 +19818,9 @@ }, { "type": "object", - "required": ["paypal_sdk"], + "required": [ + "paypal_sdk" + ], "properties": { "paypal_sdk": { "$ref": "#/components/schemas/PayPalWalletData" @@ -18219,7 +19829,9 @@ }, { "type": "object", - "required": ["paze"], + "required": [ + "paze" + ], "properties": { "paze": { "$ref": "#/components/schemas/PazeWalletData" @@ -18228,7 +19840,9 @@ }, { "type": "object", - "required": ["samsung_pay"], + "required": [ + "samsung_pay" + ], "properties": { "samsung_pay": { "$ref": "#/components/schemas/SamsungPayWalletData" @@ -18237,7 +19851,9 @@ }, { "type": "object", - "required": ["twint_redirect"], + "required": [ + "twint_redirect" + ], "properties": { "twint_redirect": { "type": "object", @@ -18247,7 +19863,9 @@ }, { "type": "object", - "required": ["vipps_redirect"], + "required": [ + "vipps_redirect" + ], "properties": { "vipps_redirect": { "type": "object", @@ -18257,7 +19875,9 @@ }, { "type": "object", - "required": ["touch_n_go_redirect"], + "required": [ + "touch_n_go_redirect" + ], "properties": { "touch_n_go_redirect": { "$ref": "#/components/schemas/TouchNGoRedirection" @@ -18266,7 +19886,9 @@ }, { "type": "object", - "required": ["we_chat_pay_redirect"], + "required": [ + "we_chat_pay_redirect" + ], "properties": { "we_chat_pay_redirect": { "$ref": "#/components/schemas/WeChatPayRedirection" @@ -18275,7 +19897,9 @@ }, { "type": "object", - "required": ["we_chat_pay_qr"], + "required": [ + "we_chat_pay_qr" + ], "properties": { "we_chat_pay_qr": { "$ref": "#/components/schemas/WeChatPayQr" @@ -18284,7 +19908,9 @@ }, { "type": "object", - "required": ["cashapp_qr"], + "required": [ + "cashapp_qr" + ], "properties": { "cashapp_qr": { "$ref": "#/components/schemas/CashappQr" @@ -18293,7 +19919,9 @@ }, { "type": "object", - "required": ["swish_qr"], + "required": [ + "swish_qr" + ], "properties": { "swish_qr": { "$ref": "#/components/schemas/SwishQrData" @@ -18302,7 +19930,9 @@ }, { "type": "object", - "required": ["mifinity"], + "required": [ + "mifinity" + ], "properties": { "mifinity": { "$ref": "#/components/schemas/MifinityData" @@ -18330,7 +19960,9 @@ "oneOf": [ { "type": "object", - "required": ["apple_pay"], + "required": [ + "apple_pay" + ], "properties": { "apple_pay": { "$ref": "#/components/schemas/WalletAdditionalDataForCard" @@ -18339,7 +19971,9 @@ }, { "type": "object", - "required": ["google_pay"], + "required": [ + "google_pay" + ], "properties": { "google_pay": { "$ref": "#/components/schemas/WalletAdditionalDataForCard" @@ -18360,7 +19994,11 @@ }, "WebhookDeliveryAttempt": { "type": "string", - "enum": ["initial_attempt", "automatic_retry", "manual_retry"] + "enum": [ + "initial_attempt", + "automatic_retry", + "manual_retry" + ] }, "WebhookDetails": { "type": "object", @@ -18499,4 +20137,4 @@ "description": "Manage events" } ] -} +} \ No newline at end of file From ebe079fedef6f7a6449dc5e517925e8ff1c6a59d Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Thu, 31 Oct 2024 16:39:46 +0530 Subject: [PATCH 11/24] chore: cargo clippy --- .../src/compatibility/stripe/payment_intents.rs | 2 +- .../src/compatibility/stripe/setup_intents.rs | 2 +- crates/router/src/core/payments/operations.rs | 7 ++----- .../payments/operations/payment_get_intent.rs | 16 +++++++++------- crates/router/src/core/payments/transformers.rs | 1 + crates/router/src/services/authentication.rs | 7 +++++++ .../down.sql | 7 ++++--- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/crates/router/src/compatibility/stripe/payment_intents.rs b/crates/router/src/compatibility/stripe/payment_intents.rs index e447e9b95357..5bbb4e7cf22a 100644 --- a/crates/router/src/compatibility/stripe/payment_intents.rs +++ b/crates/router/src/compatibility/stripe/payment_intents.rs @@ -100,7 +100,7 @@ pub async fn payment_intents_create( .await } -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] +#[cfg(feature = "v1")] #[instrument(skip_all, fields(flow = ?Flow::PaymentsRetrieveForceSync))] pub async fn payment_intents_retrieve( state: web::Data, diff --git a/crates/router/src/compatibility/stripe/setup_intents.rs b/crates/router/src/compatibility/stripe/setup_intents.rs index 66b43e4ebe90..919ced993aad 100644 --- a/crates/router/src/compatibility/stripe/setup_intents.rs +++ b/crates/router/src/compatibility/stripe/setup_intents.rs @@ -86,7 +86,7 @@ pub async fn setup_intents_create( .await } -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] +#[cfg(feature = "v1")] #[instrument(skip_all, fields(flow = ?Flow::PaymentsRetrieveForceSync))] pub async fn setup_intents_retrieve( state: web::Data, diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 539407bf1c1d..c35c60377ac3 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -50,6 +50,8 @@ pub use self::payment_confirm_intent::PaymentIntentConfirm; #[cfg(feature = "v2")] pub use self::payment_create_intent::PaymentIntentCreate; #[cfg(feature = "v2")] +pub use self::payment_get::PaymentGet; +#[cfg(feature = "v2")] pub use self::payment_get_intent::PaymentGetIntent; pub use self::payment_response::PaymentResponse; #[cfg(feature = "v1")] @@ -62,11 +64,6 @@ pub use self::{ payments_incremental_authorization::PaymentIncrementalAuthorization, tax_calculation::PaymentSessionUpdate, }; -#[cfg(feature = "v2")] -pub use self::{ - payment_confirm_intent::PaymentIntentConfirm, payment_create_intent::PaymentIntentCreate, - payment_get::PaymentGet, -}; use super::{helpers, CustomerDetails, OperationSessionGetters, OperationSessionSetters}; use crate::{ core::errors::{self, CustomResult, RouterResult}, diff --git a/crates/router/src/core/payments/operations/payment_get_intent.rs b/crates/router/src/core/payments/operations/payment_get_intent.rs index 55ddc3b482a6..ca09d021b779 100644 --- a/crates/router/src/core/payments/operations/payment_get_intent.rs +++ b/crates/router/src/core/payments/operations/payment_get_intent.rs @@ -207,15 +207,17 @@ impl Domain( + #[instrument(skip_all)] + async fn perform_routing<'a>( &'a self, - _merchant_account: &domain::MerchantAccount, + merchant_account: &domain::MerchantAccount, + business_profile: &domain::Profile, state: &SessionState, - _request: &PaymentsGetIntentRequest, - _payment_intent: &storage::PaymentIntent, - _merchant_key_store: &domain::MerchantKeyStore, - ) -> CustomResult { - helpers::get_connector_default(state, None).await + // TODO: do not take the whole payment data here + payment_data: &mut payments::PaymentIntentData, + mechant_key_store: &domain::MerchantKeyStore, + ) -> CustomResult { + Ok(api::ConnectorCallType::Skip) } #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 01ea87d36b6b..d1193338bec8 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -516,6 +516,7 @@ pub async fn construct_router_data_for_psync<'a>( integrity_check: Ok(()), additional_merchant_data: None, header_payload, + connector_mandate_request_reference_id: None, }; Ok(router_data) diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 346fea41033a..846026d42670 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -2074,6 +2074,13 @@ impl ClientSecretFetch for payments::PaymentsRequest { } } +#[cfg(feature = "v1")] +impl ClientSecretFetch for payments::PaymentsRetrieveRequest { + fn get_client_secret(&self) -> Option<&String> { + self.client_secret.as_ref() + } +} + impl ClientSecretFetch for PaymentMethodListRequest { fn get_client_secret(&self) -> Option<&String> { self.client_secret.as_ref() diff --git a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql index 3585a4551836..661f7f294e0d 100644 --- a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql +++ b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/down.sql @@ -94,6 +94,10 @@ SET NOT NULL; ALTER TABLE payment_intent ALTER COLUMN session_expiry DROP NOT NULL; +ALTER TABLE payment_intent +ALTER COLUMN active_attempt_id +SET DEFAULT 'xxx'; + ------------------------ Payment Attempt ----------------------- ALTER TABLE payment_attempt DROP CONSTRAINT payment_attempt_pkey; @@ -106,6 +110,3 @@ ALTER COLUMN net_amount DROP NOT NULL; ALTER TABLE payment_attempt ADD PRIMARY KEY (attempt_id, merchant_id); - -ALTER TABLE payment_attempt -SET DEFAULT 'xxx'; From 1c5212c7ec2cce29870cb15bd5deca0c77cf1471 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 4 Nov 2024 14:14:50 +0530 Subject: [PATCH 12/24] refactor: address PR comments --- crates/api_models/src/payments.rs | 2 +- crates/common_enums/src/enums.rs | 3 ++- .../src/merchant_connector_account.rs | 21 +++++++++++++++++++ .../hyperswitch_domain_models/src/payments.rs | 2 +- .../core/payments/operations/payment_get.rs | 16 ++------------ .../router/src/core/payments/transformers.rs | 15 ++++--------- 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 5d6d9d38b1c7..009978ba4398 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -4635,7 +4635,7 @@ pub struct PaymentsRetrieveResponse { )] pub id: id_type::GlobalPaymentId, - #[schema(value_type = IntentStatus, example = "success")] + #[schema(value_type = IntentStatus, example = "succeeded")] pub status: api_enums::IntentStatus, /// Amount related information for this payment and attempt diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 7a9334d573e2..548646ffcbe4 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1306,11 +1306,12 @@ impl IntentStatus { | Self::Failed | Self::Cancelled | Self::PartiallyCaptured + | Self::RequiresCapture | Self::PartiallyCapturedAndCapturable => false, Self::Processing | Self::RequiresCustomerAction | Self::RequiresMerchantAction - | Self::RequiresCapture => true, + => true, } } } diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index 9418f6f8f1ed..c78b526ab47c 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -1,3 +1,4 @@ +use actix_web::error; use common_utils::{ crypto::Encryptable, date_time, @@ -14,6 +15,12 @@ use rustc_hash::FxHashMap; use super::behaviour; use crate::type_encryption::{crypto_operation, CryptoOperation}; +#[cfg(feature = "v2")] +use crate::router_data; + +#[cfg(feature = "v2")] +use common_utils::ext_traits::ValueExt; + #[cfg(feature = "v1")] #[derive(Clone, Debug)] pub struct MerchantConnectorAccount { @@ -80,6 +87,20 @@ impl MerchantConnectorAccount { pub fn get_id(&self) -> id_type::MerchantConnectorAccountId { self.id.clone() } + + pub fn is_disabled(&self) -> bool { + self.disabled.unwrap_or(false) + } + + pub fn get_connector_account_details( + &self, + ) -> error_stack::Result + { + self.connector_account_details + .get_inner() + .clone() + .parse_value("ConnectorAuthType") + } } #[cfg(feature = "v1")] diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 44d5e3c43d0a..2607d397a521 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -522,6 +522,6 @@ where pub payment_intent: PaymentIntent, pub payment_attempt: Option, /// Should the payment status be synced with connector - /// This will depend on the payment status + /// This will depend on the payment status and the force sync flag in the request pub should_sync_with_connector: bool, } diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs index 0fba1607efb1..da139979df46 100644 --- a/crates/router/src/core/payments/operations/payment_get.rs +++ b/crates/router/src/core/payments/operations/payment_get.rs @@ -42,21 +42,9 @@ impl ValidateStatusForOperation for PaymentGet { /// Validate if the current operation can be performed on the current status of the payment intent fn validate_status_for_operation( &self, - intent_status: common_enums::IntentStatus, + _intent_status: common_enums::IntentStatus, ) -> Result<(), errors::ApiErrorResponse> { - match intent_status { - common_enums::IntentStatus::RequiresPaymentMethod - | common_enums::IntentStatus::Succeeded - | common_enums::IntentStatus::Failed - | common_enums::IntentStatus::Cancelled - | common_enums::IntentStatus::Processing - | common_enums::IntentStatus::RequiresCustomerAction - | common_enums::IntentStatus::RequiresMerchantAction - | common_enums::IntentStatus::RequiresCapture - | common_enums::IntentStatus::PartiallyCaptured - | common_enums::IntentStatus::RequiresConfirmation - | common_enums::IntentStatus::PartiallyCapturedAndCapturable => Ok(()), - } + Ok(()) } } diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index d1193338bec8..8642e598f8cd 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -186,15 +186,12 @@ pub async fn construct_payment_router_data_for_authorize<'a>( ) -> RouterResult { use masking::ExposeOptionInterface; - fp_utils::when(merchant_connector_account.disabled.unwrap_or(false), || { + fp_utils::when(merchant_connector_account.is_disabled(), || { Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled) })?; let auth_type = merchant_connector_account - .connector_account_details - .clone() - .into_inner() - .parse_value::("ConnectorAuthType") + .get_connector_account_details() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while parsing value for ConnectorAuthType")?; @@ -392,7 +389,7 @@ pub async fn construct_router_data_for_psync<'a>( ) -> RouterResult { use masking::ExposeOptionInterface; - fp_utils::when(merchant_connector_account.disabled.unwrap_or(false), || { + fp_utils::when(merchant_connector_account.is_disabled(), || { Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled) })?; @@ -411,14 +408,10 @@ pub async fn construct_router_data_for_psync<'a>( let payment_intent = payment_data.payment_intent; let auth_type: types::ConnectorAuthType = merchant_connector_account - .connector_account_details - .clone() - .into_inner() - .parse_value("ConnectorAuthType") + .get_connector_account_details() .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while parsing value for ConnectorAuthType")?; - let router_base_url = &state.base_url; let attempt = &payment_data .payment_attempt .get_required_value("attempt") From 57095196f05178d433c0c3cb50b80162a6053ab6 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 08:45:39 +0000 Subject: [PATCH 13/24] chore: run formatter --- .../src/merchant_connector_account.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index c78b526ab47c..f8c7a75e32ab 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -1,4 +1,6 @@ use actix_web::error; +#[cfg(feature = "v2")] +use common_utils::ext_traits::ValueExt; use common_utils::{ crypto::Encryptable, date_time, @@ -13,13 +15,9 @@ use masking::{PeekInterface, Secret}; use rustc_hash::FxHashMap; use super::behaviour; -use crate::type_encryption::{crypto_operation, CryptoOperation}; - #[cfg(feature = "v2")] use crate::router_data; - -#[cfg(feature = "v2")] -use common_utils::ext_traits::ValueExt; +use crate::type_encryption::{crypto_operation, CryptoOperation}; #[cfg(feature = "v1")] #[derive(Clone, Debug)] From 56dab7e405282de468451e460200c82c4fa6d376 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 4 Nov 2024 16:31:38 +0530 Subject: [PATCH 14/24] refactor: move updatable trackers objects to a trait on router_data --- crates/common_enums/src/transformers.rs | 40 +- .../src/merchant_connector_account.rs | 3 - .../src/router_data.rs | 253 +++++++++++++ crates/router/src/core/payments.rs | 12 +- crates/router/src/core/payments/operations.rs | 21 +- .../payments/operations/payment_response.rs | 351 ++++-------------- crates/router/src/types/transformers.rs | 37 +- 7 files changed, 392 insertions(+), 325 deletions(-) diff --git a/crates/common_enums/src/transformers.rs b/crates/common_enums/src/transformers.rs index 4fba749ef637..77ff9e8e7142 100644 --- a/crates/common_enums/src/transformers.rs +++ b/crates/common_enums/src/transformers.rs @@ -2,7 +2,10 @@ use std::fmt::{Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::enums::{Country, CountryAlpha2, CountryAlpha3, PaymentMethod, PaymentMethodType}; +use crate::enums::{ + AttemptStatus, Country, CountryAlpha2, CountryAlpha3, IntentStatus, PaymentMethod, + PaymentMethodType, +}; impl Display for NumericCountryCodeParseError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { @@ -2065,6 +2068,41 @@ impl super::PresenceOfCustomerDuringPayment { } } +impl From for IntentStatus { + fn from(s: AttemptStatus) -> Self { + match s { + AttemptStatus::Charged | AttemptStatus::AutoRefunded => Self::Succeeded, + + AttemptStatus::ConfirmationAwaited => Self::RequiresConfirmation, + AttemptStatus::PaymentMethodAwaited => Self::RequiresPaymentMethod, + + AttemptStatus::Authorized => Self::RequiresCapture, + AttemptStatus::AuthenticationPending | AttemptStatus::DeviceDataCollectionPending => { + Self::RequiresCustomerAction + } + AttemptStatus::Unresolved => Self::RequiresMerchantAction, + + AttemptStatus::PartialCharged => Self::PartiallyCaptured, + AttemptStatus::PartialChargedAndChargeable => Self::PartiallyCapturedAndCapturable, + AttemptStatus::Started + | AttemptStatus::AuthenticationSuccessful + | AttemptStatus::Authorizing + | AttemptStatus::CodInitiated + | AttemptStatus::VoidInitiated + | AttemptStatus::CaptureInitiated + | AttemptStatus::Pending => Self::Processing, + + AttemptStatus::AuthenticationFailed + | AttemptStatus::AuthorizationFailed + | AttemptStatus::VoidFailed + | AttemptStatus::RouterDeclined + | AttemptStatus::CaptureFailed + | AttemptStatus::Failure => Self::Failed, + AttemptStatus::Voided => Self::Cancelled, + } + } +} + #[cfg(test)] mod tests { #![allow(clippy::unwrap_used)] diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index f8c7a75e32ab..1116a8efa555 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -1,6 +1,3 @@ -use actix_web::error; -#[cfg(feature = "v2")] -use common_utils::ext_traits::ValueExt; use common_utils::{ crypto::Encryptable, date_time, diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index 186a4f012629..980435f9f748 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -389,3 +389,256 @@ impl ErrorResponse { } } } + +#[cfg(feature = "v2")] +use crate::{ + payments::{ + payment_attempt::{ErrorDetails, PaymentAttemptUpdate}, + payment_intent::PaymentIntentUpdate, + }, + router_flow_types, router_request_types, router_response_types, +}; + +/// Get updatable trakcer objects of payment intent and payment attempt +#[cfg(feature = "v2")] +pub trait TrackerPostUpdateObjects { + fn get_payment_intent_update( + &self, + storage_scheme: common_enums::MerchantStorageScheme, + ) -> PaymentIntentUpdate; + fn get_payment_attempt_update( + &self, + storage_scheme: common_enums::MerchantStorageScheme, + ) -> PaymentAttemptUpdate; +} + +#[cfg(feature = "v2")] +impl + TrackerPostUpdateObjects< + router_flow_types::Authorize, + router_request_types::PaymentsAuthorizeData, + > + for RouterData< + router_flow_types::Authorize, + router_request_types::PaymentsAuthorizeData, + router_response_types::PaymentsResponseData, + > +{ + fn get_payment_intent_update( + &self, + storage_scheme: common_enums::MerchantStorageScheme, + ) -> PaymentIntentUpdate { + match self.response { + Ok(ref _response) => PaymentIntentUpdate::ConfirmIntentPostUpdate { + status: common_enums::IntentStatus::from(self.status), + updated_by: storage_scheme.to_string(), + }, + Err(ref error) => PaymentIntentUpdate::ConfirmIntentPostUpdate { + status: error + .attempt_status + .map(common_enums::IntentStatus::from) + .unwrap_or(common_enums::IntentStatus::Failed), + updated_by: storage_scheme.to_string(), + }, + } + } + + fn get_payment_attempt_update( + &self, + storage_scheme: common_enums::MerchantStorageScheme, + ) -> PaymentAttemptUpdate { + match self.response { + Ok(ref response_router_data) => match response_router_data { + router_response_types::PaymentsResponseData::TransactionResponse { + resource_id, + redirection_data, + mandate_reference, + connector_metadata, + network_txn_id, + connector_response_reference_id, + incremental_authorization_allowed, + charge_id, + } => { + let attempt_status = self.status; + let connector_payment_id = match resource_id { + router_request_types::ResponseId::NoResponseId => None, + router_request_types::ResponseId::ConnectorTransactionId(id) + | router_request_types::ResponseId::EncodedData(id) => Some(id.to_owned()), + }; + + PaymentAttemptUpdate::ConfirmIntentResponse { + status: attempt_status, + connector_payment_id, + updated_by: storage_scheme.to_string(), + } + } + router_response_types::PaymentsResponseData::MultipleCaptureResponse { .. } => { + todo!() + } + router_response_types::PaymentsResponseData::SessionResponse { .. } => todo!(), + router_response_types::PaymentsResponseData::SessionTokenResponse { .. } => todo!(), + router_response_types::PaymentsResponseData::TransactionUnresolvedResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::TokenizationResponse { .. } => todo!(), + router_response_types::PaymentsResponseData::ConnectorCustomerResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::ThreeDSEnrollmentResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::PreProcessingResponse { .. } => { + todo!() + } + router_response_types::PaymentsResponseData::IncrementalAuthorizationResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::PostProcessingResponse { .. } => { + todo!() + } + router_response_types::PaymentsResponseData::SessionUpdateResponse { .. } => { + todo!() + } + }, + Err(ref error_response) => { + let ErrorResponse { + code, + message, + reason, + status_code: _, + attempt_status, + connector_transaction_id, + } = error_response.clone(); + let attempt_status = attempt_status.unwrap_or(self.status); + + let error_details = ErrorDetails { + code, + message, + reason, + unified_code: None, + unified_message: None, + }; + + PaymentAttemptUpdate::ErrorUpdate { + status: attempt_status, + error: error_details, + connector_payment_id: connector_transaction_id, + updated_by: storage_scheme.to_string(), + } + } + } + } +} + +#[cfg(feature = "v2")] +impl TrackerPostUpdateObjects + for RouterData< + router_flow_types::PSync, + router_request_types::PaymentsSyncData, + router_response_types::PaymentsResponseData, + > +{ + fn get_payment_intent_update( + &self, + storage_scheme: common_enums::MerchantStorageScheme, + ) -> PaymentIntentUpdate { + match self.response { + Ok(ref _response) => PaymentIntentUpdate::SyncUpdate { + status: common_enums::IntentStatus::from(self.status), + updated_by: storage_scheme.to_string(), + }, + Err(ref error) => PaymentIntentUpdate::SyncUpdate { + status: error + .attempt_status + .map(common_enums::IntentStatus::from) + .unwrap_or(common_enums::IntentStatus::Failed), + updated_by: storage_scheme.to_string(), + }, + } + } + + fn get_payment_attempt_update( + &self, + storage_scheme: common_enums::MerchantStorageScheme, + ) -> PaymentAttemptUpdate { + match self.response { + Ok(ref response_router_data) => match response_router_data { + router_response_types::PaymentsResponseData::TransactionResponse { + resource_id, + redirection_data, + mandate_reference, + connector_metadata, + network_txn_id, + connector_response_reference_id, + incremental_authorization_allowed, + charge_id, + } => { + let attempt_status = self.status; + let connector_payment_id = match resource_id { + router_request_types::ResponseId::NoResponseId => None, + router_request_types::ResponseId::ConnectorTransactionId(id) + | router_request_types::ResponseId::EncodedData(id) => Some(id.to_owned()), + }; + + PaymentAttemptUpdate::SyncUpdate { + status: attempt_status, + updated_by: storage_scheme.to_string(), + } + } + router_response_types::PaymentsResponseData::MultipleCaptureResponse { .. } => { + todo!() + } + router_response_types::PaymentsResponseData::SessionResponse { .. } => todo!(), + router_response_types::PaymentsResponseData::SessionTokenResponse { .. } => todo!(), + router_response_types::PaymentsResponseData::TransactionUnresolvedResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::TokenizationResponse { .. } => todo!(), + router_response_types::PaymentsResponseData::ConnectorCustomerResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::ThreeDSEnrollmentResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::PreProcessingResponse { .. } => { + todo!() + } + router_response_types::PaymentsResponseData::IncrementalAuthorizationResponse { + .. + } => todo!(), + router_response_types::PaymentsResponseData::PostProcessingResponse { .. } => { + todo!() + } + router_response_types::PaymentsResponseData::SessionUpdateResponse { .. } => { + todo!() + } + }, + Err(ref error_response) => { + let ErrorResponse { + code, + message, + reason, + status_code: _, + attempt_status, + connector_transaction_id, + } = error_response.clone(); + let attempt_status = attempt_status.unwrap_or(self.status); + + let error_details = ErrorDetails { + code, + message, + reason, + unified_code: None, + unified_message: None, + }; + + PaymentAttemptUpdate::ErrorUpdate { + status: attempt_status, + error: error_details, + connector_payment_id: connector_transaction_id, + updated_by: storage_scheme.to_string(), + } + } + } + } +} diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 977063603ff4..c6ec87014590 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -137,6 +137,9 @@ where dyn api::Connector: services::api::ConnectorIntegration, + RouterData: + hyperswitch_domain_models::router_data::TrackerPostUpdateObjects, + // To perform router related operation for PaymentResponse PaymentResponse: Operation, FData: Send + Sync + Clone, @@ -222,11 +225,6 @@ where router_data, &key_store, merchant_account.storage_scheme, - &header_payload.locale, - #[cfg(all(feature = "dynamic_routing", feature = "v1"))] - routable_connectors, - #[cfg(all(feature = "dynamic_routing", feature = "v1"))] - &business_profile, ) .await? } @@ -1512,6 +1510,10 @@ where // To perform router related operation for PaymentResponse PaymentResponse: Operation, + + // To create + RouterData: + hyperswitch_domain_models::router_data::TrackerPostUpdateObjects, { let (payment_data, _req, customer, connector_http_status_code, external_latency) = payments_operation_core::<_, _, _, _, _>( diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index c35c60377ac3..edf0485a77df 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -396,6 +396,7 @@ pub trait CallConnector: Send { pub trait PostUpdateTracker: Send { /// Update the tracker information with the response from the connector /// The response from routerdata is used to update paymentdata and also persist this in the database + #[cfg(feature = "v1")] async fn update_tracker<'b>( &'b self, db: &'b SessionState, @@ -404,14 +405,26 @@ pub trait PostUpdateTracker: Send { key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, locale: &Option, - #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec< - RoutableConnectorChoice, - >, - #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile, + #[cfg(feature = "dynamic_routing")] routable_connector: Vec, + #[cfg(feature = "dynamic_routing")] business_profile: &domain::Profile, ) -> RouterResult where F: 'b + Send + Sync; + #[cfg(feature = "v2")] + async fn update_tracker<'b>( + &'b self, + db: &'b SessionState, + payment_data: D, + response: types::RouterData, + key_store: &domain::MerchantKeyStore, + storage_scheme: enums::MerchantStorageScheme, + ) -> RouterResult + where + F: 'b + Send + Sync, + types::RouterData: + hyperswitch_domain_models::router_data::TrackerPostUpdateObjects; + async fn save_pm_and_mandate<'b>( &self, _state: &SessionState, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index e68d19501098..844669bac1fb 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -2180,154 +2180,53 @@ impl PostUpdateTracker, types::PaymentsAuthor response: types::RouterData, key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, - locale: &Option, - #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec< - RoutableConnectorChoice, - >, - #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile, ) -> RouterResult> where F: 'b + Send + Sync, + types::RouterData: + hyperswitch_domain_models::router_data::TrackerPostUpdateObjects< + F, + types::PaymentsAuthorizeData, + >, { + use hyperswitch_domain_models::router_data::TrackerPostUpdateObjects; + let db = &*state.store; let key_manager_state = &state.into(); let response_router_data = response; - match response_router_data.response { - Ok(response) => match response { - types::PaymentsResponseData::TransactionResponse { - resource_id, - redirection_data, - mandate_reference, - connector_metadata, - network_txn_id, - connector_response_reference_id, - incremental_authorization_allowed, - charge_id, - } => { - let attempt_status = response_router_data.status; - let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); - let connector_payment_id = match resource_id { - types::ResponseId::NoResponseId => None, - types::ResponseId::ConnectorTransactionId(id) - | types::ResponseId::EncodedData(id) => Some(id), - }; + let payment_intent_update = response_router_data.get_payment_intent_update(storage_scheme); + let payment_attempt_update = + response_router_data.get_payment_attempt_update(storage_scheme); - let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; - let updated_payment_intent = db - .update_payment_intent( - key_manager_state, - payment_data.payment_intent, - payment_intent_update, - key_store, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment intent")?; - payment_data.payment_intent = updated_payment_intent; - - let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentResponse { status: attempt_status, connector_payment_id, updated_by: storage_scheme.to_string() }; - let updated_payment_attempt = db - .update_payment_attempt( - key_manager_state, - key_store, - payment_data.payment_attempt, - payment_attempt_update, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment attempt")?; - payment_data.payment_attempt = updated_payment_attempt; - } - types::PaymentsResponseData::MultipleCaptureResponse { - capture_sync_response_list, - } => todo!(), - types::PaymentsResponseData::SessionResponse { session_token } => todo!(), - types::PaymentsResponseData::SessionTokenResponse { session_token } => todo!(), - types::PaymentsResponseData::TransactionUnresolvedResponse { - resource_id, - reason, - connector_response_reference_id, - } => todo!(), - types::PaymentsResponseData::TokenizationResponse { token } => todo!(), - types::PaymentsResponseData::ConnectorCustomerResponse { - connector_customer_id, - } => todo!(), - types::PaymentsResponseData::ThreeDSEnrollmentResponse { - enrolled_v2, - related_transaction_id, - } => todo!(), - types::PaymentsResponseData::PreProcessingResponse { - pre_processing_id, - connector_metadata, - session_token, - connector_response_reference_id, - } => todo!(), - types::PaymentsResponseData::IncrementalAuthorizationResponse { - status, - connector_authorization_id, - error_code, - error_message, - } => todo!(), - types::PaymentsResponseData::PostProcessingResponse { session_token } => todo!(), - types::PaymentsResponseData::SessionUpdateResponse { status } => todo!(), - }, - Err(ErrorResponse { - code, - message, - reason, - status_code, - attempt_status, - connector_transaction_id, - }) => { - let attempt_status = common_enums::AttemptStatus::Failure; - let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); - let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; - - let updated_payment_intent = db - .update_payment_intent( - key_manager_state, - payment_data.payment_intent, - payment_intent_update, - key_store, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment intent")?; - - payment_data.payment_intent = updated_payment_intent; - - // TODO: populate unified code and message and translation by calling gsm and translation table - let error_details = - hyperswitch_domain_models::payments::payment_attempt::ErrorDetails { - code, - message, - reason, - unified_code: None, - unified_message: None, - }; + let updated_payment_intent = db + .update_payment_intent( + key_manager_state, + payment_data.payment_intent, + payment_intent_update, + key_store, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment intent")?; - let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ErrorUpdate { status: attempt_status, error: error_details, connector_payment_id: connector_transaction_id, updated_by: storage_scheme.to_string() }; - let updated_payment_attempt = db - .update_payment_attempt( - key_manager_state, - key_store, - payment_data.payment_attempt, - payment_attempt_update, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment attempt")?; + let updated_payment_attempt = db + .update_payment_attempt( + key_manager_state, + key_store, + payment_data.payment_attempt, + payment_attempt_update, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment attempt")?; + + payment_data.payment_intent = updated_payment_intent; + payment_data.payment_attempt = updated_payment_attempt; - payment_data.payment_attempt = updated_payment_attempt; - } - } - // TODO: Implement this Ok(payment_data) } } @@ -2355,162 +2254,60 @@ impl PostUpdateTracker, types::PaymentsSyncDat response: types::RouterData, key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, - locale: &Option, - #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec< - RoutableConnectorChoice, - >, - #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile, ) -> RouterResult> where F: 'b + Send + Sync, + types::RouterData: + hyperswitch_domain_models::router_data::TrackerPostUpdateObjects< + F, + types::PaymentsSyncData, + >, { - use common_utils::ext_traits::OptionExt; + use hyperswitch_domain_models::router_data::TrackerPostUpdateObjects; let db = &*state.store; let key_manager_state = &state.into(); let response_router_data = response; + + let payment_intent_update = response_router_data.get_payment_intent_update(storage_scheme); + let payment_attempt_update = + response_router_data.get_payment_attempt_update(storage_scheme); + let payment_attempt = payment_data .payment_attempt - .clone() - .get_required_value("payment_attempt") + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "Payment attempt not found in payment data in post update trackers", + )?; + + let updated_payment_intent = db + .update_payment_intent( + key_manager_state, + payment_data.payment_intent, + payment_intent_update, + key_store, + storage_scheme, + ) + .await .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("payment attempt is not set in payment data")?; - - match response_router_data.response { - Ok(response) => match response { - types::PaymentsResponseData::TransactionResponse { - resource_id, - redirection_data, - mandate_reference, - connector_metadata, - network_txn_id, - connector_response_reference_id, - incremental_authorization_allowed, - charge_id, - } => { - let attempt_status = response_router_data.status; - let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); - let connector_payment_id = match resource_id { - types::ResponseId::NoResponseId => None, - types::ResponseId::ConnectorTransactionId(id) - | types::ResponseId::EncodedData(id) => Some(id), - }; + .attach_printable("Unable to update payment intent")?; - let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::SyncUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; - let updated_payment_intent = db - .update_payment_intent( - key_manager_state, - payment_data.payment_intent, - payment_intent_update, - key_store, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment intent")?; - payment_data.payment_intent = updated_payment_intent; - - let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::SyncUpdate { status: attempt_status, updated_by: storage_scheme.to_string() }; - let updated_payment_attempt = db - .update_payment_attempt( - key_manager_state, - key_store, - payment_attempt, - payment_attempt_update, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment attempt")?; - payment_data.payment_attempt = Some(updated_payment_attempt); - } - types::PaymentsResponseData::MultipleCaptureResponse { - capture_sync_response_list, - } => todo!(), - types::PaymentsResponseData::SessionResponse { session_token } => todo!(), - types::PaymentsResponseData::SessionTokenResponse { session_token } => todo!(), - types::PaymentsResponseData::TransactionUnresolvedResponse { - resource_id, - reason, - connector_response_reference_id, - } => todo!(), - types::PaymentsResponseData::TokenizationResponse { token } => todo!(), - types::PaymentsResponseData::ConnectorCustomerResponse { - connector_customer_id, - } => todo!(), - types::PaymentsResponseData::ThreeDSEnrollmentResponse { - enrolled_v2, - related_transaction_id, - } => todo!(), - types::PaymentsResponseData::PreProcessingResponse { - pre_processing_id, - connector_metadata, - session_token, - connector_response_reference_id, - } => todo!(), - types::PaymentsResponseData::IncrementalAuthorizationResponse { - status, - connector_authorization_id, - error_code, - error_message, - } => todo!(), - types::PaymentsResponseData::PostProcessingResponse { session_token } => todo!(), - types::PaymentsResponseData::SessionUpdateResponse { status } => todo!(), - }, - Err(ErrorResponse { - code, - message, - reason, - status_code, - attempt_status, - connector_transaction_id, - }) => { - let attempt_status = common_enums::AttemptStatus::Failure; - let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); - let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; - - let updated_payment_intent = db - .update_payment_intent( - key_manager_state, - payment_data.payment_intent, - payment_intent_update, - key_store, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment intent")?; - - payment_data.payment_intent = updated_payment_intent; - - // TODO: populate unified code and message and translation by calling gsm and translation table - let error_details = - hyperswitch_domain_models::payments::payment_attempt::ErrorDetails { - code, - message, - reason, - unified_code: None, - unified_message: None, - }; + let updated_payment_attempt = db + .update_payment_attempt( + key_manager_state, + key_store, + payment_attempt, + payment_attempt_update, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment attempt")?; - let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ErrorUpdate { status: attempt_status, error: error_details, connector_payment_id: connector_transaction_id, updated_by: storage_scheme.to_string() }; - let updated_payment_attempt = db - .update_payment_attempt( - key_manager_state, - key_store, - payment_attempt, - payment_attempt_update, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to update payment attempt")?; + payment_data.payment_intent = updated_payment_intent; + payment_data.payment_attempt = Some(updated_payment_attempt); - payment_data.payment_attempt = Some(updated_payment_attempt); - } - } - // TODO: Implement this Ok(payment_data) } } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 0585aee4a0e5..407654554a7a 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -134,43 +134,10 @@ impl } } +// TODO: remove this usage in v1 code impl ForeignFrom for storage_enums::IntentStatus { fn foreign_from(s: storage_enums::AttemptStatus) -> Self { - match s { - storage_enums::AttemptStatus::Charged | storage_enums::AttemptStatus::AutoRefunded => { - Self::Succeeded - } - - storage_enums::AttemptStatus::ConfirmationAwaited => Self::RequiresConfirmation, - storage_enums::AttemptStatus::PaymentMethodAwaited => Self::RequiresPaymentMethod, - - storage_enums::AttemptStatus::Authorized => Self::RequiresCapture, - storage_enums::AttemptStatus::AuthenticationPending - | storage_enums::AttemptStatus::DeviceDataCollectionPending => { - Self::RequiresCustomerAction - } - storage_enums::AttemptStatus::Unresolved => Self::RequiresMerchantAction, - - storage_enums::AttemptStatus::PartialCharged => Self::PartiallyCaptured, - storage_enums::AttemptStatus::PartialChargedAndChargeable => { - Self::PartiallyCapturedAndCapturable - } - storage_enums::AttemptStatus::Started - | storage_enums::AttemptStatus::AuthenticationSuccessful - | storage_enums::AttemptStatus::Authorizing - | storage_enums::AttemptStatus::CodInitiated - | storage_enums::AttemptStatus::VoidInitiated - | storage_enums::AttemptStatus::CaptureInitiated - | storage_enums::AttemptStatus::Pending => Self::Processing, - - storage_enums::AttemptStatus::AuthenticationFailed - | storage_enums::AttemptStatus::AuthorizationFailed - | storage_enums::AttemptStatus::VoidFailed - | storage_enums::AttemptStatus::RouterDeclined - | storage_enums::AttemptStatus::CaptureFailed - | storage_enums::AttemptStatus::Failure => Self::Failed, - storage_enums::AttemptStatus::Voided => Self::Cancelled, - } + Self::from(s) } } From 95b51f4419679bc9d86650f3a60683e0e377a6b6 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 4 Nov 2024 16:40:47 +0530 Subject: [PATCH 15/24] chore: cargo clippy --- .../hyperswitch_domain_models/src/merchant_connector_account.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index 1116a8efa555..593846ca07c4 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -91,6 +91,8 @@ impl MerchantConnectorAccount { &self, ) -> error_stack::Result { + use common_utils::ext_traits::ValueExt; + self.connector_account_details .get_inner() .clone() From 940fbe0a1d4532624866559ff6f3da6cb4aa2c27 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 4 Nov 2024 17:06:42 +0530 Subject: [PATCH 16/24] refactor: change payments retrieve to get api and added jwt auth --- crates/router/src/routes/app.rs | 2 +- crates/router/src/routes/payments.rs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 289f79f709a2..97b9ddcb43a1 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -535,7 +535,7 @@ impl Payments { web::resource("/create-external-sdk-tokens") .route(web::post().to(payments::payments_connector_session)), ) - .service(web::resource("").route(web::post().to(payments::payment_status))), + .service(web::resource("").route(web::get().to(payments::payment_status))), ); route diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index fe322c6b197c..b4cc5964e960 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -2193,7 +2193,13 @@ pub async fn payment_status( )) .await }, - &auth::PublishableKeyAuth, + auth::auth_type( + &auth::PublishableKeyAuth, + &auth::JWTAuth { + permission: Permission::ProfilePaymentRead, + }, + req.headers(), + ), locking_action, )) .await From e832d29c4a9fc23ceb79a4a8ab460b16e7f55944 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 4 Nov 2024 17:12:54 +0530 Subject: [PATCH 17/24] refactor: allow force sync for PartiallyCapturedAndCapturable status --- crates/common_enums/src/enums.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 548646ffcbe4..e5c2be8a08ce 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1306,11 +1306,11 @@ impl IntentStatus { | Self::Failed | Self::Cancelled | Self::PartiallyCaptured - | Self::RequiresCapture - | Self::PartiallyCapturedAndCapturable => false, + | Self::RequiresCapture => false, Self::Processing | Self::RequiresCustomerAction | Self::RequiresMerchantAction + | Self::PartiallyCapturedAndCapturable => true, } } From f8ed350983bef8886c32a48ac38e6ab893a48f2c Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 4 Nov 2024 17:15:50 +0530 Subject: [PATCH 18/24] chore: add a todo comment --- crates/common_enums/src/enums.rs | 1 + crates/router/src/core/payments/operations/payment_get.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index e5c2be8a08ce..a7128f2b3958 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1296,6 +1296,7 @@ pub enum IntentStatus { } impl IntentStatus { + /// Indicates whether the syncing with the connector should be allowed or not pub fn should_force_sync_with_connector(&self) -> bool { match self { // Confirm has not happened yet diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs index da139979df46..f79aa68ee717 100644 --- a/crates/router/src/core/payments/operations/payment_get.rs +++ b/crates/router/src/core/payments/operations/payment_get.rs @@ -145,6 +145,7 @@ impl GetTracker, PaymentsRetrieveReques .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; + // TODO: validate this only in case of client call self.validate_status_for_operation(payment_intent.status)?; let client_secret = header_payload .client_secret From 252bd8e9ece8394d69e0496a328cf97b2440b916 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 5 Nov 2024 15:47:38 +0530 Subject: [PATCH 19/24] chore: cargo cilipy --- crates/api_models/src/payments.rs | 1 + .../src/payments/payment_intent.rs | 3 +++ crates/router/src/core/payments.rs | 2 +- .../core/payments/operations/payment_response.rs | 2 ++ crates/router/src/core/payments/transformers.rs | 14 ++------------ .../up.sql | 9 --------- 6 files changed, 9 insertions(+), 22 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 7570f6f48912..36c0036cdade 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -4572,6 +4572,7 @@ pub struct PaymentsConfirmIntentResponse { pub error: Option, } +// TODO: have a separate response for detailed, summarized /// Response for Payment Intent Confirm #[cfg(feature = "v2")] #[derive(Debug, serde::Serialize, ToSchema)] diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index ee2a132af82f..71dc481d9651 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -268,15 +268,18 @@ pub enum PaymentIntentUpdate { #[cfg(feature = "v2")] #[derive(Debug, Clone, Serialize)] pub enum PaymentIntentUpdate { + /// PreUpdate tracker of ConfirmIntent ConfirmIntent { status: storage_enums::IntentStatus, active_attempt_id: id_type::GlobalAttemptId, updated_by: String, }, + /// PostUpdate tracker of ConfirmIntent ConfirmIntentPostUpdate { status: storage_enums::IntentStatus, updated_by: String, }, + /// SyncUpdate of ConfirmIntent in PostUpdateTrackers SyncUpdate { status: storage_enums::IntentStatus, updated_by: String, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index c6ec87014590..19455abeac8b 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1511,7 +1511,7 @@ where // To perform router related operation for PaymentResponse PaymentResponse: Operation, - // To create + // To create updatable objects in post update tracker RouterData: hyperswitch_domain_models::router_data::TrackerPostUpdateObjects, { diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 844669bac1fb..444875d4ac82 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1259,6 +1259,8 @@ async fn payment_response_update_tracker( #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile, ) -> RouterResult> { // Update additional payment data with the payment method response that we received from connector + // This is for details like whether 3ds was upgraded and which version of 3ds was used + // also some connectors might send card network details in the response, which is captured and stored let additional_payment_method_data = match payment_data.payment_method_data.clone() { Some(payment_method_data) => match payment_method_data { diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 8642e598f8cd..17dfc58ec4b3 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -393,17 +393,8 @@ pub async fn construct_router_data_for_psync<'a>( Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled) })?; - // TODO: Take Globalid and convert to connector reference id - let customer_id = customer - .to_owned() - .map(|customer| customer.id.clone()) - .map(std::borrow::Cow::Owned) - .map(common_utils::id_type::CustomerId::try_from) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "Invalid global customer generated, not able to convert to reference id", - )?; + // TODO: Take Globalid / CustomerReferenceId and convert to connector reference id + let customer_id = None; let payment_intent = payment_data.payment_intent; @@ -426,7 +417,6 @@ pub async fn construct_router_data_for_psync<'a>( let request = types::PaymentsSyncData { amount: attempt.amount_details.net_amount, integrity_object: None, - // TODO: How do we provide this in v2 mandate_id: None, connector_transaction_id: match attempt.get_connector_payment_id() { Some(connector_txn_id) => { diff --git a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql index 2494bc3c63d1..3b1fe9b46afa 100644 --- a/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql +++ b/v2_migrations/2024-08-28-081838_update_v2_primary_key_constraints/up.sql @@ -88,21 +88,12 @@ ADD PRIMARY KEY (id); ------------------------ Payment Intent ----------------------- ALTER TABLE payment_intent DROP CONSTRAINT payment_intent_pkey; --- To work around database constraints -UPDATE payment_intent -SET id = payment_id -WHERE id IS NULL; - ALTER TABLE payment_intent ADD PRIMARY KEY (id); ------------------------ Payment Attempt ----------------------- ALTER TABLE payment_attempt DROP CONSTRAINT payment_attempt_pkey; -UPDATE payment_attempt -SET id = attempt_id -WHERE id IS NULL; - ALTER TABLE payment_attempt ADD PRIMARY KEY (id); From b85b6f66638e8654bb53cf1ebc794b38ce70a719 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 5 Nov 2024 17:45:30 +0530 Subject: [PATCH 20/24] refactor: remove client secret auth and add header auth --- crates/router/src/core/payments/operations/payment_get.rs | 8 -------- crates/router/src/routes/payments.rs | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs index f79aa68ee717..2a417568047c 100644 --- a/crates/router/src/core/payments/operations/payment_get.rs +++ b/crates/router/src/core/payments/operations/payment_get.rs @@ -145,14 +145,6 @@ impl GetTracker, PaymentsRetrieveReques .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; - // TODO: validate this only in case of client call - self.validate_status_for_operation(payment_intent.status)?; - let client_secret = header_payload - .client_secret - .as_ref() - .get_required_value("client_secret header")?; - payment_intent.validate_client_secret(client_secret)?; - let payment_attempt = payment_intent .active_attempt_id .as_ref() diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index b4cc5964e960..e05fd46f4eae 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -2194,7 +2194,7 @@ pub async fn payment_status( .await }, auth::auth_type( - &auth::PublishableKeyAuth, + &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { permission: Permission::ProfilePaymentRead, }, From 62c4479bc1ac4e049fe7405d99db6899feb3f6f9 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 5 Nov 2024 18:15:09 +0530 Subject: [PATCH 21/24] chore: remove unused struct --- crates/router/src/services/authentication.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 846026d42670..fb67c5344cab 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -311,9 +311,6 @@ where #[derive(Debug)] pub struct ApiKeyAuth; -#[derive(Debug)] -pub struct ApiKeyAuthV2; - pub struct NoAuth; #[cfg(feature = "partial-auth")] From cc542845c7b66328b421c8cc38f0330cba82d36d Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Fri, 8 Nov 2024 15:44:58 +0530 Subject: [PATCH 22/24] chore: cargo clippy_v2 --- crates/router/src/routes/payments.rs | 2 +- crates/router/src/routes/routing.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index 1aafc4f13b57..14bd5edab097 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -2166,7 +2166,7 @@ pub async fn payment_status( state, &req, internal_payload, - |state, auth: auth::AuthenticationDataV2, req, req_state| async { + |state, auth: auth::AuthenticationData, req, req_state| async { let payment_id = req.global_payment_id; let request = req.payload; diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index 29c759425566..f0269bd029ab 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -84,8 +84,7 @@ pub async fn routing_create_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingWrite, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingWrite, }, req.headers(), ), @@ -255,8 +254,7 @@ pub async fn routing_retrieve_config( auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), &auth::JWTAuth { - permission: Permission::RoutingRead, - minimum_entity_level: EntityType::Profile, + permission: Permission::ProfileRoutingRead, }, req.headers(), ), From 301bd59b00c0778979936059a3fe0b81126d1f32 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Sat, 9 Nov 2024 12:21:20 +0530 Subject: [PATCH 23/24] refactor: rename authentication data to redirect form also instead of using serdejson value, use a type --- crates/common_utils/src/types.rs | 10 ++ crates/diesel_models/src/payment_attempt.rs | 55 +++++- crates/diesel_models/src/schema_v2.rs | 2 +- .../src/payments/payment_attempt.rs | 27 +-- .../src/router_data.rs | 1 + .../src/router_response_types.rs | 156 ++++++++++++++++++ crates/router/src/core/payments.rs | 14 +- .../router/src/core/payments/transformers.rs | 3 +- .../2024-08-28-081721_add_v2_columns/down.sql | 1 + .../2024-08-28-081721_add_v2_columns/up.sql | 3 +- .../down.sql | 1 + .../2024-10-08-081847_drop_v1_columns/up.sql | 1 + 12 files changed, 247 insertions(+), 27 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index ce2be525989e..ef7a4b847c45 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -627,6 +627,16 @@ impl Url { pub fn get_string_repr(&self) -> &str { self.0.as_str() } + + /// wrap the url::Url in Url type + pub fn wrap(url: url::Url) -> Self { + Self(url) + } + + /// Get the inner url + pub fn into_inner(self) -> url::Url { + self.0 + } } impl ToSql for Url diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index e233cfe390bb..32ffcb545fb7 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -65,7 +65,6 @@ pub struct PaymentAttempt { pub amount_capturable: MinorUnit, pub updated_by: String, pub merchant_connector_id: Option, - pub authentication_data: Option, pub encoded_data: Option>, pub unified_code: Option, pub unified_message: Option, @@ -89,6 +88,7 @@ pub struct PaymentAttempt { pub external_reference_id: Option, pub tax_on_surcharge: Option, pub payment_method_billing_address: Option, + pub redirection_data: Option, pub connector_payment_data: Option, pub id: id_type::GlobalAttemptId, pub shipping_cost: Option, @@ -255,7 +255,7 @@ pub struct PaymentAttemptNew { pub amount_capturable: MinorUnit, pub updated_by: String, pub merchant_connector_id: Option, - pub authentication_data: Option, + pub redirection_data: Option, pub encoded_data: Option>, pub unified_code: Option, pub unified_message: Option, @@ -770,7 +770,7 @@ pub struct PaymentAttemptUpdateInternal { pub updated_by: String, pub merchant_connector_id: Option, pub connector: Option, - pub authentication_data: Option, + pub redirection_data: Option, // encoded_data: Option, pub unified_code: Option>, pub unified_message: Option>, @@ -3283,6 +3283,55 @@ impl From for PaymentAttemptUpdateInternal { } } +#[derive(Eq, PartialEq, Clone, Debug, Deserialize, Serialize, diesel::AsExpression)] +#[diesel(sql_type = diesel::sql_types::Jsonb)] +pub enum RedirectForm { + Form { + endpoint: String, + method: common_utils::request::Method, + form_fields: std::collections::HashMap, + }, + Html { + html_data: String, + }, + BlueSnap { + payment_fields_token: String, + }, + CybersourceAuthSetup { + access_token: String, + ddc_url: String, + reference_id: String, + }, + CybersourceConsumerAuth { + access_token: String, + step_up_url: String, + }, + Payme, + Braintree { + client_token: String, + card_token: String, + bin: String, + }, + Nmi { + amount: String, + currency: common_enums::Currency, + public_key: masking::Secret, + customer_vault_id: String, + order_id: String, + }, + Mifinity { + initialization_token: String, + }, + WorldpayDDCForm { + endpoint: common_utils::types::Url, + method: common_utils::request::Method, + form_fields: std::collections::HashMap, + collection_id: Option, + }, +} + +common_utils::impl_to_sql_from_sql_json!(RedirectForm); + mod tests { #[test] diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 617d6cf182b9..3bd31f5cbf3f 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -776,7 +776,6 @@ diesel::table! { updated_by -> Varchar, #[max_length = 32] merchant_connector_id -> Nullable, - authentication_data -> Nullable, encoded_data -> Nullable, #[max_length = 255] unified_code -> Nullable, @@ -814,6 +813,7 @@ diesel::table! { external_reference_id -> Nullable, tax_on_surcharge -> Nullable, payment_method_billing_address -> Nullable, + redirection_data -> Nullable, #[max_length = 512] connector_payment_data -> Nullable, #[max_length = 64] diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index c1bc0a472836..2a8b52c2c87c 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -31,6 +31,9 @@ use crate::{ router_request_types, ForeignIDRef, }; +#[cfg(feature = "v2")] +use crate::router_response_types; + #[async_trait::async_trait] pub trait PaymentAttemptInterface { #[cfg(feature = "v1")] @@ -261,7 +264,7 @@ pub struct PaymentAttempt { /// Whether the payment was updated by postgres or redis pub updated_by: String, /// The authentication data which is used for external authentication - pub authentication_data: Option, + pub redirection_data: Option, pub encoded_data: Option>, pub merchant_connector_id: Option, /// Whether external 3DS authentication was attempted for this payment. @@ -383,7 +386,7 @@ impl PaymentAttempt { multiple_capture_count: None, connector_response_reference_id: None, updated_by: storage_scheme.to_string(), - authentication_data: None, + redirection_data: None, encoded_data: None, merchant_connector_id: None, external_three_ds_authentication_attempted: None, @@ -1295,7 +1298,7 @@ pub enum PaymentAttemptUpdate { status: storage_enums::AttemptStatus, connector_payment_id: Option, updated_by: String, - authentication_data: Option, + redirection_data: Option, }, /// Update the payment attempt after force syncing with the connector SyncUpdate { @@ -1619,7 +1622,7 @@ impl behaviour::Conversion for PaymentAttempt { multiple_capture_count, connector_response_reference_id, updated_by, - authentication_data, + redirection_data, encoded_data, merchant_connector_id, external_three_ds_authentication_attempted, @@ -1688,7 +1691,7 @@ impl behaviour::Conversion for PaymentAttempt { amount_capturable, updated_by, merchant_connector_id, - authentication_data, + redirection_data: redirection_data.map(From::from), encoded_data, unified_code: error .as_ref() @@ -1796,7 +1799,7 @@ impl behaviour::Conversion for PaymentAttempt { multiple_capture_count: storage_model.multiple_capture_count, connector_response_reference_id: storage_model.connector_response_reference_id, updated_by: storage_model.updated_by, - authentication_data: storage_model.authentication_data, + redirection_data: storage_model.redirection_data.map(From::from), encoded_data: storage_model.encoded_data, merchant_connector_id: storage_model.merchant_connector_id, external_three_ds_authentication_attempted: storage_model @@ -1872,7 +1875,7 @@ impl behaviour::Conversion for PaymentAttempt { amount_capturable: self.amount_details.amount_capturable, updated_by: self.updated_by, merchant_connector_id: self.merchant_connector_id, - authentication_data: self.authentication_data, + redirection_data: self.redirection_data.map(From::from), encoded_data: self.encoded_data, unified_code: error_details .as_ref() @@ -1929,7 +1932,7 @@ impl From for diesel_models::PaymentAttemptUpdateInternal unified_message: None, connector_payment_id: None, connector: Some(connector), - authentication_data: None, + redirection_data: None, }, PaymentAttemptUpdate::ErrorUpdate { status, @@ -1949,13 +1952,13 @@ impl From for diesel_models::PaymentAttemptUpdateInternal unified_message: None, connector_payment_id, connector: None, - authentication_data: None, + redirection_data: None, }, PaymentAttemptUpdate::ConfirmIntentResponse { status, connector_payment_id, updated_by, - authentication_data, + redirection_data, } => Self { status: Some(status), error_message: None, @@ -1969,7 +1972,8 @@ impl From for diesel_models::PaymentAttemptUpdateInternal unified_message: None, connector_payment_id, connector: None, - authentication_data, + redirection_data: redirection_data + .map(diesel_models::payment_attempt::RedirectForm::from), }, PaymentAttemptUpdate::SyncUpdate { status, updated_by } => Self { status: Some(status), @@ -1984,6 +1988,7 @@ impl From for diesel_models::PaymentAttemptUpdateInternal unified_message: None, connector_payment_id: None, connector: None, + redirection_data: None, }, } } diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index b9920bed08ce..f995c9a1e57e 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -470,6 +470,7 @@ impl status: attempt_status, connector_payment_id, updated_by: storage_scheme.to_string(), + redirection_data: *redirection_data.clone(), } } router_response_types::PaymentsResponseData::MultipleCaptureResponse { .. } => { diff --git a/crates/hyperswitch_domain_models/src/router_response_types.rs b/crates/hyperswitch_domain_models/src/router_response_types.rs index e6af5c5eb3bc..4501582d0038 100644 --- a/crates/hyperswitch_domain_models/src/router_response_types.rs +++ b/crates/hyperswitch_domain_models/src/router_response_types.rs @@ -191,6 +191,162 @@ impl From<(url::Url, Method)> for RedirectForm { } } +impl From for diesel_models::payment_attempt::RedirectForm { + fn from(redirect_form: RedirectForm) -> Self { + match redirect_form { + RedirectForm::Form { + endpoint, + method, + form_fields, + } => Self::Form { + endpoint, + method, + form_fields, + }, + RedirectForm::Html { html_data } => Self::Html { html_data }, + RedirectForm::BlueSnap { + payment_fields_token, + } => Self::BlueSnap { + payment_fields_token, + }, + RedirectForm::CybersourceAuthSetup { + access_token, + ddc_url, + reference_id, + } => Self::CybersourceAuthSetup { + access_token, + ddc_url, + reference_id, + }, + RedirectForm::CybersourceConsumerAuth { + access_token, + step_up_url, + } => Self::CybersourceConsumerAuth { + access_token, + step_up_url, + }, + RedirectForm::Payme => Self::Payme, + RedirectForm::Braintree { + client_token, + card_token, + bin, + } => Self::Braintree { + client_token, + card_token, + bin, + }, + RedirectForm::Nmi { + amount, + currency, + public_key, + customer_vault_id, + order_id, + } => Self::Nmi { + amount, + currency, + public_key, + customer_vault_id, + order_id, + }, + RedirectForm::Mifinity { + initialization_token, + } => Self::Mifinity { + initialization_token, + }, + RedirectForm::WorldpayDDCForm { + endpoint, + method, + form_fields, + collection_id, + } => Self::WorldpayDDCForm { + endpoint: common_utils::types::Url::wrap(endpoint), + method, + form_fields, + collection_id, + }, + } + } +} + +impl From for RedirectForm { + fn from(redirect_form: diesel_models::payment_attempt::RedirectForm) -> Self { + match redirect_form { + diesel_models::payment_attempt::RedirectForm::Form { + endpoint, + method, + form_fields, + } => Self::Form { + endpoint, + method, + form_fields, + }, + diesel_models::payment_attempt::RedirectForm::Html { html_data } => { + Self::Html { html_data } + } + diesel_models::payment_attempt::RedirectForm::BlueSnap { + payment_fields_token, + } => Self::BlueSnap { + payment_fields_token, + }, + diesel_models::payment_attempt::RedirectForm::CybersourceAuthSetup { + access_token, + ddc_url, + reference_id, + } => Self::CybersourceAuthSetup { + access_token, + ddc_url, + reference_id, + }, + diesel_models::payment_attempt::RedirectForm::CybersourceConsumerAuth { + access_token, + step_up_url, + } => Self::CybersourceConsumerAuth { + access_token, + step_up_url, + }, + diesel_models::payment_attempt::RedirectForm::Payme => Self::Payme, + diesel_models::payment_attempt::RedirectForm::Braintree { + client_token, + card_token, + bin, + } => Self::Braintree { + client_token, + card_token, + bin, + }, + diesel_models::payment_attempt::RedirectForm::Nmi { + amount, + currency, + public_key, + customer_vault_id, + order_id, + } => Self::Nmi { + amount, + currency, + public_key, + customer_vault_id, + order_id, + }, + diesel_models::payment_attempt::RedirectForm::Mifinity { + initialization_token, + } => Self::Mifinity { + initialization_token, + }, + diesel_models::payment_attempt::RedirectForm::WorldpayDDCForm { + endpoint, + method, + form_fields, + collection_id, + } => Self::WorldpayDDCForm { + endpoint: endpoint.into_inner(), + method, + form_fields, + collection_id, + }, + } + } +} + #[derive(Default, Clone, Debug)] pub struct UploadFileResponse { pub provider_file_id: String, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 8fc462ea30a5..7892880ae50d 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -6111,29 +6111,23 @@ pub async fn payment_start_redirection( &key_store, payment_intent .active_attempt_id - .clone() + .as_ref() .ok_or(errors::ApiErrorResponse::InternalServerError) - .attach_printable("missing active attempt in payment_intent")? - .get_string_repr(), + .attach_printable("missing active attempt in payment_intent")?, storage_scheme, ) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Error while fetching payment_attempt")?; let redirection_data = payment_attempt - .authentication_data + .redirection_data .clone() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("missing authentication_data in payment_attempt")?; - let form: RedirectForm = serde_json::from_value(redirection_data.expose()).map_err(|err| { - logger::error!(error = ?err, "Failed to deserialize redirection data"); - errors::ApiErrorResponse::InternalServerError - })?; - Ok(services::ApplicationResponse::Form(Box::new( services::RedirectionFormData { - redirect_form: form, + redirect_form: redirection_data, payment_method_data: None, amount: payment_attempt.amount_details.net_amount.to_string(), currency: payment_intent.amount_details.currency.to_string(), diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 5476a225bc59..52c0f69be166 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1035,7 +1035,7 @@ where let redirect_to_url = payment_intent .create_start_redirection_url(base_url, merchant_account.publishable_key.clone())?; let next_action = payment_attempt - .authentication_data + .redirection_data .as_ref() .map(|_| api_models::payments::NextActionData::RedirectToUrl { redirect_to_url }); @@ -1081,6 +1081,7 @@ where _connector_http_status_code: Option, _external_latency: Option, _is_latency_header_enabled: Option, + _merchant_account: &domain::MerchantAccount, ) -> RouterResponse { let payment_intent = payment_data.get_payment_intent(); let payment_attempt = payment_data.get_optional_payment_attempt(); diff --git a/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql b/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql index 70aa43951050..d008367af333 100644 --- a/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql +++ b/v2_migrations/2024-08-28-081721_add_v2_columns/down.sql @@ -41,4 +41,5 @@ ALTER TABLE payment_attempt DROP COLUMN payment_method_type_v2, DROP COLUMN external_reference_id, DROP COLUMN tax_on_surcharge, DROP COLUMN payment_method_billing_address, + DROP COLUMN redirection_data, DROP COLUMN connector_payment_data; diff --git a/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql b/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql index 64decb1a0a87..a402beac139c 100644 --- a/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql +++ b/v2_migrations/2024-08-28-081721_add_v2_columns/up.sql @@ -21,7 +21,7 @@ ADD COLUMN routing_algorithm_id VARCHAR(64) DEFAULT NULL, -- If no merchants have enabled this, then we can use `false` as the default value -- when adding the column, later we can drop the default added for the column -- so that we ensure new records inserted always have a value for the column. - ADD COLUMN should_collect_cvv_during_payment BOOLEAN NOT NULL; +ADD COLUMN should_collect_cvv_during_payment BOOLEAN NOT NULL; ALTER TABLE payment_intent ADD COLUMN merchant_reference_id VARCHAR(64), @@ -50,4 +50,5 @@ ADD COLUMN payment_method_type_v2 VARCHAR, ADD COLUMN external_reference_id VARCHAR(128), ADD COLUMN tax_on_surcharge BIGINT, ADD COLUMN payment_method_billing_address BYTEA, + ADD COLUMN redirection_data JSONB, ADD COLUMN connector_payment_data VARCHAR(512); diff --git a/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql b/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql index 55c5b3f749d4..64cbd2233eac 100644 --- a/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql +++ b/v2_migrations/2024-10-08-081847_drop_v1_columns/down.sql @@ -87,6 +87,7 @@ ADD COLUMN IF NOT EXISTS attempt_id VARCHAR(64) NOT NULL, ADD COLUMN tax_amount bigint, ADD COLUMN straight_through_algorithm JSONB, ADD COLUMN confirm BOOLEAN, + ADD COLUMN authentication_data JSONB, ADD COLUMN payment_method_billing_address_id VARCHAR(64); -- Create the index which was dropped because of dropping the column diff --git a/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql b/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql index 0d22741b9420..507b29dadf7d 100644 --- a/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql +++ b/v2_migrations/2024-10-08-081847_drop_v1_columns/up.sql @@ -85,4 +85,5 @@ ALTER TABLE payment_attempt DROP COLUMN attempt_id, DROP COLUMN tax_amount, DROP COLUMN straight_through_algorithm, DROP COLUMN confirm, + DROP COLUMN authentication_data, DROP COLUMN payment_method_billing_address_id; From ee637762277db0bba7c8086671b688c45d4b5ff4 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2024 06:53:36 +0000 Subject: [PATCH 24/24] chore: run formatter --- .../src/payments/payment_attempt.rs | 5 ++--- crates/router/src/core/payments.rs | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 2a8b52c2c87c..d6fdf9f14c0f 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -25,15 +25,14 @@ use time::PrimitiveDateTime; use super::PaymentIntent; #[cfg(feature = "v2")] use crate::merchant_key_store::MerchantKeyStore; +#[cfg(feature = "v2")] +use crate::router_response_types; use crate::{ behaviour, errors, mandates::{MandateDataType, MandateDetails}, router_request_types, ForeignIDRef, }; -#[cfg(feature = "v2")] -use crate::router_response_types; - #[async_trait::async_trait] pub trait PaymentAttemptInterface { #[cfg(feature = "v1")] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 7892880ae50d..23cb25a52d5c 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -39,10 +39,8 @@ use helpers::{decrypt_paze_token, ApplePayData}; use hyperswitch_domain_models::payments::{ PaymentConfirmData, PaymentIntentData, PaymentStatusData, }; - #[cfg(feature = "v2")] use hyperswitch_domain_models::router_response_types::RedirectForm; - pub use hyperswitch_domain_models::{ mandates::{CustomerAcceptance, MandateData}, payment_address::PaymentAddress,