Skip to content

Conversation

ShankarSinghC
Copy link
Contributor

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

Description

This pull request introduces a new feature to track and analyze debit routing savings and integrates it across multiple components of the analytics system. It also refactors the handling of co-badged card networks to provide additional details, such as saving percentages. Below is a breakdown of the most important changes grouped by theme:

Debit Routing Analytics Integration:

  • Added a new column debit_routing_savings to the payment_attempt_queue, payment_attempts, and payment_attempt_mv tables in ClickHouse for tracking debit routing savings.
  • Updated the PaymentMetricsAccumulator struct to include a new DebitRoutingAccumulator, which tracks transaction counts and savings amounts. Implemented the necessary methods for metric collection and aggregation.
  • Introduced a new PaymentMetrics::DebitRouting enum variant and its corresponding implementation to load metrics, process data, and convert savings to USD.

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?

-> Enable debit routing for a profile
-> Configure adyen connector with local debit networks enabled
-> Make some debit routing payments

{
    "amount": 1,
    "amount_to_capture": 1,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "setup_future_usage": "on_session",
    "capture_on": "2022-09-10T10:11:12Z",
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+1",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "customer_id": "cu_{{$timestamp}}",
    "return_url": "http://127.0.0.1:4040",
    "payment_method": "card",
    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
            "card_number": "4000 0330 0330 0335",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "card_cvc": "737"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX",
            "last_name": "ss"
        },
        "email": "[email protected]"
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    "browser_info": {
        "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
        "accept_header": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "125.0.0.1"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    }
}
{
    "payment_id": "pay_xrXjk0rlKJG83LNngQ2B",
    "merchant_id": "merchant_1751293949",
    "status": "succeeded",
    "amount": 150000,
    "net_amount": 150000,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 150000,
    "connector": "adyen",
    "client_secret": "pay_xrXjk0rlKJG83LNngQ2B_secret_doz5GI9CEnlmcQoBpiNT",
    "created": "2025-06-30T15:09:44.649Z",
    "currency": "USD",
    "customer_id": "cu_1751296185",
    "customer": {
        "id": "cu_1751296185",
        "name": "John Doe",
        "email": "[email protected]",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "attempts": [
        {
            "attempt_id": "pay_xrXjk0rlKJG83LNngQ2B_1",
            "status": "charged",
            "amount": 150000,
            "order_tax_amount": null,
            "currency": "USD",
            "connector": "adyen",
            "error_message": null,
            "payment_method": "card",
            "connector_transaction_id": "KGRXNH7KQZ9TPM75",
            "capture_method": "automatic",
            "authentication_type": "no_three_ds",
            "created_at": "2025-06-30T15:09:44.649Z",
            "modified_at": "2025-06-30T15:09:45.587Z",
            "cancellation_reason": null,
            "mandate_id": null,
            "error_code": null,
            "payment_token": null,
            "connector_metadata": null,
            "payment_experience": null,
            "payment_method_type": "debit",
            "reference_id": "pay_xrXjk0rlKJG83LNngQ2B_1",
            "unified_code": null,
            "unified_message": null,
            "client_source": null,
            "client_version": null
        }
    ],
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "0335",
            "card_type": null,
            "card_network": "Nyce",
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "400003",
            "card_extended_bin": null,
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": null
        },
        "phone": null,
        "email": null
    },
    "billing": {
        "address": {
            "city": "San",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": "ss"
        },
        "phone": null,
        "email": "[email protected]"
    },
    "order_details": null,
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "http://127.0.0.1:4040/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "debit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "KGRXNH7KQZ9TPM75",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_xrXjk0rlKJG83LNngQ2B_1",
    "payment_link": null,
    "profile_id": "pro_0YmTwtjkst9iUDkg4R5D",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_d1x2St1F4pbgEFYNmxOV",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-06-30T15:24:44.649Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "125.0.0.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1536,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 723,
        "java_script_enabled": true
    },
    "payment_method_id": "pm_pRJ3v7spaJ1pfIsMlAqD",
    "payment_method_status": "active",
    "updated": "2025-06-30T15:09:45.566Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}

-> Payment FIlters

