diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml index b6b6f219bd8..f829d2e48fe 100644 --- a/crates/api_models/Cargo.toml +++ b/crates/api_models/Cargo.toml @@ -17,13 +17,14 @@ frm = [] olap = [] openapi = ["common_enums/openapi", "olap", "recon", "dummy_connector", "olap"] recon = [] -v1 =[] +v1 = [] v2 = [] -routing_v2 = [] -merchant_connector_account_v2 = [] +business_profile_v2 = [] customer_v2 = [] merchant_account_v2 = [] +merchant_connector_account_v2 = [] payment_v2 = [] +routing_v2 = [] [dependencies] actix-web = { version = "4.5.1", optional = true } diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 985f7451c28..6ec400ec81c 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -3054,3 +3054,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 d021ccfff37..6b63f76cdaa 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 = [] merchant_connector_account_v2 = [] diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 30f6780e360..cc4dbe6b605 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,11 +101,15 @@ pub struct BusinessProfileNew { pub outgoing_webhook_custom_http_headers: Option, } -#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] +#[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 { 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, @@ -111,11 +136,14 @@ 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 { profile_name: Option, - modified_at: Option, return_url: Option, enable_payment_response_hash: Option, payment_response_hash_key: Option, @@ -139,6 +167,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, }, @@ -147,12 +179,17 @@ 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(); + match business_profile_update { BusinessProfileUpdate::Update { profile_name, - modified_at, return_url, enable_payment_response_hash, payment_response_hash_key, @@ -177,7 +214,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,30 +231,113 @@ 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::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, - ..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, }, } } } +// 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 { @@ -255,11 +375,15 @@ 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 { profile_name, - modified_at: _, + modified_at, return_url, enable_payment_response_hash, payment_response_hash_key, @@ -285,34 +409,497 @@ 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: 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: 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), + } + } +} + +/// 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, - routing_algorithm, - intent_fulfillment_time, - frm_routing_algorithm, - payout_routing_algorithm, - is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled), + 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, + 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, - ..source + 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 f0059994cb6..55bfa9f2f23 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 e716e45c650..1b8e54e0180 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 648e6e44652..23f9dff31ea 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/crates/hyperswitch_domain_models/Cargo.toml b/crates/hyperswitch_domain_models/Cargo.toml index 662cfcff65d..16ab18b68df 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"] merchant_connector_account_v2 = ["api_models/merchant_connector_account_v2", "diesel_models/merchant_connector_account_v2"] 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 00000000000..e6b2bcbe5b1 --- /dev/null +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -0,0 +1,763 @@ +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +use common_enums::OrderFulfillmentTimeOrigin; +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}; + +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(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 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, +} + +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(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, + 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, + }, +} + +#[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(); + + 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, + }, + } + } +} + +#[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; + 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), + }) + } +} + +#[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/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index e7ad703f927..cabeda2ccc2 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -1,5 +1,6 @@ pub mod api; pub mod behaviour; +pub mod business_profile; pub mod customer; pub mod errors; pub mod mandates; diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 398e9143cfc..3e6f470d80e 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", "kgraph_utils/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"] diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 26afafd7ad5..23d4b704cf3 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -3272,7 +3272,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 6ef66883950..f550c7e501f 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -200,31 +200,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, - modified_at: 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) diff --git a/justfile b/justfile index 228653a007a..1823c1ec19e 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,9 +120,9 @@ 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 --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 @@ -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 - - diff --git a/scripts/ci-checks.sh b/scripts/ci-checks.sh index 51089955728..5a37d2f2621 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' diff --git a/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/down.sql b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/down.sql new file mode 100644 index 00000000000..5645d4c7399 --- /dev/null +++ b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/down.sql @@ -0,0 +1,18 @@ +-- 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; + +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_business_profile_add_v2_columns_drop_v1_columns/up.sql b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/up.sql new file mode 100644 index 00000000000..f1cff174468 --- /dev/null +++ b/v2_migrations/2024-07-31-100300_business_profile_add_v2_columns_drop_v1_columns/up.sql @@ -0,0 +1,17 @@ +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; + +-- 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;