mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
fix(router): [worldpayvantiv] dispute validations and statuses (#8862)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -3856,33 +3856,86 @@ fn get_dispute_stage(
|
||||
|
||||
pub fn get_dispute_status(
|
||||
dispute_cycle: String,
|
||||
) -> Result<api_models::enums::DisputeStatus, error_stack::Report<errors::ConnectorError>> {
|
||||
match connector_utils::normalize_string(dispute_cycle.clone())
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?
|
||||
.as_str()
|
||||
{
|
||||
"arbitration"
|
||||
| "arbitrationmastercard"
|
||||
| "arbitrationsplit"
|
||||
| "representment"
|
||||
| "issuerarbitration"
|
||||
| "prearbitration"
|
||||
| "responsetoissuerarbitration"
|
||||
| "arbitrationchargeback" => Ok(api_models::enums::DisputeStatus::DisputeChallenged),
|
||||
"chargebackreversal" | "issueracceptedprearbitration" | "arbitrationwon" => {
|
||||
Ok(api_models::enums::DisputeStatus::DisputeWon)
|
||||
dispute_activities: Vec<Activity>,
|
||||
) -> Result<common_enums::DisputeStatus, error_stack::Report<errors::ConnectorError>> {
|
||||
if let Some(activity) = get_last_non_auxiliary_activity_type(dispute_activities) {
|
||||
match activity.as_ref() {
|
||||
"Merchant Accept"
|
||||
| "Issuer Accepted Pre-Arbitration"
|
||||
| "Vantiv Accept"
|
||||
| "Sent Credit" => Ok(common_enums::DisputeStatus::DisputeAccepted),
|
||||
|
||||
"Merchant Represent"
|
||||
| "Respond to Dispute"
|
||||
| "Respond to PreArb"
|
||||
| "Request Arbitration"
|
||||
| "Request Pre-Arbitration"
|
||||
| "Create Arbitration"
|
||||
| "Record Arbitration"
|
||||
| "Create Pre-Arbitration"
|
||||
| "File Arbitration"
|
||||
| "File Pre-Arbitration"
|
||||
| "File Visa Pre-Arbitration"
|
||||
| "Send Representment"
|
||||
| "Send Response"
|
||||
| "Arbitration"
|
||||
| "Arbitration (Mastercard)"
|
||||
| "Arbitration Chargeback"
|
||||
| "Issuer Declined Pre-Arbitration"
|
||||
| "Issuer Arbitration"
|
||||
| "Request Response to Pre-Arbitration"
|
||||
| "Vantiv Represent"
|
||||
| "Vantiv Respond"
|
||||
| "Auto Represent"
|
||||
| "Arbitration Ruling" => Ok(common_enums::DisputeStatus::DisputeChallenged),
|
||||
|
||||
"Arbitration Lost" | "Unsuccessful Arbitration" | "Unsuccessful Pre-Arbitration" => {
|
||||
Ok(common_enums::DisputeStatus::DisputeLost)
|
||||
}
|
||||
|
||||
"Arbitration Won"
|
||||
| "Arbitration Split"
|
||||
| "Successful Arbitration"
|
||||
| "Successful Pre-Arbitration" => Ok(common_enums::DisputeStatus::DisputeWon),
|
||||
|
||||
"Chargeback Reversal" => Ok(common_enums::DisputeStatus::DisputeCancelled),
|
||||
|
||||
"Receive Network Transaction" => Ok(common_enums::DisputeStatus::DisputeOpened),
|
||||
|
||||
"Unaccept" | "Unrepresent" => Ok(common_enums::DisputeStatus::DisputeOpened),
|
||||
|
||||
unexpected_activity => Err(errors::ConnectorError::UnexpectedResponseError(
|
||||
bytes::Bytes::from(format!("Dispute Activity: {unexpected_activity})")),
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
"arbitrationlost" | "issuerdeclinedprearbitration" => {
|
||||
Ok(api_models::enums::DisputeStatus::DisputeLost)
|
||||
} else {
|
||||
match connector_utils::normalize_string(dispute_cycle.clone())
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?
|
||||
.as_str()
|
||||
{
|
||||
"arbitration"
|
||||
| "arbitrationmastercard"
|
||||
| "arbitrationsplit"
|
||||
| "representment"
|
||||
| "issuerarbitration"
|
||||
| "prearbitration"
|
||||
| "responsetoissuerarbitration"
|
||||
| "arbitrationchargeback" => Ok(api_models::enums::DisputeStatus::DisputeChallenged),
|
||||
"chargebackreversal" | "issueracceptedprearbitration" | "arbitrationwon" => {
|
||||
Ok(api_models::enums::DisputeStatus::DisputeWon)
|
||||
}
|
||||
"arbitrationlost" | "issuerdeclinedprearbitration" => {
|
||||
Ok(api_models::enums::DisputeStatus::DisputeLost)
|
||||
}
|
||||
"firstchargeback" | "retrievalrequest" | "rapiddisputeresolution" => {
|
||||
Ok(api_models::enums::DisputeStatus::DisputeOpened)
|
||||
}
|
||||
dispute_cycle => Err(errors::ConnectorError::UnexpectedResponseError(
|
||||
bytes::Bytes::from(format!("Dispute Stage: {dispute_cycle}")),
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
"firstchargeback" | "retrievalrequest" | "rapiddisputeresolution" => {
|
||||
Ok(api_models::enums::DisputeStatus::DisputeOpened)
|
||||
}
|
||||
_ => Err(errors::ConnectorError::NotSupported {
|
||||
message: format!("Dispute status {dispute_cycle}"),
|
||||
connector: "worldpayvantiv",
|
||||
}
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -3914,7 +3967,7 @@ impl TryFrom<ChargebackCase> for DisputeSyncResponse {
|
||||
amount,
|
||||
currency: item.chargeback_currency_type,
|
||||
dispute_stage: get_dispute_stage(item.cycle.clone())?,
|
||||
dispute_status: get_dispute_status(item.cycle.clone())?,
|
||||
dispute_status: get_dispute_status(item.cycle.clone(), item.activity)?,
|
||||
connector_status: item.cycle.clone(),
|
||||
connector_dispute_id: item.case_id.clone(),
|
||||
connector_reason: item.reason_code_description.clone(),
|
||||
@ -4148,3 +4201,40 @@ impl
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_last_non_auxiliary_activity_type(activities: Vec<Activity>) -> Option<String> {
|
||||
let auxiliary_activities: std::collections::HashSet<&'static str> = [
|
||||
"Add Note",
|
||||
"Attach Document",
|
||||
"Attempted Attach Document",
|
||||
"Delete Document",
|
||||
"Update Document",
|
||||
"Move To Error Queue",
|
||||
"Assign to Vantiv",
|
||||
"Assign To Merchant",
|
||||
"Merchant Auto Assign",
|
||||
"Issuer Recalled",
|
||||
"Network Decision",
|
||||
"Request Declined",
|
||||
"Sent Gift",
|
||||
"Successful PayPal",
|
||||
]
|
||||
.iter()
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
let mut last_non_auxiliary_activity = None;
|
||||
|
||||
for activity in activities {
|
||||
let auxiliary_activity = activity
|
||||
.activity_type
|
||||
.as_deref()
|
||||
.map(|activity_type| auxiliary_activities.contains(activity_type))
|
||||
.unwrap_or(false);
|
||||
|
||||
if !auxiliary_activity {
|
||||
last_non_auxiliary_activity = activity.activity_type.clone()
|
||||
}
|
||||
}
|
||||
last_non_auxiliary_activity
|
||||
}
|
||||
|
||||
@ -276,8 +276,10 @@ pub async fn accept_dispute(
|
||||
core_utils::validate_profile_id_from_auth_layer(profile_id, &dispute)?;
|
||||
let dispute_id = dispute.dispute_id.clone();
|
||||
common_utils::fp_utils::when(
|
||||
!(dispute.dispute_stage == storage_enums::DisputeStage::Dispute
|
||||
&& dispute.dispute_status == storage_enums::DisputeStatus::DisputeOpened),
|
||||
!core_utils::should_proceed_with_accept_dispute(
|
||||
dispute.dispute_stage,
|
||||
dispute.dispute_status,
|
||||
),
|
||||
|| {
|
||||
metrics::ACCEPT_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add(1, &[]);
|
||||
Err(errors::ApiErrorResponse::DisputeStatusValidationFailed {
|
||||
|
||||
@ -929,6 +929,9 @@ pub fn validate_dispute_status(
|
||||
DisputeStatus::DisputeChallenged
|
||||
| DisputeStatus::DisputeWon
|
||||
| DisputeStatus::DisputeLost
|
||||
| DisputeStatus::DisputeAccepted
|
||||
| DisputeStatus::DisputeCancelled
|
||||
| DisputeStatus::DisputeExpired
|
||||
),
|
||||
DisputeStatus::DisputeWon => matches!(dispute_status, DisputeStatus::DisputeWon),
|
||||
DisputeStatus::DisputeLost => matches!(dispute_status, DisputeStatus::DisputeLost),
|
||||
@ -2614,12 +2617,27 @@ pub fn should_proceed_with_submit_evidence(
|
||||
dispute_stage: DisputeStage,
|
||||
dispute_status: DisputeStatus,
|
||||
) -> bool {
|
||||
matches!(dispute_stage, DisputeStage::DisputeReversal)
|
||||
|| matches!(
|
||||
dispute_status,
|
||||
DisputeStatus::DisputeExpired
|
||||
| DisputeStatus::DisputeCancelled
|
||||
| DisputeStatus::DisputeWon
|
||||
| DisputeStatus::DisputeLost,
|
||||
)
|
||||
matches!(
|
||||
dispute_stage,
|
||||
DisputeStage::PreDispute
|
||||
| DisputeStage::Dispute
|
||||
| DisputeStage::PreArbitration
|
||||
| DisputeStage::Arbitration
|
||||
) && matches!(
|
||||
dispute_status,
|
||||
DisputeStatus::DisputeOpened | DisputeStatus::DisputeChallenged
|
||||
)
|
||||
}
|
||||
|
||||
pub fn should_proceed_with_accept_dispute(
|
||||
dispute_stage: DisputeStage,
|
||||
dispute_status: DisputeStatus,
|
||||
) -> bool {
|
||||
matches!(
|
||||
dispute_stage,
|
||||
DisputeStage::PreDispute | DisputeStage::Dispute | DisputeStage::PreArbitration
|
||||
) && matches!(
|
||||
dispute_status,
|
||||
DisputeStatus::DisputeChallenged | DisputeStatus::DisputeOpened
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user