mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
fix: handle 5xx during multiple capture call (#2148)
This commit is contained in:
@ -278,6 +278,7 @@ pub struct Response {
|
||||
refusal_reason: Option<String>,
|
||||
refusal_reason_code: Option<String>,
|
||||
additional_data: Option<AdditionalData>,
|
||||
// event_code will be available only in webhook body
|
||||
event_code: Option<WebhookEventCode>,
|
||||
}
|
||||
|
||||
@ -3710,6 +3711,12 @@ impl utils::MultipleCaptureSyncResponse for Response {
|
||||
fn get_connector_reference_id(&self) -> Option<String> {
|
||||
Some(self.merchant_reference.clone())
|
||||
}
|
||||
|
||||
fn get_amount_captured(&self) -> Option<i64> {
|
||||
self.amount
|
||||
.as_ref()
|
||||
.map(|amount_struct| amount_struct.value)
|
||||
}
|
||||
}
|
||||
|
||||
// Payouts
|
||||
|
||||
@ -872,6 +872,10 @@ impl utils::MultipleCaptureSyncResponse for ActionResponse {
|
||||
fn is_capture_response(&self) -> bool {
|
||||
self.action_type == ActionType::Capture
|
||||
}
|
||||
|
||||
fn get_amount_captured(&self) -> Option<i64> {
|
||||
Some(self.amount)
|
||||
}
|
||||
}
|
||||
|
||||
impl utils::MultipleCaptureSyncResponse for Box<PaymentsResponse> {
|
||||
@ -890,6 +894,12 @@ impl utils::MultipleCaptureSyncResponse for Box<PaymentsResponse> {
|
||||
fn is_capture_response(&self) -> bool {
|
||||
self.status == CheckoutPaymentStatus::Captured
|
||||
}
|
||||
fn get_amount_captured(&self) -> Option<i64> {
|
||||
match self.amount {
|
||||
Some(amount) => amount.try_into().ok(),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Deserialize, Eq, PartialEq)]
|
||||
|
||||
@ -506,6 +506,12 @@ impl utils::MultipleCaptureSyncResponse for GlobalpayPaymentsResponse {
|
||||
true
|
||||
}
|
||||
|
||||
fn get_amount_captured(&self) -> Option<i64> {
|
||||
match self.amount.clone() {
|
||||
Some(amount) => amount.parse().ok(),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
fn get_connector_reference_id(&self) -> Option<String> {
|
||||
self.reference.clone()
|
||||
}
|
||||
|
||||
@ -1380,6 +1380,7 @@ pub trait MultipleCaptureSyncResponse {
|
||||
fn get_connector_reference_id(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
fn get_amount_captured(&self) -> Option<i64>;
|
||||
}
|
||||
|
||||
pub fn construct_captures_response_hashmap<T>(
|
||||
@ -1401,6 +1402,7 @@ where
|
||||
status: capture_sync_response.get_capture_attempt_status(),
|
||||
connector_response_reference_id: capture_sync_response
|
||||
.get_connector_reference_id(),
|
||||
amount: capture_sync_response.get_amount_captured(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -191,6 +191,7 @@ impl types::RouterData<api::PSync, types::PaymentsSyncData, types::PaymentsRespo
|
||||
message: err.message,
|
||||
reason: err.reason,
|
||||
status_code: err.status_code,
|
||||
amount: None,
|
||||
});
|
||||
},
|
||||
Ok(types::PaymentsResponseData::MultipleCaptureResponse { capture_sync_response_list })=> {
|
||||
|
||||
@ -621,16 +621,54 @@ fn response_to_capture_update(
|
||||
response_list: HashMap<String, CaptureSyncResponse>,
|
||||
) -> RouterResult<Vec<(storage::Capture, storage::CaptureUpdate)>> {
|
||||
let mut capture_update_list = vec![];
|
||||
let mut unmapped_captures = vec![];
|
||||
for (connector_capture_id, capture_sync_response) in response_list {
|
||||
let capture =
|
||||
multiple_capture_data.get_capture_by_connector_capture_id(connector_capture_id);
|
||||
if let Some(capture) = capture {
|
||||
capture_update_list.push((capture.clone(), capture_sync_response.try_into()?))
|
||||
} else {
|
||||
// connector_capture_id may not be populated in the captures table in some case
|
||||
// if so, we try to map the unmapped capture response and captures in DB.
|
||||
unmapped_captures.push(capture_sync_response)
|
||||
}
|
||||
}
|
||||
capture_update_list.extend(get_capture_update_for_unmapped_capture_responses(
|
||||
unmapped_captures,
|
||||
multiple_capture_data,
|
||||
)?);
|
||||
|
||||
Ok(capture_update_list)
|
||||
}
|
||||
|
||||
fn get_capture_update_for_unmapped_capture_responses(
|
||||
unmapped_capture_sync_response_list: Vec<CaptureSyncResponse>,
|
||||
multiple_capture_data: &MultipleCaptureData,
|
||||
) -> RouterResult<Vec<(storage::Capture, storage::CaptureUpdate)>> {
|
||||
let mut result = Vec::new();
|
||||
let captures_without_connector_capture_id: Vec<_> = multiple_capture_data
|
||||
.get_pending_captures_without_connector_capture_id()
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
for capture_sync_response in unmapped_capture_sync_response_list {
|
||||
if let Some(capture) = captures_without_connector_capture_id
|
||||
.iter()
|
||||
.find(|capture| {
|
||||
capture_sync_response.get_connector_response_reference_id()
|
||||
== Some(capture.capture_id.clone())
|
||||
|| capture_sync_response.get_amount_captured() == Some(capture.amount)
|
||||
})
|
||||
{
|
||||
result.push((
|
||||
capture.clone(),
|
||||
storage::CaptureUpdate::try_from(capture_sync_response)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn get_total_amount_captured<F: Clone, T: types::Capturable>(
|
||||
request: T,
|
||||
amount_captured: Option<i64>,
|
||||
|
||||
@ -1206,6 +1206,7 @@ impl TryFrom<types::CaptureSyncResponse> for storage::CaptureUpdate {
|
||||
resource_id,
|
||||
status,
|
||||
connector_response_reference_id,
|
||||
..
|
||||
} => {
|
||||
let connector_capture_id = match resource_id {
|
||||
types::ResponseId::ConnectorTransactionId(id) => Some(id),
|
||||
@ -1222,6 +1223,7 @@ impl TryFrom<types::CaptureSyncResponse> for storage::CaptureUpdate {
|
||||
message,
|
||||
reason,
|
||||
status_code,
|
||||
..
|
||||
} => Ok(Self::ErrorUpdate {
|
||||
status: match status_code {
|
||||
500..=511 => storage::enums::CaptureStatus::Pending,
|
||||
|
||||
@ -157,4 +157,10 @@ impl MultipleCaptureData {
|
||||
.collect();
|
||||
pending_connector_capture_ids
|
||||
}
|
||||
pub fn get_pending_captures_without_connector_capture_id(&self) -> Vec<&storage::Capture> {
|
||||
self.get_pending_captures()
|
||||
.into_iter()
|
||||
.filter(|capture| capture.connector_capture_id.is_none())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@ -572,15 +572,34 @@ pub enum CaptureSyncResponse {
|
||||
resource_id: ResponseId,
|
||||
status: storage_enums::AttemptStatus,
|
||||
connector_response_reference_id: Option<String>,
|
||||
amount: Option<i64>,
|
||||
},
|
||||
Error {
|
||||
code: String,
|
||||
message: String,
|
||||
reason: Option<String>,
|
||||
status_code: u16,
|
||||
amount: Option<i64>,
|
||||
},
|
||||
}
|
||||
|
||||
impl CaptureSyncResponse {
|
||||
pub fn get_amount_captured(&self) -> Option<i64> {
|
||||
match self {
|
||||
Self::Success { amount, .. } | Self::Error { amount, .. } => *amount,
|
||||
}
|
||||
}
|
||||
pub fn get_connector_response_reference_id(&self) -> Option<String> {
|
||||
match self {
|
||||
Self::Success {
|
||||
connector_response_reference_id,
|
||||
..
|
||||
} => connector_response_reference_id.clone(),
|
||||
Self::Error { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PaymentsResponseData {
|
||||
TransactionResponse {
|
||||
|
||||
Reference in New Issue
Block a user