curl --location 'http://localhost:8080/analytics/v1/org/filters/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZTAxZDlhMzgtMDdlMi00ZmFiLTg3ZmYtZWU0NmE2YTU2MDlhIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzUxMjkzOTQ5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc1MTQ2Njc1MSwib3JnX2lkIjoib3JnX2tOa2k3aXBKS1h4NFc3bGVJU3FQIiwicHJvZmlsZV9pZCI6InByb18wWW1Ud3Rqa3N0OWlVRGtnNFI1RCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.jty5ccBH_Em-odSAlde-FQLMC34aoGdV_UYsJFoUN-w' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '{
    "timeRange": {
        "startTime": "2024-09-03T18:30:00.000Z",
        "endTime": "2025-09-12T09:22:30.000Z"
    },
    "groupByNames": [
        "connector",
        "payment_method",
        "payment_method_type",
        "currency",
        "authentication_type",
        "status",
        "client_source",
        "client_version",
        "profile_id",
        "routing_approach"
    ],
    "source": "BATCH",
    "delta": true
}'
{
    "queryData": [
        {
            "dimension": "connector",
            "values": [
                "adyen"
            ]
        },
        {
            "dimension": "payment_method",
            "values": [
                "card"
            ]
        },
        {
            "dimension": "payment_method_type",
            "values": [
                "debit"
            ]
        },
        {
            "dimension": "currency",
            "values": [
                "USD"
            ]
        },
        {
            "dimension": "authentication_type",
            "values": [
                "no_three_ds"
            ]
        },
        {
            "dimension": "status",
            "values": [
                "charged"
            ]
        },
        {
            "dimension": "client_source",
            "values": []
        },
        {
            "dimension": "client_version",
            "values": []
        },
        {
            "dimension": "profile_id",
            "values": [
                "pro_0YmTwtjkst9iUDkg4R5D"
            ]
        },
        {
            "dimension": "routing_approach",
            "values": [
                "default_fallback",
                "debit_routing"
            ]
        }
    ]
}

-> Payment metric that gives total debit routed txn and savings

curl --location 'http://localhost:8080/analytics/v1/org/metrics/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--header 'api-key: dev_cW7LmHwdGurYUqCHLMkUX8AfU9uYzKJc6sT0bsAB1wQJFe6lOP01lRO30Dj0WpcH' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZTAxZDlhMzgtMDdlMi00ZmFiLTg3ZmYtZWU0NmE2YTU2MDlhIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzUxMjkzOTQ5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc1MTQ2Njc1MSwib3JnX2lkIjoib3JnX2tOa2k3aXBKS1h4NFc3bGVJU3FQIiwicHJvZmlsZV9pZCI6InByb18wWW1Ud3Rqa3N0OWlVRGtnNFI1RCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.jty5ccBH_Em-odSAlde-FQLMC34aoGdV_UYsJFoUN-w' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-03-01T18:30:00Z",
            "endTime": "2025-07-31T09:22:00Z"
        },
        
        
        
        
        
        "filters": {
          "routing_approach": [
            "debit_routing"
          ]
        },
        "source": "BATCH",
        "metrics": [
            "debit_routing"
        ],
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "delta": true
    }
]'
{
    "queryData": [
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 8,
            "debit_routing_savings": 369,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": null,
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        }
    ],
    "metaData": [
        {
            "total_payment_processed_amount": 0,
            "total_payment_processed_amount_in_usd": null,
            "total_payment_processed_amount_without_smart_retries": 0,
            "total_payment_processed_amount_without_smart_retries_usd": null,
            "total_payment_processed_count": 0,
            "total_payment_processed_count_without_smart_retries": 0,
            "total_failure_reasons_count": 0,
            "total_failure_reasons_count_without_smart_retries": 0
        }
    ]
}

-> Payment metrics that gives savings per txn

