Skip to content

Commit 9e8df84

Browse files
srujanchikkeChikke Srujanhyperswitch-bot[bot]
authored
feat(recovery): add support for custom billing api for v2 (#8838)
Co-authored-by: Chikke Srujan <[email protected]> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent b0b7193 commit 9e8df84

File tree

15 files changed

+622
-178
lines changed

15 files changed

+622
-178
lines changed

crates/api_models/src/events/payment.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use common_utils::events::{ApiEventMetric, ApiEventsType};
44
use super::{
55
PaymentAttemptListRequest, PaymentAttemptListResponse, PaymentStartRedirectionRequest,
66
PaymentsCreateIntentRequest, PaymentsGetIntentRequest, PaymentsIntentResponse, PaymentsRequest,
7+
RecoveryPaymentsCreate, RecoveryPaymentsResponse,
78
};
89
#[cfg(feature = "v2")]
910
use crate::payment_methods::{
@@ -416,6 +417,20 @@ impl ApiEventMetric for PaymentListResponse {
416417
}
417418
}
418419

420+
#[cfg(feature = "v2")]
421+
impl ApiEventMetric for RecoveryPaymentsCreate {
422+
fn get_api_event_type(&self) -> Option<ApiEventsType> {
423+
None
424+
}
425+
}
426+
427+
#[cfg(feature = "v2")]
428+
impl ApiEventMetric for RecoveryPaymentsResponse {
429+
fn get_api_event_type(&self) -> Option<ApiEventsType> {
430+
None
431+
}
432+
}
433+
419434
#[cfg(feature = "v1")]
420435
impl ApiEventMetric for PaymentListResponseV2 {
421436
fn get_api_event_type(&self) -> Option<ApiEventsType> {
@@ -496,7 +511,6 @@ impl ApiEventMetric for payments::PaymentMethodListResponseForPayments {
496511
None
497512
}
498513
}
499-
500514
#[cfg(feature = "v2")]
501515
impl ApiEventMetric for PaymentMethodListResponseForSession {}
502516

crates/api_models/src/payments.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,32 @@ pub struct PaymentAttemptRecordResponse {
16961696
pub created_at: PrimitiveDateTime,
16971697
}
16981698

1699+
#[cfg(feature = "v2")]
1700+
#[derive(Debug, serde::Serialize, Clone, ToSchema)]
1701+
pub struct RecoveryPaymentsResponse {
1702+
/// Unique identifier for the payment.
1703+
#[schema(
1704+
min_length = 30,
1705+
max_length = 30,
1706+
example = "pay_mbabizu24mvu3mela5njyhpit4",
1707+
value_type = String,
1708+
)]
1709+
pub id: id_type::GlobalPaymentId,
1710+
1711+
#[schema(value_type = IntentStatus, example = "failed", default = "requires_confirmation")]
1712+
pub intent_status: api_enums::IntentStatus,
1713+
1714+
/// Unique identifier for the payment. This ensures idempotency for multiple payments
1715+
/// that have been done by a single merchant.
1716+
#[schema(
1717+
value_type = Option<String>,
1718+
min_length = 30,
1719+
max_length = 30,
1720+
example = "pay_mbabizu24mvu3mela5njyhpit4"
1721+
)]
1722+
pub merchant_reference_id: Option<id_type::PaymentReferenceId>,
1723+
}
1724+
16991725
#[cfg(feature = "v2")]
17001726
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, ToSchema)]
17011727
pub struct PaymentAttemptFeatureMetadata {
@@ -4318,6 +4344,12 @@ pub struct PaymentMethodDataResponseWithBilling {
43184344
pub billing: Option<Address>,
43194345
}
43204346

4347+
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, ToSchema, serde::Serialize)]
4348+
pub struct CustomRecoveryPaymentMethodData {
4349+
#[serde(flatten)]
4350+
pub units: HashMap<String, AdditionalCardInfo>,
4351+
}
4352+
43214353
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, ToSchema)]
43224354
#[cfg(feature = "v1")]
43234355
pub enum PaymentIdType {
@@ -9100,6 +9132,78 @@ pub struct PaymentsAttemptRecordRequest {
91009132
pub card_issuer: Option<String>,
91019133
}
91029134

9135+
// Serialize is required because the api event requires Serialize to be implemented
9136+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
9137+
#[serde(deny_unknown_fields)]
9138+
#[cfg(feature = "v2")]
9139+
pub struct RecoveryPaymentsCreate {
9140+
/// The amount details for the payment
9141+
pub amount_details: AmountDetails,
9142+
9143+
/// Unique identifier for the payment. This ensures idempotency for multiple payments
9144+
/// that have been done by a single merchant.
9145+
#[schema(
9146+
value_type = Option<String>,
9147+
min_length = 30,
9148+
max_length = 30,
9149+
example = "pay_mbabizu24mvu3mela5njyhpit4"
9150+
)]
9151+
pub merchant_reference_id: id_type::PaymentReferenceId,
9152+
9153+
/// Error details for the payment if any
9154+
pub error: Option<ErrorDetails>,
9155+
9156+
/// Billing connector id to update the invoices.
9157+
#[schema(value_type = String, example = "mca_1234567890")]
9158+
pub billing_merchant_connector_id: id_type::MerchantConnectorAccountId,
9159+
9160+
/// Payments connector id to update the invoices.
9161+
#[schema(value_type = String, example = "mca_1234567890")]
9162+
pub payment_merchant_connector_id: id_type::MerchantConnectorAccountId,
9163+
9164+
#[schema(value_type = AttemptStatus, example = "charged")]
9165+
pub attempt_status: enums::AttemptStatus,
9166+
9167+
/// The billing details of the payment attempt.
9168+
pub billing: Option<Address>,
9169+
9170+
/// The payment method subtype to be used for the payment. This should match with the `payment_method_data` provided
9171+
#[schema(value_type = PaymentMethodType, example = "apple_pay")]
9172+
pub payment_method_sub_type: api_enums::PaymentMethodType,
9173+
9174+
/// primary payment method token at payment processor end.
9175+
#[schema(value_type = String, example = "token_1234")]
9176+
pub primary_processor_payment_method_token: Secret<String>,
9177+
9178+
/// The time at which payment attempt was created.
9179+
#[schema(example = "2022-09-10T10:11:12Z")]
9180+
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
9181+
pub transaction_created_at: Option<PrimitiveDateTime>,
9182+
9183+
/// Payment method type for the payment attempt
9184+
#[schema(value_type = Option<PaymentMethod>, example = "wallet")]
9185+
pub payment_method_type: common_enums::PaymentMethod,
9186+
9187+
/// customer id at payment connector for which mandate is attached.
9188+
#[schema(value_type = String, example = "cust_12345")]
9189+
pub connector_customer_id: Secret<String>,
9190+
9191+
/// Invoice billing started at billing connector end.
9192+
#[schema(example = "2022-09-10T10:11:12Z")]
9193+
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
9194+
pub billing_started_at: Option<PrimitiveDateTime>,
9195+
9196+
/// A unique identifier for a payment provided by the payment connector
9197+
#[schema(value_type = Option<String>, example = "993672945374576J")]
9198+
pub connector_transaction_id: Option<Secret<String>>,
9199+
9200+
/// payment method token units at payment processor end.
9201+
pub payment_method_units: CustomRecoveryPaymentMethodData,
9202+
9203+
/// Type of action that needs to be taken after consuming the recovery payload. For example: scheduling a failed payment or stopping the invoice.
9204+
pub action: common_payments_types::RecoveryAction,
9205+
}
9206+
91039207
/// Error details for the payment
91049208
#[cfg(feature = "v2")]
91059209
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]

