mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +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")]
|
||||
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<ApiErrorResponse> 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
|
||||
|
||||
@ -214,7 +214,7 @@ impl<F, T>
|
||||
&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,
|
||||
|
||||
@ -381,7 +381,7 @@ impl TryFrom<types::PaymentsCancelResponseRouterData<AdyenCancelResponse>>
|
||||
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,
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use error_stack::ResultExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@ -299,7 +300,9 @@ impl<F, T>
|
||||
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<F, Req>
|
||||
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,
|
||||
}),
|
||||
|
||||
@ -190,7 +190,7 @@ impl<F, Req>
|
||||
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,
|
||||
}),
|
||||
|
||||
@ -314,7 +314,7 @@ impl<F, T>
|
||||
// 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,
|
||||
}),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -123,7 +123,12 @@ async fn payment_response_ut<F: Clone, T>(
|
||||
|
||||
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<F: Clone, T>(
|
||||
.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(),
|
||||
};
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<api::Authorize, PaymentsAuthorizeData, PaymentsResponseData>;
|
||||
@ -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<i32>, // Calculation for amount received not in place yet
|
||||
pub redirection_data: Option<services::RedirectForm>,
|
||||
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)]
|
||||
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<ApiErrorResponse> for ErrorResponse {
|
||||
fn from(error: ApiErrorResponse) -> Self {
|
||||
impl From<errors::ApiErrorResponse> for ErrorResponse {
|
||||
fn from(error: errors::ApiErrorResponse) -> Self {
|
||||
Self {
|
||||
code: error.error_code(),
|
||||
message: error.error_message(),
|
||||
@ -224,6 +249,6 @@ impl From<ApiErrorResponse> for ErrorResponse {
|
||||
|
||||
impl Default for ErrorResponse {
|
||||
fn default() -> Self {
|
||||
Self::from(ApiErrorResponse::InternalServerError)
|
||||
Self::from(errors::ApiErrorResponse::InternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,7 +478,6 @@ pub enum PaymentMethodType {
|
||||
Copy,
|
||||
Debug,
|
||||
Eq,
|
||||
Hash,
|
||||
PartialEq,
|
||||
router_derive::DieselEnum,
|
||||
serde::Deserialize,
|
||||
|
||||
Reference in New Issue
Block a user