Skip to content

feat(business_profile): added merchant country code in business profile#8529

Merged
likhinbopanna merged 11 commits intomainfrom
10137-flatten-merchant_country_code-into-business-profile-from-acquirer_config
Jul 14, 2025
Merged

feat(business_profile): added merchant country code in business profile#8529
likhinbopanna merged 11 commits intomainfrom
10137-flatten-merchant_country_code-into-business-profile-from-acquirer_config

Conversation

@sahkal
Copy link
Contributor

@sahkal sahkal commented Jul 2, 2025

Type of Change

  • New feature

Description

1. Database Migration

  • Added: New migration 2025-07-02-071146_add-merchant-country-code-in-business-profile

    • Up migration: Adds merchant_country_code INTEGER column to business_profile table
    • Down migration: Removes the merchant_country_code column

2. Database Model Updates

  • File: crates/diesel_models/src/business_profile.rs

    • Added merchant_country_code: Option<i32> field to all profile structs:

      • Profile struct (both v1 and v2 versions)
      • ProfileNew struct (both v1 and v2 versions)
      • ProfileUpdateInternal struct (both v1 and v2 versions)
    • Updated apply_changeset methods to handle the new field

    • Field is positioned as the last field in all structs

3. Domain Model Updates

  • File: crates/hyperswitch_domain_models/src/business_profile.rs

    • Added merchant_country_code: Option<i32> to domain Profile structs (both v1 and v2)
    • Added field to ProfileSetter structs
    • Updated ProfileGeneralUpdate structs to include the new field
    • Updated conversion methods (convert, convert_back, construct_new) to handle the field
    • Updated all ProfileUpdate enum variants to include merchant_country_code: None in update operations

4. API Model Updates

  • File: crates/api_models/src/admin.rs

    • Added merchant_country_code field to profile-related structs:

      • ProfileCreate (both v1 and v2 versions)
      • ProfileResponse (both v1 and v2 versions)
      • ProfileUpdate (both v1 and v2 versions)
    • Field is documented with schema annotations: value_type = Option<i32>, example = 840

    • Field represents a numeric country code (e.g., 840 for United States)

Key Technical Details

Data Type:

  • Uses Option<i32> to allow null values (optional field)
  • Stores numeric country codes rather than alpha codes

Backward Compatibility:

  • All changes maintain backward compatibility by making the field optional
  • Existing profiles will have NULL values for this field initially
  • Database migration uses IF NOT EXISTS to safely add the column

Feature Flags:

  • Changes are properly segregated between v1 and v2 feature flags
  • Both versions of the API support the new field

Integration Points:

  • Field is integrated into all CRUD operations for business profiles
  • Conversion between different model layers (API → Domain → Database) properly handles the field
  • Update operations preserve existing values when not explicitly changed

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
  • This PR modifies application configuration/environment variables

Do Profile Acquirer Create

curl --location 'localhost:8080/profile_acquirer' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_yxuko5Ijbd9iJUbWT1EUGXH7tKDQXWXPSh7GAZY9BOsbSDsqFihTVSaMPwrMsGCC' \
--data '{
  "acquirer_assigned_merchant_id": "00002000000",
  "merchant_name": "Demo Merchant",
  "network": "AmericanExpress",
  "acquirer_bin": "400000",
  "acquirer_fraud_rate": 0.2345545234765,
  "profile_id": "pro_czw39KVGhlGIexP6JBzC"
}'

the response should return 200

Create Business_profile with merchant_country_code

curl --location 'http://localhost:8080/account/sahkal11/business_profile'
--header 'Content-Type: application/json'
--header 'api-key: dev_yxuko5Ijbd9iJUbWT1EUGXH7tKDQXWXPSh7GAZY9BOsbSDsqFihTVSaMPwrMsGCC'
--data '{
"profile_name": "dqwdwcweqcewcxqwcwqqd",
"merchant_country_code": 840
}
'

Response

{
    "merchant_id": "sahkal11",
    "profile_id": "pro_d1IU0buWxmb29dk9889e",
    "profile_name": "dqwdwcweqcewcxqwcwqqd",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "FFGOhmbQrxLOGIAGmsLSfwkgOGZY8l2ybzh8t7xd29apSI6C665ysYiuKtjB6U2O",
    "redirect_to_merchant_with_http_post": false,
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": null,
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true,
        "payment_statuses_enabled": null,
        "refund_statuses_enabled": null,
        "payout_statuses_enabled": null
    },
    "metadata": null,
    "routing_algorithm": null,
    "intent_fulfillment_time": 900,
    "frm_routing_algorithm": null,
    "payout_routing_algorithm": null,
    "applepay_verified_domains": null,
    "session_expiry": 900,
    "payment_link_config": null,
    "authentication_connector_details": null,
    "use_billing_as_payment_method_billing": true,
    "extended_card_info_config": null,
    "collect_shipping_details_from_wallet_connector": false,
    "collect_billing_details_from_wallet_connector": false,
    "always_collect_shipping_details_from_wallet_connector": false,
    "always_collect_billing_details_from_wallet_connector": false,
    "is_connector_agnostic_mit_enabled": false,
    "payout_link_config": null,
    "outgoing_webhook_custom_http_headers": null,
    "tax_connector_id": null,
    "is_tax_connector_enabled": false,
    "is_network_tokenization_enabled": false,
    "is_auto_retries_enabled": false,
    "max_auto_retries_enabled": null,
    "always_request_extended_authorization": null,
    "is_click_to_pay_enabled": false,
    "authentication_product_ids": null,
    "card_testing_guard_config": {
        "card_ip_blocking_status": "disabled",
        "card_ip_blocking_threshold": 3,
        "guest_user_card_blocking_status": "disabled",
        "guest_user_card_blocking_threshold": 10,
        "customer_id_blocking_status": "disabled",
        "customer_id_blocking_threshold": 5,
        "card_testing_guard_expiry": 3600
    },
    "is_clear_pan_retries_enabled": false,
    "force_3ds_challenge": false,
    "is_debit_routing_enabled": false,
    "merchant_business_country": null,
    "is_pre_network_tokenization_enabled": false,
    "acquirer_configs": null,
    "is_iframe_redirection_enabled": null,
    "merchant_category_code": null,
    "merchant_country_code": "840"
}