crates/common_types/src/payments.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,3 +525,21 @@ impl ApplePayPredecryptData {
525525
Ok(Secret::new(format!("{month}{year}")))
526526
}
527527
}
528+
529+
/// type of action that needs to taken after consuming recovery payload
530+
#[derive(Debug, Clone, Serialize, Deserialize)]
531+
#[serde(rename_all = "snake_case")]
532+
pub enum RecoveryAction {
533+
/// Stops the process tracker and update the payment intent.
534+
CancelInvoice,
535+
/// Records the external transaction against payment intent.
536+
ScheduleFailedPayment,
537+
/// Records the external payment and stops the internal process tracker.
538+
SuccessPaymentExternal,
539+
/// Pending payments from billing processor.
540+
PendingPayment,
541+
/// No action required.
542+
NoAction,
543+
/// Invalid event has been received.
544+
InvalidAction,
545+
}

crates/hyperswitch_connectors/src/connectors/custombilling.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ use hyperswitch_interfaces::{
3636
types::{self, Response},
3737
webhooks,
3838
};
39-
use masking::{ExposeInterface, Mask};
4039
use transformers as custombilling;
4140

4241
use crate::{constants::headers, types::ResponseRouterData, utils};
@@ -114,14 +113,9 @@ impl ConnectorCommon for Custombilling {
114113

115114
fn get_auth_header(
116115
&self,
117-
auth_type: &ConnectorAuthType,
116+
_auth_type: &ConnectorAuthType,
118117
) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
119-
let auth = custombilling::CustombillingAuthType::try_from(auth_type)
120-
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
121-
Ok(vec![(
122-
headers::AUTHORIZATION.to_string(),
123-
auth.api_key.expose().into_masked(),
124-
)])
118+
Ok(vec![])
125119
}
126120

