mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
fix(connector): [Payme] populate error message in case of 2xx payment failures (#2037)
This commit is contained in:
@ -9,6 +9,7 @@ use crate::{
|
||||
self, missing_field_err, AddressDetailsData, CardData, PaymentsAuthorizeRequestData,
|
||||
PaymentsPreProcessingData, PaymentsSyncRequestData, RouterData,
|
||||
},
|
||||
consts,
|
||||
core::errors,
|
||||
types::{self, api, storage::enums, MandateReference},
|
||||
};
|
||||
@ -120,30 +121,61 @@ impl<F, T>
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<F, PaymePaySaleResponse, T, types::PaymentsResponseData>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let response = if item.response.sale_status == SaleStatus::Failed {
|
||||
// To populate error message in case of failure
|
||||
Err(types::ErrorResponse::from((&item.response, item.http_code)))
|
||||
} else {
|
||||
Ok(types::PaymentsResponseData::try_from(&item.response)?)
|
||||
};
|
||||
Ok(Self {
|
||||
status: enums::AttemptStatus::from(item.response.sale_status),
|
||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(item.response.payme_sale_id),
|
||||
redirection_data: None,
|
||||
mandate_reference: item.response.buyer_key.map(|buyer_key| MandateReference {
|
||||
connector_mandate_id: Some(buyer_key.expose()),
|
||||
payment_method_id: None,
|
||||
}),
|
||||
connector_metadata: Some(
|
||||
serde_json::to_value(PaymeMetadata {
|
||||
payme_transaction_id: item.response.payme_transaction_id,
|
||||
})
|
||||
.into_report()
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)?,
|
||||
),
|
||||
network_txn_id: None,
|
||||
connector_response_reference_id: None,
|
||||
}),
|
||||
response,
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&PaymePaySaleResponse, u16)> for types::ErrorResponse {
|
||||
fn from((pay_sale_response, http_code): (&PaymePaySaleResponse, u16)) -> Self {
|
||||
let code = pay_sale_response
|
||||
.status_error_code
|
||||
.map(|error_code| error_code.to_string())
|
||||
.unwrap_or(consts::NO_ERROR_CODE.to_string());
|
||||
Self {
|
||||
code,
|
||||
message: pay_sale_response
|
||||
.status_error_details
|
||||
.clone()
|
||||
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
|
||||
reason: pay_sale_response.status_error_details.to_owned(),
|
||||
status_code: http_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PaymePaySaleResponse> for types::PaymentsResponseData {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(value: &PaymePaySaleResponse) -> Result<Self, Self::Error> {
|
||||
Ok(Self::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(value.payme_sale_id.clone()),
|
||||
redirection_data: None,
|
||||
mandate_reference: value.buyer_key.clone().map(|buyer_key| MandateReference {
|
||||
connector_mandate_id: Some(buyer_key.expose()),
|
||||
payment_method_id: None,
|
||||
}),
|
||||
connector_metadata: Some(
|
||||
serde_json::to_value(PaymeMetadata {
|
||||
payme_transaction_id: value.payme_transaction_id.clone(),
|
||||
})
|
||||
.into_report()
|
||||
.change_context(errors::ConnectorError::ResponseHandlingFailed)?,
|
||||
),
|
||||
network_txn_id: None,
|
||||
connector_response_reference_id: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T> TryFrom<types::ResponseRouterData<F, SaleQueryResponse, T, types::PaymentsResponseData>>
|
||||
for types::RouterData<F, T, types::PaymentsResponseData>
|
||||
{
|
||||
@ -158,24 +190,54 @@ impl<F, T> TryFrom<types::ResponseRouterData<F, SaleQueryResponse, T, types::Pay
|
||||
.first()
|
||||
.cloned()
|
||||
.ok_or(errors::ConnectorError::ResponseHandlingFailed)?;
|
||||
let response = if transaction_response.sale_status == SaleStatus::Failed {
|
||||
// To populate error message in case of failure
|
||||
Err(types::ErrorResponse::from((
|
||||
&transaction_response,
|
||||
item.http_code,
|
||||
)))
|
||||
} else {
|
||||
Ok(types::PaymentsResponseData::from(&transaction_response))
|
||||
};
|
||||
Ok(Self {
|
||||
status: enums::AttemptStatus::from(transaction_response.sale_status),
|
||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(
|
||||
transaction_response.sale_payme_id,
|
||||
),
|
||||
redirection_data: None,
|
||||
// mandate reference will be updated with webhooks only. That has been handled with PaymePaySaleResponse struct
|
||||
mandate_reference: None,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
connector_response_reference_id: None,
|
||||
}),
|
||||
response,
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&SaleQuery, u16)> for types::ErrorResponse {
|
||||
fn from((sale_query_response, http_code): (&SaleQuery, u16)) -> Self {
|
||||
Self {
|
||||
code: sale_query_response
|
||||
.sale_error_code
|
||||
.clone()
|
||||
.unwrap_or(consts::NO_ERROR_CODE.to_string()),
|
||||
message: sale_query_response
|
||||
.sale_error_text
|
||||
.clone()
|
||||
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
|
||||
reason: sale_query_response.sale_error_text.clone(),
|
||||
status_code: http_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SaleQuery> for types::PaymentsResponseData {
|
||||
fn from(value: &SaleQuery) -> Self {
|
||||
Self::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(value.sale_payme_id.clone()),
|
||||
redirection_data: None,
|
||||
// mandate reference will be updated with webhooks only. That has been handled with PaymePaySaleResponse struct
|
||||
mandate_reference: None,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
connector_response_reference_id: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum SaleType {
|
||||
@ -483,7 +545,7 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for SaleType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum SaleStatus {
|
||||
Initial,
|
||||
@ -527,6 +589,8 @@ pub struct SaleQueryResponse {
|
||||
pub struct SaleQuery {
|
||||
sale_status: SaleStatus,
|
||||
sale_payme_id: String,
|
||||
sale_error_text: Option<String>,
|
||||
sale_error_code: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -535,6 +599,8 @@ pub struct PaymePaySaleResponse {
|
||||
payme_sale_id: String,
|
||||
payme_transaction_id: String,
|
||||
buyer_key: Option<Secret<String>>,
|
||||
status_error_details: Option<String>,
|
||||
status_error_code: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@ -673,7 +739,7 @@ pub struct PaymeErrorResponse {
|
||||
pub status_code: u16,
|
||||
pub status_error_details: String,
|
||||
pub status_additional_info: serde_json::Value,
|
||||
pub status_error_code: u16,
|
||||
pub status_error_code: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -695,6 +761,8 @@ pub struct WebhookEventDataResource {
|
||||
pub notify_type: NotifyType,
|
||||
pub payme_sale_id: String,
|
||||
pub payme_transaction_id: String,
|
||||
pub status_error_details: Option<String>,
|
||||
pub status_error_code: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@ -715,6 +783,8 @@ impl From<WebhookEventDataResource> for PaymePaySaleResponse {
|
||||
payme_sale_id: value.payme_sale_id,
|
||||
payme_transaction_id: value.payme_transaction_id,
|
||||
buyer_key: value.buyer_key,
|
||||
status_error_code: value.status_error_code,
|
||||
status_error_details: value.status_error_details,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user