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}")] #[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

View File

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

View File

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

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