127121
fn build_error_response(

crates/hyperswitch_connectors/src/connectors/custombilling/transformers.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use common_enums::enums;
22
use common_utils::types::StringMinorUnit;
33
use hyperswitch_domain_models::{
44
payment_method_data::PaymentMethodData,
5-
router_data::{ConnectorAuthType, RouterData},
5+
router_data::RouterData,
66
router_flow_types::refunds::{Execute, RSync},
77
router_request_types::ResponseId,
88
router_response_types::{PaymentsResponseData, RefundsResponseData},
@@ -75,23 +75,6 @@ impl TryFrom<&CustombillingRouterData<&PaymentsAuthorizeRouterData>>
7575
}
7676
}
7777

78-
//TODO: Fill the struct with respective fields
79-
// Auth Struct
80-
pub struct CustombillingAuthType {
81-
pub(super) api_key: Secret<String>,
82-
}
83-
84-
impl TryFrom<&ConnectorAuthType> for CustombillingAuthType {
85-
type Error = error_stack::Report<errors::ConnectorError>;
86-
fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
87-
match auth_type {
88-
ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
89-
api_key: api_key.to_owned(),
90-
}),
91-
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
92-
}
93-
}
94-
}
9578
// PaymentsResponse
9679
//TODO: Append the remaining status flags
9780
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]

crates/hyperswitch_domain_models/src/revenue_recovery.rs

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -81,23 +81,6 @@ pub struct RevenueRecoveryInvoiceData {
8181
pub billing_started_at: Option<PrimitiveDateTime>,
8282
}
8383

84-
/// type of action that needs to taken after consuming recovery payload
85-
#[derive(Debug)]
86-
pub enum RecoveryAction {
87-
/// Stops the process tracker and update the payment intent.
88-
CancelInvoice,
89-
/// Records the external transaction against payment intent.
90-
ScheduleFailedPayment,
91-
/// Records the external payment and stops the internal process tracker.
92-
SuccessPaymentExternal,
93-
/// Pending payments from billing processor.
94-
PendingPayment,
95-
/// No action required.
96-
NoAction,
97-
/// Invalid event has been received.
98-
InvalidAction,
99-
}
100-
10184
#[derive(Clone, Debug)]
10285
pub struct RecoveryPaymentIntent {
10386
pub payment_id: id_type::GlobalPaymentId,
@@ -134,63 +117,6 @@ impl RecoveryPaymentAttempt {
134117
}
135118
}
136119

