mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
fix(connector): Trustpay zen error mapping (#3255)
Co-authored-by: Prasunna Soppa <prasunna.soppa@juspay.in> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -813,7 +813,7 @@ fn handle_bank_redirects_sync_response(
|
||||
errors::ConnectorError,
|
||||
> {
|
||||
let status = enums::AttemptStatus::from(response.payment_information.status);
|
||||
let error = if status == enums::AttemptStatus::AuthorizationFailed {
|
||||
let error = if utils::is_payment_failure(status) {
|
||||
let reason_info = response
|
||||
.payment_information
|
||||
.status_reason_information
|
||||
@ -856,6 +856,7 @@ fn handle_bank_redirects_sync_response(
|
||||
|
||||
pub fn handle_webhook_response(
|
||||
payment_information: WebhookPaymentInformation,
|
||||
status_code: u16,
|
||||
) -> CustomResult<
|
||||
(
|
||||
enums::AttemptStatus,
|
||||
@ -865,6 +866,22 @@ pub fn handle_webhook_response(
|
||||
errors::ConnectorError,
|
||||
> {
|
||||
let status = enums::AttemptStatus::try_from(payment_information.status)?;
|
||||
let error = if utils::is_payment_failure(status) {
|
||||
let reason_info = payment_information
|
||||
.status_reason_information
|
||||
.unwrap_or_default();
|
||||
Some(types::ErrorResponse {
|
||||
code: reason_info.reason.code.clone(),
|
||||
// message vary for the same code, so relying on code alone as it is unique
|
||||
message: reason_info.reason.code,
|
||||
reason: reason_info.reason.reject_reason,
|
||||
status_code,
|
||||
attempt_status: None,
|
||||
connector_transaction_id: payment_information.references.payment_request_id.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let payment_response_data = types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::NoResponseId,
|
||||
redirection_data: None,
|
||||
@ -874,7 +891,7 @@ pub fn handle_webhook_response(
|
||||
connector_response_reference_id: None,
|
||||
incremental_authorization_allowed: None,
|
||||
};
|
||||
Ok((status, None, payment_response_data))
|
||||
Ok((status, error, payment_response_data))
|
||||
}
|
||||
|
||||
pub fn get_trustpay_response(
|
||||
@ -901,7 +918,9 @@ pub fn get_trustpay_response(
|
||||
TrustpayPaymentsResponse::BankRedirectError(response) => {
|
||||
handle_bank_redirects_error_response(*response, status_code)
|
||||
}
|
||||
TrustpayPaymentsResponse::WebhookResponse(response) => handle_webhook_response(*response),
|
||||
TrustpayPaymentsResponse::WebhookResponse(response) => {
|
||||
handle_webhook_response(*response, status_code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1452,9 +1471,24 @@ fn handle_cards_refund_response(
|
||||
|
||||
fn handle_webhooks_refund_response(
|
||||
response: WebhookPaymentInformation,
|
||||
status_code: u16,
|
||||
) -> CustomResult<(Option<types::ErrorResponse>, types::RefundsResponseData), errors::ConnectorError>
|
||||
{
|
||||
let refund_status = diesel_models::enums::RefundStatus::try_from(response.status)?;
|
||||
let error = if utils::is_refund_failure(refund_status) {
|
||||
let reason_info = response.status_reason_information.unwrap_or_default();
|
||||
Some(types::ErrorResponse {
|
||||
code: reason_info.reason.code.clone(),
|
||||
// message vary for the same code, so relying on code alone as it is unique
|
||||
message: reason_info.reason.code,
|
||||
reason: reason_info.reason.reject_reason,
|
||||
status_code,
|
||||
attempt_status: None,
|
||||
connector_transaction_id: response.references.payment_request_id.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let refund_response_data = types::RefundsResponseData {
|
||||
connector_refund_id: response
|
||||
.references
|
||||
@ -1462,7 +1496,7 @@ fn handle_webhooks_refund_response(
|
||||
.ok_or(errors::ConnectorError::MissingConnectorRefundID)?,
|
||||
refund_status,
|
||||
};
|
||||
Ok((None, refund_response_data))
|
||||
Ok((error, refund_response_data))
|
||||
}
|
||||
|
||||
fn handle_bank_redirects_refund_response(
|
||||
@ -1495,7 +1529,7 @@ fn handle_bank_redirects_refund_sync_response(
|
||||
status_code: u16,
|
||||
) -> (Option<types::ErrorResponse>, types::RefundsResponseData) {
|
||||
let refund_status = enums::RefundStatus::from(response.payment_information.status);
|
||||
let error = if refund_status == enums::RefundStatus::Failure {
|
||||
let error = if utils::is_refund_failure(refund_status) {
|
||||
let reason_info = response
|
||||
.payment_information
|
||||
.status_reason_information
|
||||
@ -1551,7 +1585,9 @@ impl<F> TryFrom<types::RefundsResponseRouterData<F, RefundResponse>>
|
||||
RefundResponse::CardsRefund(response) => {
|
||||
handle_cards_refund_response(*response, item.http_code)?
|
||||
}
|
||||
RefundResponse::WebhookRefund(response) => handle_webhooks_refund_response(*response)?,
|
||||
RefundResponse::WebhookRefund(response) => {
|
||||
handle_webhooks_refund_response(*response, item.http_code)?
|
||||
}
|
||||
RefundResponse::BankRedirectRefund(response) => {
|
||||
handle_bank_redirects_refund_response(*response, item.http_code)
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ use crate::{
|
||||
connector::utils::{
|
||||
self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, RouterData,
|
||||
},
|
||||
consts,
|
||||
core::errors::{self, CustomResult},
|
||||
services::{self, Method},
|
||||
types::{self, api, storage::enums, transformers::ForeignTryFrom},
|
||||
@ -848,12 +849,15 @@ impl ForeignTryFrom<(ZenPaymentStatus, Option<ZenActions>)> for enums::AttemptSt
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ApiResponse {
|
||||
status: ZenPaymentStatus,
|
||||
id: String,
|
||||
// merchant_transaction_id: Option<String>,
|
||||
merchant_action: Option<ZenMerchantAction>,
|
||||
reject_code: Option<String>,
|
||||
reject_reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@ -869,18 +873,18 @@ pub struct CheckoutResponse {
|
||||
redirect_url: url::Url,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ZenMerchantAction {
|
||||
action: ZenActions,
|
||||
data: ZenMerchantActionData,
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum ZenActions {
|
||||
Redirect,
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ZenMerchantActionData {
|
||||
redirect_url: url::Url,
|
||||
@ -913,6 +917,57 @@ impl<F, T>
|
||||
}
|
||||
}
|
||||
|
||||
fn get_zen_response(
|
||||
response: ApiResponse,
|
||||
status_code: u16,
|
||||
) -> CustomResult<
|
||||
(
|
||||
enums::AttemptStatus,
|
||||
Option<types::ErrorResponse>,
|
||||
types::PaymentsResponseData,
|
||||
),
|
||||
errors::ConnectorError,
|
||||
> {
|
||||
let redirection_data_action = response.merchant_action.map(|merchant_action| {
|
||||
(
|
||||
services::RedirectForm::from((merchant_action.data.redirect_url, Method::Get)),
|
||||
merchant_action.action,
|
||||
)
|
||||
});
|
||||
let (redirection_data, action) = match redirection_data_action {
|
||||
Some((redirect_form, action)) => (Some(redirect_form), Some(action)),
|
||||
None => (None, None),
|
||||
};
|
||||
let status = enums::AttemptStatus::foreign_try_from((response.status, action))?;
|
||||
let error = if utils::is_payment_failure(status) {
|
||||
Some(types::ErrorResponse {
|
||||
code: response
|
||||
.reject_code
|
||||
.unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
|
||||
message: response
|
||||
.reject_reason
|
||||
.clone()
|
||||
.unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
|
||||
reason: response.reject_reason,
|
||||
status_code,
|
||||
attempt_status: Some(status),
|
||||
connector_transaction_id: Some(response.id.clone()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let payment_response_data = types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(response.id.clone()),
|
||||
redirection_data,
|
||||
mandate_reference: None,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
connector_response_reference_id: None,
|
||||
incremental_authorization_allowed: None,
|
||||
};
|
||||
Ok((status, error, payment_response_data))
|
||||
}
|
||||
|
||||
impl<F, T> TryFrom<types::ResponseRouterData<F, ApiResponse, T, types::PaymentsResponseData>>
|
||||
for types::RouterData<F, T, types::PaymentsResponseData>
|
||||
{
|
||||
@ -920,28 +975,12 @@ impl<F, T> TryFrom<types::ResponseRouterData<F, ApiResponse, T, types::PaymentsR
|
||||
fn try_from(
|
||||
value: types::ResponseRouterData<F, ApiResponse, T, types::PaymentsResponseData>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let redirection_data_action = value.response.merchant_action.map(|merchant_action| {
|
||||
(
|
||||
services::RedirectForm::from((merchant_action.data.redirect_url, Method::Get)),
|
||||
merchant_action.action,
|
||||
)
|
||||
});
|
||||
let (redirection_data, action) = match redirection_data_action {
|
||||
Some((redirect_form, action)) => (Some(redirect_form), Some(action)),
|
||||
None => (None, None),
|
||||
};
|
||||
let (status, error, payment_response_data) =
|
||||
get_zen_response(value.response.clone(), value.http_code)?;
|
||||
|
||||
Ok(Self {
|
||||
status: enums::AttemptStatus::foreign_try_from((value.response.status, action))?,
|
||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(value.response.id),
|
||||
redirection_data,
|
||||
mandate_reference: None,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
connector_response_reference_id: None,
|
||||
incremental_authorization_allowed: None,
|
||||
}),
|
||||
status,
|
||||
response: error.map_or_else(|| Ok(payment_response_data), Err),
|
||||
..value.data
|
||||
})
|
||||
}
|
||||
@ -1016,9 +1055,12 @@ impl From<RefundStatus> for enums::RefundStatus {
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RefundResponse {
|
||||
id: String,
|
||||
status: RefundStatus,
|
||||
reject_code: Option<String>,
|
||||
reject_reason: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
|
||||
@ -1028,17 +1070,44 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
|
||||
fn try_from(
|
||||
item: types::RefundsResponseRouterData<api::Execute, RefundResponse>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let refund_status = enums::RefundStatus::from(item.response.status);
|
||||
let (error, refund_response_data) = get_zen_refund_response(item.response, item.http_code)?;
|
||||
Ok(Self {
|
||||
response: Ok(types::RefundsResponseData {
|
||||
connector_refund_id: item.response.id,
|
||||
refund_status,
|
||||
}),
|
||||
response: error.map_or_else(|| Ok(refund_response_data), Err),
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_zen_refund_response(
|
||||
response: RefundResponse,
|
||||
status_code: u16,
|
||||
) -> CustomResult<(Option<types::ErrorResponse>, types::RefundsResponseData), errors::ConnectorError>
|
||||
{
|
||||
let refund_status = enums::RefundStatus::from(response.status);
|
||||
let error = if utils::is_refund_failure(refund_status) {
|
||||
Some(types::ErrorResponse {
|
||||
code: response
|
||||
.reject_code
|
||||
.unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
|
||||
message: response
|
||||
.reject_reason
|
||||
.clone()
|
||||
.unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
|
||||
reason: response.reject_reason,
|
||||
status_code,
|
||||
attempt_status: None,
|
||||
connector_transaction_id: Some(response.id.clone()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let refund_response_data = types::RefundsResponseData {
|
||||
connector_refund_id: response.id,
|
||||
refund_status,
|
||||
};
|
||||
Ok((error, refund_response_data))
|
||||
}
|
||||
|
||||
impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
|
||||
for types::RefundsRouterData<api::RSync>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user