From 5b8c261d1ec34fab850c33f5d59d46255c7ebe4f Mon Sep 17 00:00:00 2001 From: Shanks Date: Tue, 27 Feb 2024 16:51:25 +0530 Subject: [PATCH] feat(router): add connector mit related columns to the payment methods table (#3764) --- crates/common_enums/src/enums.rs | 26 +++++++++ crates/diesel_models/src/payment_method.rs | 9 +++ .../diesel_models/src/query/payment_method.rs | 27 ++++++++- crates/diesel_models/src/schema.rs | 4 ++ .../router/src/core/payment_methods/cards.rs | 3 +- crates/router/src/db/kafka_store.rs | 11 ++++ crates/router/src/db/payment_method.rs | 55 +++++++++++++++++++ .../down.sql | 10 ++++ .../up.sql | 13 +++++ 9 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/down.sql create mode 100644 migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/up.sql diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index c3976321f0ad..29c416e9a856 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1177,6 +1177,32 @@ pub enum PaymentMethodIssuerCode { JpBacs, } +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + serde::Serialize, + serde::Deserialize, + strum::Display, + strum::EnumString, + ToSchema, +)] +#[router_derive::diesel_enum(storage_type = "text")] +#[strum(serialize_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum PaymentMethodStatus { + /// Indicates that the payment method is active and can be used for payments. + Active, + /// Indicates that the payment method is not active and hence cannot be used for payments. + Inactive, + /// Indicates that the payment method is awaiting some data or action before it can be marked + /// as 'active'. + Processing, +} + /// To indicate the type of payment experience that the customer would go through #[derive( Eq, diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs index f9767e2939b2..09be739581ed 100644 --- a/crates/diesel_models/src/payment_method.rs +++ b/crates/diesel_models/src/payment_method.rs @@ -34,6 +34,9 @@ pub struct PaymentMethod { pub metadata: Option, pub payment_method_data: Option, pub locker_id: Option, + pub connector_mandate_details: Option, + pub customer_acceptance: Option, + pub status: storage_enums::PaymentMethodStatus, } #[derive(Clone, Debug, Eq, PartialEq, Insertable, Queryable, router_derive::DebugAsDisplay)] @@ -61,6 +64,9 @@ pub struct PaymentMethodNew { pub metadata: Option, pub payment_method_data: Option, pub locker_id: Option, + pub connector_mandate_details: Option, + pub customer_acceptance: Option, + pub status: storage_enums::PaymentMethodStatus, } impl Default for PaymentMethodNew { @@ -90,6 +96,9 @@ impl Default for PaymentMethodNew { last_modified: now, metadata: Option::default(), payment_method_data: Option::default(), + connector_mandate_details: Option::default(), + customer_acceptance: Option::default(), + status: storage_enums::PaymentMethodStatus::Active, } } } diff --git a/crates/diesel_models/src/query/payment_method.rs b/crates/diesel_models/src/query/payment_method.rs index 298db2a234b0..aa2279627601 100644 --- a/crates/diesel_models/src/query/payment_method.rs +++ b/crates/diesel_models/src/query/payment_method.rs @@ -3,7 +3,7 @@ use router_env::{instrument, tracing}; use super::generics; use crate::{ - errors, + enums as storage_enums, errors, payment_method::{self, PaymentMethod, PaymentMethodNew}, schema::payment_methods::dsl, PgPooledConn, StorageResult, @@ -108,6 +108,31 @@ impl PaymentMethod { .await } + #[instrument(skip(conn))] + pub async fn find_by_customer_id_merchant_id_status( + conn: &PgPooledConn, + customer_id: &str, + merchant_id: &str, + status: storage_enums::PaymentMethodStatus, + ) -> StorageResult> { + generics::generic_filter::< + ::Table, + _, + <::Table as Table>::PrimaryKey, + _, + >( + conn, + dsl::customer_id + .eq(customer_id.to_owned()) + .and(dsl::merchant_id.eq(merchant_id.to_owned())) + .and(dsl::status.eq(status)), + None, + None, + None, + ) + .await + } + pub async fn update_with_payment_method_id( self, conn: &PgPooledConn, diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 4ac75f5e7dec..f3c6f23e0864 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -831,6 +831,10 @@ diesel::table! { payment_method_data -> Nullable, #[max_length = 64] locker_id -> Nullable, + connector_mandate_details -> Nullable, + customer_acceptance -> Nullable, + #[max_length = 64] + status -> Varchar, } } diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 0a1cc023ecea..a92215936a09 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2667,9 +2667,10 @@ pub async fn list_customer_payment_method( let requires_cvv = is_requires_cvv.config != "false"; let resp = db - .find_payment_method_by_customer_id_merchant_id_list( + .find_payment_method_by_customer_id_merchant_id_status( customer_id, &merchant_account.merchant_id, + common_enums::PaymentMethodStatus::Active, ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?; diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index acc703d5c1be..1c1ec00ce793 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1273,6 +1273,17 @@ impl PaymentMethodInterface for KafkaStore { .await } + async fn find_payment_method_by_customer_id_merchant_id_status( + &self, + customer_id: &str, + merchant_id: &str, + status: common_enums::PaymentMethodStatus, + ) -> CustomResult, errors::StorageError> { + self.diesel_store + .find_payment_method_by_customer_id_merchant_id_status(customer_id, merchant_id, status) + .await + } + async fn find_payment_method_by_locker_id( &self, locker_id: &str, diff --git a/crates/router/src/db/payment_method.rs b/crates/router/src/db/payment_method.rs index 4f4087f552ee..f15ceecd1c44 100644 --- a/crates/router/src/db/payment_method.rs +++ b/crates/router/src/db/payment_method.rs @@ -26,6 +26,13 @@ pub trait PaymentMethodInterface { merchant_id: &str, ) -> CustomResult, errors::StorageError>; + async fn find_payment_method_by_customer_id_merchant_id_status( + &self, + customer_id: &str, + merchant_id: &str, + status: common_enums::PaymentMethodStatus, + ) -> CustomResult, errors::StorageError>; + async fn insert_payment_method( &self, payment_method_new: storage::PaymentMethodNew, @@ -105,6 +112,24 @@ impl PaymentMethodInterface for Store { .into_report() } + async fn find_payment_method_by_customer_id_merchant_id_status( + &self, + customer_id: &str, + merchant_id: &str, + status: common_enums::PaymentMethodStatus, + ) -> CustomResult, errors::StorageError> { + let conn = connection::pg_connection_read(self).await?; + storage::PaymentMethod::find_by_customer_id_merchant_id_status( + &conn, + customer_id, + merchant_id, + status, + ) + .await + .map_err(Into::into) + .into_report() + } + async fn delete_payment_method_by_merchant_id_payment_method_id( &self, merchant_id: &str, @@ -196,6 +221,9 @@ impl PaymentMethodInterface for MockDb { payment_method_issuer_code: payment_method_new.payment_method_issuer_code, metadata: payment_method_new.metadata, payment_method_data: payment_method_new.payment_method_data, + connector_mandate_details: payment_method_new.connector_mandate_details, + customer_acceptance: payment_method_new.customer_acceptance, + status: payment_method_new.status, }; payment_methods.push(payment_method.clone()); Ok(payment_method) @@ -223,6 +251,33 @@ impl PaymentMethodInterface for MockDb { } } + async fn find_payment_method_by_customer_id_merchant_id_status( + &self, + customer_id: &str, + merchant_id: &str, + status: common_enums::PaymentMethodStatus, + ) -> CustomResult, errors::StorageError> { + let payment_methods = self.payment_methods.lock().await; + let payment_methods_found: Vec = payment_methods + .iter() + .filter(|pm| { + pm.customer_id == customer_id + && pm.merchant_id == merchant_id + && pm.status == status + }) + .cloned() + .collect(); + + if payment_methods_found.is_empty() { + Err(errors::StorageError::ValueNotFound( + "cannot find payment methods".to_string(), + )) + .into_report() + } else { + Ok(payment_methods_found) + } + } + async fn delete_payment_method_by_merchant_id_payment_method_id( &self, merchant_id: &str, diff --git a/migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/down.sql b/migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/down.sql new file mode 100644 index 000000000000..65367b5cd548 --- /dev/null +++ b/migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/down.sql @@ -0,0 +1,10 @@ +-- This file should undo anything in `up.sql` + +ALTER TABLE payment_methods +DROP COLUMN status; + +ALTER TABLE payment_methods +DROP COLUMN customer_acceptance; + +ALTER TABLE payment_methods +DROP COLUMN connector_mandate_details; diff --git a/migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/up.sql b/migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/up.sql new file mode 100644 index 000000000000..c43c347da384 --- /dev/null +++ b/migrations/2024-02-22-060352_add_mit_columns_to_payment_methods/up.sql @@ -0,0 +1,13 @@ +-- Your SQL goes here + +ALTER TABLE payment_methods +ADD COLUMN connector_mandate_details JSONB +DEFAULT NULL; + +ALTER TABLE payment_methods +ADD COLUMN customer_acceptance JSONB +DEFAULT NULL; + +ALTER TABLE payment_methods +ADD COLUMN status VARCHAR(64) +NOT NULL DEFAULT 'active';