From d66cf2ce9890dc326d427185b6a75124dc88f64e Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Tue, 30 Jul 2024 17:47:28 +0530 Subject: [PATCH 01/11] refactor(diesel_models): always update `modified_at` field during business profile update --- crates/diesel_models/src/business_profile.rs | 62 +++++++++++++++++--- crates/router/src/core/admin.rs | 1 - crates/router/src/core/routing/helpers.rs | 1 - 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 30f6780e3600..0c9a6a924d5f 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -80,11 +80,11 @@ pub struct BusinessProfileNew { pub outgoing_webhook_custom_http_headers: Option, } -#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] +#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = business_profile)] pub struct BusinessProfileUpdateInternal { pub profile_name: Option, - pub modified_at: Option, + pub modified_at: time::PrimitiveDateTime, pub return_url: Option, pub enable_payment_response_hash: Option, pub payment_response_hash_key: Option, @@ -115,7 +115,6 @@ pub struct BusinessProfileUpdateInternal { pub enum BusinessProfileUpdate { Update { profile_name: Option, - modified_at: Option, return_url: Option, enable_payment_response_hash: Option, payment_response_hash_key: Option, @@ -149,10 +148,11 @@ pub enum BusinessProfileUpdate { impl From for BusinessProfileUpdateInternal { fn from(business_profile_update: BusinessProfileUpdate) -> Self { + let now = common_utils::date_time::now(); + match business_profile_update { BusinessProfileUpdate::Update { profile_name, - modified_at, return_url, enable_payment_response_hash, payment_response_hash_key, @@ -177,7 +177,7 @@ impl From for BusinessProfileUpdateInternal { outgoing_webhook_custom_http_headers, } => Self { profile_name, - modified_at, + modified_at: now, return_url, enable_payment_response_hash, payment_response_hash_key, @@ -194,25 +194,71 @@ impl From for BusinessProfileUpdateInternal { session_expiry, authentication_connector_details, payout_link_config, + is_extended_card_info_enabled: None, extended_card_info_config, use_billing_as_payment_method_billing, collect_shipping_details_from_wallet_connector, collect_billing_details_from_wallet_connector, is_connector_agnostic_mit_enabled, outgoing_webhook_custom_http_headers, - ..Default::default() }, BusinessProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + routing_algorithm: None, + intent_fulfillment_time: None, + frm_routing_algorithm: None, + payout_routing_algorithm: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, is_extended_card_info_enabled, - ..Default::default() + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, }, BusinessProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + routing_algorithm: None, + intent_fulfillment_time: None, + frm_routing_algorithm: None, + payout_routing_algorithm: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, is_connector_agnostic_mit_enabled, - ..Default::default() + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, }, } } diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 530f85795071..7ca02b524deb 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -3193,7 +3193,6 @@ pub async fn update_business_profile( let business_profile_update = storage::business_profile::BusinessProfileUpdate::Update { profile_name: request.profile_name, - modified_at: Some(date_time::now()), return_url: request.return_url.map(|return_url| return_url.to_string()), enable_payment_response_hash: request.enable_payment_response_hash, payment_response_hash_key: request.payment_response_hash_key, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 5978ef521a8a..b52e8daa0dd7 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -281,7 +281,6 @@ pub async fn update_business_profile_active_algorithm_ref( frm_routing_algorithm: None, payout_routing_algorithm, applepay_verified_domains: None, - modified_at: None, is_recon_enabled: None, payment_link_config: None, session_expiry: None, From 5568dd1422eae84d9c5a8498d30540c25df2c28b Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Tue, 30 Jul 2024 17:53:11 +0530 Subject: [PATCH 02/11] refactor(diesel_models): introduce `BusinessProfileUpdate::RoutingAlgorithmUpdate` enum variant --- crates/diesel_models/src/business_profile.rs | 34 ++++++++++++++++++++ crates/router/src/core/routing/helpers.rs | 23 +------------ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 0c9a6a924d5f..cb9e749936ae 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -138,6 +138,10 @@ pub enum BusinessProfileUpdate { is_connector_agnostic_mit_enabled: Option, outgoing_webhook_custom_http_headers: Option, }, + RoutingAlgorithmUpdate { + routing_algorithm: Option, + payout_routing_algorithm: Option, + }, ExtendedCardInfoUpdate { is_extended_card_info_enabled: Option, }, @@ -202,6 +206,36 @@ impl From for BusinessProfileUpdateInternal { is_connector_agnostic_mit_enabled, outgoing_webhook_custom_http_headers, }, + BusinessProfileUpdate::RoutingAlgorithmUpdate { + routing_algorithm, + payout_routing_algorithm, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + routing_algorithm, + intent_fulfillment_time: None, + frm_routing_algorithm: None, + payout_routing_algorithm, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + }, BusinessProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, } => Self { diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index b52e8daa0dd7..188caf61ba88 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -268,30 +268,9 @@ pub async fn update_business_profile_active_algorithm_ref( storage::enums::TransactionType::Payout => (None, Some(ref_val)), }; - let business_profile_update = BusinessProfileUpdate::Update { - profile_name: None, - return_url: None, - enable_payment_response_hash: None, - payment_response_hash_key: None, - redirect_to_merchant_with_http_post: None, - webhook_details: None, - metadata: None, + let business_profile_update = BusinessProfileUpdate::RoutingAlgorithmUpdate { routing_algorithm, - intent_fulfillment_time: None, - frm_routing_algorithm: None, payout_routing_algorithm, - applepay_verified_domains: None, - is_recon_enabled: None, - payment_link_config: None, - session_expiry: None, - authentication_connector_details: None, - payout_link_config: None, - extended_card_info_config: None, - use_billing_as_payment_method_billing: None, - collect_shipping_details_from_wallet_connector: None, - collect_billing_details_from_wallet_connector: None, - is_connector_agnostic_mit_enabled: None, - outgoing_webhook_custom_http_headers: None, }; db.update_business_profile_by_profile_id(current_business_profile, business_profile_update) From f101682d853330e3a6fa1ae7ff7a7b86cdc8d83b Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Tue, 30 Jul 2024 18:16:30 +0530 Subject: [PATCH 03/11] feat(hyperswitch_domain_models): introduce domain models for business profiles --- .../src/business_profile.rs | 367 ++++++++++++++++++ crates/hyperswitch_domain_models/src/lib.rs | 1 + 2 files changed, 368 insertions(+) create mode 100644 crates/hyperswitch_domain_models/src/business_profile.rs diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs new file mode 100644 index 000000000000..948d856238da --- /dev/null +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -0,0 +1,367 @@ +use common_utils::{ + crypto::OptionalEncryptableValue, + date_time, + encryption::Encryption, + errors::{CustomResult, ValidationError}, + pii, + types::keymanager, +}; +use diesel_models::business_profile::BusinessProfileUpdateInternal; +use error_stack::ResultExt; +use masking::{PeekInterface, Secret}; + +use crate::type_encryption::{decrypt_optional, AsyncLift}; + +#[derive(Clone, Debug)] +pub struct BusinessProfile { + pub profile_id: String, + pub merchant_id: common_utils::id_type::MerchantId, + pub profile_name: String, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + 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 webhook_details: Option, + pub metadata: Option, + pub routing_algorithm: Option, + pub intent_fulfillment_time: Option, + pub frm_routing_algorithm: Option, + pub payout_routing_algorithm: Option, + pub is_recon_enabled: bool, + pub applepay_verified_domains: Option>, + pub payment_link_config: Option, + pub session_expiry: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, + pub is_extended_card_info_enabled: Option, + pub extended_card_info_config: Option, + pub is_connector_agnostic_mit_enabled: Option, + pub use_billing_as_payment_method_billing: Option, + pub collect_shipping_details_from_wallet_connector: Option, + pub collect_billing_details_from_wallet_connector: Option, + pub outgoing_webhook_custom_http_headers: OptionalEncryptableValue, +} + +#[derive(Debug)] +pub enum BusinessProfileUpdate { + Update { + profile_name: Option, + return_url: Option, + enable_payment_response_hash: Option, + payment_response_hash_key: Option, + redirect_to_merchant_with_http_post: Option, + webhook_details: Option, + metadata: Option, + routing_algorithm: Option, + intent_fulfillment_time: Option, + frm_routing_algorithm: Option, + payout_routing_algorithm: Option, + is_recon_enabled: Option, + applepay_verified_domains: Option>, + payment_link_config: Option, + session_expiry: Option, + authentication_connector_details: Option, + payout_link_config: Option, + extended_card_info_config: Option, + use_billing_as_payment_method_billing: Option, + collect_shipping_details_from_wallet_connector: Option, + collect_billing_details_from_wallet_connector: Option, + is_connector_agnostic_mit_enabled: Option, + outgoing_webhook_custom_http_headers: OptionalEncryptableValue, + }, + RoutingAlgorithmUpdate { + routing_algorithm: Option, + payout_routing_algorithm: Option, + }, + ExtendedCardInfoUpdate { + is_extended_card_info_enabled: Option, + }, + ConnectorAgnosticMitUpdate { + is_connector_agnostic_mit_enabled: Option, + }, +} + +impl From for BusinessProfileUpdateInternal { + fn from(business_profile_update: BusinessProfileUpdate) -> Self { + let now = date_time::now(); + + match business_profile_update { + BusinessProfileUpdate::Update { + profile_name, + return_url, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + webhook_details, + metadata, + routing_algorithm, + intent_fulfillment_time, + frm_routing_algorithm, + payout_routing_algorithm, + is_recon_enabled, + applepay_verified_domains, + payment_link_config, + session_expiry, + authentication_connector_details, + payout_link_config, + extended_card_info_config, + use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector, + is_connector_agnostic_mit_enabled, + outgoing_webhook_custom_http_headers, + } => Self { + profile_name, + modified_at: now, + return_url, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + webhook_details, + metadata, + routing_algorithm, + intent_fulfillment_time, + frm_routing_algorithm, + payout_routing_algorithm, + is_recon_enabled, + applepay_verified_domains, + payment_link_config, + session_expiry, + authentication_connector_details, + payout_link_config, + is_extended_card_info_enabled: None, + extended_card_info_config, + is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers + .map(Encryption::from), + }, + BusinessProfileUpdate::RoutingAlgorithmUpdate { + routing_algorithm, + payout_routing_algorithm, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + routing_algorithm, + intent_fulfillment_time: None, + frm_routing_algorithm: None, + payout_routing_algorithm, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + }, + BusinessProfileUpdate::ExtendedCardInfoUpdate { + is_extended_card_info_enabled, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + routing_algorithm: None, + intent_fulfillment_time: None, + frm_routing_algorithm: None, + payout_routing_algorithm: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + }, + BusinessProfileUpdate::ConnectorAgnosticMitUpdate { + is_connector_agnostic_mit_enabled, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + routing_algorithm: None, + intent_fulfillment_time: None, + frm_routing_algorithm: None, + payout_routing_algorithm: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + }, + } + } +} + +#[async_trait::async_trait] +impl super::behaviour::Conversion for BusinessProfile { + type DstType = diesel_models::business_profile::BusinessProfile; + type NewDstType = diesel_models::business_profile::BusinessProfileNew; + + async fn convert(self) -> CustomResult { + Ok(diesel_models::business_profile::BusinessProfile { + profile_id: self.profile_id, + merchant_id: self.merchant_id, + profile_name: self.profile_name, + created_at: self.created_at, + modified_at: self.modified_at, + return_url: self.return_url, + enable_payment_response_hash: self.enable_payment_response_hash, + payment_response_hash_key: self.payment_response_hash_key, + redirect_to_merchant_with_http_post: self.redirect_to_merchant_with_http_post, + webhook_details: self.webhook_details, + metadata: self.metadata, + routing_algorithm: self.routing_algorithm, + intent_fulfillment_time: self.intent_fulfillment_time, + frm_routing_algorithm: self.frm_routing_algorithm, + payout_routing_algorithm: self.payout_routing_algorithm, + is_recon_enabled: self.is_recon_enabled, + applepay_verified_domains: self.applepay_verified_domains, + payment_link_config: self.payment_link_config, + session_expiry: self.session_expiry, + authentication_connector_details: self.authentication_connector_details, + payout_link_config: self.payout_link_config, + is_extended_card_info_enabled: self.is_extended_card_info_enabled, + extended_card_info_config: self.extended_card_info_config, + is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: self.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: self + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: self + .collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: self + .outgoing_webhook_custom_http_headers + .map(Encryption::from), + }) + } + + async fn convert_back( + state: &keymanager::KeyManagerState, + item: Self::DstType, + key: &Secret>, + key_manager_identifier: keymanager::Identifier, + ) -> CustomResult + where + Self: Sized, + { + async { + Ok::>(Self { + profile_id: item.profile_id, + merchant_id: item.merchant_id, + profile_name: item.profile_name, + created_at: item.created_at, + modified_at: item.modified_at, + 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, + webhook_details: item.webhook_details, + metadata: item.metadata, + routing_algorithm: item.routing_algorithm, + intent_fulfillment_time: item.intent_fulfillment_time, + frm_routing_algorithm: item.frm_routing_algorithm, + payout_routing_algorithm: item.payout_routing_algorithm, + is_recon_enabled: item.is_recon_enabled, + applepay_verified_domains: item.applepay_verified_domains, + payment_link_config: item.payment_link_config, + session_expiry: item.session_expiry, + authentication_connector_details: item.authentication_connector_details, + payout_link_config: item.payout_link_config, + is_extended_card_info_enabled: item.is_extended_card_info_enabled, + extended_card_info_config: item.extended_card_info_config, + is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: item + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: item + .collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: item + .outgoing_webhook_custom_http_headers + .async_lift(|inner| { + decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + }) + .await?, + }) + } + .await + .change_context(ValidationError::InvalidValue { + message: "Failed while decrypting business profile data".to_string(), + }) + } + + async fn construct_new(self) -> CustomResult { + Ok(diesel_models::business_profile::BusinessProfileNew { + profile_id: self.profile_id, + merchant_id: self.merchant_id, + profile_name: self.profile_name, + created_at: self.created_at, + modified_at: self.modified_at, + return_url: self.return_url, + enable_payment_response_hash: self.enable_payment_response_hash, + payment_response_hash_key: self.payment_response_hash_key, + redirect_to_merchant_with_http_post: self.redirect_to_merchant_with_http_post, + webhook_details: self.webhook_details, + metadata: self.metadata, + routing_algorithm: self.routing_algorithm, + intent_fulfillment_time: self.intent_fulfillment_time, + frm_routing_algorithm: self.frm_routing_algorithm, + payout_routing_algorithm: self.payout_routing_algorithm, + is_recon_enabled: self.is_recon_enabled, + applepay_verified_domains: self.applepay_verified_domains, + payment_link_config: self.payment_link_config, + session_expiry: self.session_expiry, + authentication_connector_details: self.authentication_connector_details, + payout_link_config: self.payout_link_config, + is_extended_card_info_enabled: self.is_extended_card_info_enabled, + extended_card_info_config: self.extended_card_info_config, + is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: self.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: self + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: self + .collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: self + .outgoing_webhook_custom_http_headers + .map(Encryption::from), + }) + } +} diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index c48f721b2102..2a04f20fe15e 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -1,4 +1,5 @@ pub mod api; +pub mod business_profile; pub mod customer; pub mod errors; pub mod mandates; From fbd874926d4db1703d7b3a060c341d325742d4da Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Wed, 31 Jul 2024 19:13:23 +0530 Subject: [PATCH 04/11] refactor(business_profile): update `apply_changeset()` method to fallback to source values for fields not updated --- crates/diesel_models/src/business_profile.rs | 60 ++++++++++++-------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index cb9e749936ae..1a968b598e00 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -339,7 +339,7 @@ impl BusinessProfileUpdate { pub fn apply_changeset(self, source: BusinessProfile) -> BusinessProfile { let BusinessProfileUpdateInternal { profile_name, - modified_at: _, + modified_at, return_url, enable_payment_response_hash, payment_response_hash_key, @@ -365,34 +365,48 @@ impl BusinessProfileUpdate { outgoing_webhook_custom_http_headers, } = self.into(); BusinessProfile { + profile_id: source.profile_id, + merchant_id: source.merchant_id, profile_name: profile_name.unwrap_or(source.profile_name), - modified_at: common_utils::date_time::now(), - return_url, + created_at: source.created_at, + modified_at, + return_url: return_url.or(source.return_url), enable_payment_response_hash: enable_payment_response_hash .unwrap_or(source.enable_payment_response_hash), - payment_response_hash_key, + payment_response_hash_key: payment_response_hash_key + .or(source.payment_response_hash_key), redirect_to_merchant_with_http_post: redirect_to_merchant_with_http_post .unwrap_or(source.redirect_to_merchant_with_http_post), - webhook_details, - metadata, - routing_algorithm, - intent_fulfillment_time, - frm_routing_algorithm, - payout_routing_algorithm, + webhook_details: webhook_details.or(source.webhook_details), + metadata: metadata.or(source.metadata), + routing_algorithm: routing_algorithm.or(source.routing_algorithm), + intent_fulfillment_time: intent_fulfillment_time.or(source.intent_fulfillment_time), + frm_routing_algorithm: frm_routing_algorithm.or(source.frm_routing_algorithm), + payout_routing_algorithm: payout_routing_algorithm.or(source.payout_routing_algorithm), is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled), - applepay_verified_domains, - payment_link_config, - session_expiry, - authentication_connector_details, - payout_link_config, - is_extended_card_info_enabled, - is_connector_agnostic_mit_enabled, - extended_card_info_config, - use_billing_as_payment_method_billing, - collect_shipping_details_from_wallet_connector, - collect_billing_details_from_wallet_connector, - outgoing_webhook_custom_http_headers, - ..source + applepay_verified_domains: applepay_verified_domains + .or(source.applepay_verified_domains), + payment_link_config: payment_link_config.or(source.payment_link_config), + session_expiry: session_expiry.or(source.session_expiry), + authentication_connector_details: authentication_connector_details + .or(source.authentication_connector_details), + payout_link_config: payout_link_config.or(source.payout_link_config), + is_extended_card_info_enabled: is_extended_card_info_enabled + .or(source.is_extended_card_info_enabled), + is_connector_agnostic_mit_enabled: is_connector_agnostic_mit_enabled + .or(source.is_connector_agnostic_mit_enabled), + extended_card_info_config: extended_card_info_config + .or(source.extended_card_info_config), + use_billing_as_payment_method_billing: use_billing_as_payment_method_billing + .or(source.use_billing_as_payment_method_billing), + collect_shipping_details_from_wallet_connector: + collect_shipping_details_from_wallet_connector + .or(source.collect_shipping_details_from_wallet_connector), + collect_billing_details_from_wallet_connector: + collect_billing_details_from_wallet_connector + .or(source.collect_billing_details_from_wallet_connector), + outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers + .or(source.outgoing_webhook_custom_http_headers), } } } From d8e1b3022c91495fc40be4bba2ca3ab5002fb2e4 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Wed, 31 Jul 2024 19:19:53 +0530 Subject: [PATCH 05/11] feat(diesel_models): introduce diesel models for business profile v2 --- crates/common_enums/src/enums.rs | 21 + crates/diesel_models/Cargo.toml | 3 +- crates/diesel_models/src/business_profile.rs | 493 ++++++++++++++++++ crates/diesel_models/src/enums.rs | 1 + .../src/query/business_profile.rs | 11 +- crates/diesel_models/src/schema_v2.rs | 13 +- .../down.sql | 9 + .../up.sql | 9 + .../down.sql | 8 + .../up.sql | 7 + 10 files changed, 567 insertions(+), 8 deletions(-) create mode 100644 v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql create mode 100644 v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/up.sql create mode 100644 v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/down.sql create mode 100644 v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 5c8a860c168b..817ebc7a3f2d 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -3032,3 +3032,24 @@ pub enum PayoutRetryType { SingleConnector, MultiConnector, } + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, + ToSchema, + Hash, +)] +#[router_derive::diesel_enum(storage_type = "db_enum")] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum OrderFulfillmentTimeOrigin { + Create, + Confirm, +} diff --git a/crates/diesel_models/Cargo.toml b/crates/diesel_models/Cargo.toml index 9024ffe79d78..67c82672dbbf 100644 --- a/crates/diesel_models/Cargo.toml +++ b/crates/diesel_models/Cargo.toml @@ -8,10 +8,11 @@ readme = "README.md" license.workspace = true [features] -default = ["kv_store", "v1"] +default = ["kv_store", "v1"] kv_store = [] v1 = [] v2 = [] +business_profile_v2 = [] customer_v2 = [] merchant_account_v2 = [] payment_v2 = [] diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 1a968b598e00..5e2daea49262 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -1,8 +1,25 @@ +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +use common_enums::OrderFulfillmentTimeOrigin; use common_utils::{encryption::Encryption, pii}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] use crate::schema::business_profile; +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +use crate::schema_v2::business_profile; +/// 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 = "business_profile_v2") +))] #[derive( Clone, Debug, @@ -46,6 +63,10 @@ pub struct BusinessProfile { pub outgoing_webhook_custom_http_headers: Option, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)] #[diesel(table_name = business_profile, primary_key(profile_id))] pub struct BusinessProfileNew { @@ -80,6 +101,10 @@ pub struct BusinessProfileNew { pub outgoing_webhook_custom_http_headers: Option, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = business_profile)] pub struct BusinessProfileUpdateInternal { @@ -111,6 +136,10 @@ pub struct BusinessProfileUpdateInternal { pub outgoing_webhook_custom_http_headers: Option, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum BusinessProfileUpdate { Update { @@ -150,6 +179,10 @@ pub enum BusinessProfileUpdate { }, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] impl From for BusinessProfileUpdateInternal { fn from(business_profile_update: BusinessProfileUpdate) -> Self { let now = common_utils::date_time::now(); @@ -298,6 +331,13 @@ impl From for BusinessProfileUpdateInternal { } } +// This is being used only in the `BusinessProfileInterface` implementation for `MockDb`. +// This can be removed once the `BusinessProfileInterface` trait has been updated to use the domain +// model instead. +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] impl From for BusinessProfile { fn from(new: BusinessProfileNew) -> Self { Self { @@ -335,6 +375,10 @@ impl From for BusinessProfile { } } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] impl BusinessProfileUpdate { pub fn apply_changeset(self, source: BusinessProfile) -> BusinessProfile { let BusinessProfileUpdateInternal { @@ -410,3 +454,452 @@ impl BusinessProfileUpdate { } } } + +/// 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 = "business_profile_v2"))] +#[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + Identifiable, + Queryable, + Selectable, + router_derive::DebugAsDisplay, +)] +#[diesel(table_name = business_profile, primary_key(profile_id), check_for_backend(diesel::pg::Pg))] +pub struct BusinessProfile { + pub profile_id: String, + pub merchant_id: common_utils::id_type::MerchantId, + pub profile_name: String, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + 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 webhook_details: Option, + pub metadata: Option, + pub is_recon_enabled: bool, + #[diesel(deserialize_as = super::OptionalDieselArray)] + pub applepay_verified_domains: Option>, + pub payment_link_config: Option, + pub session_expiry: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, + pub is_extended_card_info_enabled: Option, + pub extended_card_info_config: Option, + pub is_connector_agnostic_mit_enabled: Option, + pub use_billing_as_payment_method_billing: Option, + pub collect_shipping_details_from_wallet_connector: Option, + pub collect_billing_details_from_wallet_connector: Option, + pub outgoing_webhook_custom_http_headers: Option, + pub routing_algorithm_id: Option, + pub order_fulfillment_time: Option, + pub order_fulfillment_time_origin: Option, + pub frm_routing_algorithm_id: Option, + pub payout_routing_algorithm_id: Option, + pub default_fallback_routing: Option, +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)] +#[diesel(table_name = business_profile, primary_key(profile_id))] +pub struct BusinessProfileNew { + pub profile_id: String, + pub merchant_id: common_utils::id_type::MerchantId, + pub profile_name: String, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + 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 webhook_details: Option, + pub metadata: Option, + pub is_recon_enabled: bool, + #[diesel(deserialize_as = super::OptionalDieselArray)] + pub applepay_verified_domains: Option>, + pub payment_link_config: Option, + pub session_expiry: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, + pub is_extended_card_info_enabled: Option, + pub extended_card_info_config: Option, + pub is_connector_agnostic_mit_enabled: Option, + pub use_billing_as_payment_method_billing: Option, + pub collect_shipping_details_from_wallet_connector: Option, + pub collect_billing_details_from_wallet_connector: Option, + pub outgoing_webhook_custom_http_headers: Option, + pub routing_algorithm_id: Option, + pub order_fulfillment_time: Option, + pub order_fulfillment_time_origin: Option, + pub frm_routing_algorithm_id: Option, + pub payout_routing_algorithm_id: Option, + pub default_fallback_routing: Option, +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] +#[diesel(table_name = business_profile)] +pub struct BusinessProfileUpdateInternal { + pub profile_name: Option, + pub modified_at: time::PrimitiveDateTime, + pub return_url: Option, + pub enable_payment_response_hash: Option, + pub payment_response_hash_key: Option, + pub redirect_to_merchant_with_http_post: Option, + pub webhook_details: Option, + pub metadata: Option, + pub is_recon_enabled: Option, + #[diesel(deserialize_as = super::OptionalDieselArray)] + pub applepay_verified_domains: Option>, + pub payment_link_config: Option, + pub session_expiry: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, + pub is_extended_card_info_enabled: Option, + pub extended_card_info_config: Option, + pub is_connector_agnostic_mit_enabled: Option, + pub use_billing_as_payment_method_billing: Option, + pub collect_shipping_details_from_wallet_connector: Option, + pub collect_billing_details_from_wallet_connector: Option, + pub outgoing_webhook_custom_http_headers: Option, + pub routing_algorithm_id: Option, + pub order_fulfillment_time: Option, + pub order_fulfillment_time_origin: Option, + pub frm_routing_algorithm_id: Option, + pub payout_routing_algorithm_id: Option, + pub default_fallback_routing: Option, +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub enum BusinessProfileUpdate { + Update { + profile_name: Option, + return_url: Option, + enable_payment_response_hash: Option, + payment_response_hash_key: Option, + redirect_to_merchant_with_http_post: Option, + webhook_details: Option, + metadata: Option, + is_recon_enabled: Option, + applepay_verified_domains: Option>, + payment_link_config: Option, + session_expiry: Option, + authentication_connector_details: Option, + payout_link_config: Option, + extended_card_info_config: Option, + use_billing_as_payment_method_billing: Option, + collect_shipping_details_from_wallet_connector: Option, + collect_billing_details_from_wallet_connector: Option, + is_connector_agnostic_mit_enabled: Option, + outgoing_webhook_custom_http_headers: Option, + routing_algorithm_id: Option, + order_fulfillment_time: Option, + order_fulfillment_time_origin: Option, + frm_routing_algorithm_id: Option, + payout_routing_algorithm_id: Option, + default_fallback_routing: Option, + }, + RoutingAlgorithmUpdate { + routing_algorithm_id: Option, + payout_routing_algorithm_id: Option, + }, + ExtendedCardInfoUpdate { + is_extended_card_info_enabled: Option, + }, + ConnectorAgnosticMitUpdate { + is_connector_agnostic_mit_enabled: Option, + }, +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +impl From for BusinessProfileUpdateInternal { + fn from(business_profile_update: BusinessProfileUpdate) -> Self { + let now = common_utils::date_time::now(); + + match business_profile_update { + BusinessProfileUpdate::Update { + profile_name, + return_url, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + webhook_details, + metadata, + is_recon_enabled, + applepay_verified_domains, + payment_link_config, + session_expiry, + authentication_connector_details, + payout_link_config, + extended_card_info_config, + use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector, + is_connector_agnostic_mit_enabled, + outgoing_webhook_custom_http_headers, + routing_algorithm_id, + order_fulfillment_time, + order_fulfillment_time_origin, + frm_routing_algorithm_id, + payout_routing_algorithm_id, + default_fallback_routing, + } => Self { + profile_name, + modified_at: now, + return_url, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + webhook_details, + metadata, + is_recon_enabled, + applepay_verified_domains, + payment_link_config, + session_expiry, + authentication_connector_details, + payout_link_config, + is_extended_card_info_enabled: None, + extended_card_info_config, + use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector, + is_connector_agnostic_mit_enabled, + outgoing_webhook_custom_http_headers, + routing_algorithm_id, + order_fulfillment_time, + order_fulfillment_time_origin, + frm_routing_algorithm_id, + payout_routing_algorithm_id, + default_fallback_routing, + }, + BusinessProfileUpdate::RoutingAlgorithmUpdate { + routing_algorithm_id, + payout_routing_algorithm_id, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + routing_algorithm_id, + order_fulfillment_time: None, + order_fulfillment_time_origin: None, + frm_routing_algorithm_id: None, + payout_routing_algorithm_id, + default_fallback_routing: None, + }, + BusinessProfileUpdate::ExtendedCardInfoUpdate { + is_extended_card_info_enabled, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + routing_algorithm_id: None, + order_fulfillment_time: None, + order_fulfillment_time_origin: None, + frm_routing_algorithm_id: None, + payout_routing_algorithm_id: None, + default_fallback_routing: None, + }, + BusinessProfileUpdate::ConnectorAgnosticMitUpdate { + is_connector_agnostic_mit_enabled, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + routing_algorithm_id: None, + order_fulfillment_time: None, + order_fulfillment_time_origin: None, + frm_routing_algorithm_id: None, + payout_routing_algorithm_id: None, + default_fallback_routing: None, + }, + } + } +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +impl BusinessProfileUpdate { + pub fn apply_changeset(self, source: BusinessProfile) -> BusinessProfile { + let BusinessProfileUpdateInternal { + profile_name, + modified_at, + return_url, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + webhook_details, + metadata, + is_recon_enabled, + applepay_verified_domains, + payment_link_config, + session_expiry, + authentication_connector_details, + payout_link_config, + is_extended_card_info_enabled, + extended_card_info_config, + is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers, + routing_algorithm_id, + order_fulfillment_time, + order_fulfillment_time_origin, + frm_routing_algorithm_id, + payout_routing_algorithm_id, + default_fallback_routing, + } = self.into(); + BusinessProfile { + profile_id: source.profile_id, + merchant_id: source.merchant_id, + profile_name: profile_name.unwrap_or(source.profile_name), + created_at: source.created_at, + modified_at, + return_url: return_url.or(source.return_url), + enable_payment_response_hash: enable_payment_response_hash + .unwrap_or(source.enable_payment_response_hash), + payment_response_hash_key: payment_response_hash_key + .or(source.payment_response_hash_key), + redirect_to_merchant_with_http_post: redirect_to_merchant_with_http_post + .unwrap_or(source.redirect_to_merchant_with_http_post), + webhook_details: webhook_details.or(source.webhook_details), + metadata: metadata.or(source.metadata), + is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled), + applepay_verified_domains: applepay_verified_domains + .or(source.applepay_verified_domains), + payment_link_config: payment_link_config.or(source.payment_link_config), + session_expiry: session_expiry.or(source.session_expiry), + authentication_connector_details: authentication_connector_details + .or(source.authentication_connector_details), + payout_link_config: payout_link_config.or(source.payout_link_config), + is_extended_card_info_enabled: is_extended_card_info_enabled + .or(source.is_extended_card_info_enabled), + is_connector_agnostic_mit_enabled: is_connector_agnostic_mit_enabled + .or(source.is_connector_agnostic_mit_enabled), + extended_card_info_config: extended_card_info_config + .or(source.extended_card_info_config), + use_billing_as_payment_method_billing: use_billing_as_payment_method_billing + .or(source.use_billing_as_payment_method_billing), + collect_shipping_details_from_wallet_connector: + collect_shipping_details_from_wallet_connector + .or(source.collect_shipping_details_from_wallet_connector), + collect_billing_details_from_wallet_connector: + collect_billing_details_from_wallet_connector + .or(source.collect_billing_details_from_wallet_connector), + outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers + .or(source.outgoing_webhook_custom_http_headers), + routing_algorithm_id: routing_algorithm_id.or(source.routing_algorithm_id), + order_fulfillment_time: order_fulfillment_time.or(source.order_fulfillment_time), + order_fulfillment_time_origin: order_fulfillment_time_origin + .or(source.order_fulfillment_time_origin), + frm_routing_algorithm_id: frm_routing_algorithm_id.or(source.frm_routing_algorithm_id), + payout_routing_algorithm_id: payout_routing_algorithm_id + .or(source.payout_routing_algorithm_id), + default_fallback_routing: default_fallback_routing.or(source.default_fallback_routing), + } + } +} + +// This is being used only in the `BusinessProfileInterface` implementation for `MockDb`. +// This can be removed once the `BusinessProfileInterface` trait has been updated to use the domain +// model instead. +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +impl From for BusinessProfile { + fn from(new: BusinessProfileNew) -> Self { + Self { + profile_id: new.profile_id, + merchant_id: new.merchant_id, + profile_name: new.profile_name, + created_at: new.created_at, + modified_at: new.modified_at, + return_url: new.return_url, + enable_payment_response_hash: new.enable_payment_response_hash, + payment_response_hash_key: new.payment_response_hash_key, + redirect_to_merchant_with_http_post: new.redirect_to_merchant_with_http_post, + webhook_details: new.webhook_details, + metadata: new.metadata, + is_recon_enabled: new.is_recon_enabled, + applepay_verified_domains: new.applepay_verified_domains, + payment_link_config: new.payment_link_config, + session_expiry: new.session_expiry, + authentication_connector_details: new.authentication_connector_details, + payout_link_config: new.payout_link_config, + is_connector_agnostic_mit_enabled: new.is_connector_agnostic_mit_enabled, + is_extended_card_info_enabled: new.is_extended_card_info_enabled, + extended_card_info_config: new.extended_card_info_config, + use_billing_as_payment_method_billing: new.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: new + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: new + .collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: new.outgoing_webhook_custom_http_headers, + routing_algorithm_id: new.routing_algorithm_id, + order_fulfillment_time: new.order_fulfillment_time, + order_fulfillment_time_origin: new.order_fulfillment_time_origin, + frm_routing_algorithm_id: new.frm_routing_algorithm_id, + payout_routing_algorithm_id: new.payout_routing_algorithm_id, + default_fallback_routing: new.default_fallback_routing, + } + } +} diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs index f0059994cb67..55bfa9f2f231 100644 --- a/crates/diesel_models/src/enums.rs +++ b/crates/diesel_models/src/enums.rs @@ -12,6 +12,7 @@ pub mod diesel_exports { DbFutureUsage as FutureUsage, DbGenericLinkType as GenericLinkType, DbIntentStatus as IntentStatus, DbMandateStatus as MandateStatus, DbMandateType as MandateType, DbMerchantStorageScheme as MerchantStorageScheme, + DbOrderFulfillmentTimeOrigin as OrderFulfillmentTimeOrigin, DbPaymentMethodIssuerCode as PaymentMethodIssuerCode, DbPaymentSource as PaymentSource, DbPaymentType as PaymentType, DbPayoutStatus as PayoutStatus, DbPayoutType as PayoutType, DbProcessTrackerStatus as ProcessTrackerStatus, DbReconStatus as ReconStatus, diff --git a/crates/diesel_models/src/query/business_profile.rs b/crates/diesel_models/src/query/business_profile.rs index e716e45c6504..1b8e54e0180b 100644 --- a/crates/diesel_models/src/query/business_profile.rs +++ b/crates/diesel_models/src/query/business_profile.rs @@ -1,13 +1,18 @@ use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods, Table}; use super::generics; +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] +use crate::schema::business_profile::dsl; +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +use crate::schema_v2::business_profile::dsl; use crate::{ business_profile::{ BusinessProfile, BusinessProfileNew, BusinessProfileUpdate, BusinessProfileUpdateInternal, }, - errors, - schema::business_profile::dsl, - PgPooledConn, StorageResult, + errors, PgPooledConn, StorageResult, }; impl BusinessProfileNew { diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 5854fa5f385b..82db0c945f3c 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -188,10 +188,6 @@ diesel::table! { redirect_to_merchant_with_http_post -> Bool, webhook_details -> Nullable, metadata -> Nullable, - routing_algorithm -> Nullable, - intent_fulfillment_time -> Nullable, - frm_routing_algorithm -> Nullable, - payout_routing_algorithm -> Nullable, is_recon_enabled -> Bool, applepay_verified_domains -> Nullable>>, payment_link_config -> Nullable, @@ -205,6 +201,15 @@ diesel::table! { collect_shipping_details_from_wallet_connector -> Nullable, collect_billing_details_from_wallet_connector -> Nullable, outgoing_webhook_custom_http_headers -> Nullable, + #[max_length = 64] + routing_algorithm_id -> Nullable, + order_fulfillment_time -> Nullable, + order_fulfillment_time_origin -> Nullable, + #[max_length = 64] + frm_routing_algorithm_id -> Nullable, + #[max_length = 64] + payout_routing_algorithm_id -> Nullable, + default_fallback_routing -> Nullable, } } diff --git a/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql b/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql new file mode 100644 index 000000000000..209af2cee422 --- /dev/null +++ b/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql @@ -0,0 +1,9 @@ +ALTER TABLE business_profile + DROP COLUMN routing_algorithm_id, + DROP COLUMN order_fulfillment_time, + DROP COLUMN order_fulfillment_time_origin, + DROP COLUMN frm_routing_algorithm_id, + DROP COLUMN payout_routing_algorithm_id, + DROP COLUMN default_fallback_routing; + +DROP TYPE "OrderFulfillmentTimeOrigin"; diff --git a/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/up.sql b/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/up.sql new file mode 100644 index 000000000000..68d81e66d75d --- /dev/null +++ b/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/up.sql @@ -0,0 +1,9 @@ +CREATE TYPE "OrderFulfillmentTimeOrigin" AS ENUM ('create', 'confirm'); + +ALTER TABLE business_profile + ADD COLUMN routing_algorithm_id VARCHAR(64) DEFAULT NULL, + ADD COLUMN order_fulfillment_time BIGINT DEFAULT NULL, + ADD COLUMN order_fulfillment_time_origin "OrderFulfillmentTimeOrigin" DEFAULT NULL, + ADD COLUMN frm_routing_algorithm_id VARCHAR(64) DEFAULT NULL, + ADD COLUMN payout_routing_algorithm_id VARCHAR(64) DEFAULT NULL, + ADD COLUMN default_fallback_routing JSONB DEFAULT NULL; diff --git a/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/down.sql b/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/down.sql new file mode 100644 index 000000000000..3d1f299a024a --- /dev/null +++ b/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/down.sql @@ -0,0 +1,8 @@ +-- This adds back dropped columns in `up.sql`. +-- However, if the old columns were dropped, then we won't have data previously +-- stored in these columns. +ALTER TABLE business_profile + ADD COLUMN routing_algorithm JSON DEFAULT NULL, + ADD COLUMN intent_fulfillment_time BIGINT DEFAULT NULL, + ADD COLUMN frm_routing_algorithm JSONB DEFAULT NULL, + ADD COLUMN payout_routing_algorithm JSONB DEFAULT NULL; diff --git a/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql b/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql new file mode 100644 index 000000000000..8a5d300b3135 --- /dev/null +++ b/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql @@ -0,0 +1,7 @@ +-- 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 being run. +ALTER TABLE business_profile + DROP COLUMN routing_algorithm, + DROP COLUMN intent_fulfillment_time, + DROP COLUMN frm_routing_algorithm, + DROP COLUMN payout_routing_algorithm; From 342fbdbdb3eba22c39d0625a3afdb8c5a93cdb49 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Wed, 31 Jul 2024 20:21:32 +0530 Subject: [PATCH 06/11] feat(hyperswitch_domain_models): introduce domain models for business profile v2 --- crates/api_models/Cargo.toml | 3 +- crates/hyperswitch_domain_models/Cargo.toml | 1 + .../src/business_profile.rs | 396 ++++++++++++++++++ crates/router/Cargo.toml | 1 + 4 files changed, 400 insertions(+), 1 deletion(-) diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml index 84f8d2f01e91..06a6029ab57f 100644 --- a/crates/api_models/Cargo.toml +++ b/crates/api_models/Cargo.toml @@ -19,9 +19,10 @@ openapi = ["common_enums/openapi", "olap", "recon", "dummy_connector", "olap"] recon = [] v2 = [] v1 = [] -merchant_connector_account_v2 = [] +business_profile_v2 = [] customer_v2 = [] merchant_account_v2 = [] +merchant_connector_account_v2 = [] payment_v2 = [] [dependencies] diff --git a/crates/hyperswitch_domain_models/Cargo.toml b/crates/hyperswitch_domain_models/Cargo.toml index adbea0effb57..bb91d7db0e77 100644 --- a/crates/hyperswitch_domain_models/Cargo.toml +++ b/crates/hyperswitch_domain_models/Cargo.toml @@ -15,6 +15,7 @@ payouts = ["api_models/payouts"] frm = ["api_models/frm"] v2 = ["api_models/v2", "diesel_models/v2"] v1 = ["api_models/v1", "diesel_models/v1"] +business_profile_v2 = ["api_models/business_profile_v2", "diesel_models/business_profile_v2"] customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2"] merchant_account_v2 = ["api_models/merchant_account_v2", "diesel_models/merchant_account_v2"] payment_v2 = ["api_models/payment_v2", "diesel_models/payment_v2"] diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 948d856238da..f157dcf8eb9b 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -1,3 +1,5 @@ +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +use common_enums::OrderFulfillmentTimeOrigin; use common_utils::{ crypto::OptionalEncryptableValue, date_time, @@ -12,6 +14,10 @@ use masking::{PeekInterface, Secret}; use crate::type_encryption::{decrypt_optional, AsyncLift}; +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[derive(Clone, Debug)] pub struct BusinessProfile { pub profile_id: String, @@ -44,6 +50,10 @@ pub struct BusinessProfile { pub outgoing_webhook_custom_http_headers: OptionalEncryptableValue, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[derive(Debug)] pub enum BusinessProfileUpdate { Update { @@ -83,6 +93,10 @@ pub enum BusinessProfileUpdate { }, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] impl From for BusinessProfileUpdateInternal { fn from(business_profile_update: BusinessProfileUpdate) -> Self { let now = date_time::now(); @@ -232,6 +246,10 @@ impl From for BusinessProfileUpdateInternal { } } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[async_trait::async_trait] impl super::behaviour::Conversion for BusinessProfile { type DstType = diesel_models::business_profile::BusinessProfile; @@ -365,3 +383,381 @@ impl super::behaviour::Conversion for BusinessProfile { }) } } + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[derive(Clone, Debug)] +pub struct BusinessProfile { + pub profile_id: String, + pub merchant_id: common_utils::id_type::MerchantId, + pub profile_name: String, + pub created_at: time::PrimitiveDateTime, + pub modified_at: time::PrimitiveDateTime, + 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 webhook_details: Option, + pub metadata: Option, + pub is_recon_enabled: bool, + pub applepay_verified_domains: Option>, + pub payment_link_config: Option, + pub session_expiry: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, + pub is_extended_card_info_enabled: Option, + pub extended_card_info_config: Option, + pub is_connector_agnostic_mit_enabled: Option, + pub use_billing_as_payment_method_billing: Option, + pub collect_shipping_details_from_wallet_connector: Option, + pub collect_billing_details_from_wallet_connector: Option, + pub outgoing_webhook_custom_http_headers: OptionalEncryptableValue, + pub routing_algorithm_id: Option, + pub order_fulfillment_time: Option, + pub order_fulfillment_time_origin: Option, + pub frm_routing_algorithm_id: Option, + pub payout_routing_algorithm_id: Option, + pub default_fallback_routing: Option, +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[derive(Debug)] +pub enum BusinessProfileUpdate { + Update { + profile_name: Option, + return_url: Option, + enable_payment_response_hash: Option, + payment_response_hash_key: Option, + redirect_to_merchant_with_http_post: Option, + webhook_details: Option, + metadata: Option, + is_recon_enabled: Option, + applepay_verified_domains: Option>, + payment_link_config: Option, + session_expiry: Option, + authentication_connector_details: Option, + payout_link_config: Option, + extended_card_info_config: Option, + use_billing_as_payment_method_billing: Option, + collect_shipping_details_from_wallet_connector: Option, + collect_billing_details_from_wallet_connector: Option, + is_connector_agnostic_mit_enabled: Option, + outgoing_webhook_custom_http_headers: OptionalEncryptableValue, + routing_algorithm_id: Option, + order_fulfillment_time: Option, + order_fulfillment_time_origin: Option, + frm_routing_algorithm_id: Option, + payout_routing_algorithm_id: Option, + default_fallback_routing: Option, + }, + RoutingAlgorithmUpdate { + routing_algorithm_id: Option, + payout_routing_algorithm_id: Option, + }, + ExtendedCardInfoUpdate { + is_extended_card_info_enabled: Option, + }, + ConnectorAgnosticMitUpdate { + is_connector_agnostic_mit_enabled: Option, + }, +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +impl From for BusinessProfileUpdateInternal { + fn from(business_profile_update: BusinessProfileUpdate) -> Self { + let now = date_time::now(); + + match business_profile_update { + BusinessProfileUpdate::Update { + profile_name, + return_url, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + webhook_details, + metadata, + is_recon_enabled, + applepay_verified_domains, + payment_link_config, + session_expiry, + authentication_connector_details, + payout_link_config, + extended_card_info_config, + use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector, + is_connector_agnostic_mit_enabled, + outgoing_webhook_custom_http_headers, + routing_algorithm_id, + order_fulfillment_time, + order_fulfillment_time_origin, + frm_routing_algorithm_id, + payout_routing_algorithm_id, + default_fallback_routing, + } => Self { + profile_name, + modified_at: now, + return_url, + enable_payment_response_hash, + payment_response_hash_key, + redirect_to_merchant_with_http_post, + webhook_details, + metadata, + is_recon_enabled, + applepay_verified_domains, + payment_link_config, + session_expiry, + authentication_connector_details, + payout_link_config, + is_extended_card_info_enabled: None, + extended_card_info_config, + is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers + .map(Encryption::from), + routing_algorithm_id, + order_fulfillment_time, + order_fulfillment_time_origin, + frm_routing_algorithm_id, + payout_routing_algorithm_id, + default_fallback_routing, + }, + BusinessProfileUpdate::RoutingAlgorithmUpdate { + routing_algorithm_id, + payout_routing_algorithm_id, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + routing_algorithm_id, + order_fulfillment_time: None, + order_fulfillment_time_origin: None, + frm_routing_algorithm_id: None, + payout_routing_algorithm_id, + default_fallback_routing: None, + }, + BusinessProfileUpdate::ExtendedCardInfoUpdate { + is_extended_card_info_enabled, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled: None, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + routing_algorithm_id: None, + order_fulfillment_time: None, + order_fulfillment_time_origin: None, + frm_routing_algorithm_id: None, + payout_routing_algorithm_id: None, + default_fallback_routing: None, + }, + BusinessProfileUpdate::ConnectorAgnosticMitUpdate { + is_connector_agnostic_mit_enabled, + } => Self { + profile_name: None, + modified_at: now, + return_url: None, + enable_payment_response_hash: None, + payment_response_hash_key: None, + redirect_to_merchant_with_http_post: None, + webhook_details: None, + metadata: None, + is_recon_enabled: None, + applepay_verified_domains: None, + payment_link_config: None, + session_expiry: None, + authentication_connector_details: None, + payout_link_config: None, + is_extended_card_info_enabled: None, + extended_card_info_config: None, + is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: None, + collect_shipping_details_from_wallet_connector: None, + collect_billing_details_from_wallet_connector: None, + outgoing_webhook_custom_http_headers: None, + routing_algorithm_id: None, + order_fulfillment_time: None, + order_fulfillment_time_origin: None, + frm_routing_algorithm_id: None, + payout_routing_algorithm_id: None, + default_fallback_routing: None, + }, + } + } +} + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[async_trait::async_trait] +impl super::behaviour::Conversion for BusinessProfile { + type DstType = diesel_models::business_profile::BusinessProfile; + type NewDstType = diesel_models::business_profile::BusinessProfileNew; + + async fn convert(self) -> CustomResult { + Ok(diesel_models::business_profile::BusinessProfile { + profile_id: self.profile_id, + merchant_id: self.merchant_id, + profile_name: self.profile_name, + created_at: self.created_at, + modified_at: self.modified_at, + return_url: self.return_url, + enable_payment_response_hash: self.enable_payment_response_hash, + payment_response_hash_key: self.payment_response_hash_key, + redirect_to_merchant_with_http_post: self.redirect_to_merchant_with_http_post, + webhook_details: self.webhook_details, + metadata: self.metadata, + is_recon_enabled: self.is_recon_enabled, + applepay_verified_domains: self.applepay_verified_domains, + payment_link_config: self.payment_link_config, + session_expiry: self.session_expiry, + authentication_connector_details: self.authentication_connector_details, + payout_link_config: self.payout_link_config, + is_extended_card_info_enabled: self.is_extended_card_info_enabled, + extended_card_info_config: self.extended_card_info_config, + is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: self.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: self + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: self + .collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: self + .outgoing_webhook_custom_http_headers + .map(Encryption::from), + routing_algorithm_id: self.routing_algorithm_id, + order_fulfillment_time: self.order_fulfillment_time, + order_fulfillment_time_origin: self.order_fulfillment_time_origin, + frm_routing_algorithm_id: self.frm_routing_algorithm_id, + payout_routing_algorithm_id: self.payout_routing_algorithm_id, + default_fallback_routing: self.default_fallback_routing, + }) + } + + async fn convert_back( + state: &keymanager::KeyManagerState, + item: Self::DstType, + key: &Secret>, + key_manager_identifier: keymanager::Identifier, + ) -> CustomResult + where + Self: Sized, + { + async { + Ok::>(Self { + profile_id: item.profile_id, + merchant_id: item.merchant_id, + profile_name: item.profile_name, + created_at: item.created_at, + modified_at: item.modified_at, + 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, + webhook_details: item.webhook_details, + metadata: item.metadata, + is_recon_enabled: item.is_recon_enabled, + applepay_verified_domains: item.applepay_verified_domains, + payment_link_config: item.payment_link_config, + session_expiry: item.session_expiry, + authentication_connector_details: item.authentication_connector_details, + payout_link_config: item.payout_link_config, + is_extended_card_info_enabled: item.is_extended_card_info_enabled, + extended_card_info_config: item.extended_card_info_config, + is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: item + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: item + .collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: item + .outgoing_webhook_custom_http_headers + .async_lift(|inner| { + decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + }) + .await?, + routing_algorithm_id: item.routing_algorithm_id, + order_fulfillment_time: item.order_fulfillment_time, + order_fulfillment_time_origin: item.order_fulfillment_time_origin, + frm_routing_algorithm_id: item.frm_routing_algorithm_id, + payout_routing_algorithm_id: item.payout_routing_algorithm_id, + default_fallback_routing: item.default_fallback_routing, + }) + } + .await + .change_context(ValidationError::InvalidValue { + message: "Failed while decrypting business profile data".to_string(), + }) + } + + async fn construct_new(self) -> CustomResult { + Ok(diesel_models::business_profile::BusinessProfileNew { + profile_id: self.profile_id, + merchant_id: self.merchant_id, + profile_name: self.profile_name, + created_at: self.created_at, + modified_at: self.modified_at, + return_url: self.return_url, + enable_payment_response_hash: self.enable_payment_response_hash, + payment_response_hash_key: self.payment_response_hash_key, + redirect_to_merchant_with_http_post: self.redirect_to_merchant_with_http_post, + webhook_details: self.webhook_details, + metadata: self.metadata, + is_recon_enabled: self.is_recon_enabled, + applepay_verified_domains: self.applepay_verified_domains, + payment_link_config: self.payment_link_config, + session_expiry: self.session_expiry, + authentication_connector_details: self.authentication_connector_details, + payout_link_config: self.payout_link_config, + is_extended_card_info_enabled: self.is_extended_card_info_enabled, + extended_card_info_config: self.extended_card_info_config, + is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled, + use_billing_as_payment_method_billing: self.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: self + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: self + .collect_billing_details_from_wallet_connector, + outgoing_webhook_custom_http_headers: self + .outgoing_webhook_custom_http_headers + .map(Encryption::from), + routing_algorithm_id: self.routing_algorithm_id, + order_fulfillment_time: self.order_fulfillment_time, + order_fulfillment_time_origin: self.order_fulfillment_time_origin, + frm_routing_algorithm_id: self.frm_routing_algorithm_id, + payout_routing_algorithm_id: self.payout_routing_algorithm_id, + default_fallback_routing: self.default_fallback_routing, + }) + } +} diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 54cdb068ec53..20ef618e621b 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -33,6 +33,7 @@ recon = ["email", "api_models/recon"] retry = [] v2 = ["api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2", "kgraph_utils/v2"] v1 = ["api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "hyperswitch_interfaces/v1"] +# business_profile_v2 = ["api_models/business_profile_v2", "diesel_models/business_profile_v2", "hyperswitch_domain_models/business_profile_v2"] customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2"] merchant_account_v2 = ["api_models/merchant_account_v2", "diesel_models/merchant_account_v2", "hyperswitch_domain_models/merchant_account_v2"] payment_v2 = ["api_models/payment_v2", "diesel_models/payment_v2", "hyperswitch_domain_models/payment_v2"] From 1a4c020701f200694c8fa70d39f37920702944b0 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Wed, 31 Jul 2024 21:16:15 +0530 Subject: [PATCH 07/11] ci: use regex to exclude v2 features from feature list --- scripts/ci-checks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci-checks.sh b/scripts/ci-checks.sh index 51089955728a..5a37d2f26218 100755 --- a/scripts/ci-checks.sh +++ b/scripts/ci-checks.sh @@ -77,7 +77,7 @@ crates_with_v1_feature="$( --null-input \ '$crates_with_features[] | select( IN("v1"; .features[])) # Select crates with `v1` feature - | { name, features: (.features - ["v1", "v2", "default", "payment_v2", "merchant_account_v2","customer_v2", "merchant_connector_account_v2"]) } # Remove specific features to generate feature combinations + | { name, features: ( .features | del( .[] | select( any( . ; test("(([a-z_]+)_)?v2|v1|default") ) ) ) ) } # Remove specific features to generate feature combinations | { name, features: ( .features | map([., "v1"] | join(",")) ) } # Add `v1` to remaining features and join them by comma | .name as $name | .features[] | { $name, features: . } # Expand nested features object to have package - features combinations | "\(.name) \(.features)" # Print out package name and features separated by space' From 63e5e3a49b5413b081cbd66357a82fdf81fe36bc Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Wed, 31 Jul 2024 21:32:33 +0530 Subject: [PATCH 08/11] ci: include `business_profile_v2` in `hack_v2` just recipe --- justfile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/justfile b/justfile index b755e3d7de0f..9150cb9b3ac4 100644 --- a/justfile +++ b/justfile @@ -14,7 +14,7 @@ alias c := check # Check compilation of Rust code and catch common mistakes # We cannot run --all-features because v1 and v2 are mutually exclusive features -# Create a list of features by excluding certain features +# Create a list of features by excluding certain features clippy *FLAGS: #! /usr/bin/env bash set -euo pipefail @@ -120,7 +120,7 @@ euclid-wasm features='dummy_connector': precommit: fmt clippy # Check compilation of v2 feature on base dependencies -v2_intermediate_features := "merchant_account_v2,payment_v2,customer_v2" +v2_intermediate_features := "merchant_account_v2,payment_v2,customer_v2,business_profile_v2" hack_v2: cargo hack clippy --feature-powerset --ignore-unknown-features --at-least-one-of "v2 " --include-features "v2" --include-features {{ v2_intermediate_features }} --package "hyperswitch_domain_models" --package "diesel_models" --package "api_models" cargo hack clippy --features "v2,payment_v2" -p storage_impl @@ -174,7 +174,7 @@ migrate_v2 operation=default_operation *args='': set -euo pipefail EXIT_CODE=0 - just copy_migrations + just copy_migrations just run_migration {{ operation }} {{ resultant_dir }} {{ v2_config_file_dir }} {{ database_url }} {{ args }} || EXIT_CODE=$? just delete_dir_if_exists exit $EXIT_CODE @@ -186,5 +186,3 @@ resurrect: ci_hack: scripts/ci-checks.sh - - From 76b504e8d22fd6e9551b1ea3865dbec3f9971718 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Thu, 1 Aug 2024 13:07:38 +0530 Subject: [PATCH 09/11] refactor(v2_migrations): merge all migrations related to business profiles --- .../down.sql | 9 --------- .../down.sql | 10 ++++++++++ .../up.sql | 8 ++++++++ .../up.sql | 7 ------- 4 files changed, 18 insertions(+), 16 deletions(-) delete mode 100644 v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql rename v2_migrations/{2024-07-31-100310_remove_business_profile_v1_columns => 2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns}/down.sql (55%) rename v2_migrations/{2024-07-31-100300_add_business_profile_v2_columns => 2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns}/up.sql (59%) delete mode 100644 v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql diff --git a/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql b/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql deleted file mode 100644 index 209af2cee422..000000000000 --- a/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/down.sql +++ /dev/null @@ -1,9 +0,0 @@ -ALTER TABLE business_profile - DROP COLUMN routing_algorithm_id, - DROP COLUMN order_fulfillment_time, - DROP COLUMN order_fulfillment_time_origin, - DROP COLUMN frm_routing_algorithm_id, - DROP COLUMN payout_routing_algorithm_id, - DROP COLUMN default_fallback_routing; - -DROP TYPE "OrderFulfillmentTimeOrigin"; diff --git a/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/down.sql b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/down.sql similarity index 55% rename from v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/down.sql rename to v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/down.sql index 3d1f299a024a..5645d4c73997 100644 --- a/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/down.sql +++ b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/down.sql @@ -6,3 +6,13 @@ ALTER TABLE business_profile ADD COLUMN intent_fulfillment_time BIGINT DEFAULT NULL, ADD COLUMN frm_routing_algorithm JSONB DEFAULT NULL, ADD COLUMN payout_routing_algorithm JSONB DEFAULT NULL; + +ALTER TABLE business_profile + DROP COLUMN routing_algorithm_id, + DROP COLUMN order_fulfillment_time, + DROP COLUMN order_fulfillment_time_origin, + DROP COLUMN frm_routing_algorithm_id, + DROP COLUMN payout_routing_algorithm_id, + DROP COLUMN default_fallback_routing; + +DROP TYPE "OrderFulfillmentTimeOrigin"; diff --git a/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/up.sql b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/up.sql similarity index 59% rename from v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/up.sql rename to v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/up.sql index 68d81e66d75d..f1cff1744681 100644 --- a/v2_migrations/2024-07-31-100300_add_business_profile_v2_columns/up.sql +++ b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/up.sql @@ -7,3 +7,11 @@ ALTER TABLE business_profile ADD COLUMN frm_routing_algorithm_id VARCHAR(64) DEFAULT NULL, ADD COLUMN payout_routing_algorithm_id VARCHAR(64) DEFAULT NULL, ADD COLUMN default_fallback_routing JSONB DEFAULT NULL; + +-- 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 being run. +ALTER TABLE business_profile + DROP COLUMN routing_algorithm, + DROP COLUMN intent_fulfillment_time, + DROP COLUMN frm_routing_algorithm, + DROP COLUMN payout_routing_algorithm; diff --git a/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql b/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql deleted file mode 100644 index 8a5d300b3135..000000000000 --- a/v2_migrations/2024-07-31-100310_remove_business_profile_v1_columns/up.sql +++ /dev/null @@ -1,7 +0,0 @@ --- 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 being run. -ALTER TABLE business_profile - DROP COLUMN routing_algorithm, - DROP COLUMN intent_fulfillment_time, - DROP COLUMN frm_routing_algorithm, - DROP COLUMN payout_routing_algorithm; From 2870c22ae3980c4aace801246291107ef368a1f9 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Thu, 1 Aug 2024 14:54:22 +0530 Subject: [PATCH 10/11] refactor(business_profile): wrap some JSON fields of business profile v2 domain models within `Secret` --- crates/diesel_models/src/business_profile.rs | 40 +++++++++---------- .../src/business_profile.rs | 20 +++++----- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 5e2daea49262..cc4dbe6b605e 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -482,15 +482,15 @@ pub struct BusinessProfile { pub enable_payment_response_hash: bool, pub payment_response_hash_key: Option, pub redirect_to_merchant_with_http_post: bool, - pub webhook_details: Option, + pub webhook_details: Option, pub metadata: Option, pub is_recon_enabled: bool, #[diesel(deserialize_as = super::OptionalDieselArray)] pub applepay_verified_domains: Option>, - pub payment_link_config: Option, + pub payment_link_config: Option, pub session_expiry: Option, - pub authentication_connector_details: Option, - pub payout_link_config: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, pub is_extended_card_info_enabled: Option, pub extended_card_info_config: Option, pub is_connector_agnostic_mit_enabled: Option, @@ -503,7 +503,7 @@ pub struct BusinessProfile { pub order_fulfillment_time_origin: Option, pub frm_routing_algorithm_id: Option, pub payout_routing_algorithm_id: Option, - pub default_fallback_routing: Option, + pub default_fallback_routing: Option, } #[cfg(all(feature = "v2", feature = "business_profile_v2"))] @@ -519,15 +519,15 @@ pub struct BusinessProfileNew { pub enable_payment_response_hash: bool, pub payment_response_hash_key: Option, pub redirect_to_merchant_with_http_post: bool, - pub webhook_details: Option, + pub webhook_details: Option, pub metadata: Option, pub is_recon_enabled: bool, #[diesel(deserialize_as = super::OptionalDieselArray)] pub applepay_verified_domains: Option>, - pub payment_link_config: Option, + pub payment_link_config: Option, pub session_expiry: Option, - pub authentication_connector_details: Option, - pub payout_link_config: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, pub is_extended_card_info_enabled: Option, pub extended_card_info_config: Option, pub is_connector_agnostic_mit_enabled: Option, @@ -540,7 +540,7 @@ pub struct BusinessProfileNew { pub order_fulfillment_time_origin: Option, pub frm_routing_algorithm_id: Option, pub payout_routing_algorithm_id: Option, - pub default_fallback_routing: Option, + pub default_fallback_routing: Option, } #[cfg(all(feature = "v2", feature = "business_profile_v2"))] @@ -553,15 +553,15 @@ pub struct BusinessProfileUpdateInternal { pub enable_payment_response_hash: Option, pub payment_response_hash_key: Option, pub redirect_to_merchant_with_http_post: Option, - pub webhook_details: Option, + pub webhook_details: Option, pub metadata: Option, pub is_recon_enabled: Option, #[diesel(deserialize_as = super::OptionalDieselArray)] pub applepay_verified_domains: Option>, - pub payment_link_config: Option, + pub payment_link_config: Option, pub session_expiry: Option, - pub authentication_connector_details: Option, - pub payout_link_config: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, pub is_extended_card_info_enabled: Option, pub extended_card_info_config: Option, pub is_connector_agnostic_mit_enabled: Option, @@ -574,7 +574,7 @@ pub struct BusinessProfileUpdateInternal { pub order_fulfillment_time_origin: Option, pub frm_routing_algorithm_id: Option, pub payout_routing_algorithm_id: Option, - pub default_fallback_routing: Option, + pub default_fallback_routing: Option, } #[cfg(all(feature = "v2", feature = "business_profile_v2"))] @@ -586,14 +586,14 @@ pub enum BusinessProfileUpdate { enable_payment_response_hash: Option, payment_response_hash_key: Option, redirect_to_merchant_with_http_post: Option, - webhook_details: Option, + webhook_details: Option, metadata: Option, is_recon_enabled: Option, applepay_verified_domains: Option>, - payment_link_config: Option, + payment_link_config: Option, session_expiry: Option, - authentication_connector_details: Option, - payout_link_config: Option, + authentication_connector_details: Option, + payout_link_config: Option, extended_card_info_config: Option, use_billing_as_payment_method_billing: Option, collect_shipping_details_from_wallet_connector: Option, @@ -605,7 +605,7 @@ pub enum BusinessProfileUpdate { order_fulfillment_time_origin: Option, frm_routing_algorithm_id: Option, payout_routing_algorithm_id: Option, - default_fallback_routing: Option, + default_fallback_routing: Option, }, RoutingAlgorithmUpdate { routing_algorithm_id: Option, diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index f157dcf8eb9b..e6b2bcbe5b11 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -396,14 +396,14 @@ pub struct BusinessProfile { pub enable_payment_response_hash: bool, pub payment_response_hash_key: Option, pub redirect_to_merchant_with_http_post: bool, - pub webhook_details: Option, + pub webhook_details: Option, pub metadata: Option, pub is_recon_enabled: bool, pub applepay_verified_domains: Option>, - pub payment_link_config: Option, + pub payment_link_config: Option, pub session_expiry: Option, - pub authentication_connector_details: Option, - pub payout_link_config: Option, + pub authentication_connector_details: Option, + pub payout_link_config: Option, pub is_extended_card_info_enabled: Option, pub extended_card_info_config: Option, pub is_connector_agnostic_mit_enabled: Option, @@ -416,7 +416,7 @@ pub struct BusinessProfile { pub order_fulfillment_time_origin: Option, pub frm_routing_algorithm_id: Option, pub payout_routing_algorithm_id: Option, - pub default_fallback_routing: Option, + pub default_fallback_routing: Option, } #[cfg(all(feature = "v2", feature = "business_profile_v2"))] @@ -428,14 +428,14 @@ pub enum BusinessProfileUpdate { enable_payment_response_hash: Option, payment_response_hash_key: Option, redirect_to_merchant_with_http_post: Option, - webhook_details: Option, + webhook_details: Option, metadata: Option, is_recon_enabled: Option, applepay_verified_domains: Option>, - payment_link_config: Option, + payment_link_config: Option, session_expiry: Option, - authentication_connector_details: Option, - payout_link_config: Option, + authentication_connector_details: Option, + payout_link_config: Option, extended_card_info_config: Option, use_billing_as_payment_method_billing: Option, collect_shipping_details_from_wallet_connector: Option, @@ -447,7 +447,7 @@ pub enum BusinessProfileUpdate { order_fulfillment_time_origin: Option, frm_routing_algorithm_id: Option, payout_routing_algorithm_id: Option, - default_fallback_routing: Option, + default_fallback_routing: Option, }, RoutingAlgorithmUpdate { routing_algorithm_id: Option, From 0629ec6a0f916fa5661548fd085fb240498461b1 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde Date: Thu, 1 Aug 2024 15:14:17 +0530 Subject: [PATCH 11/11] ci: specify depth 2 for `hack_v2` just recipe --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index 9150cb9b3ac4..12ad58921228 100644 --- a/justfile +++ b/justfile @@ -122,7 +122,7 @@ precommit: fmt clippy # Check compilation of v2 feature on base dependencies v2_intermediate_features := "merchant_account_v2,payment_v2,customer_v2,business_profile_v2" hack_v2: - cargo hack clippy --feature-powerset --ignore-unknown-features --at-least-one-of "v2 " --include-features "v2" --include-features {{ v2_intermediate_features }} --package "hyperswitch_domain_models" --package "diesel_models" --package "api_models" + cargo hack clippy --feature-powerset --depth 2 --ignore-unknown-features --at-least-one-of "v2 " --include-features "v2" --include-features {{ v2_intermediate_features }} --package "hyperswitch_domain_models" --package "diesel_models" --package "api_models" cargo hack clippy --features "v2,payment_v2" -p storage_impl # Use the env variables if present, or fallback to default values