curl --location 'http://localhost:8080/analytics/v1/org/metrics/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--header 'api-key: dev_cW7LmHwdGurYUqCHLMkUX8AfU9uYzKJc6sT0bsAB1wQJFe6lOP01lRO30Dj0WpcH' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZTAxZDlhMzgtMDdlMi00ZmFiLTg3ZmYtZWU0NmE2YTU2MDlhIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzUxMjkzOTQ5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc1MTQ2Njc1MSwib3JnX2lkIjoib3JnX2tOa2k3aXBKS1h4NFc3bGVJU3FQIiwicHJvZmlsZV9pZCI6InByb18wWW1Ud3Rqa3N0OWlVRGtnNFI1RCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.jty5ccBH_Em-odSAlde-FQLMC34aoGdV_UYsJFoUN-w' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-03-01T18:30:00Z",
            "endTime": "2025-07-31T09:22:00Z"
        },
        "groupByNames": [
            "card_network"
        ],
        
        
        "filters": {
          "routing_approach": [
            "debit_routing"
          ]
        },
        "source": "BATCH",
        "metrics": [
            "debit_routing"
        ],
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "delta": true
    }
]'
{
    "queryData": [
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 2,
            "debit_routing_savings": 107,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Star",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 2,
            "debit_routing_savings": 199,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Nyce",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 3,
            "debit_routing_savings": 0,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Visa",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 1,
            "debit_routing_savings": 63,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Accel",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        }
    ],
    "metaData": [
        {
            "total_payment_processed_amount": 0,
            "total_payment_processed_amount_in_usd": null,
            "total_payment_processed_amount_without_smart_retries": 0,
            "total_payment_processed_amount_without_smart_retries_usd": null,
            "total_payment_processed_count": 0,
            "total_payment_processed_count_without_smart_retries": 0,
            "total_failure_reasons_count": 0,
            "total_failure_reasons_count_without_smart_retries": 0
        }
    ]
}

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

@ShankarSinghC ShankarSinghC self-assigned this Jul 2, 2025
@ShankarSinghC ShankarSinghC requested review from a team as code owners July 2, 2025 07:21
@ShankarSinghC ShankarSinghC added A-core Area: Core flows M-database-changes Metadata: This PR involves database schema changes A-routing Area: Routing A-Analytics labels Jul 2, 2025
Copy link

semanticdiff-com bot commented Jul 2, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/core/payment_methods/tokenize.rs  83% smaller
  crates/router/src/core/payment_methods.rs  80% smaller
  crates/router/src/db/kafka_store.rs  72% smaller
  crates/router/src/core/debit_routing.rs  50% smaller
  crates/api_models/src/open_router.rs  49% smaller
  crates/hyperswitch_domain_models/src/api.rs  25% smaller
  crates/api_models/src/payment_methods.rs  9% smaller
  crates/api_models/src/analytics/payments.rs  8% smaller
  crates/hyperswitch_domain_models/src/payments/payment_attempt.rs  7% smaller
  crates/router/src/core/payments.rs  4% smaller
  crates/router/src/core/payments/retry.rs  1% smaller
  crates/hyperswitch_domain_models/src/payment_method_data.rs  1% smaller
  crates/analytics/docs/clickhouse/scripts/payment_attempts.sql Unsupported file format
  crates/analytics/src/payments/accumulator.rs  0% smaller
  crates/analytics/src/payments/core.rs  0% smaller
  crates/analytics/src/payments/metrics.rs  0% smaller
  crates/analytics/src/payments/metrics/debit_routing.rs  0% smaller
  crates/analytics/src/payments/metrics/sessionized_metrics.rs  0% smaller
  crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs  0% smaller
  crates/router/src/core/payments/helpers.rs  0% smaller
  crates/router/src/core/payments/operations/payment_response.rs  0% smaller
  crates/router/src/core/routing/transformers.rs  0% smaller
  crates/router/src/services/kafka/payment_attempt.rs  0% smaller
  crates/router/src/services/kafka/payment_attempt_event.rs  0% smaller
  crates/storage_impl/src/mock_db/payment_attempt.rs  0% smaller
  crates/storage_impl/src/payments/payment_attempt.rs  0% smaller

