Skip to content

Commit

Permalink
refactor(connector): [BOA/CYBS] refund error handling (#4632)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
AkshayaFoiger and hyperswitch-bot[bot] authored May 14, 2024
1 parent 03ed6dc commit 99702ed
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 74 deletions.
112 changes: 78 additions & 34 deletions crates/router/src/connector/bankofamerica/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1597,6 +1597,7 @@ fn get_error_response_if_failure(
Some(types::ErrorResponse::from((
&info_response.error_information,
&info_response.risk_information,
Some(status),
http_code,
info_response.id.clone(),
)))
Expand Down Expand Up @@ -1995,6 +1996,7 @@ impl<F>
let response = Err(types::ErrorResponse::from((
&info_response.error_information,
&risk_info,
Some(status),
item.http_code,
info_response.id.clone(),
)));
Expand Down Expand Up @@ -2420,6 +2422,7 @@ impl<F>
response: Err(types::ErrorResponse::from((
&app_response.error_information,
&risk_info,
Some(status),
item.http_code,
app_response.id.clone(),
))),
Expand Down Expand Up @@ -2611,6 +2614,7 @@ impl From<BankofamericaRefundStatus> for enums::RefundStatus {
pub struct BankOfAmericaRefundResponse {
id: String,
status: BankofamericaRefundStatus,
error_information: Option<BankOfAmericaErrorInformation>,
}

impl TryFrom<types::RefundsResponseRouterData<api::Execute, BankOfAmericaRefundResponse>>
Expand All @@ -2620,17 +2624,30 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, BankOfAmericaRefundR
fn try_from(
item: types::RefundsResponseRouterData<api::Execute, BankOfAmericaRefundResponse>,
) -> Result<Self, Self::Error> {
Ok(Self {
response: Ok(types::RefundsResponseData {
let refund_status = enums::RefundStatus::from(item.response.status.clone());
let response = if utils::is_refund_failure(refund_status) {
Err(types::ErrorResponse::from((
&item.response.error_information,
&None,
None,
item.http_code,
item.response.id.clone(),
)))
} else {
Ok(types::RefundsResponseData {
connector_refund_id: item.response.id,
refund_status: enums::RefundStatus::from(item.response.status),
}),
})
};

Ok(Self {
response,
..item.data
})
}
}

#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum BankofamericaRefundStatus {
Succeeded,
Expand All @@ -2644,21 +2661,15 @@ pub enum BankofamericaRefundStatus {
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RsyncApplicationInformation {
status: BankofamericaRefundStatus,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BankOfAmericaRsyncResponse {
RsyncApplicationResponse(Box<BankOfAmericaRsyncApplicationResponse>),
ErrorInformation(BankOfAmericaErrorInformationResponse),
status: Option<BankofamericaRefundStatus>,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BankOfAmericaRsyncApplicationResponse {
pub struct BankOfAmericaRsyncResponse {
id: String,
application_information: RsyncApplicationInformation,
application_information: Option<RsyncApplicationInformation>,
error_information: Option<BankOfAmericaErrorInformation>,
}

impl TryFrom<types::RefundsResponseRouterData<api::RSync, BankOfAmericaRsyncResponse>>
Expand All @@ -2668,25 +2679,56 @@ impl TryFrom<types::RefundsResponseRouterData<api::RSync, BankOfAmericaRsyncResp
fn try_from(
item: types::RefundsResponseRouterData<api::RSync, BankOfAmericaRsyncResponse>,
) -> Result<Self, Self::Error> {
match item.response {
BankOfAmericaRsyncResponse::RsyncApplicationResponse(rsync_response) => Ok(Self {
response: Ok(types::RefundsResponseData {
connector_refund_id: rsync_response.id,
refund_status: enums::RefundStatus::from(
rsync_response.application_information.status,
),
}),
..item.data
}),
BankOfAmericaRsyncResponse::ErrorInformation(error_response) => Ok(Self {
status: item.data.status,
response: Ok(types::RefundsResponseData {
refund_status: common_enums::RefundStatus::Pending,
connector_refund_id: error_response.id.clone(),
}),
..item.data
let response = match item
.response
.application_information
.and_then(|application_information| application_information.status)
{
Some(status) => {
let refund_status: common_enums::RefundStatus =
enums::RefundStatus::from(status.clone());
if utils::is_refund_failure(refund_status) {
if status == BankofamericaRefundStatus::Voided {
Err(types::ErrorResponse::from((
&Some(BankOfAmericaErrorInformation {
message: Some(consts::REFUND_VOIDED.to_string()),
reason: None,
}),
&None,
None,
item.http_code,
item.response.id.clone(),
)))
} else {
Err(types::ErrorResponse::from((
&item.response.error_information,
&None,
None,
item.http_code,
item.response.id.clone(),
)))
}
} else {
Ok(types::RefundsResponseData {
connector_refund_id: item.response.id,
refund_status,
})
}
}

None => Ok(types::RefundsResponseData {
connector_refund_id: item.response.id.clone(),
refund_status: match item.data.response {
Ok(response) => response.refund_status,
Err(_) => common_enums::RefundStatus::Pending,
},
}),
}
};

Ok(Self {
response,
..item.data
})
}
}

Expand Down Expand Up @@ -2750,14 +2792,16 @@ impl
From<(
&Option<BankOfAmericaErrorInformation>,
&Option<ClientRiskInformation>,
Option<enums::AttemptStatus>,
u16,
String,
)> for types::ErrorResponse
{
fn from(
(error_data, risk_information, status_code, transaction_id): (
(error_data, risk_information, attempt_status, status_code, transaction_id): (
&Option<BankOfAmericaErrorInformation>,
&Option<ClientRiskInformation>,
Option<enums::AttemptStatus>,
u16,
String,
),
Expand Down Expand Up @@ -2794,7 +2838,7 @@ impl
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: Some(error_reason.clone()),
status_code,
attempt_status: Some(enums::AttemptStatus::Failure),
attempt_status,
connector_transaction_id: Some(transaction_id.clone()),
}
}
Expand Down
111 changes: 77 additions & 34 deletions crates/router/src/connector/cybersource/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1729,6 +1729,7 @@ fn get_error_response_if_failure(
Some(types::ErrorResponse::from((
&info_response.error_information,
&info_response.risk_information,
Some(status),
http_code,
info_response.id.clone(),
)))
Expand Down Expand Up @@ -2191,6 +2192,7 @@ impl<F>
let response = Err(types::ErrorResponse::from((
&info_response.error_information,
&risk_info,
Some(status),
item.http_code,
info_response.id.clone(),
)));
Expand Down Expand Up @@ -2616,6 +2618,7 @@ impl<F>
response: Err(types::ErrorResponse::from((
&app_response.error_information,
&risk_info,
Some(status),
item.http_code,
app_response.id.clone(),
))),
Expand Down Expand Up @@ -2702,7 +2705,7 @@ impl From<CybersourceRefundStatus> for enums::RefundStatus {
}
}

#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum CybersourceRefundStatus {
Succeeded,
Expand All @@ -2718,6 +2721,7 @@ pub enum CybersourceRefundStatus {
pub struct CybersourceRefundResponse {
id: String,
status: CybersourceRefundStatus,
error_information: Option<CybersourceErrorInformation>,
}

impl TryFrom<types::RefundsResponseRouterData<api::Execute, CybersourceRefundResponse>>
Expand All @@ -2727,11 +2731,24 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, CybersourceRefundRes
fn try_from(
item: types::RefundsResponseRouterData<api::Execute, CybersourceRefundResponse>,
) -> Result<Self, Self::Error> {
Ok(Self {
response: Ok(types::RefundsResponseData {
let refund_status = enums::RefundStatus::from(item.response.status.clone());
let response = if utils::is_refund_failure(refund_status) {
Err(types::ErrorResponse::from((
&item.response.error_information,
&None,
None,
item.http_code,
item.response.id.clone(),
)))
} else {
Ok(types::RefundsResponseData {
connector_refund_id: item.response.id,
refund_status: enums::RefundStatus::from(item.response.status),
}),
})
};

Ok(Self {
response,
..item.data
})
}
Expand All @@ -2740,21 +2757,15 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, CybersourceRefundRes
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RsyncApplicationInformation {
status: CybersourceRefundStatus,
status: Option<CybersourceRefundStatus>,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CybersourceRsyncApplicationResponse {
pub struct CybersourceRsyncResponse {
id: String,
application_information: RsyncApplicationInformation,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum CybersourceRsyncResponse {
RsyncApplicationResponse(Box<CybersourceRsyncApplicationResponse>),
ErrorInformation(CybersourceErrorInformationResponse),
application_information: Option<RsyncApplicationInformation>,
error_information: Option<CybersourceErrorInformation>,
}

impl TryFrom<types::RefundsResponseRouterData<api::RSync, CybersourceRsyncResponse>>
Expand All @@ -2764,25 +2775,55 @@ impl TryFrom<types::RefundsResponseRouterData<api::RSync, CybersourceRsyncRespon
fn try_from(
item: types::RefundsResponseRouterData<api::RSync, CybersourceRsyncResponse>,
) -> Result<Self, Self::Error> {
match item.response {
CybersourceRsyncResponse::RsyncApplicationResponse(rsync_reponse) => Ok(Self {
response: Ok(types::RefundsResponseData {
connector_refund_id: rsync_reponse.id,
refund_status: enums::RefundStatus::from(
rsync_reponse.application_information.status,
),
}),
..item.data
}),
CybersourceRsyncResponse::ErrorInformation(error_response) => Ok(Self {
status: item.data.status,
response: Ok(types::RefundsResponseData {
refund_status: common_enums::RefundStatus::Pending,
connector_refund_id: error_response.id.clone(),
}),
..item.data
let response = match item
.response
.application_information
.and_then(|application_information| application_information.status)
{
Some(status) => {
let refund_status = enums::RefundStatus::from(status.clone());
if utils::is_refund_failure(refund_status) {
if status == CybersourceRefundStatus::Voided {
Err(types::ErrorResponse::from((
&Some(CybersourceErrorInformation {
message: Some(consts::REFUND_VOIDED.to_string()),
reason: None,
}),
&None,
None,
item.http_code,
item.response.id.clone(),
)))
} else {
Err(types::ErrorResponse::from((
&item.response.error_information,
&None,
None,
item.http_code,
item.response.id.clone(),
)))
}
} else {
Ok(types::RefundsResponseData {
connector_refund_id: item.response.id,
refund_status,
})
}
}

None => Ok(types::RefundsResponseData {
connector_refund_id: item.response.id.clone(),
refund_status: match item.data.response {
Ok(response) => response.refund_status,
Err(_) => common_enums::RefundStatus::Pending,
},
}),
}
};

Ok(Self {
response,
..item.data
})
}
}

Expand Down Expand Up @@ -3079,14 +3120,16 @@ impl
From<(
&Option<CybersourceErrorInformation>,
&Option<ClientRiskInformation>,
Option<enums::AttemptStatus>,
u16,
String,
)> for types::ErrorResponse
{
fn from(
(error_data, risk_information, status_code, transaction_id): (
(error_data, risk_information, attempt_status, status_code, transaction_id): (
&Option<CybersourceErrorInformation>,
&Option<ClientRiskInformation>,
Option<enums::AttemptStatus>,
u16,
String,
),
Expand Down Expand Up @@ -3123,7 +3166,7 @@ impl
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
reason: Some(error_reason.clone()),
status_code,
attempt_status: Some(enums::AttemptStatus::Failure),
attempt_status,
connector_transaction_id: Some(transaction_id.clone()),
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/router/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub(crate) const NO_ERROR_CODE: &str = "No error code";
pub(crate) const UNSUPPORTED_ERROR_MESSAGE: &str = "Unsupported response type";
pub(crate) const LOW_BALANCE_ERROR_MESSAGE: &str = "Insufficient balance in the payment method";
pub(crate) const CONNECTOR_UNAUTHORIZED_ERROR: &str = "Authentication Error from the connector";
pub(crate) const REFUND_VOIDED: &str = "Refund request has been voided.";

pub(crate) const CANNOT_CONTINUE_AUTH: &str =
"Cannot continue with Authorization due to failed Liability Shift.";
#[cfg(feature = "payouts")]
Expand Down
Loading

0 comments on commit 99702ed

Please sign in to comment.