feat: handle no connector txn id (#39)

This commit is contained in:
Sangamesh Kulkarni
2022-12-01 16:53:30 +05:30
committed by GitHub
parent 473d8f7a1b
commit f47c06a517
13 changed files with 94 additions and 27 deletions

View File

@ -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

View File

@ -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,

View File

@ -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,
};

View File

@ -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,
}),

View File

@ -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,
}),

View File

@ -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,
}),

View File

@ -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

View File

@ -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(),
};

View File

@ -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,

View File

@ -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)
}
}

View File

@ -478,7 +478,6 @@ pub enum PaymentMethodType {
Copy,
Debug,
Eq,
Hash,
PartialEq,
router_derive::DieselEnum,
serde::Deserialize,