137-
impl RecoveryAction {
138-
pub fn get_action(
139-
event_type: webhooks::IncomingWebhookEvent,
140-
attempt_triggered_by: Option<common_enums::TriggeredBy>,
141-
) -> Self {
142-
match event_type {
143-
webhooks::IncomingWebhookEvent::PaymentIntentFailure
144-
| webhooks::IncomingWebhookEvent::PaymentIntentSuccess
145-
| webhooks::IncomingWebhookEvent::PaymentIntentProcessing
146-
| webhooks::IncomingWebhookEvent::PaymentIntentPartiallyFunded
147-
| webhooks::IncomingWebhookEvent::PaymentIntentCancelled
148-
| webhooks::IncomingWebhookEvent::PaymentIntentCancelFailure
149-
| webhooks::IncomingWebhookEvent::PaymentIntentAuthorizationSuccess
150-
| webhooks::IncomingWebhookEvent::PaymentIntentAuthorizationFailure
151-
| webhooks::IncomingWebhookEvent::PaymentIntentCaptureSuccess
152-
| webhooks::IncomingWebhookEvent::PaymentIntentCaptureFailure
153-
| webhooks::IncomingWebhookEvent::PaymentIntentExpired
154-
| webhooks::IncomingWebhookEvent::PaymentActionRequired
155-
| webhooks::IncomingWebhookEvent::EventNotSupported
156-
| webhooks::IncomingWebhookEvent::SourceChargeable
157-
| webhooks::IncomingWebhookEvent::SourceTransactionCreated
158-
| webhooks::IncomingWebhookEvent::RefundFailure
159-
| webhooks::IncomingWebhookEvent::RefundSuccess
160-
| webhooks::IncomingWebhookEvent::DisputeOpened
161-
| webhooks::IncomingWebhookEvent::DisputeExpired
162-
| webhooks::IncomingWebhookEvent::DisputeAccepted
163-
| webhooks::IncomingWebhookEvent::DisputeCancelled
164-
| webhooks::IncomingWebhookEvent::DisputeChallenged
165-
| webhooks::IncomingWebhookEvent::DisputeWon
166-
| webhooks::IncomingWebhookEvent::DisputeLost
167-
| webhooks::IncomingWebhookEvent::MandateActive
168-
| webhooks::IncomingWebhookEvent::MandateRevoked
169-
| webhooks::IncomingWebhookEvent::EndpointVerification
170-
| webhooks::IncomingWebhookEvent::ExternalAuthenticationARes
171-
| webhooks::IncomingWebhookEvent::FrmApproved
172-
| webhooks::IncomingWebhookEvent::FrmRejected
173-
| webhooks::IncomingWebhookEvent::PayoutSuccess
174-
| webhooks::IncomingWebhookEvent::PayoutFailure
175-
| webhooks::IncomingWebhookEvent::PayoutProcessing
176-
| webhooks::IncomingWebhookEvent::PayoutCancelled
177-
| webhooks::IncomingWebhookEvent::PayoutCreated
178-
| webhooks::IncomingWebhookEvent::PayoutExpired
179-
| webhooks::IncomingWebhookEvent::PayoutReversed => Self::InvalidAction,
180-
webhooks::IncomingWebhookEvent::RecoveryPaymentFailure => match attempt_triggered_by {
181-
Some(common_enums::TriggeredBy::Internal) => Self::NoAction,
182-
Some(common_enums::TriggeredBy::External) | None => Self::ScheduleFailedPayment,
183-
},
184-
webhooks::IncomingWebhookEvent::RecoveryPaymentSuccess => match attempt_triggered_by {
185-
Some(common_enums::TriggeredBy::Internal) => Self::NoAction,
186-
Some(common_enums::TriggeredBy::External) | None => Self::SuccessPaymentExternal,
187-
},
188-
webhooks::IncomingWebhookEvent::RecoveryPaymentPending => Self::PendingPayment,
189-
webhooks::IncomingWebhookEvent::RecoveryInvoiceCancel => Self::CancelInvoice,
190-
}
191-
}
192-
}
193-
194120
impl From<&RevenueRecoveryInvoiceData> for api_payments::AmountDetails {
195121
fn from(data: &RevenueRecoveryInvoiceData) -> Self {
196122
let amount = api_payments::AmountDetailsSetter {

0 commit comments

Comments
 (0)