mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
feat: handle no connector txn id (#39)
This commit is contained in:
committed by
GitHub
parent
473d8f7a1b
commit
f47c06a517
@ -67,6 +67,9 @@ pub(crate) enum ErrorCode {
|
|||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such merchant account")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such merchant account")]
|
||||||
MerchantAccountNotFound,
|
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")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such merchant connector account")]
|
||||||
MerchantConnectorAccountNotFound,
|
MerchantConnectorAccountNotFound,
|
||||||
|
|
||||||
@ -327,6 +330,7 @@ impl From<ApiErrorResponse> for ErrorCode {
|
|||||||
ApiErrorResponse::PaymentNotFound => ErrorCode::PaymentNotFound,
|
ApiErrorResponse::PaymentNotFound => ErrorCode::PaymentNotFound,
|
||||||
ApiErrorResponse::PaymentMethodNotFound => ErrorCode::PaymentMethodNotFound,
|
ApiErrorResponse::PaymentMethodNotFound => ErrorCode::PaymentMethodNotFound,
|
||||||
ApiErrorResponse::MerchantAccountNotFound => ErrorCode::MerchantAccountNotFound,
|
ApiErrorResponse::MerchantAccountNotFound => ErrorCode::MerchantAccountNotFound,
|
||||||
|
ApiErrorResponse::ResourceIdNotFound => ErrorCode::ResourceIdNotFound,
|
||||||
ApiErrorResponse::MerchantConnectorAccountNotFound => {
|
ApiErrorResponse::MerchantConnectorAccountNotFound => {
|
||||||
ErrorCode::MerchantConnectorAccountNotFound
|
ErrorCode::MerchantConnectorAccountNotFound
|
||||||
}
|
}
|
||||||
@ -402,6 +406,7 @@ impl actix_web::ResponseError for ErrorCode {
|
|||||||
| ErrorCode::DuplicateMandate
|
| ErrorCode::DuplicateMandate
|
||||||
| ErrorCode::SuccessfulPaymentNotFound
|
| ErrorCode::SuccessfulPaymentNotFound
|
||||||
| ErrorCode::AddressNotFound
|
| ErrorCode::AddressNotFound
|
||||||
|
| ErrorCode::ResourceIdNotFound
|
||||||
| ErrorCode::PaymentIntentUnexpectedState { .. } => StatusCode::BAD_REQUEST,
|
| ErrorCode::PaymentIntentUnexpectedState { .. } => StatusCode::BAD_REQUEST,
|
||||||
ErrorCode::RefundFailed | ErrorCode::InternalServerError => {
|
ErrorCode::RefundFailed | ErrorCode::InternalServerError => {
|
||||||
StatusCode::INTERNAL_SERVER_ERROR
|
StatusCode::INTERNAL_SERVER_ERROR
|
||||||
|
|||||||
@ -214,7 +214,7 @@ impl<F, T>
|
|||||||
&item.response.result.code,
|
&item.response.result.code,
|
||||||
)?),
|
)?),
|
||||||
response: Ok(types::PaymentsResponseData {
|
response: Ok(types::PaymentsResponseData {
|
||||||
connector_transaction_id: item.response.id,
|
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
|
||||||
//TODO: Add redirection details here
|
//TODO: Add redirection details here
|
||||||
redirection_data: None,
|
redirection_data: None,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
|
|||||||
@ -381,7 +381,7 @@ impl TryFrom<types::PaymentsCancelResponseRouterData<AdyenCancelResponse>>
|
|||||||
Ok(types::RouterData {
|
Ok(types::RouterData {
|
||||||
status,
|
status,
|
||||||
response: Ok(types::PaymentsResponseData {
|
response: Ok(types::PaymentsResponseData {
|
||||||
connector_transaction_id: item.response.psp_reference,
|
resource_id: types::ResponseId::ConnectorTransactionId(item.response.psp_reference),
|
||||||
redirection_data: None,
|
redirection_data: None,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
}),
|
}),
|
||||||
@ -421,7 +421,7 @@ pub fn get_adyen_response(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let payments_response_data = types::PaymentsResponseData {
|
let payments_response_data = types::PaymentsResponseData {
|
||||||
connector_transaction_id: response.psp_reference,
|
resource_id: types::ResponseId::ConnectorTransactionId(response.psp_reference),
|
||||||
redirection_data: None,
|
redirection_data: None,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
};
|
};
|
||||||
@ -476,7 +476,7 @@ pub fn get_redirection_response(
|
|||||||
|
|
||||||
// We don't get connector transaction id for redirections in Adyen.
|
// We don't get connector transaction id for redirections in Adyen.
|
||||||
let payments_response_data = types::PaymentsResponseData {
|
let payments_response_data = types::PaymentsResponseData {
|
||||||
connector_transaction_id: "".to_string(),
|
resource_id: types::ResponseId::NoResponseId,
|
||||||
redirection_data: Some(redirection_data),
|
redirection_data: Some(redirection_data),
|
||||||
redirect: true,
|
redirect: true,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use error_stack::ResultExt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -299,7 +300,9 @@ impl<F, T>
|
|||||||
Some(err) => Err(err),
|
Some(err) => Err(err),
|
||||||
None => {
|
None => {
|
||||||
Ok(types::PaymentsResponseData {
|
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
|
//TODO: Add redirection details here
|
||||||
redirection_data: None,
|
redirection_data: None,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
@ -468,8 +471,15 @@ impl TryFrom<&types::PaymentsSyncRouterData> for AuthorizedotnetCreateSyncReques
|
|||||||
let transaction_id = item
|
let transaction_id = item
|
||||||
.response
|
.response
|
||||||
.as_ref()
|
.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 merchant_authentication = MerchantAuthentication::try_from(&item.connector_auth_type)?;
|
||||||
|
|
||||||
let payload = AuthorizedotnetCreateSyncRequest {
|
let payload = AuthorizedotnetCreateSyncRequest {
|
||||||
@ -571,7 +581,9 @@ impl<F, Req>
|
|||||||
enums::AttemptStatus::from(item.response.transaction.transaction_status);
|
enums::AttemptStatus::from(item.response.transaction.transaction_status);
|
||||||
Ok(types::RouterData {
|
Ok(types::RouterData {
|
||||||
response: Ok(types::PaymentsResponseData {
|
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,
|
redirection_data: None,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -190,7 +190,7 @@ impl<F, Req>
|
|||||||
Ok(types::RouterData {
|
Ok(types::RouterData {
|
||||||
status: enums::AttemptStatus::from(item.response.status),
|
status: enums::AttemptStatus::from(item.response.status),
|
||||||
response: Ok(types::PaymentsResponseData {
|
response: Ok(types::PaymentsResponseData {
|
||||||
connector_transaction_id: item.response.id,
|
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
|
||||||
redirect: redirection_data.is_some(),
|
redirect: redirection_data.is_some(),
|
||||||
redirection_data,
|
redirection_data,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -314,7 +314,7 @@ impl<F, T>
|
|||||||
// statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()),
|
// statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()),
|
||||||
// three_ds_form,
|
// three_ds_form,
|
||||||
response: Ok(types::PaymentsResponseData {
|
response: Ok(types::PaymentsResponseData {
|
||||||
connector_transaction_id: item.response.id,
|
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
|
||||||
redirect: redirection_data.is_some(),
|
redirect: redirection_data.is_some(),
|
||||||
redirection_data,
|
redirection_data,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -93,6 +93,8 @@ pub enum ApiErrorResponse {
|
|||||||
MerchantAccountNotFound,
|
MerchantAccountNotFound,
|
||||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Merchant connector account does not exist in our records.")]
|
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Merchant connector account does not exist in our records.")]
|
||||||
MerchantConnectorAccountNotFound,
|
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.")]
|
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_01", message = "Duplicate mandate request. Mandate already attempted with the Mandate ID.")]
|
||||||
DuplicateMandate,
|
DuplicateMandate,
|
||||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Mandate does not exist in our records.")]
|
#[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::MandateNotFound
|
||||||
| ApiErrorResponse::ClientSecretInvalid
|
| ApiErrorResponse::ClientSecretInvalid
|
||||||
| ApiErrorResponse::SuccessfulPaymentNotFound
|
| ApiErrorResponse::SuccessfulPaymentNotFound
|
||||||
|
| ApiErrorResponse::ResourceIdNotFound
|
||||||
| ApiErrorResponse::AddressNotFound => StatusCode::BAD_REQUEST, // 400
|
| ApiErrorResponse::AddressNotFound => StatusCode::BAD_REQUEST, // 400
|
||||||
ApiErrorResponse::DuplicateMerchantAccount
|
ApiErrorResponse::DuplicateMerchantAccount
|
||||||
| ApiErrorResponse::DuplicateMerchantConnectorAccount
|
| ApiErrorResponse::DuplicateMerchantConnectorAccount
|
||||||
|
|||||||
@ -123,7 +123,12 @@ async fn payment_response_ut<F: Clone, T>(
|
|||||||
|
|
||||||
storage::PaymentAttemptUpdate::ResponseUpdate {
|
storage::PaymentAttemptUpdate::ResponseUpdate {
|
||||||
status: router_data.status,
|
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,
|
authentication_type: None,
|
||||||
payment_method_id: Some(router_data.payment_method_id),
|
payment_method_id: Some(router_data.payment_method_id),
|
||||||
redirect: Some(response.redirect),
|
redirect: Some(response.redirect),
|
||||||
@ -147,7 +152,12 @@ async fn payment_response_ut<F: Clone, T>(
|
|||||||
.attach_printable("Could not parse the connector response")?;
|
.attach_printable("Could not parse the connector response")?;
|
||||||
|
|
||||||
let connector_response_update = storage::ConnectorResponseUpdate::ResponseUpdate {
|
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,
|
authentication_data,
|
||||||
encoded_data: payment_data.connector_response.encoded_data.clone(),
|
encoded_data: payment_data.connector_response.encoded_data.clone(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -68,7 +68,7 @@ where
|
|||||||
.connector_transaction_id
|
.connector_transaction_id
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|id| types::PaymentsResponseData {
|
.map(|id| types::PaymentsResponseData {
|
||||||
connector_transaction_id: id.to_string(),
|
resource_id: types::ResponseId::ConnectorTransactionId(id.to_string()),
|
||||||
//TODO: Add redirection details here
|
//TODO: Add redirection details here
|
||||||
redirection_data: None,
|
redirection_data: None,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
|
|||||||
@ -12,10 +12,12 @@ pub mod storage;
|
|||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use error_stack::{IntoReport, ResultExt};
|
||||||
|
|
||||||
pub use self::connector::Connector;
|
pub use self::connector::Connector;
|
||||||
use self::{api::payments, storage::enums};
|
use self::{api::payments, storage::enums};
|
||||||
pub use crate::core::payments::PaymentAddress;
|
pub use crate::core::payments::PaymentAddress;
|
||||||
use crate::{core::errors::ApiErrorResponse, services};
|
use crate::{core::errors, services};
|
||||||
|
|
||||||
pub type PaymentsAuthorizeRouterData =
|
pub type PaymentsAuthorizeRouterData =
|
||||||
RouterData<api::Authorize, PaymentsAuthorizeData, PaymentsResponseData>;
|
RouterData<api::Authorize, PaymentsAuthorizeData, PaymentsResponseData>;
|
||||||
@ -108,12 +110,35 @@ pub struct PaymentsCancelData {
|
|||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PaymentsResponseData {
|
pub struct PaymentsResponseData {
|
||||||
pub connector_transaction_id: String,
|
pub resource_id: ResponseId,
|
||||||
// pub amount_received: Option<i32>, // Calculation for amount received not in place yet
|
// pub amount_received: Option<i32>, // Calculation for amount received not in place yet
|
||||||
pub redirection_data: Option<services::RedirectForm>,
|
pub redirection_data: Option<services::RedirectForm>,
|
||||||
pub redirect: bool,
|
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<String, errors::ValidationError> {
|
||||||
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RefundsData {
|
pub struct RefundsData {
|
||||||
pub refund_id: String,
|
pub refund_id: String,
|
||||||
@ -205,15 +230,15 @@ pub struct ErrorResponse {
|
|||||||
impl ErrorResponse {
|
impl ErrorResponse {
|
||||||
pub fn get_not_implemented() -> Self {
|
pub fn get_not_implemented() -> Self {
|
||||||
Self {
|
Self {
|
||||||
code: ApiErrorResponse::NotImplemented.error_code(),
|
code: errors::ApiErrorResponse::NotImplemented.error_code(),
|
||||||
message: ApiErrorResponse::NotImplemented.error_message(),
|
message: errors::ApiErrorResponse::NotImplemented.error_message(),
|
||||||
reason: None,
|
reason: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ApiErrorResponse> for ErrorResponse {
|
impl From<errors::ApiErrorResponse> for ErrorResponse {
|
||||||
fn from(error: ApiErrorResponse) -> Self {
|
fn from(error: errors::ApiErrorResponse) -> Self {
|
||||||
Self {
|
Self {
|
||||||
code: error.error_code(),
|
code: error.error_code(),
|
||||||
message: error.error_message(),
|
message: error.error_message(),
|
||||||
@ -224,6 +249,6 @@ impl From<ApiErrorResponse> for ErrorResponse {
|
|||||||
|
|
||||||
impl Default for ErrorResponse {
|
impl Default for ErrorResponse {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::from(ApiErrorResponse::InternalServerError)
|
Self::from(errors::ApiErrorResponse::InternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -478,7 +478,6 @@ pub enum PaymentMethodType {
|
|||||||
Copy,
|
Copy,
|
||||||
Debug,
|
Debug,
|
||||||
Eq,
|
Eq,
|
||||||
Hash,
|
|
||||||
PartialEq,
|
PartialEq,
|
||||||
router_derive::DieselEnum,
|
router_derive::DieselEnum,
|
||||||
serde::Deserialize,
|
serde::Deserialize,
|
||||||
|
|||||||
@ -207,8 +207,12 @@ async fn refund_for_successful_payments() {
|
|||||||
types::RefundsResponseData,
|
types::RefundsResponseData,
|
||||||
> = connector.connector.get_connector_integration();
|
> = connector.connector.get_connector_integration();
|
||||||
let mut refund_request = construct_refund_router_data();
|
let mut refund_request = construct_refund_router_data();
|
||||||
refund_request.request.connector_transaction_id =
|
refund_request.request.connector_transaction_id = response
|
||||||
response.response.unwrap().connector_transaction_id;
|
.response
|
||||||
|
.unwrap()
|
||||||
|
.resource_id
|
||||||
|
.get_connector_transaction_id()
|
||||||
|
.unwrap();
|
||||||
let response = services::api::execute_connector_processing_step(
|
let response = services::api::execute_connector_processing_step(
|
||||||
&state,
|
&state,
|
||||||
connector_integration,
|
connector_integration,
|
||||||
|
|||||||
@ -171,8 +171,13 @@ async fn test_checkout_refund_success() {
|
|||||||
types::RefundsResponseData,
|
types::RefundsResponseData,
|
||||||
> = connector.connector.get_connector_integration();
|
> = connector.connector.get_connector_integration();
|
||||||
let mut refund_request = construct_refund_router_data();
|
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(
|
let response = services::api::execute_connector_processing_step(
|
||||||
&state,
|
&state,
|
||||||
@ -267,8 +272,12 @@ async fn test_checkout_refund_failure() {
|
|||||||
types::RefundsResponseData,
|
types::RefundsResponseData,
|
||||||
> = connector.connector.get_connector_integration();
|
> = connector.connector.get_connector_integration();
|
||||||
let mut refund_request = construct_refund_router_data();
|
let mut refund_request = construct_refund_router_data();
|
||||||
refund_request.request.connector_transaction_id =
|
refund_request.request.connector_transaction_id = response
|
||||||
response.response.unwrap().connector_transaction_id;
|
.response
|
||||||
|
.unwrap()
|
||||||
|
.resource_id
|
||||||
|
.get_connector_transaction_id()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Higher amout than that of payment
|
// Higher amout than that of payment
|
||||||
refund_request.request.refund_amount = 696969;
|
refund_request.request.refund_amount = 696969;
|
||||||
|
|||||||
Reference in New Issue
Block a user