Skip to content

refactor(dynamic_routing): add logic for creating merchant account in decision engine#8191

Merged
Gnanasundari24 merged 9 commits intomainfrom
add-merchant-creation-in-de
Jun 4, 2025
Merged

refactor(dynamic_routing): add logic for creating merchant account in decision engine#8191
Gnanasundari24 merged 9 commits intomainfrom
add-merchant-creation-in-de

Conversation

@Chethan-rao
Copy link
Contributor

@Chethan-rao Chethan-rao commented May 31, 2025

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

Merchant account creation on decision-engine is pre-requisite for making success based routing calls to it. Since toggle SR endpoint on Hyperswitch is the place where rule creation API of DE is being called, we can check whether merchant_account exists in DE, if exists, toggle endpoint will go ahead with creating the rule. If not, it will first call DE to create a merchant_account and then create the rule.
I have created the is_merchant_created_in_decision_engine flag inside the dynamic_routing_algorithm column which is of type JSON in profile table. I have added a #[serde(default)] attribute on top of is_merchant_created_in_decision_engine. Hence it shouldn't break for older profiles which doesn't have this field itself.

Additional Changes

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

Motivation and Context

How did you test it?

  1. Create merchant_account and API key in Hyperswitch.
  2. Toggle SR for the default profile created above.
curl --location --request POST 'http://localhost:8080/account/merchant_1748681084/business_profile/pro_3gHXWoq1Xh3AKi6tNZV1/dynamic_routing/success_based/toggle?enable=dynamic_connector_selection' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: xyz'

Check logs for toggle call which should have something like Creating merchant_account in decision engine for profile <profile_id>

  1. Try hitting same API again by disabling the SR, it shouldn't have above merchant_account creation log anymore as it should be created once per profile.
  2. Also hit toggle API for the profile which already has SR toggled. Even for it, the merchant_account should be created during first toggle call and not during further calls.

Create merchant in debit routing flow

-> Update business profile by setting is_debit_routing_enabled

curl --location 'http://localhost:8080/account/merchant_1748956040/business_profile/pro_6QFJX6m7xjQacyygMmBT' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: ' \
--data '{
    "is_debit_routing_enabled": true
}'
{
    "merchant_id": "merchant_1748956040",
    "profile_id": "pro_6QFJX6m7xjQacyygMmBT",
    "profile_name": "US_default",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "THd00F3c6WIXOXufmm6sFsUL0zRUFVL2llcMS1SG9rdco16PFty01OOkLcY8IbSS",
    "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
    },
    "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": true,
    "merchant_business_country": null,
    "is_pre_network_tokenization_enabled": false
}

-> Db screenshot
image
-> Db entry when business profile is created
image

Test sr

image image

-> Update profile to enable debit routing
image

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

@Chethan-rao Chethan-rao self-assigned this May 31, 2025
@Chethan-rao Chethan-rao requested review from a team as code owners May 31, 2025 08:26
@Chethan-rao Chethan-rao added C-refactor Category: Refactor A-routing Area: Routing labels May 31, 2025
@semanticdiff-com
Copy link

semanticdiff-com bot commented May 31, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/core/routing/helpers.rs  12% smaller
  crates/api_models/src/routing.rs  0% smaller
  crates/router/src/core/admin.rs  0% smaller
  crates/router/src/core/routing.rs  0% smaller

Comment on lines -267 to -286
// Call to DE here
// Check if creation should be based on default profile
#[cfg(all(feature = "dynamic_routing", feature = "v1"))]
{
if state.conf.open_router.enabled {
merchant_account
.default_profile
.as_ref()
.async_map(|profile_id| {
routing::helpers::create_decision_engine_merchant(&state, profile_id)
})
.await
.transpose()
.map_err(|err| {
crate::logger::error!("Failed to create merchant in Decision Engine {err:?}");
})
.ok();
}
}

Copy link
Contributor Author

@Chethan-rao Chethan-rao May 31, 2025

Choose a reason for hiding this comment

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

