Skip to content

Commit 57e92c9

Browse files
feat(core): Add support for Void after Capture (#8839)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 0598782 commit 57e92c9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1422
-87
lines changed

api-reference/docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"v1/payments/payments--confirm",
4343
"v1/payments/payments--retrieve",
4444
"v1/payments/payments--cancel",
45+
"v1/payments/payments--cancel-post-capture",
4546
"v1/payments/payments--capture",
4647
"v1/payments/payments--incremental-authorization",
4748
"v1/payments/payments--session-token",

api-reference/v1/openapi_spec_v1.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,67 @@
10831083
]
10841084
}
10851085
},
1086+
"/payments/{payment_id}/cancel_post_capture": {
1087+
"post": {
1088+
"tags": [
1089+
"Payments"
1090+
],
1091+
"summary": "Payments - Cancel Post Capture",
1092+
"description": "A Payment could can be cancelled when it is in one of these statuses: `succeeded`, `partially_captured`, `partially_captured_and_capturable`.",
1093+
"operationId": "Cancel a Payment Post Capture",
1094+
"parameters": [
1095+
{
1096+
"name": "payment_id",
1097+
"in": "path",
1098+
"description": "The identifier for payment",
1099+
"required": true,
1100+
"schema": {
1101+
"type": "string"
1102+
}
1103+
}
1104+
],
1105+
"requestBody": {
1106+
"content": {
1107+
"application/json": {
1108+
"schema": {
1109+
"$ref": "#/components/schemas/PaymentsCancelPostCaptureRequest"
1110+
},
1111+
"examples": {
1112+
"Cancel the payment post capture with cancellation reason": {
1113+
"value": {
1114+
"cancellation_reason": "requested_by_customer"
1115+
}
1116+
},
1117+
"Cancel the payment post capture with minimal fields": {
1118+
"value": {}
1119+
}
1120+
}
1121+
}
1122+
},
1123+
"required": true
1124+
},
1125+
"responses": {
1126+
"200": {
1127+
"description": "Payment canceled post capture"
1128+
},
1129+
"400": {
1130+
"description": "Missing mandatory fields",
1131+
"content": {
1132+
"application/json": {
1133+
"schema": {
1134+
"$ref": "#/components/schemas/GenericErrorResponseOpenApi"
1135+
}
1136+
}
1137+
}
1138+
}
1139+
},
1140+
"security": [
1141+
{
1142+
"api_key": []
1143+
}
1144+
]
1145+
}
1146+
},
10861147
"/payments/list": {
10871148
"get": {
10881149
"tags": [
@@ -7894,6 +7955,7 @@
78947955
"authorizing",
78957956
"cod_initiated",
78967957
"voided",
7958+
"voided_post_charge",
78977959
"void_initiated",
78987960
"capture_initiated",
78997961
"capture_failed",
@@ -14734,6 +14796,7 @@
1473414796
"payment_failed",
1473514797
"payment_processing",
1473614798
"payment_cancelled",
14799+
"payment_cancelled_post_capture",
1473714800
"payment_authorized",
1473814801
"payment_captured",
1473914802
"payment_expired",
@@ -16581,6 +16644,7 @@
1658116644
"succeeded",
1658216645
"failed",
1658316646
"cancelled",
16647+
"cancelled_post_capture",
1658416648
"processing",
1658516649
"requires_customer_action",
1658616650
"requires_merchant_action",
@@ -22069,6 +22133,17 @@
2206922133
"recurring_mandate"
2207022134
]
2207122135
},
22136+
"PaymentsCancelPostCaptureRequest": {
22137+
"type": "object",
22138+
"description": "Request to cancel a payment when the payment is already captured",
22139+
"properties": {
22140+
"cancellation_reason": {
22141+
"type": "string",
22142+
"description": "The reason for the payment cancel",
22143+
"nullable": true
22144+
}
22145+
}
22146+
},
2207222147
"PaymentsCancelRequest": {
2207322148
"type": "object",
2207422149
"properties": {
@@ -31718,6 +31793,7 @@
3171831793
"AUTHORIZING",
3171931794
"C_O_D_INITIATED",
3172031795
"VOIDED",
31796+
"VOIDED_POST_CHARGE",
3172131797
"VOID_INITIATED",
3172231798
"NOP",
3172331799
"CAPTURE_INITIATED",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
openapi: post /payments/{payment_id}/cancel_post_capture
3+
---

api-reference/v2/openapi_spec_v2.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4902,6 +4902,7 @@
49024902
"authorizing",
49034903
"cod_initiated",
49044904
"voided",
4905+
"voided_post_charge",
49054906
"void_initiated",
49064907
"capture_initiated",
49074908
"capture_failed",
@@ -10781,6 +10782,7 @@
1078110782
"payment_failed",
1078210783
"payment_processing",
1078310784
"payment_cancelled",
10785+
"payment_cancelled_post_capture",
1078410786
"payment_authorized",
1078510787
"payment_captured",
1078610788
"payment_expired",
@@ -12740,6 +12742,7 @@
1274012742
"succeeded",
1274112743
"failed",
1274212744
"cancelled",
12745+
"cancelled_post_capture",
1274312746
"processing",
1274412747
"requires_customer_action",
1274512748
"requires_merchant_action",

crates/api_models/src/events/payment.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use crate::{
2727
payment_methods::{PaymentMethodListRequest, PaymentMethodListResponse},
2828
payments::{
2929
ExtendedCardInfoResponse, PaymentIdType, PaymentListFilterConstraints,
30-
PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelRequest,
31-
PaymentsCaptureRequest, PaymentsCompleteAuthorizeRequest,
30+
PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelPostCaptureRequest,
31+
PaymentsCancelRequest, PaymentsCaptureRequest, PaymentsCompleteAuthorizeRequest,
3232
PaymentsDynamicTaxCalculationRequest, PaymentsDynamicTaxCalculationResponse,
3333
PaymentsExternalAuthenticationRequest, PaymentsExternalAuthenticationResponse,
3434
PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest,
@@ -134,6 +134,15 @@ impl ApiEventMetric for PaymentsCancelRequest {
134134
}
135135
}
136136

137+
#[cfg(feature = "v1")]
138+
impl ApiEventMetric for PaymentsCancelPostCaptureRequest {
139+
fn get_api_event_type(&self) -> Option<ApiEventsType> {
140+
Some(ApiEventsType::Payment {
141+
payment_id: self.payment_id.clone(),
142+
})
143+
}
144+
}
145+
137146
#[cfg(feature = "v1")]
138147
impl ApiEventMetric for PaymentsApproveRequest {
139148
fn get_api_event_type(&self) -> Option<ApiEventsType> {

crates/api_models/src/open_router.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ pub enum TxnStatus {
221221
Authorizing,
222222
CODInitiated,
223223
Voided,
224+
VoidedPostCharge,
224225
VoidInitiated,
225226
Nop,
226227
CaptureInitiated,

crates/api_models/src/payments.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7689,6 +7689,16 @@ pub struct PaymentsCancelRequest {
76897689
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
76907690
}
76917691

7692+
/// Request to cancel a payment when the payment is already captured
7693+
#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
7694+
pub struct PaymentsCancelPostCaptureRequest {
7695+
/// The identifier for the payment
7696+
#[serde(skip)]
7697+
pub payment_id: id_type::PaymentId,
7698+
/// The reason for the payment cancel
7699+
pub cancellation_reason: Option<String>,
7700+
}
7701+
76927702
#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
76937703
pub struct PaymentsIncrementalAuthorizationRequest {
76947704
/// The identifier for the payment

crates/common_enums/src/enums.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ pub enum AttemptStatus {
141141
Authorizing,
142142
CodInitiated,
143143
Voided,
144+
VoidedPostCharge,
144145
VoidInitiated,
145146
CaptureInitiated,
146147
CaptureFailed,
@@ -166,6 +167,7 @@ impl AttemptStatus {
166167
| Self::Charged
167168
| Self::AutoRefunded
168169
| Self::Voided
170+
| Self::VoidedPostCharge
169171
| Self::VoidFailed
170172
| Self::CaptureFailed
171173
| Self::Failure
@@ -1501,6 +1503,7 @@ impl EventClass {
15011503
EventType::PaymentFailed,
15021504
EventType::PaymentProcessing,
15031505
EventType::PaymentCancelled,
1506+
EventType::PaymentCancelledPostCapture,
15041507
EventType::PaymentAuthorized,
15051508
EventType::PaymentCaptured,
15061509
EventType::PaymentExpired,
@@ -1555,6 +1558,7 @@ pub enum EventType {
15551558
PaymentFailed,
15561559
PaymentProcessing,
15571560
PaymentCancelled,
1561+
PaymentCancelledPostCapture,
15581562
PaymentAuthorized,
15591563
PaymentCaptured,
15601564
PaymentExpired,
@@ -1659,6 +1663,8 @@ pub enum IntentStatus {
16591663
Failed,
16601664
/// This payment has been cancelled.
16611665
Cancelled,
1666+
/// This payment has been cancelled post capture.
1667+
CancelledPostCapture,
16621668
/// This payment is still being processed by the payment processor.
16631669
/// The status update might happen through webhooks or polling with the connector.
16641670
Processing,
@@ -1690,6 +1696,7 @@ impl IntentStatus {
16901696
Self::Succeeded
16911697
| Self::Failed
16921698
| Self::Cancelled
1699+
| Self::CancelledPostCapture
16931700
| Self::PartiallyCaptured
16941701
| Self::Expired => true,
16951702
Self::Processing
@@ -1713,6 +1720,7 @@ impl IntentStatus {
17131720
| Self::Succeeded
17141721
| Self::Failed
17151722
| Self::Cancelled
1723+
| Self::CancelledPostCapture
17161724
| Self::PartiallyCaptured
17171725
| Self::RequiresCapture | Self::Conflicted | Self::Expired=> false,
17181726
Self::Processing
@@ -1826,6 +1834,7 @@ impl From<AttemptStatus> for PaymentMethodStatus {
18261834
match attempt_status {
18271835
AttemptStatus::Failure
18281836
| AttemptStatus::Voided
1837+
| AttemptStatus::VoidedPostCharge
18291838
| AttemptStatus::Started
18301839
| AttemptStatus::Pending
18311840
| AttemptStatus::Unresolved

crates/common_enums/src/transformers.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,6 +2123,7 @@ impl From<AttemptStatus> for IntentStatus {
21232123
| AttemptStatus::CaptureFailed
21242124
| AttemptStatus::Failure => Self::Failed,
21252125
AttemptStatus::Voided => Self::Cancelled,
2126+
AttemptStatus::VoidedPostCharge => Self::CancelledPostCapture,
21262127
AttemptStatus::Expired => Self::Expired,
21272128
}
21282129
}
@@ -2138,6 +2139,7 @@ impl From<IntentStatus> for Option<EventType> {
21382139
| IntentStatus::RequiresCustomerAction
21392140
| IntentStatus::Conflicted => Some(EventType::ActionRequired),
21402141
IntentStatus::Cancelled => Some(EventType::PaymentCancelled),
2142+
IntentStatus::CancelledPostCapture => Some(EventType::PaymentCancelledPostCapture),
21412143
IntentStatus::Expired => Some(EventType::PaymentExpired),
21422144
IntentStatus::PartiallyCaptured | IntentStatus::PartiallyCapturedAndCapturable => {
21432145
Some(EventType::PaymentCaptured)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ impl TryFrom<enums::AttemptStatus> for ChargebeeRecordStatus {
698698
| enums::AttemptStatus::Authorizing
699699
| enums::AttemptStatus::CodInitiated
700700
| enums::AttemptStatus::Voided
701+
| enums::AttemptStatus::VoidedPostCharge
701702
| enums::AttemptStatus::VoidInitiated
702703
| enums::AttemptStatus::CaptureInitiated
703704
| enums::AttemptStatus::VoidFailed

0 commit comments

Comments
 (0)