@hyperswitch-bot hyperswitch-bot bot removed the M-database-changes Metadata: This PR involves database schema changes label Jul 2, 2025
@ShankarSinghC ShankarSinghC linked an issue Jul 2, 2025 that may be closed by this pull request
@@ -128,6 +129,7 @@ impl ForexMetric for PaymentMetrics {
self,
Self::PaymentProcessedAmount
| Self::AvgTicketSize
// add here New Metric
Copy link
Contributor

@tsdk02 tsdk02 Jul 2, 2025

Choose a reason for hiding this comment

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

Can add Self::DebitRouting here and can remove this comment
This is for the forex conversion of other currencies to USD for debit_routing_savings

@@ -1073,6 +1074,10 @@ impl PaymentAttempt {
pub fn get_total_surcharge_amount(&self) -> Option<MinorUnit> {
self.net_amount.get_total_surcharge_amount()
}

pub fn set_debit_routing_savings(&mut self, debit_routing_savings: Option<&MinorUnit>) {
self.debit_routing_savings = debit_routing_savings.copied();
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you explain why we have used .copied() here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

debit_routing_savings is an optional reference: Option<&MinorUnit>
self.debit_routing_savings is of type Option, not a reference

Comment on lines +1759 to +1786
pub fn get_debit_routing_savings(&self) -> Option<&MinorUnit> {
match self {
Self::ResponseUpdate {
debit_routing_savings,
..
} => debit_routing_savings.as_ref(),
Self::Update { .. }
| Self::UpdateTrackers { .. }
| Self::AuthenticationTypeUpdate { .. }
| Self::ConfirmUpdate { .. }
| Self::RejectUpdate { .. }
| Self::BlocklistUpdate { .. }
| Self::PaymentMethodDetailsUpdate { .. }
| Self::ConnectorMandateDetailUpdate { .. }
| Self::VoidUpdate { .. }
| Self::UnresolvedResponseUpdate { .. }
| Self::StatusUpdate { .. }
| Self::ErrorUpdate { .. }
| Self::CaptureUpdate { .. }
| Self::AmountToCaptureUpdate { .. }
| Self::PreprocessingUpdate { .. }
| Self::ConnectorResponse { .. }
| Self::IncrementalAuthorizationAmountUpdate { .. }
| Self::AuthenticationUpdate { .. }
| Self::ManualUpdate { .. }
| Self::PostSessionTokensUpdate { .. } => None,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be done in any simpler way?

@tsdk02
Copy link
Contributor

tsdk02 commented Jul 2, 2025

You might have to create another metric, say SessionizedDebitRouting as you would be populating debit_routing_savings through the Sessionizer, and querying will also need to be done through the Sessionizer Payment Attempt table. The new metric which you have currently added will query Payment Attempts table in Clickhouse, where debit_routing_savings may not be populated.

The changes can be similar to DebitRouting metric you have created. You can refer to the sessionized_metrics directory under payments in the analytics section for reference.

@@ -281,7 +281,10 @@ where
&profile_id,
&key_store,
vec![connector_data.clone()],
debit_routing_output.get_co_badged_card_networks(),
open_router::CoBadgedCardNetworks(
debit_routing_output.co_badged_card_networks_info.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

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

debit_routing_output.co_badged_card_networks_info can be a domain type

@@ -451,6 +451,13 @@ where
.and_then(|connector_response| connector_response.additional_payment_method_data),
)?;

let debit_routing_savings = payment_data.get_payment_method_data().and_then(|data| {
payments::helpers::get_debit_routing_savings_amount(
Copy link
Contributor

Choose a reason for hiding this comment

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

get_debit_routing_savings_amount can be a impl based fn on get_payment_method_data

@@ -5209,6 +5211,85 @@ pub fn get_applepay_metadata(
})
}

pub fn extract_saving_percentage(
Copy link
Contributor

Choose a reason for hiding this comment

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

can move this to impl based fn as well

"Calculating debit routing saving amount"
);

let savings_float = (net_amount * (saving_percentage / 100.0)).round();
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 somehow avoid two step conversion?

@ShankarSinghC ShankarSinghC requested a review from tsdk02 July 3, 2025 17:20
@@ -128,6 +130,7 @@ impl ForexMetric for PaymentMetrics {
self,
Self::PaymentProcessedAmount
| Self::AvgTicketSize
| Self::DebitRouting
Copy link
Contributor

@tsdk02 tsdk02 Jul 3, 2025

Choose a reason for hiding this comment

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

Add the SessionizedDebitRouting metric here as well
(To enable the currency conversion from other currencies to USD for debit_routing_savings)

tsdk02
tsdk02 previously approved these changes Jul 3, 2025
@ShankarSinghC ShankarSinghC dismissed stale reviews from sai-harsha-vardhan and tsdk02 via c0a1a9a July 3, 2025 18:02
Copy link
Contributor

@prasunna09 prasunna09 left a comment

Choose a reason for hiding this comment

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

Payment method changes looks good to me!

@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Jul 4, 2025
Merged via the queue into main with commit fc3c64f Jul 4, 2025
17 of 20 checks passed
@Gnanasundari24 Gnanasundari24 deleted the debit-routing/analytics/add-savings branch July 4, 2025 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Analytics A-core Area: Core flows A-routing Area: Routing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add debit_routing_savings in analytics payment attempt
6 participants