diff --git a/Cargo.lock b/Cargo.lock index 2deee56c2d..2e585ced7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4369,9 +4369,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.7" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ "indexmap", "serde", @@ -5024,9 +5024,9 @@ checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winnow" -version = "0.3.6" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" dependencies = [ "memchr", ] diff --git a/crates/drainer/src/lib.rs b/crates/drainer/src/lib.rs index 6ab1287495..87baf90bd9 100644 --- a/crates/drainer/src/lib.rs +++ b/crates/drainer/src/lib.rs @@ -193,7 +193,7 @@ async fn drainer( } kv::Updateable::PaymentAttemptUpdate(a) => { macro_util::handle_resp!( - a.orig.update(&conn, a.update_data).await, + a.orig.update_with_attempt_id(&conn, a.update_data).await, update_op, payment_attempt ) diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs index fd40a9b0d1..322b530df5 100644 --- a/crates/router/src/connector/nuvei/transformers.rs +++ b/crates/router/src/connector/nuvei/transformers.rs @@ -880,7 +880,7 @@ impl .transaction_id .map_or(response.order_id, Some) // For paypal there will be no transaction_id, only order_id will be present .map(types::ResponseId::ConnectorTransactionId) - .ok_or_else(|| errors::ConnectorError::MissingConnectorTransactionID)?, + .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?, redirection_data, mandate_reference: None, // we don't need to save session token for capture, void flow so ignoring if it is not present diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index ea1cc2e424..04305b6072 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -817,9 +817,10 @@ pub async fn list_payment_methods( let payment_attempt = payment_intent .as_ref() .async_map(|pi| async { - db.find_payment_attempt_by_payment_id_merchant_id( + db.find_payment_attempt_by_payment_id_merchant_id_attempt_id( &pi.payment_id, &pi.merchant_id, + &pi.active_attempt_id, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 3bdba9bbd5..3ad6ad84ab 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -6,7 +6,6 @@ pub mod transformers; use std::{fmt::Debug, marker::PhantomData, time::Instant}; -use common_utils::ext_traits::AsyncExt; use error_stack::{IntoReport, ResultExt}; use futures::future::join_all; use router_env::{instrument, tracing}; @@ -127,17 +126,29 @@ where payment_data = match connector_details { api::ConnectorCallType::Single(connector) => { - call_connector_service( + let router_data = call_connector_service( state, &merchant_account, - &validate_result.payment_id, connector, &operation, - payment_data, + &payment_data, &customer, call_connector_action, ) - .await? + .await?; + + let operation = Box::new(PaymentResponse); + let db = &*state.store; + operation + .to_post_update_tracker()? + .update_tracker( + db, + &validate_result.payment_id, + payment_data, + router_data, + merchant_account.storage_scheme, + ) + .await? } api::ConnectorCallType::Multiple(connectors) => { @@ -367,13 +378,12 @@ impl PaymentRedirectFlow for PaymentRedirectSync { pub async fn call_connector_service( state: &AppState, merchant_account: &storage::MerchantAccount, - payment_id: &api::PaymentIdType, connector: api::ConnectorData, _operation: &Op, - payment_data: PaymentData, + payment_data: &PaymentData, customer: &Option, call_connector_action: CallConnectorAction, -) -> RouterResult> +) -> RouterResult> where Op: Debug + Sync, F: Send + Clone, @@ -388,8 +398,6 @@ where // To perform router related operation for PaymentResponse PaymentResponse: Operation, { - let db = &*state.store; - let stime_connector = Instant::now(); let mut router_data = payment_data @@ -420,28 +428,11 @@ where Ok(router_data) }; - let response = router_data_res - .async_and_then(|response| async { - let operation = helpers::response_operation::(); - let payment_data = operation - .to_post_update_tracker()? - .update_tracker( - db, - payment_id, - payment_data, - response, - merchant_account.storage_scheme, - ) - .await?; - Ok(payment_data) - }) - .await?; - let etime_connector = Instant::now(); let duration_connector = etime_connector.saturating_duration_since(stime_connector); tracing::info!(duration = format!("Duration taken: {}", duration_connector.as_millis())); - Ok(response) + router_data_res } pub async fn call_multiple_connectors_service( @@ -668,9 +659,10 @@ pub async fn list_payments( let pi = futures::stream::iter(payment_intents) .filter_map(|pi| async { let pa = db - .find_payment_attempt_by_payment_id_merchant_id( + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( &pi.payment_id, merchant_id, + &pi.active_attempt_id, // since OLAP doesn't have KV. Force to get the data from PSQL. storage_enums::MerchantStorageScheme::PostgresOnly, ) diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index 406f2d15d6..f12a817d50 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -56,9 +56,10 @@ impl GetTracker, api::PaymentsCancelRequest> })?; let mut payment_attempt = db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + payment_intent.payment_id.as_str(), merchant_id, + payment_intent.active_attempt_id.as_str(), storage_scheme, ) .await @@ -175,7 +176,7 @@ impl UpdateTracker, api::PaymentsCancelRequest> for { let cancellation_reason = payment_data.payment_attempt.cancellation_reason.clone(); payment_data.payment_attempt = db - .update_payment_attempt( + .update_payment_attempt_with_attempt_id( payment_data.payment_attempt, storage::PaymentAttemptUpdate::VoidUpdate { status: enums::AttemptStatus::VoidInitiated, diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index 7eb8f61ef2..dd3d21faae 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -63,9 +63,10 @@ impl GetTracker, api::PaymentsCaptu helpers::validate_amount_to_capture(payment_intent.amount, request.amount_to_capture)?; payment_attempt = db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + payment_intent.payment_id.as_str(), merchant_id, + payment_intent.active_attempt_id.as_str(), storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index 662fb30cb9..2c91683035 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -94,9 +94,10 @@ impl GetTracker, api::PaymentsRequest> for Co })?; payment_attempt = db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + &payment_intent.payment_id, merchant_id, + &payment_intent.active_attempt_id, storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index b060d9d3b9..14f8e9b4c1 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -96,9 +96,10 @@ impl GetTracker, api::PaymentsRequest> for Pa })?; payment_attempt = db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + payment_intent.payment_id.as_str(), merchant_id, + payment_intent.active_attempt_id.as_str(), storage_scheme, ) .await @@ -338,7 +339,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen .attach_printable("Failed to encode additional pm data")?; payment_data.payment_attempt = db - .update_payment_attempt( + .update_payment_attempt_with_attempt_id( payment_data.payment_attempt, storage::PaymentAttemptUpdate::ConfirmUpdate { amount: payment_data.amount.into(), diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 576fa3d501..7d32be8536 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -127,6 +127,7 @@ impl GetTracker, api::PaymentsRequest> for Pa request, shipping_address.clone().map(|x| x.address_id), billing_address.clone().map(|x| x.address_id), + payment_attempt.attempt_id.to_owned(), )?, storage_scheme, ) @@ -316,7 +317,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let connector = payment_data.payment_attempt.connector.clone(); payment_data.payment_attempt = db - .update_payment_attempt( + .update_payment_attempt_with_attempt_id( payment_data.payment_attempt, storage::PaymentAttemptUpdate::UpdateTrackers { payment_token, @@ -479,6 +480,7 @@ impl PaymentCreate { request: &api::PaymentsRequest, shipping_address_id: Option, billing_address_id: Option, + active_attempt_id: String, ) -> RouterResult { let created_at @ modified_at @ last_synced = Some(common_utils::date_time::now()); let status = @@ -512,6 +514,7 @@ impl PaymentCreate { statement_descriptor_name: request.statement_descriptor_name.clone(), statement_descriptor_suffix: request.statement_descriptor_suffix.clone(), metadata: metadata.map(masking::Secret::new), + active_attempt_id, ..storage::PaymentIntentNew::default() }) } diff --git a/crates/router/src/core/payments/operations/payment_method_validate.rs b/crates/router/src/core/payments/operations/payment_method_validate.rs index beaad93a57..a823d3d069 100644 --- a/crates/router/src/core/payments/operations/payment_method_validate.rs +++ b/crates/router/src/core/payments/operations/payment_method_validate.rs @@ -106,7 +106,12 @@ impl GetTracker, api::VerifyRequest> for Paym payment_intent = match db .insert_payment_intent( - Self::make_payment_intent(&payment_id, merchant_id, request), + Self::make_payment_intent( + &payment_id, + merchant_id, + request, + payment_attempt.attempt_id.to_owned(), + ), storage_scheme, ) .await @@ -312,6 +317,7 @@ impl PaymentMethodValidate { payment_id: &str, merchant_id: &str, request: &api::VerifyRequest, + active_attempt_id: String, ) -> storage::PaymentIntentNew { let created_at @ modified_at @ last_synced = Some(date_time::now()); let status = helpers::payment_intent_status_fsm(&request.payment_method_data, Some(true)); @@ -331,6 +337,7 @@ impl PaymentMethodValidate { client_secret: Some(client_secret), setup_future_usage: request.setup_future_usage.map(ForeignInto::foreign_into), off_session: request.off_session, + active_attempt_id, ..Default::default() } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 2459db55a3..d75b35aefd 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -361,7 +361,7 @@ async fn payment_response_update_tracker( payment_data.payment_attempt = match payment_attempt_update { Some(payment_attempt_update) => db - .update_payment_attempt( + .update_payment_attempt_with_attempt_id( payment_data.payment_attempt, payment_attempt_update, storage_scheme, diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 38424d8b98..f9d758095c 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -71,9 +71,10 @@ impl GetTracker, api::PaymentsSessionRequest> )?; let mut payment_attempt = db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + payment_intent.payment_id.as_str(), merchant_id, + payment_intent.active_attempt_id.as_str(), storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index c9492f2354..a7e075768b 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -68,9 +68,10 @@ impl GetTracker, api::PaymentsStartRequest> f )?; payment_attempt = db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + payment_intent.payment_id.as_str(), merchant_id, + payment_intent.active_attempt_id.as_str(), storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index c56e14f5f3..5285658b53 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -191,27 +191,11 @@ async fn get_tracker_for_sync< )> { let (payment_intent, payment_attempt, currency, amount); - payment_attempt = match payment_id { - api::PaymentIdType::PaymentIntentId(ref id) => { - db.find_payment_attempt_by_payment_id_merchant_id(id, merchant_id, storage_scheme) - } - api::PaymentIdType::ConnectorTransactionId(ref id) => { - db.find_payment_attempt_by_merchant_id_connector_txn_id(merchant_id, id, storage_scheme) - } - api::PaymentIdType::PaymentAttemptId(ref id) => { - db.find_payment_attempt_by_merchant_id_attempt_id(merchant_id, id, storage_scheme) - } - } - .await - .map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound))?; + (payment_intent, payment_attempt) = + get_payment_intent_payment_attempt(db, payment_id, merchant_id, storage_scheme).await?; let payment_id_str = payment_attempt.payment_id.clone(); - payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id_str, merchant_id, storage_scheme) - .await - .map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound))?; - let mut connector_response = db .find_connector_response_by_payment_id_merchant_id_attempt_id( &payment_intent.payment_id, @@ -319,3 +303,63 @@ impl ValidateRequest for Payme )) } } + +#[inline] +pub async fn get_payment_intent_payment_attempt( + db: &dyn StorageInterface, + payment_id: &api::PaymentIdType, + merchant_id: &str, + storage_scheme: enums::MerchantStorageScheme, +) -> RouterResult<(storage::PaymentIntent, storage::PaymentAttempt)> { + (|| async { + let (pi, pa); + match payment_id { + api_models::payments::PaymentIdType::PaymentIntentId(ref id) => { + pi = db + .find_payment_intent_by_payment_id_merchant_id(id, merchant_id, storage_scheme) + .await?; + pa = db + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + pi.payment_id.as_str(), + merchant_id, + pi.active_attempt_id.as_str(), + storage_scheme, + ) + .await?; + } + api_models::payments::PaymentIdType::ConnectorTransactionId(ref id) => { + pa = db + .find_payment_attempt_by_merchant_id_connector_txn_id( + merchant_id, + id, + storage_scheme, + ) + .await?; + pi = db + .find_payment_intent_by_payment_id_merchant_id( + pa.payment_id.as_str(), + merchant_id, + storage_scheme, + ) + .await?; + } + api_models::payments::PaymentIdType::PaymentAttemptId(ref id) => { + pa = db + .find_payment_attempt_by_attempt_id_merchant_id(id, merchant_id, storage_scheme) + .await?; + pi = db + .find_payment_intent_by_payment_id_merchant_id( + pa.payment_id.as_str(), + merchant_id, + storage_scheme, + ) + .await?; + } + } + Ok((pi, pa)) + })() + .await + .map_err(|error: error_stack::Report| { + error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound) + }) +} diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 0c8ace0a4d..332320f1da 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -87,10 +87,18 @@ impl GetTracker, api::PaymentsRequest> for Pa ) .await?; + payment_intent = 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) + })?; + payment_attempt = db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( + payment_intent.payment_id.as_str(), merchant_id, + payment_intent.active_attempt_id.as_str(), storage_scheme, ) .await @@ -364,7 +372,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let payment_method_type = payment_data.payment_attempt.payment_method_type.clone(); let payment_experience = payment_data.payment_attempt.payment_experience.clone(); payment_data.payment_attempt = db - .update_payment_attempt( + .update_payment_attempt_with_attempt_id( payment_data.payment_attempt, storage::PaymentAttemptUpdate::Update { amount: payment_data.amount.into(), diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 2e734e9b21..d252bfee68 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -37,26 +37,6 @@ pub async fn refund_create_core( merchant_id = &merchant_account.merchant_id; - payment_attempt = db - .find_payment_attempt_last_successful_attempt_by_payment_id_merchant_id( - &req.payment_id, - merchant_id, - merchant_account.storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::SuccessfulPaymentNotFound)?; - - // Amount is not passed in request refer from payment attempt. - amount = req.amount.unwrap_or(payment_attempt.amount); // [#298]: Need to that capture amount - //[#299]: Can we change the flow based on some workflow idea - utils::when(amount <= 0, || { - Err(report!(errors::ApiErrorResponse::InvalidDataFormat { - field_name: "amount".to_string(), - expected_format: "positive integer".to_string() - }) - .attach_printable("amount less than zero")) - })?; - payment_intent = db .find_payment_intent_by_payment_id_merchant_id( &req.payment_id, @@ -74,6 +54,32 @@ pub async fn refund_create_core( }, )?; + // Amount is not passed in request refer from payment attempt. + amount = req.amount.unwrap_or( + payment_intent + .amount_captured + .ok_or(errors::ApiErrorResponse::InternalServerError) + .into_report() + .attach_printable("amount captured is none in a successful payment")?, + ); + //[#299]: Can we change the flow based on some workflow idea + utils::when(amount <= 0, || { + Err(report!(errors::ApiErrorResponse::InvalidDataFormat { + field_name: "amount".to_string(), + expected_format: "positive integer".to_string() + }) + .attach_printable("amount less than zero")) + })?; + + payment_attempt = db + .find_payment_attempt_last_successful_attempt_by_payment_id_merchant_id( + &req.payment_id, + merchant_id, + merchant_account.storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::SuccessfulPaymentNotFound)?; + let creds_identifier = req .merchant_connector_details .as_ref() diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs index 60b5887ecc..36fd535cd5 100644 --- a/crates/router/src/core/webhooks.rs +++ b/crates/router/src/core/webhooks.rs @@ -214,9 +214,9 @@ async fn get_payment_attempt_from_object_reference_id( .await .change_context(errors::WebhooksFlowError::ResourceNotFound), api::ObjectReferenceId::PaymentId(api::PaymentIdType::PaymentAttemptId(ref id)) => db - .find_payment_attempt_by_merchant_id_attempt_id( - &merchant_account.merchant_id, + .find_payment_attempt_by_attempt_id_merchant_id( id, + &merchant_account.merchant_id, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/db/payment_attempt.rs b/crates/router/src/db/payment_attempt.rs index a74d751eca..7703d6b4e6 100644 --- a/crates/router/src/db/payment_attempt.rs +++ b/crates/router/src/db/payment_attempt.rs @@ -12,20 +12,13 @@ pub trait PaymentAttemptInterface { storage_scheme: enums::MerchantStorageScheme, ) -> CustomResult; - async fn update_payment_attempt( + async fn update_payment_attempt_with_attempt_id( &self, this: types::PaymentAttempt, payment_attempt: types::PaymentAttemptUpdate, storage_scheme: enums::MerchantStorageScheme, ) -> CustomResult; - async fn find_payment_attempt_by_payment_id_merchant_id( - &self, - payment_id: &str, - merchant_id: &str, - storage_scheme: enums::MerchantStorageScheme, - ) -> CustomResult; - async fn find_payment_attempt_by_connector_transaction_id_payment_id_merchant_id( &self, connector_transaction_id: &str, @@ -48,12 +41,20 @@ pub trait PaymentAttemptInterface { storage_scheme: enums::MerchantStorageScheme, ) -> CustomResult; - async fn find_payment_attempt_by_merchant_id_attempt_id( + async fn find_payment_attempt_by_payment_id_merchant_id_attempt_id( &self, + payment_id: &str, merchant_id: &str, attempt_id: &str, storage_scheme: enums::MerchantStorageScheme, ) -> CustomResult; + + async fn find_payment_attempt_by_attempt_id_merchant_id( + &self, + attempt_id: &str, + merchant_id: &str, + storage_scheme: enums::MerchantStorageScheme, + ) -> CustomResult; } #[cfg(not(feature = "kv_store"))] @@ -83,27 +84,14 @@ mod storage { .into_report() } - async fn update_payment_attempt( + async fn update_payment_attempt_with_attempt_id( &self, this: PaymentAttempt, payment_attempt: PaymentAttemptUpdate, _storage_scheme: enums::MerchantStorageScheme, ) -> CustomResult { - let conn = connection::pg_connection_write(self).await?; - this.update(&conn, payment_attempt) - .await - .map_err(Into::into) - .into_report() - } - - async fn find_payment_attempt_by_payment_id_merchant_id( - &self, - payment_id: &str, - merchant_id: &str, - _storage_scheme: enums::MerchantStorageScheme, - ) -> CustomResult { - let conn = connection::pg_connection_read(self).await?; - PaymentAttempt::find_by_payment_id_merchant_id(&conn, payment_id, merchant_id) + let conn = connection::pg_connection_write(&self).await?; + this.update_with_attempt_id(&conn, payment_attempt) .await .map_err(Into::into) .into_report() @@ -162,7 +150,26 @@ mod storage { .into_report() } - async fn find_payment_attempt_by_merchant_id_attempt_id( + async fn find_payment_attempt_by_payment_id_merchant_id_attempt_id( + &self, + payment_id: &str, + merchant_id: &str, + attempt_id: &str, + _storage_scheme: enums::MerchantStorageScheme, + ) -> CustomResult { + let conn = connection::pg_connection_read(self).await?; + + PaymentAttempt::find_by_payment_id_merchant_id_attempt_id( + &conn, + payment_id, + merchant_id, + attempt_id, + ) + .await + .map_err(Into::into) + .into_report() + } + async fn find_payment_attempt_by_attempt_id_merchant_id( &self, merchant_id: &str, attempt_id: &str, @@ -180,8 +187,9 @@ mod storage { #[async_trait::async_trait] impl PaymentAttemptInterface for MockDb { - async fn find_payment_attempt_by_merchant_id_attempt_id( + async fn find_payment_attempt_by_payment_id_merchant_id_attempt_id( &self, + _payment_id: &str, _merchant_id: &str, _attempt_id: &str, _storage_scheme: enums::MerchantStorageScheme, @@ -190,6 +198,16 @@ impl PaymentAttemptInterface for MockDb { Err(errors::StorageError::MockDbError)? } + async fn find_payment_attempt_by_attempt_id_merchant_id( + &self, + _attempt_id: &str, + _merchant_id: &str, + _storage_scheme: enums::MerchantStorageScheme, + ) -> CustomResult { + // [#172]: Implement function for `MockDb` + Err(errors::StorageError::MockDbError)? + } + async fn find_payment_attempt_by_merchant_id_connector_txn_id( &self, _merchant_id: &str, @@ -252,7 +270,7 @@ impl PaymentAttemptInterface for MockDb { // safety: only used for testing #[allow(clippy::unwrap_used)] - async fn update_payment_attempt( + async fn update_payment_attempt_with_attempt_id( &self, this: types::PaymentAttempt, payment_attempt: types::PaymentAttemptUpdate, @@ -262,7 +280,7 @@ impl PaymentAttemptInterface for MockDb { let item = payment_attempts .iter_mut() - .find(|item| item.id == this.id) + .find(|item| item.attempt_id == this.attempt_id) .unwrap(); *item = payment_attempt.apply_changeset(this); @@ -270,16 +288,6 @@ impl PaymentAttemptInterface for MockDb { Ok(item.clone()) } - async fn find_payment_attempt_by_payment_id_merchant_id( - &self, - _payment_id: &str, - _merchant_id: &str, - _storage_scheme: enums::MerchantStorageScheme, - ) -> CustomResult { - // [#172]: Implement function for `MockDb` - Err(errors::StorageError::MockDbError)? - } - async fn find_payment_attempt_by_connector_transaction_id_payment_id_merchant_id( &self, _connector_transaction_id: &str, @@ -317,6 +325,7 @@ mod storage { use common_utils::date_time; use error_stack::{IntoReport, ResultExt}; use redis_interface::HsetnxReply; + use storage_models::reverse_lookup::ReverseLookup; use super::PaymentAttemptInterface; use crate::{ @@ -406,9 +415,7 @@ mod storage { ReverseLookupNew { lookup_id: format!( "{}_{}", - &created_attempt.merchant_id, - // [#439]: Change this to `attempt_id` - &created_attempt.payment_id, + &created_attempt.merchant_id, &created_attempt.attempt_id, ), pk_id: key, sk_id: field, @@ -440,7 +447,7 @@ mod storage { } } - async fn update_payment_attempt( + async fn update_payment_attempt_with_attempt_id( &self, this: PaymentAttempt, payment_attempt: PaymentAttemptUpdate, @@ -449,7 +456,7 @@ mod storage { match storage_scheme { enums::MerchantStorageScheme::PostgresOnly => { let conn = connection::pg_connection_write(self).await?; - this.update(&conn, payment_attempt) + this.update_with_attempt_id(&conn, payment_attempt) .await .map_err(Into::into) .into_report() @@ -465,33 +472,39 @@ mod storage { .change_context(errors::StorageError::KVError)?; let field = format!("pa_{}", updated_attempt.attempt_id); let updated_attempt = self - .redis_conn() - .map_err(Into::::into)? + .redis_conn .set_hash_fields(&key, (&field, &redis_value)) .await .map(|_| updated_attempt) .change_context(errors::StorageError::KVError)?; - let conn = connection::pg_connection_write(self).await?; - // Reverse lookup for connector_transaction_id - if let (None, Some(connector_transaction_id)) = ( + match ( old_connector_transaction_id, &updated_attempt.connector_transaction_id, ) { - let field = format!("pa_{}", updated_attempt.attempt_id); - ReverseLookupNew { - lookup_id: format!( - "{}_{}", - &updated_attempt.merchant_id, connector_transaction_id - ), - pk_id: key.clone(), - sk_id: field.clone(), - source: "payment_attempt".to_string(), + (None, Some(connector_transaction_id)) => { + add_connector_txn_id_to_reverse_lookup( + self, + key.as_str(), + this.merchant_id.as_str(), + updated_attempt.attempt_id.as_str(), + connector_transaction_id.as_str(), + ) + .await?; } - .insert(&conn) - .await - .map_err(Into::::into) - .into_report()?; + (Some(old_connector_transaction_id), Some(connector_transaction_id)) => { + if old_connector_transaction_id.ne(connector_transaction_id) { + add_connector_txn_id_to_reverse_lookup( + self, + key.as_str(), + this.merchant_id.as_str(), + updated_attempt.attempt_id.as_str(), + connector_transaction_id.as_str(), + ) + .await?; + } + } + (_, _) => {} } let redis_entry = kv::TypedSql { @@ -517,41 +530,6 @@ mod storage { } } - async fn find_payment_attempt_by_payment_id_merchant_id( - &self, - payment_id: &str, - merchant_id: &str, - storage_scheme: enums::MerchantStorageScheme, - ) -> CustomResult { - let database_call = || async { - let conn = connection::pg_connection_read(self).await?; - PaymentAttempt::find_by_payment_id_merchant_id(&conn, payment_id, merchant_id) - .await - .map_err(Into::into) - .into_report() - }; - match storage_scheme { - enums::MerchantStorageScheme::PostgresOnly => database_call().await, - enums::MerchantStorageScheme::RedisKv => { - // [#439]: get the attempt_id from payment_intent - let key = format!("{merchant_id}_{payment_id}"); - let lookup = self.get_lookup_by_lookup_id(&key).await?; - - db_utils::try_redis_get_else_try_database_get( - self.redis_conn() - .map_err(Into::::into)? - .get_hash_field_and_deserialize( - &lookup.pk_id, - &lookup.sk_id, - "PaymentAttempt", - ), - database_call, - ) - .await - } - } - } - async fn find_payment_attempt_by_connector_transaction_id_payment_id_merchant_id( &self, connector_transaction_id: &str, @@ -594,21 +572,17 @@ mod storage { &self, payment_id: &str, merchant_id: &str, - storage_scheme: enums::MerchantStorageScheme, + _storage_scheme: enums::MerchantStorageScheme, ) -> CustomResult { - self.find_payment_attempt_by_payment_id_merchant_id( + let conn = connection::pg_connection_read(self).await?; + PaymentAttempt::find_last_successful_attempt_by_payment_id_merchant_id( + &conn, payment_id, merchant_id, - storage_scheme, ) .await - .and_then(|attempt| match attempt.status { - enums::AttemptStatus::Charged => Ok(attempt), - _ => Err(errors::StorageError::ValueNotFound(format!( - "Successful payment attempt does not exist for {payment_id}_{merchant_id}" - ))) - .into_report(), - }) + .map_err(Into::into) + .into_report() } async fn find_payment_attempt_by_merchant_id_connector_txn_id( @@ -647,10 +621,10 @@ mod storage { } } - async fn find_payment_attempt_by_merchant_id_attempt_id( + async fn find_payment_attempt_by_attempt_id_merchant_id( &self, - merchant_id: &str, attempt_id: &str, + merchant_id: &str, storage_scheme: enums::MerchantStorageScheme, ) -> CustomResult { let database_call = || async { @@ -677,5 +651,64 @@ mod storage { } } } + + async fn find_payment_attempt_by_payment_id_merchant_id_attempt_id( + &self, + payment_id: &str, + merchant_id: &str, + attempt_id: &str, + storage_scheme: enums::MerchantStorageScheme, + ) -> CustomResult { + let database_call = || async { + let conn = connection::pg_connection_read(self).await?; + PaymentAttempt::find_by_payment_id_merchant_id_attempt_id( + &conn, + payment_id, + merchant_id, + attempt_id, + ) + .await + .map_err(Into::into) + .into_report() + }; + match storage_scheme { + enums::MerchantStorageScheme::PostgresOnly => database_call().await, + + enums::MerchantStorageScheme::RedisKv => { + let lookup_id = format!("{merchant_id}_{attempt_id}"); + let lookup = self.get_lookup_by_lookup_id(&lookup_id).await?; + let key = &lookup.pk_id; + db_utils::try_redis_get_else_try_database_get( + self.redis_conn() + .map_err(Into::::into)? + .get_hash_field_and_deserialize(key, &lookup.sk_id, "PaymentAttempt"), + database_call, + ) + .await + } + } + } + } + + #[inline] + async fn add_connector_txn_id_to_reverse_lookup( + store: &Store, + key: &str, + merchant_id: &str, + updated_attempt_attempt_id: &str, + connector_transaction_id: &str, + ) -> CustomResult { + let conn = connection::pg_connection_write(store).await?; + let field = format!("pa_{}", updated_attempt_attempt_id); + ReverseLookupNew { + lookup_id: format!("{}_{}", merchant_id, connector_transaction_id), + pk_id: key.to_owned(), + sk_id: field.clone(), + source: "payment_attempt".to_string(), + } + .insert(&conn) + .await + .map_err(Into::::into) + .into_report() } } diff --git a/crates/router/src/db/payment_intent.rs b/crates/router/src/db/payment_intent.rs index b177f5307b..751386040d 100644 --- a/crates/router/src/db/payment_intent.rs +++ b/crates/router/src/db/payment_intent.rs @@ -92,6 +92,7 @@ mod storage { setup_future_usage: new.setup_future_usage, off_session: new.off_session, client_secret: new.client_secret.clone(), + active_attempt_id: new.active_attempt_id.to_owned(), }; match self @@ -347,6 +348,7 @@ impl PaymentIntentInterface for MockDb { setup_future_usage: new.setup_future_usage, off_session: new.off_session, client_secret: new.client_secret, + active_attempt_id: new.active_attempt_id.to_owned(), }; payment_intents.push(payment_intent.clone()); Ok(payment_intent) diff --git a/crates/router/src/db_wrapper.rs b/crates/router/src/db_wrapper.rs deleted file mode 100644 index 17048b2f50..0000000000 --- a/crates/router/src/db_wrapper.rs +++ /dev/null @@ -1,279 +0,0 @@ -use error_stack::{FutureExt, IntoReport, ResultExt}; -use futures::{ - future::{join_all, try_join, try_join_all}, - join, -}; -use router_derive::Setter; -use storage_models::enums::MerchantStorageScheme; - -use crate::{ - core::errors::{self, RouterResult, StorageErrorExt}, - db::StorageInterface, - types::storage::{self as storage_types}, -}; - -pub enum PaymentAttemptDbCall { - Query { - merchant_id: String, - payment_id: String, - }, - Insert(storage_types::PaymentAttemptNew), - Update { - current_payment_attempt: storage_types::PaymentAttempt, - updated_payment_attempt: storage_types::PaymentAttemptUpdate, - }, -} - -impl PaymentAttemptDbCall { - async fn get_db_call( - self, - db: &dyn StorageInterface, - storage_scheme: MerchantStorageScheme, - ) -> Result> { - match self { - PaymentAttemptDbCall::Query { - merchant_id, - payment_id, - } => db - .find_payment_attempt_by_payment_id_merchant_id( - &payment_id, - &merchant_id, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::PaymentNotFound), - PaymentAttemptDbCall::Insert(payment_attempt_new) => { - let payment_id = payment_attempt_new.payment_id.clone(); - db.insert_payment_attempt(payment_attempt_new, storage_scheme) - .await - .change_context(errors::ApiErrorResponse::DuplicatePayment { payment_id }) - } - PaymentAttemptDbCall::Update { - current_payment_attempt, - updated_payment_attempt, - } => db - .update_payment_attempt( - current_payment_attempt, - updated_payment_attempt, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to update payment attempt"), - } - } -} - -pub enum PaymentIntentDbCall { - Insert(storage_types::PaymentIntentNew), -} - -impl PaymentIntentDbCall { - async fn get_db_call( - self, - db: &dyn StorageInterface, - storage_scheme: MerchantStorageScheme, - ) -> Result> { - match self { - PaymentIntentDbCall::Insert(payment_intent_new) => { - let payment_id = payment_intent_new.payment_id.clone(); - db.insert_payment_intent(payment_intent_new, storage_scheme) - .await - .change_context(errors::ApiErrorResponse::DuplicatePayment { payment_id }) - } - } - } -} - -pub enum ConnectorResponseDbCall { - Query { - merchant_id: String, - payment_id: String, - attempt_id: String, - }, - Insert(storage_types::ConnectorResponseNew), - Update(storage_types::ConnectorResponseUpdate), -} - -pub enum AddressDbCall { - Query { address_id: String }, - Insert(storage_types::AddressNew), - Update(storage_types::AddressUpdate), -} - -pub struct DbCall { - payment_intent: PaymentIntentDbCall, - payment_attempt: PaymentAttemptDbCall, - connector_response: ConnectorResponseDbCall, - shipping_address: Option, - billing_address: Option, -} - -pub enum EntityRequest { - PaymentIntent {}, - PaymentAttempt { - payment_id: String, - merchant_id: String, - }, - Address { - address_id: String, - }, - ConnectorResponse { - payment_id: String, - attempt_id: String, - merchant_id: String, - }, -} - -#[derive(Debug)] -pub enum Entity { - PaymentIntent( - Result>, - ), - PaymentAttempt( - Result>, - ), - Address(Result>), - ConnectorResponse( - Result>, - ), - None, //FIXME: for testing purposes only -} - -#[derive(Setter)] -pub struct EntityResult { - pub payment_intent: - Result>, - pub payment_attempt: - Result>, - pub connector_response: - Result>, - pub billing_address: - Result, error_stack::Report>, - pub shipping_address: - Result, error_stack::Report>, -} - -// #[derive(Setter)] -// pub struct DbCallRequest Result> { -// pub payment_attempt: F, -// pub connector_response: -// Result>, -// pub billing_address: -// Result, error_stack::Report>, -// pub shipping_address: -// Result, error_stack::Report>, -// pub mandate: -// Result, error_stack::Report>, -// } - -impl EntityResult { - fn new() -> Self { - Self { - payment_intent: Err(error_stack::report!( - errors::ApiErrorResponse::PaymentNotFound - )), - payment_attempt: Err(error_stack::report!( - errors::ApiErrorResponse::PaymentNotFound - )), - connector_response: Err(error_stack::report!( - errors::ApiErrorResponse::PaymentNotFound - )), - billing_address: Ok(None), - shipping_address: Ok(None), - } - } -} - -impl Default for EntityResult { - fn default() -> Self { - Self::new() - } -} - -#[async_trait::async_trait] -pub trait QueryEntity { - async fn query_entity( - &self, - db: &dyn StorageInterface, - storage_scheme: MerchantStorageScheme, - ) -> Entity; -} - -#[async_trait::async_trait] -impl QueryEntity for EntityRequest { - async fn query_entity( - &self, - db: &dyn StorageInterface, - storage_scheme: MerchantStorageScheme, - ) -> Entity { - match self { - EntityRequest::PaymentIntent { - payment_id, - merchant_id, - } => Entity::PaymentIntent( - db.find_payment_intent_by_payment_id_merchant_id( - payment_id, - merchant_id, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::PaymentNotFound), - ), - EntityRequest::PaymentAttempt { - payment_id, - merchant_id, - } => Entity::PaymentAttempt( - db.find_payment_attempt_by_payment_id_merchant_id( - payment_id, - merchant_id, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::PaymentNotFound), - ), - EntityRequest::Address { address_id } => Entity::Address( - db.find_address(address_id) - .await - .change_context(errors::ApiErrorResponse::AddressNotFound), //FIXME: do not change context - ), - EntityRequest::ConnectorResponse { - payment_id, - attempt_id, - merchant_id, - } => Entity::ConnectorResponse( - db.find_connector_response_by_payment_id_merchant_id_attempt_id( - &payment_id, - &merchant_id, - &attempt_id, - storage_scheme, - ) - .await - .change_context(errors::ApiErrorResponse::PaymentNotFound), - ), - } - } -} - -pub async fn make_parallel_db_call( - db: &dyn StorageInterface, - db_calls: DbCall, - storage_scheme: MerchantStorageScheme, -) -> EntityResult { - let (payment_intent_res) = join!( - db_calls.payment_attempt.get_db_call(db, storage_scheme), - db_calls.payment_intent.get_db_call(db, storage_scheme) - ); - - let mut entities_result = EntityResult::new(); - - for entity in combined_res { - match entity { - Entity::PaymentIntent(pi_res) => entities_result.set_payment_intent(pi_res), - Entity::PaymentAttempt(pa_res) => entities_result.set_payment_attempt(pa_res), - _ => &mut entities_result, - }; - } - - entities_result -} diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 87682b6a0a..5a57998b18 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -95,6 +95,7 @@ mod tests { let current_time = common_utils::date_time::now(); let payment_id = Uuid::new_v4().to_string(); + let attempt_id = Uuid::new_v4().to_string(); let merchant_id = Uuid::new_v4().to_string(); let connector = types::Connector::Dummy.to_string(); @@ -106,6 +107,7 @@ mod tests { })), created_at: current_time.into(), modified_at: current_time.into(), + attempt_id: attempt_id.clone(), ..PaymentAttemptNew::default() }; state @@ -116,9 +118,10 @@ mod tests { let response = state .store - .find_payment_attempt_by_payment_id_merchant_id( + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( &payment_id, &merchant_id, + &attempt_id, enums::MerchantStorageScheme::PostgresOnly, ) .await @@ -150,6 +153,7 @@ mod tests { modified_at: current_time.into(), // Adding a mandate_id mandate_id: Some("man_121212".to_string()), + attempt_id: uuid.clone(), ..PaymentAttemptNew::default() }; state @@ -160,9 +164,10 @@ mod tests { let response = state .store - .find_payment_attempt_by_payment_id_merchant_id( + .find_payment_attempt_by_payment_id_merchant_id_attempt_id( &uuid, "1", + &uuid, enums::MerchantStorageScheme::PostgresOnly, ) .await diff --git a/crates/storage_models/src/payment_intent.rs b/crates/storage_models/src/payment_intent.rs index 39447215e3..9a02bc2048 100644 --- a/crates/storage_models/src/payment_intent.rs +++ b/crates/storage_models/src/payment_intent.rs @@ -33,6 +33,7 @@ pub struct PaymentIntent { pub setup_future_usage: Option, pub off_session: Option, pub client_secret: Option, + pub active_attempt_id: String, } #[derive( @@ -72,6 +73,7 @@ pub struct PaymentIntentNew { pub client_secret: Option, pub setup_future_usage: Option, pub off_session: Option, + pub active_attempt_id: String, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -109,6 +111,9 @@ pub enum PaymentIntentUpdate { billing_address_id: Option, return_url: Option, }, + PaymentAttemptUpdate { + active_attempt_id: String, + }, } #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] @@ -128,6 +133,7 @@ pub struct PaymentIntentUpdateInternal { pub billing_address_id: Option, pub shipping_address_id: Option, pub modified_at: Option, + pub active_attempt_id: Option, } impl PaymentIntentUpdate { @@ -242,6 +248,10 @@ impl From for PaymentIntentUpdateInternal { modified_at: Some(common_utils::date_time::now()), ..Default::default() }, + PaymentIntentUpdate::PaymentAttemptUpdate { active_attempt_id } => Self { + active_attempt_id: Some(active_attempt_id), + ..Default::default() + }, } } } diff --git a/crates/storage_models/src/query/payment_attempt.rs b/crates/storage_models/src/query/payment_attempt.rs index 4f057781ff..ec05c1b91d 100644 --- a/crates/storage_models/src/query/payment_attempt.rs +++ b/crates/storage_models/src/query/payment_attempt.rs @@ -21,15 +21,20 @@ impl PaymentAttemptNew { impl PaymentAttempt { #[instrument(skip(conn))] - pub async fn update( + pub async fn update_with_attempt_id( self, conn: &PgPooledConn, payment_attempt: PaymentAttemptUpdate, ) -> StorageResult { - match generics::generic_update_with_results::<::Table, _, _, _>( + match generics::generic_update_with_unique_predicate_get_result::< + ::Table, + _, + _, + _, + >( conn, - dsl::payment_id - .eq(self.payment_id.to_owned()) + dsl::attempt_id + .eq(self.attempt_id.to_owned()) .and(dsl::merchant_id.eq(self.merchant_id.to_owned())), PaymentAttemptUpdateInternal::from(payment_attempt), ) @@ -39,27 +44,10 @@ impl PaymentAttempt { errors::DatabaseError::NoFieldsToUpdate => Ok(self), _ => Err(error), }, - Ok(mut payment_attempts) => payment_attempts - .pop() - .ok_or(error_stack::report!(errors::DatabaseError::NotFound)), + result => result, } } - #[instrument(skip(conn))] - pub async fn find_by_payment_id_merchant_id( - conn: &PgPooledConn, - payment_id: &str, - merchant_id: &str, - ) -> StorageResult { - generics::generic_find_one::<::Table, _, _>( - conn, - dsl::merchant_id - .eq(merchant_id.to_owned()) - .and(dsl::payment_id.eq(payment_id.to_owned())), - ) - .await - } - #[instrument(skip(conn))] pub async fn find_optional_by_payment_id_merchant_id( conn: &PgPooledConn, @@ -118,7 +106,7 @@ impl PaymentAttempt { .fold( Err(errors::DatabaseError::NotFound).into_report(), |acc, cur| match acc { - Ok(value) if value.created_at > cur.created_at => Ok(value), + Ok(value) if value.modified_at > cur.modified_at => Ok(value), _ => Ok(cur), }, ) @@ -153,4 +141,22 @@ impl PaymentAttempt { ) .await } + + #[instrument(skip(conn))] + pub async fn find_by_payment_id_merchant_id_attempt_id( + conn: &PgPooledConn, + payment_id: &str, + merchant_id: &str, + attempt_id: &str, + ) -> StorageResult { + generics::generic_find_one::<::Table, _, _>( + conn, + dsl::payment_id.eq(payment_id.to_owned()).and( + dsl::merchant_id + .eq(merchant_id.to_owned()) + .and(dsl::attempt_id.eq(attempt_id.to_owned())), + ), + ) + .await + } } diff --git a/crates/storage_models/src/schema.rs b/crates/storage_models/src/schema.rs index da11b492d6..737d1b6453 100644 --- a/crates/storage_models/src/schema.rs +++ b/crates/storage_models/src/schema.rs @@ -312,6 +312,7 @@ diesel::table! { setup_future_usage -> Nullable, off_session -> Nullable, client_secret -> Nullable, + active_attempt_id -> Varchar, } } diff --git a/migrations/2023-01-20-113235_add_attempt_id_to_payment_intent/down.sql b/migrations/2023-01-20-113235_add_attempt_id_to_payment_intent/down.sql new file mode 100644 index 0000000000..dd47bba7b5 --- /dev/null +++ b/migrations/2023-01-20-113235_add_attempt_id_to_payment_intent/down.sql @@ -0,0 +1,5 @@ +-- This file should undo anything in `up.sql` +DROP INDEX payment_attempt_payment_id_merchant_id_index; +CREATE UNIQUE INDEX payment_attempt_payment_id_merchant_id_index ON payment_attempt (payment_id, merchant_id); +DROP INDEX payment_attempt_payment_id_merchant_id_attempt_id_index; +ALTER TABLE PAYMENT_INTENT DROP COLUMN attempt_id; \ No newline at end of file diff --git a/migrations/2023-01-20-113235_add_attempt_id_to_payment_intent/up.sql b/migrations/2023-01-20-113235_add_attempt_id_to_payment_intent/up.sql new file mode 100644 index 0000000000..913b0b6fa9 --- /dev/null +++ b/migrations/2023-01-20-113235_add_attempt_id_to_payment_intent/up.sql @@ -0,0 +1,11 @@ +-- Your SQL goes here +ALTER TABLE payment_intent ADD COLUMN active_attempt_id VARCHAR(64) NOT NULL DEFAULT 'xxx'; + +UPDATE payment_intent SET active_attempt_id = payment_attempt.attempt_id from payment_attempt where payment_intent.active_attempt_id = payment_attempt.payment_id; + +CREATE UNIQUE INDEX payment_attempt_payment_id_merchant_id_attempt_id_index ON payment_attempt (payment_id, merchant_id, attempt_id); + +-- Because payment_attempt table can have rows with same payment_id and merchant_id, this index is dropped. +DROP index payment_attempt_payment_id_merchant_id_index; + +CREATE INDEX payment_attempt_payment_id_merchant_id_index ON payment_attempt (payment_id, merchant_id); diff --git a/migrations/2023-03-15-082312_add_connector_txn_id_merchant_id_index_in_payment_attempt/down.sql b/migrations/2023-03-15-082312_add_connector_txn_id_merchant_id_index_in_payment_attempt/down.sql new file mode 100644 index 0000000000..daa4d21c59 --- /dev/null +++ b/migrations/2023-03-15-082312_add_connector_txn_id_merchant_id_index_in_payment_attempt/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP INDEX payment_attempt_connector_transaction_id_merchant_id_index; diff --git a/migrations/2023-03-15-082312_add_connector_txn_id_merchant_id_index_in_payment_attempt/up.sql b/migrations/2023-03-15-082312_add_connector_txn_id_merchant_id_index_in_payment_attempt/up.sql new file mode 100644 index 0000000000..ac31d39173 --- /dev/null +++ b/migrations/2023-03-15-082312_add_connector_txn_id_merchant_id_index_in_payment_attempt/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +CREATE INDEX payment_attempt_connector_transaction_id_merchant_id_index ON payment_attempt (connector_transaction_id, merchant_id);