fix(core): payment create throws duplicate payment error (#319)

This commit is contained in:
Abhishek
2023-01-09 17:55:41 +05:30
committed by GitHub
parent 097807cbe9
commit 3dae8e5614
4 changed files with 32 additions and 74 deletions

View File

@ -157,6 +157,8 @@ pub enum StripeErrorCode {
},
#[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "The mandate information is invalid. {message}")]
PaymentIntentMandateInvalid { message: String },
#[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "The payment with the specified payment_id '{payment_id}' already exists in our records.")]
DuplicatePayment { payment_id: String },
// [#216]: https://github.com/juspay/hyperswitch/issues/216
// Implement the remaining stripe error codes
@ -409,6 +411,9 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
current_value,
states,
},
errors::ApiErrorResponse::DuplicatePayment { payment_id } => {
Self::DuplicatePayment { payment_id }
}
}
}
}
@ -451,7 +456,8 @@ impl actix_web::ResponseError for StripeErrorCode {
| Self::AddressNotFound
| Self::ResourceIdNotFound
| Self::PaymentIntentMandateInvalid { .. }
| Self::PaymentIntentUnexpectedState { .. } => StatusCode::BAD_REQUEST,
| Self::PaymentIntentUnexpectedState { .. }
| Self::DuplicatePayment { .. } => StatusCode::BAD_REQUEST,
Self::RefundFailed
| Self::InternalServerError
| Self::MandateActive

View File

@ -113,6 +113,8 @@ pub enum ApiErrorResponse {
DuplicateMerchantConnectorAccount,
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The payment method with the specified details already exists in our records.")]
DuplicatePaymentMethod,
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The payment with the specified payment_id '{payment_id}' already exists in our records.")]
DuplicatePayment { payment_id: String },
#[error(error_type= ErrorType::InvalidRequestError, code = "RE_05", message = "The payment has not succeeded yet")]
PaymentNotSucceeded,
#[error(error_type= ErrorType::ObjectNotFound, code = "RE_05", message = "Successful payment not found for the given payment id")]
@ -166,7 +168,7 @@ impl actix_web::ResponseError for ApiErrorResponse {
| Self::MandateValidationFailed { .. } => StatusCode::BAD_REQUEST, // 400
Self::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, // 500
Self::DuplicateRefundRequest => StatusCode::BAD_REQUEST, // 400
Self::DuplicateRefundRequest | Self::DuplicatePayment { .. } => StatusCode::BAD_REQUEST, // 400
Self::RefundNotFound
| Self::CustomerNotFound
| Self::MandateActive
@ -186,9 +188,9 @@ impl actix_web::ResponseError for ApiErrorResponse {
| Self::DuplicateMerchantConnectorAccount
| Self::DuplicatePaymentMethod
| Self::DuplicateMandate => StatusCode::BAD_REQUEST, // 400
Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, // 503
Self::PaymentNotSucceeded => StatusCode::BAD_REQUEST, // 400
Self::NotImplemented => StatusCode::NOT_IMPLEMENTED, // 501
Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, // 503
Self::PaymentNotSucceeded => StatusCode::BAD_REQUEST, // 400
Self::NotImplemented => StatusCode::NOT_IMPLEMENTED, // 501
}
}

View File

@ -469,7 +469,6 @@ pub struct CustomerDetails {
}
pub fn if_not_create_change_operation<'a, Op, F>(
is_update: bool,
status: storage_enums::IntentStatus,
confirm: Option<bool>,
current: &'a Op,
@ -485,13 +484,7 @@ where
match status {
storage_enums::IntentStatus::RequiresConfirmation
| storage_enums::IntentStatus::RequiresCustomerAction
| storage_enums::IntentStatus::RequiresPaymentMethod => {
if is_update {
Box::new(&PaymentUpdate)
} else {
Box::new(current)
}
}
| storage_enums::IntentStatus::RequiresPaymentMethod => Box::new(current),
_ => Box::new(&PaymentStatus),
}
}

View File

@ -56,8 +56,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
let money @ (amount, currency) = payments_create_request_validation(request)?;
let mut is_update = false;
let payment_id = payment_id
.get_payment_intent_id()
.change_context(errors::ApiErrorResponse::PaymentNotFound)?;
@ -100,7 +98,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
field_name: "browser_info",
})?;
payment_attempt = match db
payment_attempt = db
.insert_payment_attempt(
Self::make_payment_attempt(
&payment_id,
@ -113,28 +111,13 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
storage_scheme,
)
.await
{
Ok(payment_attempt) => Ok(payment_attempt),
.map_err(|err| {
err.to_duplicate_response(errors::ApiErrorResponse::DuplicatePayment {
payment_id: payment_id.clone(),
})
})?;
Err(err) => {
if err.current_context().is_db_unique_violation() {
is_update = true;
db.find_payment_attempt_by_payment_id_merchant_id(
&payment_id,
merchant_id,
storage_scheme,
)
.await
.map_err(|error| {
error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
})
} else {
Err(err).change_context(errors::ApiErrorResponse::InternalServerError)
}
}
}?;
payment_intent = match db
payment_intent = db
.insert_payment_intent(
Self::make_payment_intent(
&payment_id,
@ -147,47 +130,22 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
storage_scheme,
)
.await
{
Ok(payment_intent) => Ok(payment_intent),
Err(err) => {
if err.current_context().is_db_unique_violation() {
is_update = true;
db.find_payment_intent_by_payment_id_merchant_id(
&payment_id,
merchant_id,
storage_scheme,
)
.await
.map_err(|error| {
error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
})
} else {
Err(err).change_context(errors::ApiErrorResponse::InternalServerError)
}
}
}?;
connector_response = match db
.map_err(|err| {
err.to_duplicate_response(errors::ApiErrorResponse::DuplicatePayment {
payment_id: payment_id.clone(),
})
})?;
connector_response = db
.insert_connector_response(
Self::make_connector_response(&payment_attempt),
storage_scheme,
)
.await
{
Ok(connector_resp) => Ok(connector_resp),
Err(err) => {
if err.current_context().is_db_unique_violation() {
Err(err)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Duplicate connector response in the database")
} else {
Err(err)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error occured when inserting connector response")
}
}
}?;
.map_err(|err| {
err.to_duplicate_response(errors::ApiErrorResponse::DuplicatePayment {
payment_id: payment_id.clone(),
})
})?;
let mandate_id = request
.mandate_id
@ -206,7 +164,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
.transpose()?;
let operation = payments::if_not_create_change_operation::<_, F>(
is_update,
payment_intent.status,
request.confirm,
self,