diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index cadae4fa45c..3a43b1bfca2 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -5793,6 +5793,23 @@ } } }, + "BillingConnectorPaymentDetails": { + "type": "object", + "required": [ + "payment_processor_token", + "connector_customer_id" + ], + "properties": { + "payment_processor_token": { + "type": "string", + "description": "Payment Processor Token to process the Revenue Recovery Payment" + }, + "connector_customer_id": { + "type": "string", + "description": "Billing Connector's Customer Id" + } + } + }, "BlikBankRedirectAdditionalData": { "type": "object", "properties": { @@ -9025,6 +9042,14 @@ } ], "nullable": true + }, + "payment_revenue_recovery_metadata": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentRevenueRecoveryMetadata" + } + ], + "nullable": true } } }, @@ -13167,6 +13192,13 @@ "bank_acquirer" ] }, + "PaymentConnectorTransmission": { + "type": "string", + "enum": [ + "ConnectorCallFailed", + "ConnectorCallSucceeded" + ] + }, "PaymentCreatePaymentLinkConfig": { "allOf": [ { @@ -14926,6 +14958,49 @@ } } }, + "PaymentRevenueRecoveryMetadata": { + "type": "object", + "required": [ + "total_retry_count", + "payment_connector_transmission", + "billing_connector_id", + "active_attempt_payment_connector_id", + "billing_connector_payment_details", + "payment_method_type", + "payment_method_subtype" + ], + "properties": { + "total_retry_count": { + "type": "integer", + "format": "int32", + "description": "Total number of billing connector + recovery retries for a payment intent.", + "example": "1", + "minimum": 0 + }, + "payment_connector_transmission": { + "$ref": "#/components/schemas/PaymentConnectorTransmission" + }, + "billing_connector_id": { + "type": "string", + "description": "Billing Connector Id to update the invoices", + "example": "mca_1234567890" + }, + "active_attempt_payment_connector_id": { + "type": "string", + "description": "Payment Connector Id to retry the payments", + "example": "mca_1234567890" + }, + "billing_connector_payment_details": { + "$ref": "#/components/schemas/BillingConnectorPaymentDetails" + }, + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethod" + }, + "payment_method_subtype": { + "$ref": "#/components/schemas/PaymentMethodType" + } + } + }, "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.", diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 47f43f982f5..fb033230654 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -5,6 +5,8 @@ use std::{ }; pub mod additional_info; use cards::CardNumber; +#[cfg(feature = "v2")] +use common_enums::enums::PaymentConnectorTransmission; use common_enums::ProductType; #[cfg(feature = "v2")] use common_utils::id_type::GlobalPaymentId; @@ -7111,12 +7113,28 @@ pub struct PaymentsStartRequest { } /// additional data that might be required by hyperswitch +#[cfg(feature = "v2")] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct FeatureMetadata { + /// Redirection response coming in request as metadata field only for redirection scenarios + #[schema(value_type = Option)] + pub redirect_response: Option, + /// Additional tags to be used for global search + #[schema(value_type = Option>)] + pub search_tags: Option>>, + /// Recurring payment details required for apple pay Merchant Token + pub apple_pay_recurring_details: Option, + /// revenue recovery data for payment intent + pub payment_revenue_recovery_metadata: Option, +} + +/// additional data that might be required by hyperswitch +#[cfg(feature = "v1")] #[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)] pub struct FeatureMetadata { /// Redirection response coming in request as metadata field only for redirection scenarios #[schema(value_type = Option)] pub redirect_response: Option, - // TODO: Convert this to hashedstrings to avoid PII sensitive data /// Additional tags to be used for global search #[schema(value_type = Option>)] pub search_tags: Option>>, @@ -7977,3 +7995,36 @@ mod billing_from_payment_method_data { assert!(billing_details.is_none()); } } + +#[cfg(feature = "v2")] +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct PaymentRevenueRecoveryMetadata { + /// Total number of billing connector + recovery retries for a payment intent. + #[schema(value_type = u16,example = "1")] + pub total_retry_count: u16, + /// Flag for the payment connector's call + pub payment_connector_transmission: PaymentConnectorTransmission, + /// Billing Connector Id to update the invoices + #[schema(value_type = String, example = "mca_1234567890")] + pub billing_connector_id: id_type::MerchantConnectorAccountId, + /// Payment Connector Id to retry the payments + #[schema(value_type = String, example = "mca_1234567890")] + pub active_attempt_payment_connector_id: id_type::MerchantConnectorAccountId, + /// Billing Connector Payment Details + #[schema(value_type = BillingConnectorPaymentDetails)] + pub billing_connector_payment_details: BillingConnectorPaymentDetails, + /// Payment Method Type + #[schema(example = "pay_later", value_type = PaymentMethod)] + pub payment_method_type: common_enums::PaymentMethod, + /// PaymentMethod Subtype + #[schema(example = "klarna", value_type = PaymentMethodType)] + pub payment_method_subtype: common_enums::PaymentMethodType, +} +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg(feature = "v2")] +pub struct BillingConnectorPaymentDetails { + /// Payment Processor Token to process the Revenue Recovery Payment + pub payment_processor_token: String, + /// Billing Connector's Customer Id + pub connector_customer_id: String, +} diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 99442d3080c..f7ea487e91e 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -3768,3 +3768,12 @@ pub enum AdyenSplitType { /// The value-added tax charged on the payment, booked to your platforms liable balance account. Vat, } + +#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] +#[serde(rename = "snake_case")] +pub enum PaymentConnectorTransmission { + /// Failed to call the payment connector + ConnectorCallFailed, + /// Payment Connector call succeeded + ConnectorCallSucceeded, +} diff --git a/crates/diesel_models/src/types.rs b/crates/diesel_models/src/types.rs index 7806a7c6e1b..6bc8aee2893 100644 --- a/crates/diesel_models/src/types.rs +++ b/crates/diesel_models/src/types.rs @@ -1,10 +1,12 @@ +#[cfg(feature = "v2")] +use common_enums::{enums::PaymentConnectorTransmission, PaymentMethod, PaymentMethodType}; use common_utils::{hashing::HashedString, pii, types::MinorUnit}; use diesel::{ sql_types::{Json, Jsonb}, AsExpression, FromSqlRow, }; use masking::{Secret, WithType}; -use serde::{Deserialize, Serialize}; +use serde::{self, Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, FromSqlRow, AsExpression)] #[diesel(sql_type = Jsonb)] pub struct OrderDetailsWithAmount { @@ -40,12 +42,26 @@ impl masking::SerializableSecret for OrderDetailsWithAmount {} common_utils::impl_to_sql_from_sql_json!(OrderDetailsWithAmount); +#[cfg(feature = "v2")] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, FromSqlRow, AsExpression)] +#[diesel(sql_type = Json)] +pub struct FeatureMetadata { + /// Redirection response coming in request as metadata field only for redirection scenarios + pub redirect_response: Option, + /// Additional tags to be used for global search + pub search_tags: Option>>, + /// Recurring payment details required for apple pay Merchant Token + pub apple_pay_recurring_details: Option, + /// revenue recovery data for payment intent + pub payment_revenue_recovery_metadata: Option, +} + +#[cfg(feature = "v1")] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, FromSqlRow, AsExpression)] #[diesel(sql_type = Json)] pub struct FeatureMetadata { /// Redirection response coming in request as metadata field only for redirection scenarios pub redirect_response: Option, - // TODO: Convert this to hashedstrings to avoid PII sensitive data /// Additional tags to be used for global search pub search_tags: Option>>, /// Recurring payment details required for apple pay Merchant Token @@ -106,3 +122,31 @@ pub struct RedirectResponse { } impl masking::SerializableSecret for RedirectResponse {} common_utils::impl_to_sql_from_sql_json!(RedirectResponse); + +#[cfg(feature = "v2")] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct PaymentRevenueRecoveryMetadata { + /// Total number of billing connector + recovery retries for a payment intent. + pub total_retry_count: u16, + /// Flag for the payment connector's call + pub payment_connector_transmission: PaymentConnectorTransmission, + /// Billing Connector Id to update the invoices + pub billing_connector_id: common_utils::id_type::MerchantConnectorAccountId, + /// Payment Connector Id to retry the payments + pub active_attempt_payment_connector_id: common_utils::id_type::MerchantConnectorAccountId, + /// Billing Connector Payment Details + pub billing_connector_payment_details: BillingConnectorPaymentDetails, + ///Payment Method Type + pub payment_method_type: PaymentMethod, + /// PaymentMethod Subtype + pub payment_method_subtype: PaymentMethodType, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[cfg(feature = "v2")] +pub struct BillingConnectorPaymentDetails { + /// Payment Processor Token to process the Revenue Recovery Payment + pub payment_processor_token: String, + /// Billing Connector's Customer Id + pub connector_customer_id: String, +} diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index bd6dd2e5371..b2546e3a049 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -40,10 +40,17 @@ use api_models::payments::{ RecurringPaymentIntervalUnit as ApiRecurringPaymentIntervalUnit, RedirectResponse as ApiRedirectResponse, }; +#[cfg(feature = "v2")] +use api_models::payments::{ + BillingConnectorPaymentDetails as ApiBillingConnectorPaymentDetails, + PaymentRevenueRecoveryMetadata as ApiRevenueRecoveryMetadata, +}; use diesel_models::types::{ ApplePayRecurringDetails, ApplePayRegularBillingDetails, FeatureMetadata, OrderDetailsWithAmount, RecurringPaymentIntervalUnit, RedirectResponse, }; +#[cfg(feature = "v2")] +use diesel_models::types::{BillingConnectorPaymentDetails, PaymentRevenueRecoveryMetadata}; #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] pub enum RemoteStorageObject { @@ -78,18 +85,57 @@ pub trait ApiModelToDieselModelConvertor { fn convert_back(self) -> F; } +#[cfg(feature = "v1")] +impl ApiModelToDieselModelConvertor for FeatureMetadata { + fn convert_from(from: ApiFeatureMetadata) -> Self { + let ApiFeatureMetadata { + redirect_response, + search_tags, + apple_pay_recurring_details, + } = from; + + Self { + redirect_response: redirect_response.map(RedirectResponse::convert_from), + search_tags, + apple_pay_recurring_details: apple_pay_recurring_details + .map(ApplePayRecurringDetails::convert_from), + } + } + + fn convert_back(self) -> ApiFeatureMetadata { + let Self { + redirect_response, + search_tags, + apple_pay_recurring_details, + } = self; + + ApiFeatureMetadata { + redirect_response: redirect_response + .map(|redirect_response| redirect_response.convert_back()), + search_tags, + apple_pay_recurring_details: apple_pay_recurring_details + .map(|value| value.convert_back()), + } + } +} + +#[cfg(feature = "v2")] impl ApiModelToDieselModelConvertor for FeatureMetadata { fn convert_from(from: ApiFeatureMetadata) -> Self { let ApiFeatureMetadata { redirect_response, search_tags, apple_pay_recurring_details, + payment_revenue_recovery_metadata, } = from; + Self { redirect_response: redirect_response.map(RedirectResponse::convert_from), search_tags, apple_pay_recurring_details: apple_pay_recurring_details .map(ApplePayRecurringDetails::convert_from), + payment_revenue_recovery_metadata: payment_revenue_recovery_metadata + .map(PaymentRevenueRecoveryMetadata::convert_from), } } @@ -98,13 +144,17 @@ impl ApiModelToDieselModelConvertor for FeatureMetadata { redirect_response, search_tags, apple_pay_recurring_details, + payment_revenue_recovery_metadata, } = self; + ApiFeatureMetadata { redirect_response: redirect_response .map(|redirect_response| redirect_response.convert_back()), search_tags, apple_pay_recurring_details: apple_pay_recurring_details .map(|value| value.convert_back()), + payment_revenue_recovery_metadata: payment_revenue_recovery_metadata + .map(|value| value.convert_back()), } } } @@ -204,6 +254,56 @@ impl ApiModelToDieselModelConvertor for ApplePayRec } } +#[cfg(feature = "v2")] +impl ApiModelToDieselModelConvertor for PaymentRevenueRecoveryMetadata { + fn convert_from(from: ApiRevenueRecoveryMetadata) -> Self { + Self { + total_retry_count: from.total_retry_count, + payment_connector_transmission: from.payment_connector_transmission, + billing_connector_id: from.billing_connector_id, + active_attempt_payment_connector_id: from.active_attempt_payment_connector_id, + billing_connector_payment_details: BillingConnectorPaymentDetails::convert_from( + from.billing_connector_payment_details, + ), + payment_method_type: from.payment_method_type, + payment_method_subtype: from.payment_method_subtype, + } + } + + fn convert_back(self) -> ApiRevenueRecoveryMetadata { + ApiRevenueRecoveryMetadata { + total_retry_count: self.total_retry_count, + payment_connector_transmission: self.payment_connector_transmission, + billing_connector_id: self.billing_connector_id, + active_attempt_payment_connector_id: self.active_attempt_payment_connector_id, + billing_connector_payment_details: self + .billing_connector_payment_details + .convert_back(), + payment_method_type: self.payment_method_type, + payment_method_subtype: self.payment_method_subtype, + } + } +} + +#[cfg(feature = "v2")] +impl ApiModelToDieselModelConvertor + for BillingConnectorPaymentDetails +{ + fn convert_from(from: ApiBillingConnectorPaymentDetails) -> Self { + Self { + payment_processor_token: from.payment_processor_token, + connector_customer_id: from.connector_customer_id, + } + } + + fn convert_back(self) -> ApiBillingConnectorPaymentDetails { + ApiBillingConnectorPaymentDetails { + payment_processor_token: self.payment_processor_token, + connector_customer_id: self.connector_customer_id, + } + } +} + impl ApiModelToDieselModelConvertor for OrderDetailsWithAmount { fn convert_from(from: ApiOrderDetailsWithAmount) -> Self { let ApiOrderDetailsWithAmount { diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index cc6f1b0e411..e5c9c6fa81f 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -466,6 +466,9 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::BacsBankTransferInstructions, api_models::payments::RedirectResponse, api_models::payments::RequestSurchargeDetails, + api_models::payments::PaymentRevenueRecoveryMetadata, + api_models::payments::BillingConnectorPaymentDetails, + api_models::enums::PaymentConnectorTransmission, api_models::payments::PaymentAttemptResponse, api_models::payments::PaymentAttemptAmountDetails, api_models::payments::CaptureResponse,