diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml index 386cb7d8c1..59f99cb7ca 100644 --- a/crates/api_models/Cargo.toml +++ b/crates/api_models/Cargo.toml @@ -9,6 +9,7 @@ errors = [ "dep:actix-web", "dep:reqwest", ] +multiple_mca = [] [dependencies] actix-web = { version = "4.3.1", optional = true } @@ -24,6 +25,7 @@ time = { version = "0.3.20", features = ["serde", "serde-well-known", "std"] } url = { version = "2.3.1", features = ["serde"] } utoipa = { version = "3.2.0", features = ["preserve_order"] } + # First party crates common_utils = { version = "0.1.0", path = "../common_utils" } masking = { version = "0.1.0", path = "../masking" } diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 3494f5bda0..1944403fbe 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -68,8 +68,13 @@ pub struct MerchantAccountCreate { pub locker_id: Option, ///Default business details for connector routing + #[cfg(feature = "multiple_mca")] #[schema(value_type = PrimaryBusinessDetails)] - pub primary_business_details: pii::SecretSerdeValue, + pub primary_business_details: Vec, + + #[cfg(not(feature = "multiple_mca"))] + #[schema(value_type = Option)] + pub primary_business_details: Option>, } #[derive(Clone, Debug, Deserialize, ToSchema)] @@ -194,8 +199,8 @@ pub struct MerchantAccountResponse { #[schema(example = "locker_abc123")] pub locker_id: Option, ///Default business details for connector routing - #[schema(value_type = Option)] - pub primary_business_details: pii::SecretSerdeValue, + #[schema(value_type = Vec)] + pub primary_business_details: Vec, } #[derive(Clone, Debug, Deserialize, ToSchema, Serialize)] @@ -249,8 +254,8 @@ pub enum RoutingAlgorithm { #[derive(Clone, Debug, Deserialize, ToSchema, Serialize)] #[serde(deny_unknown_fields)] pub struct PrimaryBusinessDetails { - pub country: Vec, - pub business: Vec, + pub country: api_enums::CountryCode, + pub business: String, } #[derive(Clone, Debug, Deserialize, ToSchema, Serialize)] @@ -309,7 +314,7 @@ pub struct MerchantConnectorId { /// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc." #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(deny_unknown_fields)] -pub struct MerchantConnector { +pub struct MerchantConnectorCreate { /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking. #[schema(value_type = ConnectorType, example = "payment_processor")] pub connector_type: api_enums::ConnectorType, @@ -320,15 +325,7 @@ pub struct MerchantConnector { #[serde(skip_deserializing)] #[schema(example = "stripe_US_travel")] pub connector_label: String, - /// Country through which payment should be processed - #[schema(example = "US")] - pub business_country: api_enums::CountryCode, - ///Business Type of the merchant - #[schema(example = "travel")] - pub business_label: String, - /// Business Sub label of the merchant - #[schema(example = "chase")] - pub business_sub_label: Option, + /// Unique ID of the connector #[schema(example = "mca_5apGeP94tMts6rg3U3kR")] pub merchant_connector_id: Option, @@ -375,6 +372,99 @@ pub struct MerchantConnector { /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object. #[schema(value_type = Option,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))] pub metadata: Option, + + /// Business Country of the connector + #[schema(example = "US")] + #[cfg(feature = "multiple_mca")] + pub business_country: api_enums::CountryCode, + #[cfg(not(feature = "multiple_mca"))] + pub business_country: Option, + + ///Business Type of the merchant + #[schema(example = "travel")] + #[cfg(feature = "multiple_mca")] + pub business_label: String, + #[cfg(not(feature = "multiple_mca"))] + pub business_label: Option, + + /// Business Sub label of the merchant + #[schema(example = "chase")] + pub business_sub_label: Option, +} + +/// Response of creating a new Merchant Connector for the merchant account." +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(deny_unknown_fields)] +pub struct MerchantConnectorResponse { + /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking. + #[schema(value_type = ConnectorType, example = "payment_processor")] + pub connector_type: api_enums::ConnectorType, + /// Name of the Connector + #[schema(example = "stripe")] + pub connector_name: String, + // /// Connector label for specific country and Business + #[serde(skip_deserializing)] + #[schema(example = "stripe_US_travel")] + pub connector_label: String, + + /// Unique ID of the connector + #[schema(example = "mca_5apGeP94tMts6rg3U3kR")] + pub merchant_connector_id: String, + /// Account details of the Connector. You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Useful for storing additional, structured information on an object. + #[schema(value_type = Option,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))] + pub connector_account_details: pii::SecretSerdeValue, + /// A boolean value to indicate if the connector is in Test mode. By default, its value is false. + #[schema(default = false, example = false)] + pub test_mode: Option, + /// A boolean value to indicate if the connector is disabled. By default, its value is false. + #[schema(default = false, example = false)] + pub disabled: Option, + /// Refers to the Parent Merchant ID if the merchant being created is a sub-merchant + #[schema(example = json!([ + { + "payment_method": "wallet", + "payment_method_types": [ + "upi_collect", + "upi_intent" + ], + "payment_method_issuers": [ + "labore magna ipsum", + "aute" + ], + "payment_schemes": [ + "Discover", + "Discover" + ], + "accepted_currencies": { + "type": "enable_only", + "list": ["USD", "EUR"] + }, + "accepted_countries": { + "type": "disable_only", + "list": ["FR", "DE","IN"] + }, + "minimum_amount": 1, + "maximum_amount": 68607706, + "recurring_enabled": true, + "installment_payment_enabled": true + } + ]))] + pub payment_methods_enabled: Option>, + /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object. + #[schema(value_type = Option,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))] + pub metadata: Option, + + /// Business Country of the connector + #[schema(example = "US")] + pub business_country: api_enums::CountryCode, + + ///Business Type of the merchant + #[schema(example = "travel")] + pub business_label: String, + + /// Business Sub label of the merchant + #[schema(example = "chase")] + pub business_sub_label: Option, } /// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc." diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 6a2263e539..08c15c5364 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -22,6 +22,7 @@ kv_store = [] accounts_cache = [] openapi = ["olap", "oltp"] vergen = ["router_env/vergen"] +multiple_mca = ["api_models/multiple_mca"] [dependencies] diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 8a81ac03c0..2395308874 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -1,7 +1,6 @@ use api_models::admin::PrimaryBusinessDetails; use common_utils::ext_traits::ValueExt; use error_stack::{report, FutureExt, IntoReport, ResultExt}; -use masking::ExposeInterface; use storage_models::{enums, merchant_account}; use uuid::Uuid; @@ -13,13 +12,12 @@ use crate::{ payments::helpers, }, db::StorageInterface, - pii::Secret, routes::AppState, services::api as service_api, types::{ self, api, storage::{self, MerchantAccount}, - transformers::{ForeignInto, ForeignTryInto}, + transformers::{ForeignInto, ForeignTryFrom, ForeignTryInto}, }, utils::{self, OptionExt}, }; @@ -33,6 +31,31 @@ pub fn create_merchant_publishable_key() -> String { ) } +fn get_primary_business_details( + request: &api::MerchantAccountCreate, +) -> Vec { + // In this case, business details is not optional, it will always be passed + #[cfg(feature = "multiple_mca")] + { + request.primary_business_details.to_owned() + } + + // In this case, business details will be optional, if it is not passed, then create the + // default value + #[cfg(not(feature = "multiple_mca"))] + { + request + .primary_business_details + .to_owned() + .unwrap_or_else(|| { + vec![PrimaryBusinessDetails { + country: enums::CountryCode::US, + business: "default".to_string(), + }] + }) + } +} + pub async fn create_merchant_account( state: &AppState, req: api::MerchantAccountCreate, @@ -66,36 +89,33 @@ pub async fn create_merchant_account( .attach_printable("Unexpected create API key response"), }?; - let merchant_details = req - .merchant_details - .map(|md| { - utils::Encode::::encode_to_value(&md).change_context( - errors::ApiErrorResponse::InvalidDataValue { - field_name: "merchant_details", - }, - ) - }) - .transpose()?; + let primary_business_details = + utils::Encode::::encode_to_value(&get_primary_business_details(&req)) + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "primary_business_details", + })?; - let webhook_details = req - .webhook_details - .map(|wd| { - utils::Encode::::encode_to_value(&wd).change_context( - errors::ApiErrorResponse::InvalidDataValue { - field_name: "webhook details", - }, - ) - }) - .transpose()?; + let merchant_details = + req.merchant_details + .as_ref() + .map(|merchant_details| { + utils::Encode::::encode_to_value(merchant_details) + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "merchant_details", + }) + }) + .transpose()?; - let primary_business_details = req.primary_business_details.expose(); - - let _valid_business_details: PrimaryBusinessDetails = primary_business_details - .clone() - .parse_value("primary_business_details") - .change_context(errors::ApiErrorResponse::InvalidDataValue { - field_name: "primary_business_details", - })?; + let webhook_details = + req.webhook_details + .as_ref() + .map(|webhook_details| { + utils::Encode::::encode_to_value(webhook_details) + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "webhook details", + }) + }) + .transpose()?; if let Some(ref routing_algorithm) = req.routing_algorithm { let _: api::RoutingAlgorithm = routing_algorithm @@ -139,7 +159,11 @@ pub async fn create_merchant_account( })?; Ok(service_api::ApplicationResponse::Json( - merchant_account.foreign_into(), + ForeignTryFrom::foreign_try_from(merchant_account).change_context( + errors::ApiErrorResponse::InvalidDataValue { + field_name: "merchant_account", + }, + )?, )) } @@ -155,7 +179,11 @@ pub async fn get_merchant_account( })?; Ok(service_api::ApplicationResponse::Json( - merchant_account.foreign_into(), + ForeignTryFrom::foreign_try_from(merchant_account).change_context( + errors::ApiErrorResponse::InvalidDataValue { + field_name: "merchant_account", + }, + )?, )) } @@ -236,7 +264,11 @@ pub async fn merchant_account_update( })?; Ok(service_api::ApplicationResponse::Json( - response.foreign_into(), + ForeignTryFrom::foreign_try_from(response).change_context( + errors::ApiErrorResponse::InvalidDataValue { + field_name: "merchant_account", + }, + )?, )) } @@ -295,27 +327,49 @@ async fn validate_merchant_id>( }) } +fn get_business_details_wrapper( + request: &api::MerchantConnectorCreate, + _merchant_account: &MerchantAccount, +) -> RouterResult<(enums::CountryCode, String)> { + #[cfg(feature = "multiple_mca")] + { + // The fields are mandatory + Ok((request.business_country, request.business_label.to_owned())) + } + + #[cfg(not(feature = "multiple_mca"))] + { + // If the value is not passed, then take it from Merchant account + helpers::get_business_details( + request.business_country, + request.business_label.as_ref(), + _merchant_account, + ) + } +} + pub async fn create_payment_connector( store: &dyn StorageInterface, - req: api::MerchantConnector, + req: api::MerchantConnectorCreate, merchant_id: &String, -) -> RouterResponse { - let _merchant_account = store +) -> RouterResponse { + let merchant_account = store .find_merchant_account_by_merchant_id(merchant_id) .await .map_err(|error| { error.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) })?; + let (business_country, business_label) = get_business_details_wrapper(&req, &merchant_account)?; + let connector_label = helpers::get_connector_label( - req.business_country, - &req.business_label, + business_country, + &business_label, req.business_sub_label.as_ref(), &req.connector_name, ); let mut vec = Vec::new(); - let mut response = req.clone(); let payment_methods_enabled = match req.payment_methods_enabled { Some(val) => { for pm in val.into_iter() { @@ -352,8 +406,8 @@ pub async fn create_payment_connector( disabled: req.disabled, metadata: req.metadata, connector_label: connector_label.clone(), - business_country: req.business_country, - business_label: req.business_label, + business_country, + business_label, business_sub_label: req.business_sub_label, }; @@ -364,19 +418,16 @@ pub async fn create_payment_connector( error.to_duplicate_response(errors::ApiErrorResponse::DuplicateMerchantConnectorAccount) })?; - response.merchant_connector_id = Some(mca.merchant_connector_id); - response.connector_label = connector_label; - response.business_country = mca.business_country; - response.business_label = mca.business_label; + let mca_response = ForeignTryFrom::foreign_try_from(mca)?; - Ok(service_api::ApplicationResponse::Json(response)) + Ok(service_api::ApplicationResponse::Json(mca_response)) } pub async fn retrieve_payment_connector( store: &dyn StorageInterface, merchant_id: String, merchant_connector_id: String, -) -> RouterResponse { +) -> RouterResponse { let _merchant_account = store .find_merchant_account_by_merchant_id(&merchant_id) .await @@ -395,14 +446,14 @@ pub async fn retrieve_payment_connector( })?; Ok(service_api::ApplicationResponse::Json( - mca.foreign_try_into()?, + ForeignTryFrom::foreign_try_from(mca)?, )) } pub async fn list_payment_connectors( store: &dyn StorageInterface, merchant_id: String, -) -> RouterResponse> { +) -> RouterResponse> { // Validate merchant account store .find_merchant_account_by_merchant_id(&merchant_id) @@ -432,7 +483,7 @@ pub async fn update_payment_connector( merchant_id: &str, merchant_connector_id: &str, req: api_models::admin::MerchantConnectorUpdate, -) -> RouterResponse { +) -> RouterResponse { let _merchant_account = db .find_merchant_account_by_merchant_id(merchant_id) .await @@ -478,32 +529,9 @@ pub async fn update_payment_connector( format!("Failed while updating MerchantConnectorAccount: id: {merchant_connector_id}") })?; - let updated_pm_enabled = updated_mca.payment_methods_enabled.map(|pm| { - pm.into_iter() - .flat_map(|pm_value| { - ValueExt::::parse_value( - pm_value, - "PaymentMethods", - ) - }) - .collect::>() - }); + let mca_response = ForeignTryFrom::foreign_try_from(updated_mca)?; - let response = api::MerchantConnector { - connector_type: updated_mca.connector_type.foreign_into(), - connector_name: updated_mca.connector_name, - merchant_connector_id: Some(updated_mca.merchant_connector_id), - connector_account_details: Some(Secret::new(updated_mca.connector_account_details)), - test_mode: updated_mca.test_mode, - disabled: updated_mca.disabled, - payment_methods_enabled: updated_pm_enabled, - metadata: updated_mca.metadata, - connector_label: updated_mca.connector_label, - business_country: updated_mca.business_country, - business_label: updated_mca.business_label, - business_sub_label: updated_mca.business_sub_label, - }; - Ok(service_api::ApplicationResponse::Json(response)) + Ok(service_api::ApplicationResponse::Json(mca_response)) } pub async fn delete_payment_connector( diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 52ac3c6cd6..9f589f2d95 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1285,14 +1285,14 @@ pub fn get_business_details( business_country: Option, business_label: Option<&String>, merchant_account: &storage_models::merchant_account::MerchantAccount, -) -> Result<(api_enums::CountryCode, String), error_stack::Report> { +) -> RouterResult<(api_enums::CountryCode, String)> { let (business_country, business_label) = match business_country.zip(business_label) { Some((business_country, business_label)) => { (business_country.to_owned(), business_label.to_owned()) } None => { // Parse the primary business details from merchant account - let primary_business_details: api_models::admin::PrimaryBusinessDetails = + let primary_business_details: Vec = merchant_account .primary_business_details .clone() @@ -1300,28 +1300,20 @@ pub fn get_business_details( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed to parse primary business details")?; - if primary_business_details.country.len() == 1 - && primary_business_details.business.len() == 1 - { - let primary_business_country = primary_business_details - .country - .first() - .get_required_value("business_country")? - .to_owned(); - - let primary_business_label = primary_business_details - .business - .first() - .get_required_value("business_label")? - .to_owned(); - + if primary_business_details.len() == 1 { + let primary_business_details = primary_business_details.first().ok_or( + errors::ApiErrorResponse::MissingRequiredField { + field_name: "primary_business_details", + }, + )?; ( - business_country.unwrap_or(primary_business_country), + business_country.unwrap_or(primary_business_details.country.to_owned()), business_label .map(ToString::to_string) - .unwrap_or(primary_business_label), + .unwrap_or(primary_business_details.business.to_owned()), ) } else { + // If primary business details are not present or more than one Err(report!(errors::ApiErrorResponse::MissingRequiredField { field_name: "business_country, business_label" }))? diff --git a/crates/router/src/openapi.rs b/crates/router/src/openapi.rs index 35e3cc9db6..ec506f3f10 100644 --- a/crates/router/src/openapi.rs +++ b/crates/router/src/openapi.rs @@ -149,7 +149,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::DisputeStage, api_models::enums::DisputeStatus, api_models::enums::CountryCode, - api_models::admin::MerchantConnector, + api_models::admin::MerchantConnectorCreate, api_models::admin::PaymentMethodsEnabled, api_models::disputes::DisputeResponse, api_models::payments::AddressDetails, diff --git a/crates/router/src/routes/admin.rs b/crates/router/src/routes/admin.rs index 747de8b0bb..1880801368 100644 --- a/crates/router/src/routes/admin.rs +++ b/crates/router/src/routes/admin.rs @@ -172,7 +172,7 @@ pub async fn payment_connector_create( state: web::Data, req: HttpRequest, path: web::Path, - json_payload: web::Json, + json_payload: web::Json, ) -> HttpResponse { let flow = Flow::MerchantConnectorsCreate; let merchant_id = path.into_inner(); diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index 8ac575f655..ade860b88f 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -1,17 +1,25 @@ pub use api_models::admin::{ MerchantAccountCreate, MerchantAccountDeleteResponse, MerchantAccountResponse, - MerchantAccountUpdate, MerchantConnector, MerchantConnectorDeleteResponse, + MerchantAccountUpdate, MerchantConnectorCreate, MerchantConnectorDeleteResponse, MerchantConnectorDetails, MerchantConnectorDetailsWrap, MerchantConnectorId, MerchantDetails, MerchantId, PaymentMethodsEnabled, RoutingAlgorithm, ToggleKVRequest, ToggleKVResponse, WebhookDetails, }; +use common_utils::ext_traits::ValueExt; -use crate::types::{storage, transformers::ForeignFrom}; +use crate::{ + core::errors, + types::{storage, transformers::ForeignTryFrom}, +}; -impl ForeignFrom for MerchantAccountResponse { - fn foreign_from(value: storage::MerchantAccount) -> Self { - let item = value; - Self { +impl ForeignTryFrom for MerchantAccountResponse { + type Error = error_stack::Report; + fn foreign_try_from(item: storage::MerchantAccount) -> Result { + let primary_business_details: Vec = item + .primary_business_details + .parse_value("primary_business_details")?; + + Ok(Self { merchant_id: item.merchant_id, merchant_name: item.merchant_name, api_key: item.api_key, @@ -27,7 +35,7 @@ impl ForeignFrom for MerchantAccountResponse { publishable_key: item.publishable_key, metadata: item.metadata, locker_id: item.locker_id, - primary_business_details: item.primary_business_details.into(), - } + primary_business_details, + }) } } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 80857ddfb8..92f0f8f2d8 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1,6 +1,7 @@ use api_models::enums as api_enums; use common_utils::ext_traits::ValueExt; use error_stack::ResultExt; +use masking::Secret; use storage_models::enums as storage_enums; use crate::{ @@ -336,37 +337,6 @@ impl<'a> ForeignFrom<&'a storage::Address> for api_types::Address { } } -impl ForeignTryFrom for api_models::admin::MerchantConnector { - type Error = error_stack::Report; - fn foreign_try_from(item: storage::MerchantConnectorAccount) -> Result { - let merchant_ca = item; - - let payment_methods_enabled = match merchant_ca.payment_methods_enabled { - Some(val) => serde_json::Value::Array(val) - .parse_value("PaymentMethods") - .change_context(errors::ApiErrorResponse::InternalServerError)?, - None => None, - }; - - Ok(Self { - connector_type: merchant_ca.connector_type.foreign_into(), - connector_name: merchant_ca.connector_name, - merchant_connector_id: Some(merchant_ca.merchant_connector_id), - connector_account_details: Some(masking::Secret::new( - merchant_ca.connector_account_details, - )), - test_mode: merchant_ca.test_mode, - disabled: merchant_ca.disabled, - metadata: merchant_ca.metadata, - payment_methods_enabled, - connector_label: merchant_ca.connector_label, - business_country: merchant_ca.business_country, - business_label: merchant_ca.business_label, - business_sub_label: merchant_ca.business_sub_label, - }) - } -} - impl ForeignFrom for storage_models::enums::PaymentMethodType { @@ -551,3 +521,34 @@ impl ForeignFrom } } } + +impl ForeignTryFrom + for api_models::admin::MerchantConnectorResponse +{ + type Error = error_stack::Report; + fn foreign_try_from( + item: storage_models::merchant_connector_account::MerchantConnectorAccount, + ) -> Result { + let payment_methods_enabled = match item.payment_methods_enabled { + Some(val) => serde_json::Value::Array(val) + .parse_value("PaymentMethods") + .change_context(errors::ApiErrorResponse::InternalServerError)?, + None => None, + }; + + Ok(Self { + connector_type: item.connector_type.foreign_into(), + connector_name: item.connector_name, + connector_label: item.connector_label, + merchant_connector_id: item.merchant_connector_id, + connector_account_details: Secret::new(item.connector_account_details), + test_mode: item.test_mode, + disabled: item.disabled, + payment_methods_enabled, + metadata: item.metadata, + business_country: item.business_country, + business_label: item.business_label, + business_sub_label: item.business_sub_label, + }) + } +} diff --git a/migrations/2023-04-13-094917_change_primary_business_type/down.sql b/migrations/2023-04-13-094917_change_primary_business_type/down.sql new file mode 100644 index 0000000000..2e4a980a2c --- /dev/null +++ b/migrations/2023-04-13-094917_change_primary_business_type/down.sql @@ -0,0 +1,7 @@ +-- This file should undo anything in `up.sql` +UPDATE merchant_account +SET primary_business_details = '{"country": ["US"], "business": ["default"]}'; + +ALTER TABLE merchant_connector_account +ALTER COLUMN business_sub_label +SET DEFAULT 'default'; diff --git a/migrations/2023-04-13-094917_change_primary_business_type/up.sql b/migrations/2023-04-13-094917_change_primary_business_type/up.sql new file mode 100644 index 0000000000..e35ec87972 --- /dev/null +++ b/migrations/2023-04-13-094917_change_primary_business_type/up.sql @@ -0,0 +1,7 @@ +-- This change will allow older merchant accounts to be used with new changes +UPDATE merchant_account +SET primary_business_details = '[{"country": "US", "business": "default"}]'; + +-- Since this field is optional, default is not required +ALTER TABLE merchant_connector_account +ALTER COLUMN business_sub_label DROP DEFAULT;