the response should return 200

Try Updating business profile with merchant_country_code

curl --location 'http://localhost:8080/account/sahkal11/business_profile/pro_d1IU0buWxmb29dk9889e' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_yxuko5Ijbd9iJUbWT1EUGXH7tKDQXWXPSh7GAZY9BOsbSDsqFihTVSaMPwrMsGCC' \
--data '
{
    "merchant_country_code": "840"
}
'

Response should return 200

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code
  • I added unit tests for my changes where possible

@sahkal sahkal added this to the June 2025 Release milestone Jul 2, 2025
@sahkal sahkal self-assigned this Jul 2, 2025
@sahkal sahkal added the C-feature Category: Feature request or enhancement label Jul 2, 2025
@sahkal sahkal requested review from a team as code owners July 2, 2025 08:49
@semanticdiff-com
Copy link

semanticdiff-com bot commented Jul 2, 2025

@hyperswitch-bot hyperswitch-bot bot added M-database-changes Metadata: This PR involves database schema changes M-api-contract-changes Metadata: This PR involves API contract changes labels Jul 2, 2025
@sahkal sahkal requested a review from sai-harsha-vardhan July 7, 2025 07:19
Comment on lines +222 to +227
router_env::logger::error!("Invalid country code {}: {:?}", code, err);
Err(error_stack::Report::new(
api_error_response::ApiErrorResponse::InvalidDataValue {
field_name: "merchant_country_code",
},
))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of logging an error and then returning a Report, can we do attach_printable on Report itself. because this will produce 2 different logs (one from logger:error and other from propagated parent error log) and makes debugging little difficult

.clone()
.and_then(|network| business_profile.get_acquirer_details_from_network(network))
});
let country = business_profile.get_country_from_merchant_country_code()?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it fine to break the flow because of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, its a required value so breaking the flow for 3ds intelligence should be fine

Comment on lines +231 to +240
router_env::logger::error!(
"Country code {} is negative or too large: {:?}",
country_code,
err
);
Err(error_stack::Report::new(
api_error_response::ApiErrorResponse::InvalidDataValue {
field_name: "merchant_country_code",
},
))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Comment on lines +218 to +221
.map(|country_code| match country_code.parse::<u32>() {
Ok(code) => match common_enums::Country::from_numeric(code) {
Ok(country) => Ok(country),
Err(err) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that country_code is being stored in profile table without any validation (similar to one here), but its being validated in payments flow. shouldn't it be validated during save operation also just to be sure that legit code is stored in db and payment could happen without any error? or am i missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, have added validation during insert and update Profile

@sahkal sahkal requested a review from Chethan-rao July 8, 2025 09:50
Comment on lines +111 to +113
.map_err(|_| errors::ValidationError::IncorrectValueProvided {
field_name: "merchant_country_code",
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you ignoring the error? can we do change_context instead?

Comment on lines +119 to +121
.map_err(|_| errors::ValidationError::IncorrectValueProvided {
field_name: "merchant_country_code",
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

sahkal and others added 4 commits July 8, 2025 16:44
…le-from-acquirer_config' of github.com:juspay/hyperswitch into 10137-flatten-merchant_country_code-into-business-profile-from-acquirer_config
@sahkal sahkal requested a review from Chethan-rao July 9, 2025 08:10
Chethan-rao
Chethan-rao previously approved these changes Jul 9, 2025
@likhinbopanna likhinbopanna added this pull request to the merge queue Jul 14, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 14, 2025
@likhinbopanna likhinbopanna enabled auto-merge July 14, 2025 10:43
@likhinbopanna likhinbopanna added this pull request to the merge queue Jul 14, 2025
Merged via the queue into main with commit 44f8964 Jul 14, 2025
16 of 20 checks passed
@likhinbopanna likhinbopanna deleted the 10137-flatten-merchant_country_code-into-business-profile-from-acquirer_config branch July 14, 2025 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-feature Category: Feature request or enhancement M-api-contract-changes Metadata: This PR involves API contract changes M-database-changes Metadata: This PR involves database schema changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants