Skip to content

Commit e8d948e

Browse files
fix: handle 5xx during multiple capture call (#2148)
1 parent 1ea823b commit e8d948e

File tree

9 files changed

+91
-0
lines changed

9 files changed

+91
-0
lines changed

crates/router/src/connector/adyen/transformers.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ pub struct Response {
278278
refusal_reason: Option<String>,
279279
refusal_reason_code: Option<String>,
280280
additional_data: Option<AdditionalData>,
281+
// event_code will be available only in webhook body
281282
event_code: Option<WebhookEventCode>,
282283
}
283284

@@ -3710,6 +3711,12 @@ impl utils::MultipleCaptureSyncResponse for Response {
37103711
fn get_connector_reference_id(&self) -> Option<String> {
37113712
Some(self.merchant_reference.clone())
37123713
}
3714+
3715+
fn get_amount_captured(&self) -> Option<i64> {
3716+
self.amount
3717+
.as_ref()
3718+
.map(|amount_struct| amount_struct.value)
3719+
}
37133720
}
37143721

37153722
// Payouts

crates/router/src/connector/checkout/transformers.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,10 @@ impl utils::MultipleCaptureSyncResponse for ActionResponse {
872872
fn is_capture_response(&self) -> bool {
873873
self.action_type == ActionType::Capture
874874
}
875+
876+
fn get_amount_captured(&self) -> Option<i64> {
877+
Some(self.amount)
878+
}
875879
}
876880

877881
impl utils::MultipleCaptureSyncResponse for Box<PaymentsResponse> {
@@ -890,6 +894,12 @@ impl utils::MultipleCaptureSyncResponse for Box<PaymentsResponse> {
890894
fn is_capture_response(&self) -> bool {
891895
self.status == CheckoutPaymentStatus::Captured
892896
}
897+
fn get_amount_captured(&self) -> Option<i64> {
898+
match self.amount {
899+
Some(amount) => amount.try_into().ok(),
900+
None => None,
901+
}
902+
}
893903
}
894904

895905
#[derive(Debug, Clone, serde::Deserialize, Eq, PartialEq)]

crates/router/src/connector/globalpay/transformers.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,12 @@ impl utils::MultipleCaptureSyncResponse for GlobalpayPaymentsResponse {
506506
true
507507
}
508508

509+
fn get_amount_captured(&self) -> Option<i64> {
510+
match self.amount.clone() {
511+
Some(amount) => amount.parse().ok(),
512+
None => None,
513+
}
514+
}
509515
fn get_connector_reference_id(&self) -> Option<String> {
510516
self.reference.clone()
511517
}

crates/router/src/connector/utils.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,7 @@ pub trait MultipleCaptureSyncResponse {
13801380
fn get_connector_reference_id(&self) -> Option<String> {
13811381
None
13821382
}
1383+
fn get_amount_captured(&self) -> Option<i64>;
13831384
}
13841385

13851386
pub fn construct_captures_response_hashmap<T>(
@@ -1401,6 +1402,7 @@ where
14011402
status: capture_sync_response.get_capture_attempt_status(),
14021403
connector_response_reference_id: capture_sync_response
14031404
.get_connector_reference_id(),
1405+
amount: capture_sync_response.get_amount_captured(),
14041406
},
14051407
);
14061408
}

