feat(router): add merchant_category_code in business profile#8296
feat(router): add merchant_category_code in business profile#8296SanchithHegde merged 12 commits intomainfrom
merchant_category_code in business profile#8296Conversation
…it-routing/add-merchant-category-code-in-profile
Changed Files
|
…ttps://github.com/juspay/hyperswitch into debit-routing/add-merchant-category-code-in-profile
WalkthroughMerchant category code support has been added throughout the API, data models, database schema, and OpenAPI specifications. This includes new enums for merchant category codes and names, new fields in profile-related structs, schema changes, migration scripts for the business profile table, type updates, and mapping logic. WASM support for retrieving codes with names was also introduced. Changes
Sequence Diagram(s)sequenceDiagram
participant API_Client
participant Router
participant Domain
participant DieselModels
participant Database
API_Client->>Router: Create/Update Profile (merchant_category_code)
Router->>Domain: Map API request to domain model (includes merchant_category_code)
Domain->>DieselModels: Convert domain model to DB model (merchant_category_code)
DieselModels->>Database: Insert/Update business_profile (merchant_category_code)
Database-->>DieselModels: Confirmation
DieselModels-->>Domain: DB model with merchant_category_code
Domain-->>Router: Domain model with merchant_category_code
Router-->>API_Client: API response (merchant_category_code)
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (3)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
migrations/2025-06-09-080126_add_merchant_category_code_in_business_profile/up.sql (1)
1-3: Consider column type and migration idempotency
Merchant category codes are fixed four-digit values; you could enforce that withCHAR(4)instead ofVARCHAR(16). Also, addingIF NOT EXISTSto theADD COLUMNmakes the migration safe to re-run.crates/router/src/types/api/admin.rs (1)
453-453: Persistmerchant_category_codeon profile creation
The request field is forwarded into theProfileSetter. Consider adding a unit test forcreate_profile_from_merchant_accountto assert thatmerchant_category_codeis correctly persisted.api-reference/openapi_spec.json (2)
25071-25078: Documentmerchant_category_codein PaymentsCreateRequest.
The new property is currently undocumented. Add adescriptionand anexampleto clarify its purpose and format:"merchant_category_code": { + "description": "Optional Merchant Category Code (MCC) for this payment, as defined in the MCC enum.", + "example": "5411", "allOf": [ { "$ref": "#/components/schemas/MerchantCategoryCode" } ], "nullable": true
25363-25370: Documentmerchant_category_codein PaymentsRetrieveRequest.
Apply the same documentation enhancements here to maintain consistency:"merchant_category_code": { + "description": "Optional Merchant Category Code (MCC) for this payment, as defined in the MCC enum.", + "example": "7011", "allOf": [ { "$ref": "#/components/schemas/MerchantCategoryCode" } ], "nullable": truecrates/hyperswitch_domain_models/src/business_profile.rs (1)
1036-1036: Remove unused import ofserde::de::value
This import is not used within the function body and should be cleaned up.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
api-reference-v2/openapi_spec.json(3 hunks)api-reference/openapi_spec.json(3 hunks)crates/api_models/src/admin.rs(6 hunks)crates/api_models/src/open_router.rs(1 hunks)crates/common_enums/src/enums.rs(2 hunks)crates/diesel_models/src/business_profile.rs(10 hunks)crates/diesel_models/src/schema.rs(1 hunks)crates/diesel_models/src/schema_v2.rs(1 hunks)crates/euclid_wasm/src/lib.rs(2 hunks)crates/hyperswitch_domain_models/src/business_profile.rs(33 hunks)crates/openapi/src/openapi.rs(1 hunks)crates/openapi/src/openapi_v2.rs(1 hunks)crates/router/src/core/admin.rs(4 hunks)crates/router/src/core/debit_routing.rs(1 hunks)crates/router/src/types/api/admin.rs(3 hunks)migrations/2025-06-09-080126_add_merchant_category_code_in_business_profile/down.sql(1 hunks)migrations/2025-06-09-080126_add_merchant_category_code_in_business_profile/up.sql(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
crates/openapi/src/openapi_v2.rs (1)
crates/euclid_wasm/src/lib.rs (1)
MerchantCategoryCode(98-103)
crates/openapi/src/openapi.rs (1)
crates/euclid_wasm/src/lib.rs (1)
MerchantCategoryCode(98-103)
🪛 GitHub Actions: Migration Consistency Tests
crates/diesel_models/src/schema_v2.rs
[error] 1-1: Migration command would result in changes to this file. Rerun the command locally and commit the changes.
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: Check compilation for V2 features
- GitHub Check: Run tests on stable toolchain (ubuntu-latest)
- GitHub Check: Check compilation on MSRV toolchain (ubuntu-latest)
- GitHub Check: Run Cypress tests
- GitHub Check: Check wasm build
- GitHub Check: Validate generated OpenAPI spec file
🔇 Additional comments (56)
crates/openapi/src/openapi_v2.rs (1)
288-288: Integration of MerchantCategoryCode schema looks good
The newapi_models::enums::MerchantCategoryCodeis correctly included in the OpenAPI components, ensuring it's exposed in the generated API documentation.migrations/2025-06-09-080126_add_merchant_category_code_in_business_profile/down.sql (1)
1-2: Down migration aligns with the up migration
Droppingmerchant_category_codewithIF EXISTScleanly reverses the addition, preventing errors if the column is already absent.crates/diesel_models/src/schema.rs (1)
231-232: LGTM! Schema change is well-designed.The addition of the nullable
merchant_category_codefield with a 16-character limit is appropriate. The VARCHAR(16) provides ample space for the 4-digit merchant category codes mentioned in the PR objectives while allowing for future flexibility, and the nullable constraint ensures backward compatibility.crates/api_models/src/open_router.rs (1)
110-110: LGTM! Type change improves clarity.The change from
MerchantCategoryCodetoDecisionEngineMerchantCategoryCodealigns with the PR objectives to clarify usage in decision engine contexts. This naming is more specific and appropriate for theCoBadgedCardRequeststruct used in debit routing decisions.crates/openapi/src/openapi.rs (1)
322-322: LGTM! Essential addition for API documentation.Adding
MerchantCategoryCodeto the OpenAPI components schemas is necessary to properly document the new merchant category code functionality in the API specification. This enables proper schema generation and API client support for the MCC field.crates/euclid_wasm/src/lib.rs (2)
37-37: LGTM!The import update correctly includes the new merchant category code types needed for the new function.
94-108: LGTM!The implementation follows the established pattern used by
get_two_letter_country_code()and correctly exposes merchant category codes with their human-readable names to the frontend via WASM. The function properly handles iteration over the enum variants, mapping, and serialization.crates/router/src/core/admin.rs (4)
4056-4056: LGTM! Consistent field assignment for merchant category code.The field assignment follows the established pattern for optional fields and properly propagates the merchant_category_code from the API request to the domain model.
4205-4205: LGTM! Consistent v2 implementation.The field assignment maintains consistency with the v1 implementation and properly handles the merchant_category_code in the v2 API flow.
4539-4539: LGTM! Completes v1 profile update support.The field assignment properly handles merchant_category_code in profile update operations, maintaining consistency with the create operation.
4679-4679: LGTM! Completes comprehensive merchant category code support.This final change ensures that merchant_category_code is consistently handled across all profile operations (create/update) and API versions (v1/v2). The implementation is complete and well-structured.
api-reference-v2/openapi_spec.json (3)
12989-13000: DefineMerchantCategoryCodeenum in components
The new enum correctly enumerates all supported MCC values as strings.
20744-20752: Exposemerchant_category_codein Create Intent request
The property is properly marked nullable and references the newMerchantCategoryCodecomponent.
21020-21028: Exposemerchant_category_codein Update Intent request
The update schema correctly adds the nullablemerchant_category_codefield to the request body.crates/router/src/types/api/admin.rs (2)
200-200: Mapmerchant_category_codein v1ProfileResponse
The new field is correctly pulled from the domain model. Please verify that theProfileResponsestruct for v1 and its OpenAPI spec have been updated to includemerchant_category_code.
285-285: Mapmerchant_category_codein v2ProfileResponse
This aligns with the v1 change. Confirm that the v2ProfileResponsestruct and the OpenAPI V2 schema exposemerchant_category_codeas expected.crates/diesel_models/src/business_profile.rs (10)
133-133: Insertable struct updated correctly
TheProfileNewstruct now includesmerchant_category_code, ensuring insert operations can set this field.
188-188: Include field in v1 changeset struct
TheProfileUpdateInternalstruct’sAsChangesetnow coversmerchant_category_code, enabling updates to this column.
240-240: Destructure new field in v1 apply_changeset
Themerchant_category_codevariable is correctly included in the destructuring ofself, so upstream updates carry into the merge logic.
323-323: Merge new field in v1 apply_changeset
The merge logicmerchant_category_code: merchant_category_code.or(source.merchant_category_code)properly falls back to the existing value when no update is provided.
471-471: Insertable v2 struct updated correctly
The v2ProfileNewstruct now exposesmerchant_category_codefor insert operations.
529-529: Include field in v2 changeset struct
The v2ProfileUpdateInternalstruct’sAsChangesetderive now coversmerchant_category_code, enabling PATCH updates on this field.
584-584: Destructure new field in v2 apply_changeset
The destructuring ofselfin the v2 merge now includesmerchant_category_code, so the update payload captures this change.
677-677: Merge new field in v2 apply_changeset
The merge logicmerchant_category_code: merchant_category_code.or(source.merchant_category_code)correctly handles fallback when the update does not specify a new code.
397-397:Details
✅ Verification successful
Ensure v2 schema alignment for new field
Addedmerchant_category_codeto the v2Profilestruct. Verify the v2 schema (schema_v2.rs) includes this column at the matching position to prevent Diesel compile errors.
🏁 Script executed:
#!/bin/bash # Verify merchant_category_code exists in v2 schema_v2.rs rg "merchant_category_code" -n crates/diesel_models/src/schema_v2.rsLength of output: 125
v2 schema includes
merchant_category_code
- Verified in crates/diesel_models/src/schema_v2.rs (line 242):
merchant_category_code -> Nullable<Varchar>,No further action required.
77-77:Details
✅ Verification successful
Ensure v1 schema alignment for new field
Addedmerchant_category_codeto the v1Profilestruct. Verify that thebusiness_profiletable schema (schema.rs) has the nullablemerchant_category_codecolumn in the correct position to match this struct field order.
🏁 Script executed:
#!/bin/bash # Verify merchant_category_code exists in v1 schema.rs rg "merchant_category_code" -n crates/diesel_models/src/schema.rsLength of output: 122
🏁 Script executed:
#!/bin/bash # Show struct context for merchant_category_code field rg -n -C5 "merchant_category_code" crates/diesel_models/src/business_profile.rs # Show schema context for merchant_category_code column rg -n -C5 "merchant_category_code" crates/diesel_models/src/schema.rsLength of output: 6152
v1 schema alignment confirmed
- In
crates/diesel_models/src/business_profile.rs, themerchant_category_codefield appears immediately afterthree_ds_decision_rule_algorithmin theProfilestruct (around line 77).- In
crates/diesel_models/src/schema.rs,merchant_category_code -> Nullable<Varchar>is declared right afterthree_ds_decision_rule_algorithmwithin thebusiness_profiletable (line 232).The column ordering matches the struct. Ready to merge.
crates/api_models/src/admin.rs (6)
2022-2024: Addmerchant_category_codetoProfileCreate(v1)
The new optional field aligns with other business profile properties, and the schema metadata correctly reflects a four-digit MCC.
2167-2169: Addmerchant_category_codetoProfileCreate(v2)
This mirrors the v1 addition and ensures the MCC is exposed in the v2 create payload with proper schema documentation.
2334-2336: Addmerchant_category_codetoProfileResponse(v1)
Including the MCC in the v1 response completes the contract for clients reading business profiles.
2487-2489: Addmerchant_category_codetoProfileResponse(v2)
The v2 response now consistently surfaces the merchant’s category code alongside other profile details.
2647-2649: Addmerchant_category_codetoProfileUpdate(v1)
Allowing updates to the MCC in v1 aligns with the create and response models for full CRUD support.
2783-2785: Addmerchant_category_codetoProfileUpdate(v2)
This completes the v2 update contract by permitting MCC modifications with correct schema metadata.crates/common_enums/src/enums.rs (5)
2400-2403: LGTM! Clean enum rename with appropriate attributes.The
DecisionEngineMerchantCategoryCodeenum is well-defined with proper serialization and diesel integration. The rename fromMerchantCategoryCodeto clarify its specific usage in decision engine logic is a good architectural decision.
2503-2535: Excellent design for human-readable merchant category names.The
MerchantCategoryenum provides clear, descriptive names with proper serde renaming to include the MCC codes in parentheses. This approach enhances readability while maintaining the connection to the underlying codes.
2537-2575: Well-structured merchant category code enum with proper string serialization.The enum correctly represents all seven supported MCCs (5411, 7011, 0763, 8111, 5021, 4816, 5661) with consistent naming and appropriate diesel integration for database storage as text.
2577-2589: Perfect mapping implementation between codes and names.The
to_merchant_category_namemethod provides a clean, exhaustive mapping from each MCC code to its corresponding human-readable category. The implementation correctly covers all enum variants and follows Rust best practices.
2591-2595: Clean and practical struct design for combining code and name.The
MerchantCategoryCodeWithNamestruct provides a simple, effective way to package merchant category codes with their descriptive names for API responses and frontend consumption.crates/hyperswitch_domain_models/src/business_profile.rs (19)
79-79: Addmerchant_category_codeto v1Profilestruct
Introduces the new optional MCC field to the core v1 domain model.
133-133: Addmerchant_category_codeto v1ProfileSetterstruct
Ensures the setter supports the new MCC field during profile creation/update.
193-194: Mapmerchant_category_codein v1From<ProfileSetter>conversion
Propagates the setter’s MCC into the concreteProfile.
254-254: Addmerchant_category_codeto v1ProfileGeneralUpdatestruct
Allows MCC to be updated via the general update payload.
331-331: Destructuremerchant_category_codein v1ProfileUpdate::Update
Pulls the MCC out of the update wrapper for conversion.
382-382: Setmerchant_category_codein v1ProfileUpdateInternal::Update
Includes the new MCC field in the internal changeset.
434-434: Default MCC toNonein v1 non-general update variants
Ensures that update variants unrelated to general profile changes do not overwrite MCC.Also applies to: 484-484, 534-534, 584-584, 634-634, 684-684
754-754: Includemerchant_category_codein v1Conversion::convert
Writes the domain MCC into the DieselProfilefor persistence.
850-850: Includemerchant_category_codein v1Conversion::convert_back
Restores the MCC from the database model back into the domain struct.
914-914: Includemerchant_category_codein v1Conversion::construct_new
Ensures new database inserts carry the MCC field.
974-974: Addmerchant_category_codeto v2Profilestruct
Adds the optional MCC to the v2 domain model for profiles.
1030-1030: Addmerchant_category_codeto v2ProfileSetterstruct
Supports the MCC field during v2 profile creation and updates.
1093-1093: Mapmerchant_category_codein v2From<ProfileSetter>conversion
Transfers the MCC from the setter into the v2Profile.
1173-1173: Addmerchant_category_codeto v2ProfileGeneralUpdatestruct
Enables MCC updates in the v2 general update payload.
1252-1252: Handlemerchant_category_codein v2ProfileUpdate::Update
Destructures and sets the MCC in the internal update conversion.Also applies to: 1304-1304
1359-1359: Default MCC toNonein v2 non-general update variants
Prevents unrelated update variants from clearing or altering the MCC.Also applies to: 1412-1412, 1465-1465, 1518-1518, 1571-1571, 1624-1624, 1678-1678, 1730-1730, 1784-1784
1860-1860: Includemerchant_category_codein v2Conversion::convert
Persists the MCC into the DieselProfileon conversion.
1954-1954: Includemerchant_category_codein v2Conversion::convert_back
Restores the MCC from the DB model into the v2 domain struct.
2023-2023: Includemerchant_category_codein v2Conversion::construct_new
Ensures new v2 inserts include the MCC field.
| #[max_length = 16] | ||
| merchant_category_code -> Nullable<Varchar>, |
There was a problem hiding this comment.
Schema out-of-sync: rerun Diesel CLI to update schema_v2.rs
CI migration consistency tests are failing. Please rerun the Diesel schema generation to reflect the new column, for example:
diesel print-schema --schema v2 > crates/diesel_models/src/schema_v2.rs🤖 Prompt for AI Agents
In crates/diesel_models/src/schema_v2.rs around lines 241 to 242, the schema is
out-of-sync with the database, causing CI migration consistency tests to fail.
To fix this, rerun the Diesel CLI command `diesel print-schema --schema v2 >
crates/diesel_models/src/schema_v2.rs` to regenerate the schema file and update
it with the latest database changes.
|
|
||
| let co_badged_card_request = open_router::CoBadgedCardRequest { | ||
| merchant_category_code: enums::MerchantCategoryCode::Mcc0001, | ||
| merchant_category_code: enums::DecisionEngineMerchantCategoryCode::Mcc0001, |
There was a problem hiding this comment.
Use the actual merchant category code from business profile instead of hardcoded value.
The hardcoded Mcc0001 value should be replaced with the actual merchant_category_code from the business profile. According to the PR objectives, the business profile now contains this field, but it's not being utilized here.
Apply this diff to use the business profile's merchant category code:
- merchant_category_code: enums::DecisionEngineMerchantCategoryCode::Mcc0001,
+ merchant_category_code: business_profile.merchant_category_code
+ .unwrap_or(enums::DecisionEngineMerchantCategoryCode::Mcc0001),Note: You may need to adjust the enum conversion depending on the exact type stored in the business profile.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| merchant_category_code: enums::DecisionEngineMerchantCategoryCode::Mcc0001, | |
| merchant_category_code: business_profile.merchant_category_code | |
| .unwrap_or(enums::DecisionEngineMerchantCategoryCode::Mcc0001), |
🤖 Prompt for AI Agents
In crates/router/src/core/debit_routing.rs at line 318, replace the hardcoded
merchant_category_code value enums::DecisionEngineMerchantCategoryCode::Mcc0001
with the actual merchant_category_code obtained from the business profile.
Retrieve the merchant_category_code field from the business profile object and
convert or map it appropriately to the enums::DecisionEngineMerchantCategoryCode
type before assigning it here.
| "MerchantCategoryCode": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "5411", | ||
| "7011", | ||
| "0763", | ||
| "8111", | ||
| "5021", | ||
| "4816", | ||
| "5661" | ||
| ] | ||
| }, |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add description, pattern, and example to MerchantCategoryCode schema.
The new enum schema lacks a description, pattern constraint, and an example. Including these enhances clarity, enforces the 4-digit format, and aids API consumers.
Suggestion:
"MerchantCategoryCode": {
- "type": "string",
- "enum": [
+ "type": "string",
+ "description": "Merchant Category Code (MCC), a 4-digit ISO-assigned code for merchant classification.",
+ "pattern": "^[0-9]{4}$",
+ "enum": [
"5411",
"7011",
"0763",
"8111",
"5021",
"4816",
"5661"
],
+ "example": "5411"
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "MerchantCategoryCode": { | |
| "type": "string", | |
| "enum": [ | |
| "5411", | |
| "7011", | |
| "0763", | |
| "8111", | |
| "5021", | |
| "4816", | |
| "5661" | |
| ] | |
| }, | |
| "MerchantCategoryCode": { | |
| "type": "string", | |
| "description": "Merchant Category Code (MCC), a 4-digit ISO-assigned code for merchant classification.", | |
| "pattern": "^[0-9]{4}$", | |
| "enum": [ | |
| "5411", | |
| "7011", | |
| "0763", | |
| "8111", | |
| "5021", | |
| "4816", | |
| "5661" | |
| ], | |
| "example": "5411" | |
| }, |
🤖 Prompt for AI Agents
In api-reference/openapi_spec.json around lines 15574 to 15585, the
MerchantCategoryCode schema is missing a description, a pattern to enforce the
4-digit format, and an example value. Add a "description" field explaining that
this is a 4-digit merchant category code, include a "pattern" field with a regex
to enforce exactly four digits, and add an "example" field with a valid code
such as "5411" to improve schema clarity and validation.
…it-routing/add-merchant-category-code-in-profile
…it-routing/add-merchant-category-code-in-profile
ff24b90
Type of Change
Description
This pull request introduces
merchant_category_codefield in the business profile. This is the four-digit code assigned based on business type to determine processing fees and risk level. This code can be used to make various decision during a payment flow. One such use case is network interchange fee calculation in debit routing.MerchantCategoryandMerchantCategoryCode, to represent MCCs and their corresponding human-readable names. Implemented a mapping functionto_merchant_category_nameto convert MCCs to their names.WASM Functionality
getMerchantCategoryCodeWithNameto retrieve all MCCs along with their names for frontend use. This function iterates over theMerchantCategoryCodeenum and constructs a list of MCCs and their human-readable names.Code Refactoring
MerchantCategoryCodetoDecisionEngineMerchantCategoryCodein specific contexts to clarify usage in decision engine logic. This is struct will be removed once the new struct is introduced in decision engine.-> Supported Merchant Category Codes
Additional Changes
Motivation and Context
How did you test it?
-> Update a business profile by passing merchant category code
-> Db entry

-> Wasm testing

Checklist
cargo +nightly fmt --allcargo clippySummary by CodeRabbit