From aeebc5b52584ad8d8c128fa896d39fe8576dca0c Mon Sep 17 00:00:00 2001 From: Arjun Karthik Date: Mon, 28 Aug 2023 22:34:05 +0530 Subject: [PATCH] fix(connector): [Payme] populate error message in case of 2xx payment failures (#2037) --- .../src/connector/payme/transformers.rs | 130 ++++++++++++++---- 1 file changed, 100 insertions(+), 30 deletions(-) diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index da2f98d333..d1f2b2101d 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -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 fn try_from( item: types::ResponseRouterData, ) -> Result { + 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; + fn try_from(value: &PaymePaySaleResponse) -> Result { + 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 TryFrom> for types::RouterData { @@ -158,24 +190,54 @@ impl TryFrom 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, + sale_error_code: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -535,6 +599,8 @@ pub struct PaymePaySaleResponse { payme_sale_id: String, payme_transaction_id: String, buyer_key: Option>, + status_error_details: Option, + status_error_code: Option, } #[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, + pub status_error_code: Option, } #[derive(Debug, Deserialize)] @@ -715,6 +783,8 @@ impl From 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, } } }