crates/router/src/core/payments/flows/psync_flow.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ impl types::RouterData<api::PSync, types::PaymentsSyncData, types::PaymentsRespo
191191
message: err.message,
192192
reason: err.reason,
193193
status_code: err.status_code,
194+
amount: None,
194195
});
195196
},
196197
Ok(types::PaymentsResponseData::MultipleCaptureResponse { capture_sync_response_list })=> {

crates/router/src/core/payments/operations/payment_response.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,16 +621,54 @@ fn response_to_capture_update(
621621
response_list: HashMap<String, CaptureSyncResponse>,
622622
) -> RouterResult<Vec<(storage::Capture, storage::CaptureUpdate)>> {
623623
let mut capture_update_list = vec![];
624+
let mut unmapped_captures = vec![];
624625
for (connector_capture_id, capture_sync_response) in response_list {
625626
let capture =
626627
multiple_capture_data.get_capture_by_connector_capture_id(connector_capture_id);
627628
if let Some(capture) = capture {
628629
capture_update_list.push((capture.clone(), capture_sync_response.try_into()?))
630+
} else {
631+
// connector_capture_id may not be populated in the captures table in some case
632+
// if so, we try to map the unmapped capture response and captures in DB.
633+
unmapped_captures.push(capture_sync_response)
629634
}
630635
}
636+
capture_update_list.extend(get_capture_update_for_unmapped_capture_responses(
637+
unmapped_captures,
638+
multiple_capture_data,
639+
)?);
640+
631641
Ok(capture_update_list)
632642
}
633643

644+
fn get_capture_update_for_unmapped_capture_responses(
645+
unmapped_capture_sync_response_list: Vec<CaptureSyncResponse>,
646+
multiple_capture_data: &MultipleCaptureData,
647+
) -> RouterResult<Vec<(storage::Capture, storage::CaptureUpdate)>> {
648+
let mut result = Vec::new();
649+
let captures_without_connector_capture_id: Vec<_> = multiple_capture_data
650+
.get_pending_captures_without_connector_capture_id()
651+
.into_iter()
652+
.cloned()
653+
.collect();
654+
for capture_sync_response in unmapped_capture_sync_response_list {
655+
if let Some(capture) = captures_without_connector_capture_id
656+
.iter()
657+
.find(|capture| {
658+
capture_sync_response.get_connector_response_reference_id()
659+
== Some(capture.capture_id.clone())
660+
|| capture_sync_response.get_amount_captured() == Some(capture.amount)
661+
})
662+
{
663+
result.push((
664+
capture.clone(),
665+
storage::CaptureUpdate::try_from(capture_sync_response)?,
666+
))
667+
}
668+
}
669+
Ok(result)
670+
}
671+
634672
fn get_total_amount_captured<F: Clone, T: types::Capturable>(
635673
request: T,
636674
amount_captured: Option<i64>,

crates/router/src/core/payments/transformers.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,7 @@ impl TryFrom<types::CaptureSyncResponse> for storage::CaptureUpdate {
12061206
resource_id,
12071207
status,
12081208
connector_response_reference_id,
1209+
..
12091210
} => {
12101211
let connector_capture_id = match resource_id {
12111212
types::ResponseId::ConnectorTransactionId(id) => Some(id),
@@ -1222,6 +1223,7 @@ impl TryFrom<types::CaptureSyncResponse> for storage::CaptureUpdate {
12221223
message,
12231224
reason,
12241225
status_code,
1226+
..
12251227
} => Ok(Self::ErrorUpdate {
12261228
status: match status_code {
12271229
500..=511 => storage::enums::CaptureStatus::Pending,

crates/router/src/core/payments/types.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,10 @@ impl MultipleCaptureData {
157157
.collect();
158158
pending_connector_capture_ids
159159
}
160+
pub fn get_pending_captures_without_connector_capture_id(&self) -> Vec<&storage::Capture> {
161+
self.get_pending_captures()
162+
.into_iter()
163+
.filter(|capture| capture.connector_capture_id.is_none())
164+
.collect()
165+
}
160166
}

crates/router/src/types.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,15 +572,34 @@ pub enum CaptureSyncResponse {
572572
resource_id: ResponseId,
573573
status: storage_enums::AttemptStatus,
574574
connector_response_reference_id: Option<String>,
575+
amount: Option<i64>,
575576
},
576577
Error {
577578
code: String,
578579
message: String,
579580
reason: Option<String>,
580581
status_code: u16,
582+
amount: Option<i64>,
581583
},
582584
}
583585

586+
impl CaptureSyncResponse {
587+
pub fn get_amount_captured(&self) -> Option<i64> {
588+
match self {
589+
Self::Success { amount, .. } | Self::Error { amount, .. } => *amount,
590+
}
591+
}
592+
pub fn get_connector_response_reference_id(&self) -> Option<String> {
593+
match self {
594+
Self::Success {
595+
connector_response_reference_id,
596+
..
597+
} => connector_response_reference_id.clone(),
598+
Self::Error { .. } => None,
599+
}
600+
}
601+
}
602+
584603
#[derive(Debug, Clone)]
585604
pub enum PaymentsResponseData {
586605
TransactionResponse {

0 commit comments

Comments
 (0)