diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 4f1143efaa..2819dbbb25 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -440,7 +440,7 @@ pub struct MerchantAccountResponse { pub struct MerchantAccountResponse { /// The identifier for the Merchant Account #[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44")] - pub id: String, + pub id: id_type::MerchantId, /// Name of the Merchant Account #[schema(value_type = String,example = "NewAge Retailer")] diff --git a/crates/diesel_models/src/merchant_account.rs b/crates/diesel_models/src/merchant_account.rs index 23bc642c2d..3aa4088f3b 100644 --- a/crates/diesel_models/src/merchant_account.rs +++ b/crates/diesel_models/src/merchant_account.rs @@ -1,4 +1,4 @@ -use common_utils::{encryption::Encryption, id_type, pii}; +use common_utils::{encryption::Encryption, pii}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; use crate::enums as storage_enums; @@ -10,6 +10,9 @@ use crate::schema::merchant_account; #[cfg(all(feature = "v2", feature = "merchant_account_v2"))] use crate::schema_v2::merchant_account; +/// Note: The order of fields in the struct is important. +/// This should be in the same order as the fields in the schema.rs file, otherwise the code will not compile +/// If two adjacent columns have the same type, then the compiler will not throw any error, but the fields read / written will be interchanged #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "merchant_account_v2") @@ -26,49 +29,7 @@ use crate::schema_v2::merchant_account; )] #[diesel(table_name = merchant_account, primary_key(merchant_id), check_for_backend(diesel::pg::Pg))] pub struct MerchantAccount { - pub merchant_id: id_type::MerchantId, - pub return_url: Option, - pub enable_payment_response_hash: bool, - pub payment_response_hash_key: Option, - pub redirect_to_merchant_with_http_post: bool, - pub merchant_name: Option, - pub merchant_details: Option, - pub webhook_details: Option, - pub sub_merchants_enabled: Option, - pub parent_merchant_id: Option, - pub publishable_key: Option, - pub storage_scheme: storage_enums::MerchantStorageScheme, - pub locker_id: Option, - pub metadata: Option, - pub routing_algorithm: Option, - pub primary_business_details: serde_json::Value, - pub intent_fulfillment_time: Option, - pub created_at: time::PrimitiveDateTime, - pub modified_at: time::PrimitiveDateTime, - pub frm_routing_algorithm: Option, - pub payout_routing_algorithm: Option, - pub organization_id: id_type::OrganizationId, - pub is_recon_enabled: bool, - pub default_profile: Option, - pub recon_status: storage_enums::ReconStatus, - pub payment_link_config: Option, - pub pm_collect_link_config: Option, -} - -#[cfg(all(feature = "v2", feature = "merchant_account_v2"))] -#[derive( - Clone, - Debug, - serde::Deserialize, - Identifiable, - serde::Serialize, - Queryable, - router_derive::DebugAsDisplay, - Selectable, -)] -#[diesel(table_name = merchant_account, primary_key(merchant_id), check_for_backend(diesel::pg::Pg))] -pub struct MerchantAccount { - pub merchant_id: id_type::MerchantId, + merchant_id: common_utils::id_type::MerchantId, pub return_url: Option, pub enable_payment_response_hash: bool, pub payment_response_hash_key: Option, @@ -89,7 +50,190 @@ pub struct MerchantAccount { pub modified_at: time::PrimitiveDateTime, pub frm_routing_algorithm: Option, pub payout_routing_algorithm: Option, - pub organization_id: id_type::OrganizationId, + pub organization_id: common_utils::id_type::OrganizationId, + pub is_recon_enabled: bool, + pub default_profile: Option, + pub recon_status: storage_enums::ReconStatus, + pub payment_link_config: Option, + pub pm_collect_link_config: Option, +} + +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "merchant_account_v2") +))] +pub struct MerchantAccountSetter { + pub merchant_id: common_utils::id_type::MerchantId, + pub return_url: Option, + pub enable_payment_response_hash: bool, + pub payment_response_hash_key: Option, + pub redirect_to_merchant_with_http_post: bool, + pub merchant_name: Option, + pub merchant_details: Option, + pub webhook_details: Option, + pub sub_merchants_enabled: Option, + pub parent_merchant_id: Option, + pub publishable_key: Option, + pub storage_scheme: storage_enums::MerchantStorageScheme, + pub locker_id: Option, + pub metadata: Option, + pub routing_algorithm: Option, + pub primary_business_details: serde_json::Value, + pub intent_fulfillment_time: Option, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + pub frm_routing_algorithm: Option, + pub payout_routing_algorithm: Option, + pub organization_id: common_utils::id_type::OrganizationId, + pub is_recon_enabled: bool, + pub default_profile: Option, + pub recon_status: storage_enums::ReconStatus, + pub payment_link_config: Option, + pub pm_collect_link_config: Option, +} + +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "merchant_account_v2") +))] +impl From for MerchantAccount { + fn from(item: MerchantAccountSetter) -> Self { + Self { + merchant_id: item.merchant_id, + return_url: item.return_url, + enable_payment_response_hash: item.enable_payment_response_hash, + payment_response_hash_key: item.payment_response_hash_key, + redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post, + merchant_name: item.merchant_name, + merchant_details: item.merchant_details, + webhook_details: item.webhook_details, + sub_merchants_enabled: item.sub_merchants_enabled, + parent_merchant_id: item.parent_merchant_id, + publishable_key: item.publishable_key, + storage_scheme: item.storage_scheme, + locker_id: item.locker_id, + metadata: item.metadata, + routing_algorithm: item.routing_algorithm, + primary_business_details: item.primary_business_details, + intent_fulfillment_time: item.intent_fulfillment_time, + created_at: item.created_at, + modified_at: item.modified_at, + frm_routing_algorithm: item.frm_routing_algorithm, + payout_routing_algorithm: item.payout_routing_algorithm, + organization_id: item.organization_id, + is_recon_enabled: item.is_recon_enabled, + default_profile: item.default_profile, + recon_status: item.recon_status, + payment_link_config: item.payment_link_config, + pm_collect_link_config: item.pm_collect_link_config, + } + } +} + +/// Note: The order of fields in the struct is important. +/// This should be in the same order as the fields in the schema.rs file, otherwise the code will not compile +/// If two adjacent columns have the same type, then the compiler will not throw any error, but the fields read / written will be interchanged +#[cfg(all(feature = "v2", feature = "merchant_account_v2"))] +#[derive( + Clone, + Debug, + serde::Deserialize, + Identifiable, + serde::Serialize, + Queryable, + router_derive::DebugAsDisplay, + Selectable, +)] +#[diesel(table_name = merchant_account, primary_key(id), check_for_backend(diesel::pg::Pg))] +pub struct MerchantAccount { + pub return_url: Option, + pub enable_payment_response_hash: bool, + pub payment_response_hash_key: Option, + pub redirect_to_merchant_with_http_post: bool, + pub merchant_name: Option, + pub merchant_details: Option, + pub webhook_details: Option, + pub sub_merchants_enabled: Option, + pub parent_merchant_id: Option, + pub publishable_key: Option, + pub storage_scheme: storage_enums::MerchantStorageScheme, + pub locker_id: Option, + pub metadata: Option, + pub routing_algorithm: Option, + pub primary_business_details: serde_json::Value, + pub intent_fulfillment_time: Option, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + pub frm_routing_algorithm: Option, + pub payout_routing_algorithm: Option, + pub organization_id: common_utils::id_type::OrganizationId, + pub is_recon_enabled: bool, + pub default_profile: Option, + pub recon_status: storage_enums::ReconStatus, + pub payment_link_config: Option, + pub pm_collect_link_config: Option, + pub id: common_utils::id_type::MerchantId, +} + +#[cfg(all(feature = "v2", feature = "merchant_account_v2"))] +impl From for MerchantAccount { + fn from(item: MerchantAccountSetter) -> Self { + Self { + id: item.id, + return_url: item.return_url, + enable_payment_response_hash: item.enable_payment_response_hash, + payment_response_hash_key: item.payment_response_hash_key, + redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post, + merchant_name: item.merchant_name, + merchant_details: item.merchant_details, + webhook_details: item.webhook_details, + sub_merchants_enabled: item.sub_merchants_enabled, + parent_merchant_id: item.parent_merchant_id, + publishable_key: item.publishable_key, + storage_scheme: item.storage_scheme, + locker_id: item.locker_id, + metadata: item.metadata, + routing_algorithm: item.routing_algorithm, + primary_business_details: item.primary_business_details, + intent_fulfillment_time: item.intent_fulfillment_time, + created_at: item.created_at, + modified_at: item.modified_at, + frm_routing_algorithm: item.frm_routing_algorithm, + payout_routing_algorithm: item.payout_routing_algorithm, + organization_id: item.organization_id, + is_recon_enabled: item.is_recon_enabled, + default_profile: item.default_profile, + recon_status: item.recon_status, + payment_link_config: item.payment_link_config, + pm_collect_link_config: item.pm_collect_link_config, + } + } +} + +#[cfg(all(feature = "v2", feature = "merchant_account_v2"))] +pub struct MerchantAccountSetter { + pub id: common_utils::id_type::MerchantId, + pub return_url: Option, + pub enable_payment_response_hash: bool, + pub payment_response_hash_key: Option, + pub redirect_to_merchant_with_http_post: bool, + pub merchant_name: Option, + pub merchant_details: Option, + pub webhook_details: Option, + pub sub_merchants_enabled: Option, + pub parent_merchant_id: Option, + pub publishable_key: Option, + pub storage_scheme: storage_enums::MerchantStorageScheme, + pub locker_id: Option, + pub metadata: Option, + pub routing_algorithm: Option, + pub primary_business_details: serde_json::Value, + pub intent_fulfillment_time: Option, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + pub frm_routing_algorithm: Option, + pub payout_routing_algorithm: Option, + pub organization_id: common_utils::id_type::OrganizationId, pub is_recon_enabled: bool, pub default_profile: Option, pub recon_status: storage_enums::ReconStatus, @@ -98,21 +242,35 @@ pub struct MerchantAccount { } impl MerchantAccount { - pub fn get_id(&self) -> &id_type::MerchantId { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "merchant_account_v2") + ))] + /// Get the unique identifier of MerchantAccount + pub fn get_id(&self) -> &common_utils::id_type::MerchantId { &self.merchant_id } + + #[cfg(all(feature = "v2", feature = "merchant_account_v2"))] + pub fn get_id(&self) -> &common_utils::id_type::MerchantId { + &self.id + } } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "merchant_account_v2") +))] #[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)] #[diesel(table_name = merchant_account)] pub struct MerchantAccountNew { - pub merchant_id: id_type::MerchantId, + pub merchant_id: common_utils::id_type::MerchantId, pub merchant_name: Option, pub merchant_details: Option, pub return_url: Option, pub webhook_details: Option, pub sub_merchants_enabled: Option, - pub parent_merchant_id: Option, + pub parent_merchant_id: Option, pub enable_payment_response_hash: Option, pub payment_response_hash_key: Option, pub redirect_to_merchant_with_http_post: Option, @@ -126,7 +284,7 @@ pub struct MerchantAccountNew { pub modified_at: time::PrimitiveDateTime, pub frm_routing_algorithm: Option, pub payout_routing_algorithm: Option, - pub organization_id: id_type::OrganizationId, + pub organization_id: common_utils::id_type::OrganizationId, pub is_recon_enabled: bool, pub default_profile: Option, pub recon_status: storage_enums::ReconStatus, @@ -134,6 +292,38 @@ pub struct MerchantAccountNew { pub pm_collect_link_config: Option, } +#[cfg(all(feature = "v2", feature = "merchant_account_v2"))] +#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)] +#[diesel(table_name = merchant_account)] +pub struct MerchantAccountNew { + pub merchant_name: Option, + pub merchant_details: Option, + pub return_url: Option, + pub webhook_details: Option, + pub sub_merchants_enabled: Option, + pub parent_merchant_id: Option, + pub enable_payment_response_hash: Option, + pub payment_response_hash_key: Option, + pub redirect_to_merchant_with_http_post: Option, + pub publishable_key: Option, + pub locker_id: Option, + pub metadata: Option, + pub routing_algorithm: Option, + pub primary_business_details: serde_json::Value, + pub intent_fulfillment_time: Option, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + pub frm_routing_algorithm: Option, + pub payout_routing_algorithm: Option, + pub organization_id: common_utils::id_type::OrganizationId, + pub is_recon_enabled: bool, + pub default_profile: Option, + pub recon_status: storage_enums::ReconStatus, + pub payment_link_config: Option, + pub pm_collect_link_config: Option, + pub id: common_utils::id_type::MerchantId, +} + #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = merchant_account)] pub struct MerchantAccountUpdateInternal { @@ -142,7 +332,7 @@ pub struct MerchantAccountUpdateInternal { pub return_url: Option, pub webhook_details: Option, pub sub_merchants_enabled: Option, - pub parent_merchant_id: Option, + pub parent_merchant_id: Option, pub enable_payment_response_hash: Option, pub payment_response_hash_key: Option, pub redirect_to_merchant_with_http_post: Option, @@ -156,7 +346,7 @@ pub struct MerchantAccountUpdateInternal { pub intent_fulfillment_time: Option, pub frm_routing_algorithm: Option, pub payout_routing_algorithm: Option, - pub organization_id: Option, + pub organization_id: Option, pub is_recon_enabled: bool, pub default_profile: Option>, pub recon_status: Option, diff --git a/crates/diesel_models/src/query/merchant_account.rs b/crates/diesel_models/src/query/merchant_account.rs index 578a100219..564a37d79e 100644 --- a/crates/diesel_models/src/query/merchant_account.rs +++ b/crates/diesel_models/src/query/merchant_account.rs @@ -5,9 +5,9 @@ use super::generics; any(feature = "v1", feature = "v2"), not(feature = "merchant_account_v2") ))] -use crate::schema::merchant_account::dsl; +use crate::schema::merchant_account::dsl::{self, merchant_id as dsl_identifier}; #[cfg(all(feature = "v2", feature = "merchant_account_v2"))] -use crate::schema_v2::merchant_account::dsl; +use crate::schema_v2::merchant_account::dsl::{self, id as dsl_identifier}; use crate::{ errors, merchant_account::{MerchantAccount, MerchantAccountNew, MerchantAccountUpdateInternal}, @@ -28,7 +28,7 @@ impl MerchantAccount { ) -> StorageResult { match generics::generic_update_by_id::<::Table, _, _, _>( conn, - self.merchant_id.clone(), + self.get_id().to_owned(), merchant_account, ) .await @@ -43,7 +43,7 @@ impl MerchantAccount { pub async fn update_with_specific_fields( conn: &PgPooledConn, - merchant_id: &common_utils::id_type::MerchantId, + identifier: &common_utils::id_type::MerchantId, merchant_account: MerchantAccountUpdateInternal, ) -> StorageResult { generics::generic_update_with_unique_predicate_get_result::< @@ -53,7 +53,7 @@ impl MerchantAccount { _, >( conn, - dsl::merchant_id.eq(merchant_id.to_owned()), + dsl_identifier.eq(identifier.to_owned()), merchant_account, ) .await @@ -61,22 +61,22 @@ impl MerchantAccount { pub async fn delete_by_merchant_id( conn: &PgPooledConn, - merchant_id: &common_utils::id_type::MerchantId, + identifier: &common_utils::id_type::MerchantId, ) -> StorageResult { generics::generic_delete::<::Table, _>( conn, - dsl::merchant_id.eq(merchant_id.to_owned()), + dsl_identifier.eq(identifier.to_owned()), ) .await } pub async fn find_by_merchant_id( conn: &PgPooledConn, - merchant_id: &common_utils::id_type::MerchantId, + identifier: &common_utils::id_type::MerchantId, ) -> StorageResult { generics::generic_find_one::<::Table, _, _>( conn, - dsl::merchant_id.eq(merchant_id.to_owned()), + dsl_identifier.eq(identifier.to_owned()), ) .await } @@ -120,13 +120,7 @@ impl MerchantAccount { _, <::Table as Table>::PrimaryKey, _, - >( - conn, - dsl::merchant_id.eq_any(merchant_ids), - None, - None, - None, - ) + >(conn, dsl_identifier.eq_any(merchant_ids), None, None, None) .await } @@ -136,7 +130,7 @@ impl MerchantAccount { ) -> StorageResult> { generics::generic_update_with_results::<::Table, _, _, _>( conn, - dsl::merchant_id.ne_all(vec![""]), + dsl_identifier.ne_all(vec![""]), merchant_account, ) .await diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 28937b48db..ca6a720825 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -633,9 +633,7 @@ diesel::table! { use diesel::sql_types::*; use crate::enums::diesel_exports::*; - merchant_account (merchant_id) { - #[max_length = 64] - merchant_id -> Varchar, + merchant_account (id) { #[max_length = 255] return_url -> Nullable, enable_payment_response_hash -> Bool, @@ -669,6 +667,8 @@ diesel::table! { recon_status -> ReconStatus, payment_link_config -> Nullable, pm_collect_link_config -> Nullable, + #[max_length = 64] + id -> Varchar, } } diff --git a/crates/hyperswitch_domain_models/src/merchant_account.rs b/crates/hyperswitch_domain_models/src/merchant_account.rs index 6d311ea2d4..ce11cd566c 100644 --- a/crates/hyperswitch_domain_models/src/merchant_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_account.rs @@ -126,9 +126,10 @@ impl From for MerchantAccount { } #[cfg(all(feature = "v2", feature = "merchant_account_v2"))] -#[derive(Clone, Debug, serde::Serialize)] -pub struct MerchantAccount { - merchant_id: common_utils::id_type::MerchantId, +#[derive(Clone)] +/// Set the private fields of merchant account +pub struct MerchantAccountSetter { + pub id: common_utils::id_type::MerchantId, pub return_url: Option, pub enable_payment_response_hash: bool, pub payment_response_hash_key: Option, @@ -137,7 +138,74 @@ pub struct MerchantAccount { pub merchant_details: OptionalEncryptableValue, pub webhook_details: Option, pub sub_merchants_enabled: Option, - pub parent_merchant_id: Option, + pub parent_merchant_id: Option, + pub publishable_key: String, + pub storage_scheme: MerchantStorageScheme, + pub locker_id: Option, + pub metadata: Option, + pub routing_algorithm: Option, + pub primary_business_details: serde_json::Value, + pub frm_routing_algorithm: Option, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + pub intent_fulfillment_time: Option, + pub payout_routing_algorithm: Option, + pub organization_id: common_utils::id_type::OrganizationId, + pub is_recon_enabled: bool, + pub default_profile: Option, + pub recon_status: diesel_models::enums::ReconStatus, + pub payment_link_config: Option, + pub pm_collect_link_config: Option, +} + +#[cfg(all(feature = "v2", feature = "merchant_account_v2"))] +impl From for MerchantAccount { + fn from(item: MerchantAccountSetter) -> Self { + Self { + id: item.id, + return_url: item.return_url, + enable_payment_response_hash: item.enable_payment_response_hash, + payment_response_hash_key: item.payment_response_hash_key, + redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post, + merchant_name: item.merchant_name, + merchant_details: item.merchant_details, + webhook_details: item.webhook_details, + sub_merchants_enabled: item.sub_merchants_enabled, + parent_merchant_id: item.parent_merchant_id, + publishable_key: item.publishable_key, + storage_scheme: item.storage_scheme, + locker_id: item.locker_id, + metadata: item.metadata, + routing_algorithm: item.routing_algorithm, + primary_business_details: item.primary_business_details, + frm_routing_algorithm: item.frm_routing_algorithm, + created_at: item.created_at, + modified_at: item.modified_at, + intent_fulfillment_time: item.intent_fulfillment_time, + payout_routing_algorithm: item.payout_routing_algorithm, + organization_id: item.organization_id, + is_recon_enabled: item.is_recon_enabled, + default_profile: item.default_profile, + recon_status: item.recon_status, + payment_link_config: item.payment_link_config, + pm_collect_link_config: item.pm_collect_link_config, + } + } +} + +#[cfg(all(feature = "v2", feature = "merchant_account_v2"))] +#[derive(Clone, Debug, serde::Serialize)] +pub struct MerchantAccount { + id: common_utils::id_type::MerchantId, + pub return_url: Option, + pub enable_payment_response_hash: bool, + pub payment_response_hash_key: Option, + pub redirect_to_merchant_with_http_post: bool, + pub merchant_name: OptionalEncryptableName, + pub merchant_details: OptionalEncryptableValue, + pub webhook_details: Option, + pub sub_merchants_enabled: Option, + pub parent_merchant_id: Option, pub publishable_key: String, pub storage_scheme: MerchantStorageScheme, pub locker_id: Option, @@ -158,10 +226,20 @@ pub struct MerchantAccount { } impl MerchantAccount { + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "merchant_account_v2") + ))] /// Get the unique identifier of MerchantAccount pub fn get_id(&self) -> &common_utils::id_type::MerchantId { &self.merchant_id } + + #[cfg(all(feature = "v2", feature = "merchant_account_v2"))] + /// Get the unique identifier of MerchantAccount + pub fn get_id(&self) -> &common_utils::id_type::MerchantId { + &self.id + } } #[allow(clippy::large_enum_variant)] @@ -278,8 +356,10 @@ impl super::behaviour::Conversion for MerchantAccount { type DstType = diesel_models::merchant_account::MerchantAccount; type NewDstType = diesel_models::merchant_account::MerchantAccountNew; async fn convert(self) -> CustomResult { - Ok(diesel_models::merchant_account::MerchantAccount { - merchant_id: self.merchant_id, + let id = self.get_id().to_owned(); + + let setter = diesel_models::merchant_account::MerchantAccountSetter { + id, return_url: self.return_url, enable_payment_response_hash: self.enable_payment_response_hash, payment_response_hash_key: self.payment_response_hash_key, @@ -306,7 +386,9 @@ impl super::behaviour::Conversion for MerchantAccount { recon_status: self.recon_status, payment_link_config: self.payment_link_config, pm_collect_link_config: self.pm_collect_link_config, - }) + }; + + Ok(diesel_models::MerchantAccount::from(setter)) } async fn convert_back( @@ -318,6 +400,7 @@ impl super::behaviour::Conversion for MerchantAccount { where Self: Sized, { + let id = item.get_id().to_owned(); let publishable_key = item.publishable_key .ok_or(ValidationError::MissingRequiredField { @@ -326,7 +409,7 @@ impl super::behaviour::Conversion for MerchantAccount { async { Ok::>(Self { - merchant_id: item.merchant_id, + id, return_url: item.return_url, enable_payment_response_hash: item.enable_payment_response_hash, payment_response_hash_key: item.payment_response_hash_key, @@ -374,7 +457,7 @@ impl super::behaviour::Conversion for MerchantAccount { async fn construct_new(self) -> CustomResult { let now = date_time::now(); Ok(diesel_models::merchant_account::MerchantAccountNew { - merchant_id: self.merchant_id, + id: self.id, merchant_name: self.merchant_name.map(Encryption::from), merchant_details: self.merchant_details.map(Encryption::from), return_url: self.return_url, @@ -413,7 +496,7 @@ impl super::behaviour::Conversion for MerchantAccount { type DstType = diesel_models::merchant_account::MerchantAccount; type NewDstType = diesel_models::merchant_account::MerchantAccountNew; async fn convert(self) -> CustomResult { - Ok(diesel_models::merchant_account::MerchantAccount { + let setter = diesel_models::merchant_account::MerchantAccountSetter { merchant_id: self.merchant_id, return_url: self.return_url, enable_payment_response_hash: self.enable_payment_response_hash, @@ -441,7 +524,9 @@ impl super::behaviour::Conversion for MerchantAccount { recon_status: self.recon_status, payment_link_config: self.payment_link_config, pm_collect_link_config: self.pm_collect_link_config, - }) + }; + + Ok(diesel_models::MerchantAccount::from(setter)) } async fn convert_back( @@ -453,14 +538,16 @@ impl super::behaviour::Conversion for MerchantAccount { where Self: Sized, { + let merchant_id = item.get_id().to_owned(); let publishable_key = item.publishable_key .ok_or(ValidationError::MissingRequiredField { field_name: "publishable_key".to_string(), })?; + async { Ok::>(Self { - merchant_id: item.merchant_id, + merchant_id, return_url: item.return_url, enable_payment_response_hash: item.enable_payment_response_hash, payment_response_hash_key: item.payment_response_hash_key, diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 9203a33239..15c5aded50 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -554,7 +554,7 @@ impl behaviour::Conversion for PaymentIntent { { async { let inner_decrypt = - |inner| decrypt_optional(state, inner, key_manager_identifier, key.peek()); + |inner| decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()); Ok::>(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 51fffea3b5..7003772556 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -412,7 +412,10 @@ impl MerchantAccountCreateBridge for api::MerchantAccountCreate { #[cfg(feature = "olap")] enum CreateOrValidateOrganization { /// Creates a new organization - #[cfg(any(feature = "v1", feature = "v2"))] + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "merchant_account_v2") + ))] Create, /// Validates if this organization exists in the records Validate { @@ -451,7 +454,10 @@ impl CreateOrValidateOrganization { db: &dyn StorageInterface, ) -> RouterResult { match self { - #[cfg(any(feature = "v1", feature = "v2"))] + #[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "merchant_account_v2") + ))] Self::Create => { let new_organization = api_models::organization::OrganizationNew::new(None); let db_organization = ForeignFrom::foreign_from(new_organization); @@ -637,17 +643,14 @@ impl MerchantAccountCreateBridge for api::MerchantAccountCreate { .await?; let key = key_store.key.into_inner(); - let merchant_id = self - .get_merchant_reference_id() - .get_string_repr() - .to_owned(); + let id = self.get_merchant_reference_id().to_owned(); let key_manager_state = state.into(); - let identifier = km_types::Identifier::Merchant(merchant_id.clone()); + let identifier = km_types::Identifier::Merchant(id.clone()); async { Ok::<_, error_stack::Report>( - domain::MerchantAccount { - merchant_id, + domain::MerchantAccount::from(domain::MerchantAccountSetter { + id, merchant_name: Some( domain_types::encrypt( &key_manager_state, @@ -695,7 +698,7 @@ impl MerchantAccountCreateBridge for api::MerchantAccountCreate { recon_status: diesel_models::enums::ReconStatus::NotRequested, payment_link_config: None, pm_collect_link_config: None, - }, + }), ) } .await diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index 4c96f4fbe8..a2081abddc 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -206,7 +206,7 @@ impl CustomerCreateBridge for customers::CustomerRequest { ) -> errors::CustomResult { let _default_customer_billing_address = self.get_default_customer_billing_address(); let _default_customer_shipping_address = self.get_default_customer_shipping_address(); - let merchant_id = merchant_account.merchant_id.clone(); + let merchant_id = merchant_account.get_id().clone(); let key = key_store.key.get_inner().peek(); let encrypted_data = types::batch_encrypt( @@ -230,14 +230,13 @@ impl CustomerCreateBridge for customers::CustomerRequest { customer_id: merchant_reference_id .to_owned() .ok_or(errors::CustomersErrorResponse::InternalServerError)?, // doing this to make it compile, will remove once we start moving to domain models - merchant_id: merchant_id.to_string(), + merchant_id, name: encryptable_customer.name, email: encryptable_customer.email, phone: encryptable_customer.phone, description: self.description.clone(), phone_country_code: self.phone_country_code.clone(), metadata: self.metadata.clone(), - id: None, connector_customer: None, address_id: None, created_at: common_utils::date_time::now(), diff --git a/crates/router/src/db/merchant_account.rs b/crates/router/src/db/merchant_account.rs index 1907b9bdea..aee54b3e1b 100644 --- a/crates/router/src/db/merchant_account.rs +++ b/crates/router/src/db/merchant_account.rs @@ -483,7 +483,7 @@ impl MerchantAccountInterface for MockDb { let accounts = self.merchant_accounts.lock().await; let account: Option = accounts .iter() - .find(|account| account.merchant_id == *merchant_id) + .find(|account| account.get_id() == merchant_id) .cloned() .async_map(|a| async { a.convert( @@ -608,7 +608,7 @@ async fn publish_and_redact_all_merchant_account_cache( ) -> CustomResult<(), errors::StorageError> { let merchant_ids = merchant_accounts .iter() - .map(|m| m.merchant_id.get_string_repr().to_string()); + .map(|merchant_account| merchant_account.get_id().get_string_repr().to_string()); let publishable_keys = merchant_accounts .iter() .filter_map(|m| m.publishable_key.clone()); diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 8d456bb8fd..6dfb74c378 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -20,8 +20,12 @@ use tokio::sync::oneshot; use self::settings::Tenant; #[cfg(feature = "olap")] use super::blocklist; +#[cfg(any(feature = "olap", feature = "oltp"))] +use super::currency; #[cfg(feature = "dummy_connector")] use super::dummy_connector::*; +#[cfg(all(any(feature = "olap", feature = "oltp"), not(feature = "customer_v2")))] +use super::payment_methods::*; #[cfg(feature = "payouts")] use super::payout_link::*; #[cfg(feature = "payouts")] @@ -46,8 +50,6 @@ use super::{ use super::{cache::*, health::*}; #[cfg(any(feature = "olap", feature = "oltp"))] use super::{configs::*, customers::*, mandates::*, payments::*, refunds::*}; -#[cfg(any(feature = "olap", feature = "oltp"))] -use super::{currency, payment_methods::*}; #[cfg(feature = "oltp")] use super::{ephemeral_key::*, webhooks::*}; #[cfg(feature = "olap")] @@ -58,8 +60,6 @@ use crate::analytics::AnalyticsProvider; use crate::routes::fraud_check as frm_routes; #[cfg(all(feature = "recon", feature = "olap"))] use crate::routes::recon as recon_routes; -#[cfg(all(feature = "olap", not(feature = "v2")))] -use crate::routes::verify_connector::payment_connector_verify; pub use crate::{ configs::settings, core::routing, @@ -1116,7 +1116,7 @@ impl MerchantConnectorAccount { route = route .service( web::resource("/connectors/verify") - .route(web::post().to(payment_connector_verify)), + .route(web::post().to(super::verify_connector::payment_connector_verify)), ) .service( web::resource("/{merchant_id}/connectors") diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index 0433308792..9669b8326d 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -91,13 +91,15 @@ impl ForeignTryFrom for MerchantAccountResponse { fn foreign_try_from(item: domain::MerchantAccount) -> Result { use common_utils::ext_traits::OptionExt; + let id = item.get_id().to_owned(); + let merchant_name = item .merchant_name .get_required_value("merchant_name")? .into_inner(); Ok(Self { - id: item.merchant_id, + id, merchant_name, merchant_details: item.merchant_details, publishable_key: item.publishable_key, diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index c86f9240c4..6798cdc3ea 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -22,17 +22,14 @@ use api_models::{ }; use base64::Engine; use common_utils::types::keymanager::KeyManagerState; +#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] +use common_utils::types::keymanager::{Identifier, ToEncryptable}; pub use common_utils::{ crypto, ext_traits::{ByteSliceExt, BytesExt, Encode, StringExt, ValueExt}, fp_utils::when, validation::validate_email, }; -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use common_utils::{ - id_type, - types::keymanager::{Identifier, ToEncryptable}, -}; use error_stack::ResultExt; use hyperswitch_domain_models::payments::PaymentIntent; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] @@ -677,15 +674,15 @@ pub trait CustomerAddress { address_details: payments::AddressDetails, key: &[u8], storage_scheme: storage::enums::MerchantStorageScheme, - merchant_id: id_type::MerchantId, + merchant_id: common_utils::id_type::MerchantId, ) -> CustomResult; async fn get_domain_address( &self, state: &SessionState, address_details: payments::AddressDetails, - merchant_id: &id_type::MerchantId, - customer_id: &id_type::CustomerId, + merchant_id: &common_utils::id_type::MerchantId, + customer_id: &common_utils::id_type::CustomerId, key: &[u8], storage_scheme: storage::enums::MerchantStorageScheme, ) -> CustomResult; @@ -700,7 +697,7 @@ impl CustomerAddress for api_models::customers::CustomerRequest { address_details: payments::AddressDetails, key: &[u8], storage_scheme: storage::enums::MerchantStorageScheme, - merchant_id: id_type::MerchantId, + merchant_id: common_utils::id_type::MerchantId, ) -> CustomResult { let encrypted_data = batch_encrypt( &state.into(), @@ -736,8 +733,8 @@ impl CustomerAddress for api_models::customers::CustomerRequest { &self, state: &SessionState, address_details: payments::AddressDetails, - merchant_id: &id_type::MerchantId, - customer_id: &id_type::CustomerId, + merchant_id: &common_utils::id_type::MerchantId, + customer_id: &common_utils::id_type::CustomerId, key: &[u8], storage_scheme: storage::enums::MerchantStorageScheme, ) -> CustomResult { @@ -784,7 +781,7 @@ impl CustomerAddress for api_models::customers::CustomerRequest { pub fn add_apple_pay_flow_metrics( apple_pay_flow: &Option, connector: Option, - merchant_id: id_type::MerchantId, + merchant_id: common_utils::id_type::MerchantId, ) { if let Some(flow) = apple_pay_flow { match flow { @@ -818,7 +815,7 @@ pub fn add_apple_pay_payment_status_metrics( payment_attempt_status: enums::AttemptStatus, apple_pay_flow: Option, connector: Option, - merchant_id: id_type::MerchantId, + merchant_id: common_utils::id_type::MerchantId, ) { if payment_attempt_status == enums::AttemptStatus::Charged { if let Some(flow) = apple_pay_flow { diff --git a/v2_migrations/2024-07-25-064644_add_id_in_merchant_account/down.sql b/v2_migrations/2024-07-25-064644_add_id_in_merchant_account/down.sql new file mode 100644 index 0000000000..82fc50e6f4 --- /dev/null +++ b/v2_migrations/2024-07-25-064644_add_id_in_merchant_account/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE merchant_account DROP id; diff --git a/v2_migrations/2024-07-25-064644_add_id_in_merchant_account/up.sql b/v2_migrations/2024-07-25-064644_add_id_in_merchant_account/up.sql new file mode 100644 index 0000000000..a84fe8a79c --- /dev/null +++ b/v2_migrations/2024-07-25-064644_add_id_in_merchant_account/up.sql @@ -0,0 +1,5 @@ +-- Your SQL goes here +-- Adding a new column called `id` which will be the new primary key for v2 +-- Note that even though this will be the new primary key, the v1 application would still fill in null values +ALTER TABLE merchant_account +ADD COLUMN id VARCHAR(64); diff --git a/v2_migrations/2024-07-25-065100_change_primary_key_from_merchant_id_to_id/down.sql b/v2_migrations/2024-07-25-065100_change_primary_key_from_merchant_id_to_id/down.sql new file mode 100644 index 0000000000..e3870f5982 --- /dev/null +++ b/v2_migrations/2024-07-25-065100_change_primary_key_from_merchant_id_to_id/down.sql @@ -0,0 +1,16 @@ +-- This file should undo anything in `up.sql` +-- The new primary key for v2 merchant account will be `id` +ALTER TABLE merchant_account DROP CONSTRAINT merchant_account_pkey; + +-- In order to run this query, the merchant_id column should be unique and not null +-- We need to backfill the id, a simple strategy will be to copy the values of id to merchant_id +-- Query to update the merchant_id column with values of id +UPDATE merchant_account +SET merchant_id = id; + +-- Note: This command might not run successfully for the existing table +-- This is because there will be some rows ( which are created via v2 application ) which will have id as empty +-- A backfill might be required to run this query +-- However if this is being run on a fresh database, this should succeed +ALTER TABLE merchant_account +ADD PRIMARY KEY (merchant_id); diff --git a/v2_migrations/2024-07-25-065100_change_primary_key_from_merchant_id_to_id/up.sql b/v2_migrations/2024-07-25-065100_change_primary_key_from_merchant_id_to_id/up.sql new file mode 100644 index 0000000000..ef98378907 --- /dev/null +++ b/v2_migrations/2024-07-25-065100_change_primary_key_from_merchant_id_to_id/up.sql @@ -0,0 +1,17 @@ +-- Your SQL goes here +-- The new primary key for v2 merchant account will be `id` +ALTER TABLE merchant_account DROP CONSTRAINT merchant_account_pkey; + +-- In order to make id as primary key, it should be unique and not null +-- We need to backfill the id, a simple strategy will be to copy the values of merchant_id to id +-- Query to update the id column with values of merchant_id +-- Note: This query will lock the table, so it should be run when there is no traffic +UPDATE merchant_account +SET id = merchant_id; + +-- Note: This command might not run successfully for the existing table +-- This is because there will be some rows ( which are created via v1 application ) which will have id as empty +-- A backfill might be required to run this query +-- However if this is being run on a fresh database, this should succeed +ALTER TABLE merchant_account +ADD PRIMARY KEY (id); diff --git a/v2_migrations/2024-07-25-065542_drop_merchant_id_from_merchant_account/down.sql b/v2_migrations/2024-07-25-065542_drop_merchant_id_from_merchant_account/down.sql new file mode 100644 index 0000000000..d4f61709ad --- /dev/null +++ b/v2_migrations/2024-07-25-065542_drop_merchant_id_from_merchant_account/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE merchant_account +ADD COLUMN merchant_id VARCHAR(64); diff --git a/v2_migrations/2024-07-25-065542_drop_merchant_id_from_merchant_account/up.sql b/v2_migrations/2024-07-25-065542_drop_merchant_id_from_merchant_account/up.sql new file mode 100644 index 0000000000..9bdf043ebd --- /dev/null +++ b/v2_migrations/2024-07-25-065542_drop_merchant_id_from_merchant_account/up.sql @@ -0,0 +1,4 @@ +-- Your SQL goes here +-- Note: This query should not be run on higher environments as this leads to data loss +-- The application will work fine even without these queries not being run +ALTER TABLE merchant_account DROP merchant_id;