mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 09:38:33 +08:00
fix(core): payment create throws duplicate payment error (#319)
This commit is contained in:
@ -157,6 +157,8 @@ pub enum StripeErrorCode {
|
|||||||
},
|
},
|
||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "The mandate information is invalid. {message}")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "The mandate information is invalid. {message}")]
|
||||||
PaymentIntentMandateInvalid { message: String },
|
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
|
// [#216]: https://github.com/juspay/hyperswitch/issues/216
|
||||||
// Implement the remaining stripe error codes
|
// Implement the remaining stripe error codes
|
||||||
|
|
||||||
@ -409,6 +411,9 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
|
|||||||
current_value,
|
current_value,
|
||||||
states,
|
states,
|
||||||
},
|
},
|
||||||
|
errors::ApiErrorResponse::DuplicatePayment { payment_id } => {
|
||||||
|
Self::DuplicatePayment { payment_id }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,7 +456,8 @@ impl actix_web::ResponseError for StripeErrorCode {
|
|||||||
| Self::AddressNotFound
|
| Self::AddressNotFound
|
||||||
| Self::ResourceIdNotFound
|
| Self::ResourceIdNotFound
|
||||||
| Self::PaymentIntentMandateInvalid { .. }
|
| Self::PaymentIntentMandateInvalid { .. }
|
||||||
| Self::PaymentIntentUnexpectedState { .. } => StatusCode::BAD_REQUEST,
|
| Self::PaymentIntentUnexpectedState { .. }
|
||||||
|
| Self::DuplicatePayment { .. } => StatusCode::BAD_REQUEST,
|
||||||
Self::RefundFailed
|
Self::RefundFailed
|
||||||
| Self::InternalServerError
|
| Self::InternalServerError
|
||||||
| Self::MandateActive
|
| Self::MandateActive
|
||||||
|
|||||||
@ -113,6 +113,8 @@ pub enum ApiErrorResponse {
|
|||||||
DuplicateMerchantConnectorAccount,
|
DuplicateMerchantConnectorAccount,
|
||||||
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The payment method with the specified details already exists in our records.")]
|
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The payment method with the specified details already exists in our records.")]
|
||||||
DuplicatePaymentMethod,
|
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")]
|
#[error(error_type= ErrorType::InvalidRequestError, code = "RE_05", message = "The payment has not succeeded yet")]
|
||||||
PaymentNotSucceeded,
|
PaymentNotSucceeded,
|
||||||
#[error(error_type= ErrorType::ObjectNotFound, code = "RE_05", message = "Successful payment not found for the given payment id")]
|
#[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::MandateValidationFailed { .. } => StatusCode::BAD_REQUEST, // 400
|
||||||
|
|
||||||
Self::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, // 500
|
Self::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, // 500
|
||||||
Self::DuplicateRefundRequest => StatusCode::BAD_REQUEST, // 400
|
Self::DuplicateRefundRequest | Self::DuplicatePayment { .. } => StatusCode::BAD_REQUEST, // 400
|
||||||
Self::RefundNotFound
|
Self::RefundNotFound
|
||||||
| Self::CustomerNotFound
|
| Self::CustomerNotFound
|
||||||
| Self::MandateActive
|
| Self::MandateActive
|
||||||
@ -186,9 +188,9 @@ impl actix_web::ResponseError for ApiErrorResponse {
|
|||||||
| Self::DuplicateMerchantConnectorAccount
|
| Self::DuplicateMerchantConnectorAccount
|
||||||
| Self::DuplicatePaymentMethod
|
| Self::DuplicatePaymentMethod
|
||||||
| Self::DuplicateMandate => StatusCode::BAD_REQUEST, // 400
|
| Self::DuplicateMandate => StatusCode::BAD_REQUEST, // 400
|
||||||
Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, // 503
|
Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, // 503
|
||||||
Self::PaymentNotSucceeded => StatusCode::BAD_REQUEST, // 400
|
Self::PaymentNotSucceeded => StatusCode::BAD_REQUEST, // 400
|
||||||
Self::NotImplemented => StatusCode::NOT_IMPLEMENTED, // 501
|
Self::NotImplemented => StatusCode::NOT_IMPLEMENTED, // 501
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -469,7 +469,6 @@ pub struct CustomerDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn if_not_create_change_operation<'a, Op, F>(
|
pub fn if_not_create_change_operation<'a, Op, F>(
|
||||||
is_update: bool,
|
|
||||||
status: storage_enums::IntentStatus,
|
status: storage_enums::IntentStatus,
|
||||||
confirm: Option<bool>,
|
confirm: Option<bool>,
|
||||||
current: &'a Op,
|
current: &'a Op,
|
||||||
@ -485,13 +484,7 @@ where
|
|||||||
match status {
|
match status {
|
||||||
storage_enums::IntentStatus::RequiresConfirmation
|
storage_enums::IntentStatus::RequiresConfirmation
|
||||||
| storage_enums::IntentStatus::RequiresCustomerAction
|
| storage_enums::IntentStatus::RequiresCustomerAction
|
||||||
| storage_enums::IntentStatus::RequiresPaymentMethod => {
|
| storage_enums::IntentStatus::RequiresPaymentMethod => Box::new(current),
|
||||||
if is_update {
|
|
||||||
Box::new(&PaymentUpdate)
|
|
||||||
} else {
|
|
||||||
Box::new(current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Box::new(&PaymentStatus),
|
_ => Box::new(&PaymentStatus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 money @ (amount, currency) = payments_create_request_validation(request)?;
|
||||||
|
|
||||||
let mut is_update = false;
|
|
||||||
|
|
||||||
let payment_id = payment_id
|
let payment_id = payment_id
|
||||||
.get_payment_intent_id()
|
.get_payment_intent_id()
|
||||||
.change_context(errors::ApiErrorResponse::PaymentNotFound)?;
|
.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",
|
field_name: "browser_info",
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
payment_attempt = match db
|
payment_attempt = db
|
||||||
.insert_payment_attempt(
|
.insert_payment_attempt(
|
||||||
Self::make_payment_attempt(
|
Self::make_payment_attempt(
|
||||||
&payment_id,
|
&payment_id,
|
||||||
@ -113,28 +111,13 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
.map_err(|err| {
|
||||||
Ok(payment_attempt) => Ok(payment_attempt),
|
err.to_duplicate_response(errors::ApiErrorResponse::DuplicatePayment {
|
||||||
|
payment_id: payment_id.clone(),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Err(err) => {
|
payment_intent = db
|
||||||
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
|
|
||||||
.insert_payment_intent(
|
.insert_payment_intent(
|
||||||
Self::make_payment_intent(
|
Self::make_payment_intent(
|
||||||
&payment_id,
|
&payment_id,
|
||||||
@ -147,47 +130,22 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
.map_err(|err| {
|
||||||
Ok(payment_intent) => Ok(payment_intent),
|
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;
|
connector_response = db
|
||||||
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
|
|
||||||
.insert_connector_response(
|
.insert_connector_response(
|
||||||
Self::make_connector_response(&payment_attempt),
|
Self::make_connector_response(&payment_attempt),
|
||||||
storage_scheme,
|
storage_scheme,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
.map_err(|err| {
|
||||||
Ok(connector_resp) => Ok(connector_resp),
|
err.to_duplicate_response(errors::ApiErrorResponse::DuplicatePayment {
|
||||||
Err(err) => {
|
payment_id: payment_id.clone(),
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}?;
|
|
||||||
|
|
||||||
let mandate_id = request
|
let mandate_id = request
|
||||||
.mandate_id
|
.mandate_id
|
||||||
@ -206,7 +164,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
let operation = payments::if_not_create_change_operation::<_, F>(
|
let operation = payments::if_not_create_change_operation::<_, F>(
|
||||||
is_update,
|
|
||||||
payment_intent.status,
|
payment_intent.status,
|
||||||
request.confirm,
|
request.confirm,
|
||||||
self,
|
self,
|
||||||
|
|||||||
Reference in New Issue
Block a user