refactor(router): add revenue_recovery_metadata to payment intent in diesel and api model for v2 flow (#7176)

Co-authored-by: Nishanth Challa <nishanth.challa@Nishanth-Challa-C0WGKCFHLF.local>
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
CHALLA NISHANTH BABU
2025-02-14 16:19:58 +05:30
committed by GitHub
parent fbbbe3eb90
commit 2ee22cdf8a
6 changed files with 285 additions and 3 deletions

View File

@ -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.",

View File

@ -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<RedirectResponse>)]
pub redirect_response: Option<RedirectResponse>,
/// Additional tags to be used for global search
#[schema(value_type = Option<Vec<String>>)]
pub search_tags: Option<Vec<HashedString<WithType>>>,
/// Recurring payment details required for apple pay Merchant Token
pub apple_pay_recurring_details: Option<ApplePayRecurringDetails>,
/// revenue recovery data for payment intent
pub payment_revenue_recovery_metadata: Option<PaymentRevenueRecoveryMetadata>,
}
/// 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<RedirectResponse>)]
pub redirect_response: Option<RedirectResponse>,
// TODO: Convert this to hashedstrings to avoid PII sensitive data
/// Additional tags to be used for global search
#[schema(value_type = Option<Vec<String>>)]
pub search_tags: Option<Vec<HashedString<WithType>>>,
@ -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,
}

View File

@ -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,
}

View File

@ -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<RedirectResponse>,
/// Additional tags to be used for global search
pub search_tags: Option<Vec<HashedString<WithType>>>,
/// Recurring payment details required for apple pay Merchant Token
pub apple_pay_recurring_details: Option<ApplePayRecurringDetails>,
/// revenue recovery data for payment intent
pub payment_revenue_recovery_metadata: Option<PaymentRevenueRecoveryMetadata>,
}
#[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<RedirectResponse>,
// TODO: Convert this to hashedstrings to avoid PII sensitive data
/// Additional tags to be used for global search
pub search_tags: Option<Vec<HashedString<WithType>>>,
/// 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,
}

View File

@ -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<T: ForeignIDRef> {
@ -78,6 +85,7 @@ pub trait ApiModelToDieselModelConvertor<F> {
fn convert_back(self) -> F;
}
#[cfg(feature = "v1")]
impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
fn convert_from(from: ApiFeatureMetadata) -> Self {
let ApiFeatureMetadata {
@ -85,6 +93,7 @@ impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
search_tags,
apple_pay_recurring_details,
} = from;
Self {
redirect_response: redirect_response.map(RedirectResponse::convert_from),
search_tags,
@ -99,6 +108,7 @@ impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
search_tags,
apple_pay_recurring_details,
} = self;
ApiFeatureMetadata {
redirect_response: redirect_response
.map(|redirect_response| redirect_response.convert_back()),
@ -109,6 +119,46 @@ impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
}
}
#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> 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),
}
}
fn convert_back(self) -> ApiFeatureMetadata {
let Self {
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()),
}
}
}
impl ApiModelToDieselModelConvertor<ApiRedirectResponse> for RedirectResponse {
fn convert_from(from: ApiRedirectResponse) -> Self {
let ApiRedirectResponse {
@ -204,6 +254,56 @@ impl ApiModelToDieselModelConvertor<ApiApplePayRecurringDetails> for ApplePayRec
}
}
#[cfg(feature = "v2")]
impl ApiModelToDieselModelConvertor<ApiRevenueRecoveryMetadata> 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<ApiBillingConnectorPaymentDetails>
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<ApiOrderDetailsWithAmount> for OrderDetailsWithAmount {
fn convert_from(from: ApiOrderDetailsWithAmount) -> Self {
let ApiOrderDetailsWithAmount {

View File

@ -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,