diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml index 2bfb7ebd6e..0b70631e11 100644 --- a/.github/workflows/manual-release.yml +++ b/.github/workflows/manual-release.yml @@ -11,11 +11,6 @@ on: options: - sandbox - production - multiple_mca: - description: "Whether to enable the multiple_mca feature" - required: true - default: false - type: boolean jobs: build: @@ -32,10 +27,6 @@ jobs: username: ${{ secrets.DOCKERHUB_USER }} password: ${{ secrets.DOCKERHUB_PASSWD }} - - name: Add multiple_mca feature if enabled - if: ${{ inputs.multiple_mca == true }} - run: echo 'EXTRA_FEATURES="--features multiple_mca"' >> $GITHUB_ENV - - name: Build and push router Docker image uses: docker/build-push-action@v4 with: diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml index 4e8710e031..f1c7e8396d 100644 --- a/crates/api_models/Cargo.toml +++ b/crates/api_models/Cargo.toml @@ -10,7 +10,6 @@ license.workspace = true [features] default = ["payouts"] errors = ["dep:actix-web", "dep:reqwest"] -multiple_mca = [] dummy_connector = ["common_enums/dummy_connector"] detailed_errors = [] payouts = [] diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 17fe2336d5..89a187faab 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -79,11 +79,6 @@ 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: Vec, - - #[cfg(not(feature = "multiple_mca"))] #[schema(value_type = Option)] pub primary_business_details: Option>, @@ -598,21 +593,10 @@ pub struct MerchantConnectorCreate { #[schema(example = json!(common_utils::consts::FRM_CONFIGS_EG))] pub frm_configs: Option>, - /// Business Country of the connector - #[cfg(feature = "multiple_mca")] #[schema(value_type = CountryAlpha2, example = "US")] pub business_country: api_enums::CountryAlpha2, - #[cfg(not(feature = "multiple_mca"))] - #[schema(value_type = Option, example = "US")] - 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")] diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index cccaaca5cb..45091f0f61 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -22,7 +22,6 @@ kv_store = [] accounts_cache = [] openapi = ["olap", "oltp", "payouts"] vergen = ["router_env/vergen"] -multiple_mca = ["api_models/multiple_mca"] dummy_connector = ["api_models/dummy_connector"] external_access_dc = ["dummy_connector"] detailed_errors = ["api_models/detailed_errors", "error-stack/serde"] diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 320c59c84d..f762bd6588 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -39,31 +39,6 @@ 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::CountryAlpha2::US, - business: "default".to_string(), - }] - }) - } -} - pub async fn create_merchant_account( db: &dyn StorageInterface, req: api::MerchantAccountCreate, @@ -77,7 +52,7 @@ pub async fn create_merchant_account( let publishable_key = Some(create_merchant_publishable_key()); let primary_business_details = utils::Encode::>::encode_to_value( - &get_primary_business_details(&req), + &req.primary_business_details.unwrap_or_default(), ) .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "primary_business_details", @@ -384,27 +359,6 @@ async fn validate_merchant_id>( .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) } -fn get_business_details_wrapper( - request: &api::MerchantConnectorCreate, - _merchant_account: &domain::MerchantAccount, -) -> RouterResult<(enums::CountryAlpha2, 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, - ) - } -} - fn validate_certificate_in_mca_metadata( connector_metadata: Secret, ) -> RouterResult<()> { @@ -465,11 +419,15 @@ pub async fn create_payment_connector( .await .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?; - let (business_country, business_label) = get_business_details_wrapper(&req, &merchant_account)?; + helpers::validate_business_details( + req.business_country, + &req.business_label, + &merchant_account, + )?; let connector_label = helpers::get_connector_label( - business_country, - &business_label, + req.business_country, + &req.business_label, req.business_sub_label.as_ref(), &req.connector_name.to_string(), ); @@ -532,8 +490,8 @@ pub async fn create_payment_connector( metadata: req.metadata, frm_configs, connector_label: connector_label.clone(), - business_country, - business_label, + business_country: req.business_country, + business_label: req.business_label.clone(), business_sub_label: req.business_sub_label, created_at: common_utils::date_time::now(), modified_at: common_utils::date_time::now(), diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index e5af1a5c9f..43f39e1597 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1913,6 +1913,32 @@ pub fn get_connector_label( connector_label } +/// Check whether the business details are configured in the merchant account +pub fn validate_business_details( + business_country: api_enums::CountryAlpha2, + business_label: &String, + merchant_account: &domain::MerchantAccount, +) -> RouterResult<()> { + let primary_business_details = merchant_account + .primary_business_details + .clone() + .parse_value::>("PrimaryBusinessDetails") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse primary business details")?; + + primary_business_details + .iter() + .find(|business_details| { + &business_details.business == business_label + && business_details.country == business_country + }) + .ok_or(errors::ApiErrorResponse::PreconditionFailed { + message: "business_details are not configured in the merchant account".to_string(), + })?; + + Ok(()) +} + /// Do lazy parsing of primary business details /// If both country and label are passed, no need to parse business details from merchant_account /// If any one is missing, get it from merchant_account @@ -1923,42 +1949,29 @@ pub fn get_business_details( business_label: Option<&String>, merchant_account: &domain::MerchantAccount, ) -> RouterResult<(api_enums::CountryAlpha2, String)> { - let (business_country, business_label) = match business_country.zip(business_label) { + let primary_business_details = merchant_account + .primary_business_details + .clone() + .parse_value::>("PrimaryBusinessDetails") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse primary business details")?; + + match business_country.zip(business_label) { Some((business_country, business_label)) => { - (business_country.to_owned(), business_label.to_owned()) + Ok((business_country.to_owned(), business_label.to_owned())) } - None => { - // Parse the primary business details from merchant account - let primary_business_details: Vec = - merchant_account - .primary_business_details - .clone() - .parse_value("PrimaryBusinessDetails") - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to parse primary business details")?; - - 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_else(|| primary_business_details.country.to_owned()), - business_label - .map(ToString::to_string) - .unwrap_or_else(|| 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" - }))? - } - } - }; - - Ok((business_country, business_label)) + _ => match primary_business_details.first() { + Some(business_details) if primary_business_details.len() == 1 => Ok(( + business_country.unwrap_or_else(|| business_details.country.to_owned()), + business_label + .map(ToString::to_string) + .unwrap_or_else(|| business_details.business.to_owned()), + )), + _ => Err(report!(errors::ApiErrorResponse::MissingRequiredField { + field_name: "business_country, business_label" + })), + }, + } } #[inline] diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index c491603954..d5a9af98d6 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -589,11 +589,29 @@ impl PaymentCreate { .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to convert order details to value")?; - let (business_country, business_label) = helpers::get_business_details( - request.business_country, - request.business_label.as_ref(), - merchant_account, - )?; + let (business_country, business_label) = + match (request.business_country, request.business_label.as_ref()) { + (Some(business_country), Some(business_label)) => { + helpers::validate_business_details( + business_country, + business_label, + merchant_account, + )?; + + Ok((business_country, business_label.clone())) + } + (None, Some(_)) => Err(errors::ApiErrorResponse::MissingRequiredField { + field_name: "business_country", + }), + (Some(_), None) => Err(errors::ApiErrorResponse::MissingRequiredField { + field_name: "business_label", + }), + (None, None) => Ok(helpers::get_business_details( + request.business_country, + request.business_label.as_ref(), + merchant_account, + )?), + }?; let allowed_payment_method_types = request .get_allowed_payment_method_types_as_value() diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 7b0bff6c4a..7c7fe43784 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -5749,7 +5749,9 @@ "required": [ "connector_type", "connector_name", - "connector_label" + "connector_label", + "business_country", + "business_label" ], "properties": { "connector_type": { @@ -5846,16 +5848,10 @@ "nullable": true }, "business_country": { - "allOf": [ - { - "$ref": "#/components/schemas/CountryAlpha2" - } - ], - "nullable": true + "$ref": "#/components/schemas/CountryAlpha2" }, "business_label": { - "type": "string", - "nullable": true + "type": "string" }, "business_sub_label": { "type": "string",