I don't think we should create merchant_account in decision engine for every profile creation on our side as we are not sure whether SR will be toggled for that profile. Instead I have moved the merchant creation call in DE to the place where SR is being toggled. From this we are taking of all the below cases -

  • New profile creation: Can use SR toggle API which creates both merchant and rules in DE
  • Old profile: for both the cases where SR is already toggled or not toggled, is_merchant_created_in_decision_engine flag in profile table will indicate whether merchant is created on DE. if not, we'll create it.

cc: @Sarthak1799 @jagan-jaya

jagan-jaya
jagan-jaya previously approved these changes Jun 2, 2025
prajjwalkumar17
prajjwalkumar17 previously approved these changes Jun 2, 2025
Comment on lines +2223 to +2237
if !dynamic_routing_algo_ref.is_merchant_created_in_decision_engine {
logger::debug!(
"Creating merchant_account in decision engine for profile {}",
profile_id.get_string_repr()
);

create_decision_engine_merchant(state, profile_id)
.await
.map_err(|err| {
logger::warn!("Merchant creation error in decision_engine: {err:?}");
})
.ok();

// TODO: Update the status based on the status code or error message from the API call
dynamic_routing_algo_ref.update_merchant_creation_status_in_decision_engine(true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Rare edge case but if DE response does not come through while the operation still being a success on DE, We'd again make a call for merchant creation next time around, which would fail and this status would never get updated.

A workaround would be to do a GET call on the merchant-account instead of maintaining state at Hyperswitch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And when does this GET call be executed?

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 looking up the is_merchant_created_in_decision_engine, we can do a GET call instead. These are functionally equivalent right?

Copy link
Contributor Author

@Chethan-rao Chethan-rao Jun 3, 2025

Choose a reason for hiding this comment

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

We didn't want to do this extra call everytime something is toggled. Also your case won't even occur if we switch the is_merchant_created_in_decision_engine flag based on status from create merchant call which will be picked up by @jagan-jaya

};

// Create merchant in Decision Engine if it is not already created
create_merchant_in_decision_engine_if_not_exists(state, profile_id, dynamic_routing_algo_ref)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we move this function to a common location in the routing logic? We need to create a merchant whenever debit routing or dynamic routing is enabled.

Sarthak1799
Sarthak1799 previously approved these changes Jun 3, 2025
@ShankarSinghC ShankarSinghC requested a review from a team as a code owner June 3, 2025 15:54
@Chethan-rao Chethan-rao requested a review from Sarthak1799 June 3, 2025 16:00
jagan-jaya
jagan-jaya previously approved these changes Jun 3, 2025
jagan-jaya
jagan-jaya previously approved these changes Jun 3, 2025
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Jun 3, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jun 3, 2025
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Jun 4, 2025
Merged via the queue into main with commit 835a425 Jun 4, 2025
15 of 20 checks passed
@Gnanasundari24 Gnanasundari24 deleted the add-merchant-creation-in-de branch June 4, 2025 08:50
pixincreate added a commit that referenced this pull request Jun 9, 2025
…tch into cypress/fix

* 'cypress/fix' of github.com:juspay/hyperswitch:
  chore(cypress): run formatter and address lints

* 'main' of github.com:juspay/hyperswitch:
  feat(router): add merchantId authentication for Payments v2 (#8239)
  chore(version): 2025.06.06.0
  Documentation edits made through Mintlify web editor
  Documentation edits made through Mintlify web editor
  feat(router): Return payment_experience in PML for payment (v2) (#8255)
  refactor: add infra-values in intent kafka events (#8264)
  fix(wasm): [Worldpayvantiv] add support for metadata.report_group (#8260)
  chore(version): 2025.06.05.0
  revert(routing): Add connectors from current active routing algorithm before adding fallback connectors (#8207)
  feat(connectors): [Worldpayvantiv] add card support (#8219)
  feat(connectors): [Template] add Worldpayvantiv  (#8226)
  refactor(dynamic_routing): add logic for creating merchant account in decision engine (#8191)
  feat(events): adding infra level components to api-events (#8214)
  chore(version): 2025.06.04.0
  feat(core): add support for consuming eci for AuthNResponse in Authentication flow (#8225)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-routing Area: Routing C-refactor Category: Refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(dynamic_routing): add logic for creating merchant account in decision engine

7 participants