mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 20:23:43 +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,
|
errors::ConnectorError,
|
||||||
> {
|
> {
|
||||||
let status = enums::AttemptStatus::from(response.payment_information.status);
|
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
|
let reason_info = response
|
||||||
.payment_information
|
.payment_information
|
||||||
.status_reason_information
|
.status_reason_information
|
||||||
@ -856,6 +856,7 @@ fn handle_bank_redirects_sync_response(
|
|||||||
|
|
||||||
pub fn handle_webhook_response(
|
pub fn handle_webhook_response(
|
||||||
payment_information: WebhookPaymentInformation,
|
payment_information: WebhookPaymentInformation,
|
||||||
|
status_code: u16,
|
||||||
) -> CustomResult<
|
) -> CustomResult<
|
||||||
(
|
(
|
||||||
enums::AttemptStatus,
|
enums::AttemptStatus,
|
||||||
@ -865,6 +866,22 @@ pub fn handle_webhook_response(
|
|||||||
errors::ConnectorError,
|
errors::ConnectorError,
|
||||||
> {
|
> {
|
||||||
let status = enums::AttemptStatus::try_from(payment_information.status)?;
|
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 {
|
let payment_response_data = types::PaymentsResponseData::TransactionResponse {
|
||||||
resource_id: types::ResponseId::NoResponseId,
|
resource_id: types::ResponseId::NoResponseId,
|
||||||
redirection_data: None,
|
redirection_data: None,
|
||||||
@ -874,7 +891,7 @@ pub fn handle_webhook_response(
|
|||||||
connector_response_reference_id: None,
|
connector_response_reference_id: None,
|
||||||
incremental_authorization_allowed: None,
|
incremental_authorization_allowed: None,
|
||||||
};
|
};
|
||||||
Ok((status, None, payment_response_data))
|
Ok((status, error, payment_response_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_trustpay_response(
|
pub fn get_trustpay_response(
|
||||||
@ -901,7 +918,9 @@ pub fn get_trustpay_response(
|
|||||||
TrustpayPaymentsResponse::BankRedirectError(response) => {
|
TrustpayPaymentsResponse::BankRedirectError(response) => {
|
||||||
handle_bank_redirects_error_response(*response, status_code)
|
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(
|
fn handle_webhooks_refund_response(
|
||||||
response: WebhookPaymentInformation,
|
response: WebhookPaymentInformation,
|
||||||
|
status_code: u16,
|
||||||
) -> CustomResult<(Option<types::ErrorResponse>, types::RefundsResponseData), errors::ConnectorError>
|
) -> CustomResult<(Option<types::ErrorResponse>, types::RefundsResponseData), errors::ConnectorError>
|
||||||
{
|
{
|
||||||
let refund_status = diesel_models::enums::RefundStatus::try_from(response.status)?;
|
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 {
|
let refund_response_data = types::RefundsResponseData {
|
||||||
connector_refund_id: response
|
connector_refund_id: response
|
||||||
.references
|
.references
|
||||||
@ -1462,7 +1496,7 @@ fn handle_webhooks_refund_response(
|
|||||||
.ok_or(errors::ConnectorError::MissingConnectorRefundID)?,
|
.ok_or(errors::ConnectorError::MissingConnectorRefundID)?,
|
||||||
refund_status,
|
refund_status,
|
||||||
};
|
};
|
||||||
Ok((None, refund_response_data))
|
Ok((error, refund_response_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_bank_redirects_refund_response(
|
fn handle_bank_redirects_refund_response(
|
||||||
@ -1495,7 +1529,7 @@ fn handle_bank_redirects_refund_sync_response(
|
|||||||
status_code: u16,
|
status_code: u16,
|
||||||
) -> (Option<types::ErrorResponse>, types::RefundsResponseData) {
|
) -> (Option<types::ErrorResponse>, types::RefundsResponseData) {
|
||||||
let refund_status = enums::RefundStatus::from(response.payment_information.status);
|
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
|
let reason_info = response
|
||||||
.payment_information
|
.payment_information
|
||||||
.status_reason_information
|
.status_reason_information
|
||||||
@ -1551,7 +1585,9 @@ impl<F> TryFrom<types::RefundsResponseRouterData<F, RefundResponse>>
|
|||||||
RefundResponse::CardsRefund(response) => {
|
RefundResponse::CardsRefund(response) => {
|
||||||
handle_cards_refund_response(*response, item.http_code)?
|
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) => {
|
RefundResponse::BankRedirectRefund(response) => {
|
||||||
handle_bank_redirects_refund_response(*response, item.http_code)
|
handle_bank_redirects_refund_response(*response, item.http_code)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use crate::{
|
|||||||
connector::utils::{
|
connector::utils::{
|
||||||
self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, RouterData,
|
self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, RouterData,
|
||||||
},
|
},
|
||||||
|
consts,
|
||||||
core::errors::{self, CustomResult},
|
core::errors::{self, CustomResult},
|
||||||
services::{self, Method},
|
services::{self, Method},
|
||||||
types::{self, api, storage::enums, transformers::ForeignTryFrom},
|
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")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ApiResponse {
|
pub struct ApiResponse {
|
||||||
status: ZenPaymentStatus,
|
status: ZenPaymentStatus,
|
||||||
id: String,
|
id: String,
|
||||||
|
// merchant_transaction_id: Option<String>,
|
||||||
merchant_action: Option<ZenMerchantAction>,
|
merchant_action: Option<ZenMerchantAction>,
|
||||||
|
reject_code: Option<String>,
|
||||||
|
reject_reason: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -869,18 +873,18 @@ pub struct CheckoutResponse {
|
|||||||
redirect_url: url::Url,
|
redirect_url: url::Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ZenMerchantAction {
|
pub struct ZenMerchantAction {
|
||||||
action: ZenActions,
|
action: ZenActions,
|
||||||
data: ZenMerchantActionData,
|
data: ZenMerchantActionData,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
pub enum ZenActions {
|
pub enum ZenActions {
|
||||||
Redirect,
|
Redirect,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ZenMerchantActionData {
|
pub struct ZenMerchantActionData {
|
||||||
redirect_url: url::Url,
|
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>>
|
impl<F, T> TryFrom<types::ResponseRouterData<F, ApiResponse, T, types::PaymentsResponseData>>
|
||||||
for types::RouterData<F, 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(
|
fn try_from(
|
||||||
value: types::ResponseRouterData<F, ApiResponse, T, types::PaymentsResponseData>,
|
value: types::ResponseRouterData<F, ApiResponse, T, types::PaymentsResponseData>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
let redirection_data_action = value.response.merchant_action.map(|merchant_action| {
|
let (status, error, payment_response_data) =
|
||||||
(
|
get_zen_response(value.response.clone(), value.http_code)?;
|
||||||
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),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
status: enums::AttemptStatus::foreign_try_from((value.response.status, action))?,
|
status,
|
||||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
response: error.map_or_else(|| Ok(payment_response_data), Err),
|
||||||
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,
|
|
||||||
}),
|
|
||||||
..value.data
|
..value.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1016,9 +1055,12 @@ impl From<RefundStatus> for enums::RefundStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Deserialize)]
|
#[derive(Default, Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RefundResponse {
|
pub struct RefundResponse {
|
||||||
id: String,
|
id: String,
|
||||||
status: RefundStatus,
|
status: RefundStatus,
|
||||||
|
reject_code: Option<String>,
|
||||||
|
reject_reason: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
|
impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
|
||||||
@ -1028,17 +1070,44 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
|
|||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::RefundsResponseRouterData<api::Execute, RefundResponse>,
|
item: types::RefundsResponseRouterData<api::Execute, RefundResponse>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> 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 {
|
Ok(Self {
|
||||||
response: Ok(types::RefundsResponseData {
|
response: error.map_or_else(|| Ok(refund_response_data), Err),
|
||||||
connector_refund_id: item.response.id,
|
|
||||||
refund_status,
|
|
||||||
}),
|
|
||||||
..item.data
|
..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>>
|
impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
|
||||||
for types::RefundsRouterData<api::RSync>
|
for types::RefundsRouterData<api::RSync>
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user