diff --git a/crates/router/src/compatibility/stripe/errors.rs b/crates/router/src/compatibility/stripe/errors.rs index bade2c64b4..a098fb68d6 100644 --- a/crates/router/src/compatibility/stripe/errors.rs +++ b/crates/router/src/compatibility/stripe/errors.rs @@ -67,6 +67,9 @@ pub(crate) enum ErrorCode { #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such merchant account")] MerchantAccountNotFound, + #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such resource ID")] + ResourceIdNotFound, + #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such merchant connector account")] MerchantConnectorAccountNotFound, @@ -327,6 +330,7 @@ impl From for ErrorCode { ApiErrorResponse::PaymentNotFound => ErrorCode::PaymentNotFound, ApiErrorResponse::PaymentMethodNotFound => ErrorCode::PaymentMethodNotFound, ApiErrorResponse::MerchantAccountNotFound => ErrorCode::MerchantAccountNotFound, + ApiErrorResponse::ResourceIdNotFound => ErrorCode::ResourceIdNotFound, ApiErrorResponse::MerchantConnectorAccountNotFound => { ErrorCode::MerchantConnectorAccountNotFound } @@ -402,6 +406,7 @@ impl actix_web::ResponseError for ErrorCode { | ErrorCode::DuplicateMandate | ErrorCode::SuccessfulPaymentNotFound | ErrorCode::AddressNotFound + | ErrorCode::ResourceIdNotFound | ErrorCode::PaymentIntentUnexpectedState { .. } => StatusCode::BAD_REQUEST, ErrorCode::RefundFailed | ErrorCode::InternalServerError => { StatusCode::INTERNAL_SERVER_ERROR diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs index 2344e9a689..5b45bd58c7 100644 --- a/crates/router/src/connector/aci/transformers.rs +++ b/crates/router/src/connector/aci/transformers.rs @@ -214,7 +214,7 @@ impl &item.response.result.code, )?), response: Ok(types::PaymentsResponseData { - connector_transaction_id: item.response.id, + resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), //TODO: Add redirection details here redirection_data: None, redirect: false, diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index f620a50316..eaf8e8af54 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -381,7 +381,7 @@ impl TryFrom> Ok(types::RouterData { status, response: Ok(types::PaymentsResponseData { - connector_transaction_id: item.response.psp_reference, + resource_id: types::ResponseId::ConnectorTransactionId(item.response.psp_reference), redirection_data: None, redirect: false, }), @@ -421,7 +421,7 @@ pub fn get_adyen_response( }; let payments_response_data = types::PaymentsResponseData { - connector_transaction_id: response.psp_reference, + resource_id: types::ResponseId::ConnectorTransactionId(response.psp_reference), redirection_data: None, redirect: false, }; @@ -476,7 +476,7 @@ pub fn get_redirection_response( // We don't get connector transaction id for redirections in Adyen. let payments_response_data = types::PaymentsResponseData { - connector_transaction_id: "".to_string(), + resource_id: types::ResponseId::NoResponseId, redirection_data: Some(redirection_data), redirect: true, }; diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs index 34372342fa..982a031f45 100644 --- a/crates/router/src/connector/authorizedotnet/transformers.rs +++ b/crates/router/src/connector/authorizedotnet/transformers.rs @@ -1,3 +1,4 @@ +use error_stack::ResultExt; use serde::{Deserialize, Serialize}; use crate::{ @@ -299,7 +300,9 @@ impl Some(err) => Err(err), None => { Ok(types::PaymentsResponseData { - connector_transaction_id: item.response.transaction_response.transaction_id, + resource_id: types::ResponseId::ConnectorTransactionId( + item.response.transaction_response.transaction_id, + ), //TODO: Add redirection details here redirection_data: None, redirect: false, @@ -468,8 +471,15 @@ impl TryFrom<&types::PaymentsSyncRouterData> for AuthorizedotnetCreateSyncReques let transaction_id = item .response .as_ref() - .map(|payment_response_data| payment_response_data.connector_transaction_id.clone()) - .ok(); + .ok() + .map(|payment_response_data| { + payment_response_data + .resource_id + .get_connector_transaction_id() + }) + .transpose() + .change_context(errors::ConnectorError::ResponseHandlingFailed)?; + let merchant_authentication = MerchantAuthentication::try_from(&item.connector_auth_type)?; let payload = AuthorizedotnetCreateSyncRequest { @@ -571,7 +581,9 @@ impl enums::AttemptStatus::from(item.response.transaction.transaction_status); Ok(types::RouterData { response: Ok(types::PaymentsResponseData { - connector_transaction_id: item.response.transaction.transaction_id, + resource_id: types::ResponseId::ConnectorTransactionId( + item.response.transaction.transaction_id, + ), redirection_data: None, redirect: false, }), diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index c7971d426a..d52e17c740 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -190,7 +190,7 @@ impl Ok(types::RouterData { status: enums::AttemptStatus::from(item.response.status), response: Ok(types::PaymentsResponseData { - connector_transaction_id: item.response.id, + resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirect: redirection_data.is_some(), redirection_data, }), diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 5bacb47de1..fa34c2dfb4 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -314,7 +314,7 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response: Ok(types::PaymentsResponseData { - connector_transaction_id: item.response.id, + resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirect: redirection_data.is_some(), redirection_data, }), diff --git a/crates/router/src/core/errors/api_error_response.rs b/crates/router/src/core/errors/api_error_response.rs index 5a836916a6..2a54dabc12 100644 --- a/crates/router/src/core/errors/api_error_response.rs +++ b/crates/router/src/core/errors/api_error_response.rs @@ -93,6 +93,8 @@ pub enum ApiErrorResponse { MerchantAccountNotFound, #[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Merchant connector account does not exist in our records.")] MerchantConnectorAccountNotFound, + #[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Resource ID does not exist in our records.")] + ResourceIdNotFound, #[error(error_type = ErrorType::DuplicateRequest, code = "RE_01", message = "Duplicate mandate request. Mandate already attempted with the Mandate ID.")] DuplicateMandate, #[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Mandate does not exist in our records.")] @@ -161,6 +163,7 @@ impl actix_web::ResponseError for ApiErrorResponse { | ApiErrorResponse::MandateNotFound | ApiErrorResponse::ClientSecretInvalid | ApiErrorResponse::SuccessfulPaymentNotFound + | ApiErrorResponse::ResourceIdNotFound | ApiErrorResponse::AddressNotFound => StatusCode::BAD_REQUEST, // 400 ApiErrorResponse::DuplicateMerchantAccount | ApiErrorResponse::DuplicateMerchantConnectorAccount diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 6d281dd27b..a982ee5574 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -123,7 +123,12 @@ async fn payment_response_ut( storage::PaymentAttemptUpdate::ResponseUpdate { status: router_data.status, - connector_transaction_id: Some(response.connector_transaction_id), + connector_transaction_id: Some( + response + .resource_id + .get_connector_transaction_id() + .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?, + ), authentication_type: None, payment_method_id: Some(router_data.payment_method_id), redirect: Some(response.redirect), @@ -147,7 +152,12 @@ async fn payment_response_ut( .attach_printable("Could not parse the connector response")?; let connector_response_update = storage::ConnectorResponseUpdate::ResponseUpdate { - connector_transaction_id: Some(connector_response.connector_transaction_id.clone()), + connector_transaction_id: Some( + connector_response + .resource_id + .get_connector_transaction_id() + .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?, + ), authentication_data, encoded_data: payment_data.connector_response.encoded_data.clone(), }; diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index d51028c86a..d54ce4f118 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -68,7 +68,7 @@ where .connector_transaction_id .as_ref() .map(|id| types::PaymentsResponseData { - connector_transaction_id: id.to_string(), + resource_id: types::ResponseId::ConnectorTransactionId(id.to_string()), //TODO: Add redirection details here redirection_data: None, redirect: false, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 6ea5615485..6dc3d1fb4c 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -12,10 +12,12 @@ pub mod storage; use std::marker::PhantomData; +use error_stack::{IntoReport, ResultExt}; + pub use self::connector::Connector; use self::{api::payments, storage::enums}; pub use crate::core::payments::PaymentAddress; -use crate::{core::errors::ApiErrorResponse, services}; +use crate::{core::errors, services}; pub type PaymentsAuthorizeRouterData = RouterData; @@ -108,12 +110,35 @@ pub struct PaymentsCancelData { } #[derive(Debug, Clone)] pub struct PaymentsResponseData { - pub connector_transaction_id: String, + pub resource_id: ResponseId, // pub amount_received: Option, // Calculation for amount received not in place yet pub redirection_data: Option, pub redirect: bool, } +#[derive(Debug, Clone, Default)] +pub enum ResponseId { + ConnectorTransactionId(String), + EncodedData(String), + #[default] + NoResponseId, +} + +impl ResponseId { + pub fn get_connector_transaction_id( + &self, + ) -> errors::CustomResult { + match self { + Self::ConnectorTransactionId(txn_id) => Ok(txn_id.to_string()), + _ => Err(errors::ValidationError::IncorrectValueProvided { + field_name: "connector_transaction_id", + }) + .into_report() + .attach_printable("Expected connector transaction ID not found"), + } + } +} + #[derive(Debug, Clone)] pub struct RefundsData { pub refund_id: String, @@ -205,15 +230,15 @@ pub struct ErrorResponse { impl ErrorResponse { pub fn get_not_implemented() -> Self { Self { - code: ApiErrorResponse::NotImplemented.error_code(), - message: ApiErrorResponse::NotImplemented.error_message(), + code: errors::ApiErrorResponse::NotImplemented.error_code(), + message: errors::ApiErrorResponse::NotImplemented.error_message(), reason: None, } } } -impl From for ErrorResponse { - fn from(error: ApiErrorResponse) -> Self { +impl From for ErrorResponse { + fn from(error: errors::ApiErrorResponse) -> Self { Self { code: error.error_code(), message: error.error_message(), @@ -224,6 +249,6 @@ impl From for ErrorResponse { impl Default for ErrorResponse { fn default() -> Self { - Self::from(ApiErrorResponse::InternalServerError) + Self::from(errors::ApiErrorResponse::InternalServerError) } } diff --git a/crates/router/src/types/storage/enums.rs b/crates/router/src/types/storage/enums.rs index 5f5c24b28f..5056dea750 100644 --- a/crates/router/src/types/storage/enums.rs +++ b/crates/router/src/types/storage/enums.rs @@ -478,7 +478,6 @@ pub enum PaymentMethodType { Copy, Debug, Eq, - Hash, PartialEq, router_derive::DieselEnum, serde::Deserialize, diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index e27b9e91ce..b67ecb1766 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -207,8 +207,12 @@ async fn refund_for_successful_payments() { types::RefundsResponseData, > = connector.connector.get_connector_integration(); let mut refund_request = construct_refund_router_data(); - refund_request.request.connector_transaction_id = - response.response.unwrap().connector_transaction_id; + refund_request.request.connector_transaction_id = response + .response + .unwrap() + .resource_id + .get_connector_transaction_id() + .unwrap(); let response = services::api::execute_connector_processing_step( &state, connector_integration, diff --git a/crates/router/tests/connectors/checkout.rs b/crates/router/tests/connectors/checkout.rs index d6de0f8a85..1d932d9445 100644 --- a/crates/router/tests/connectors/checkout.rs +++ b/crates/router/tests/connectors/checkout.rs @@ -171,8 +171,13 @@ async fn test_checkout_refund_success() { types::RefundsResponseData, > = connector.connector.get_connector_integration(); let mut refund_request = construct_refund_router_data(); - refund_request.request.connector_transaction_id = - response.response.unwrap().connector_transaction_id; + + refund_request.request.connector_transaction_id = response + .response + .unwrap() + .resource_id + .get_connector_transaction_id() + .unwrap(); let response = services::api::execute_connector_processing_step( &state, @@ -267,8 +272,12 @@ async fn test_checkout_refund_failure() { types::RefundsResponseData, > = connector.connector.get_connector_integration(); let mut refund_request = construct_refund_router_data(); - refund_request.request.connector_transaction_id = - response.response.unwrap().connector_transaction_id; + refund_request.request.connector_transaction_id = response + .response + .unwrap() + .resource_id + .get_connector_transaction_id() + .unwrap(); // Higher amout than that of payment refund_request.request.refund_amount = 696969;