Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(analytics): implement currency conversion to power multi-currency aggregation #6418

Merged
merged 12 commits into from
Nov 6, 2024

Conversation

maverox
Copy link
Contributor

@maverox maverox commented Oct 23, 2024

Type of Change

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

Description

  • implemented currency_conversion for calculating values of amount related metrics from their currency (i.e INR) to
    USD and store it in a separate field variant I created <fieldname>_in_usd
  • Implemented a total_amount_in_usd variant for all the total fields related to amounts in query Metadata

Fixes #6416

Additional Changes

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

Motivation and Context

The total amount calculated for all payment analytics buckets related to amounts is incorrect because currency conversion is not being applied before summing the values. As a result, amounts in different currencies are being added together, leading to an inaccurate total.

Dependency

This functionality depends on currency_conversion crate directly to fetch exchange rates.

How did you test it?

API request for metrics

curl --location 'http://localhost:8080/analytics/v1/org/metrics/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'QueryType: SingleStat' \
--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/130.0.0.0 Safari/537.36' \
--header 'api-key: dev_r3kVZ4URj3fMiHhJJuhHOVqteaXwKyEMGCaFo6PiCS6S9vZsb0ErV4kCVqogM60H' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMDZlOGRmZWYtMzI0Zi00Yjc0LTg2MTItYzdkZjNhOGZmZTcyIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzI3NDM0NTkzIiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTcyOTgzNzUwNywib3JnX2lkIjoib3JnXzl3Y0kxQ2hTOGVEdnRRQmRXak9IIiwicHJvZmlsZV9pZCI6InByb19FNW5lek43YjZUbVB1WlUzbEU1VSJ9.KlBRpu8DpGZ43u9hsB4xE2oSXNM21HC0RadRdfMe2VI' \
--header 'sec-ch-ua: "Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2024-10-13T18:30:00Z",
            "endTime": "2024-10-21T12:54:00Z"
        },
        "mode": "ORDER",
        "source": "BATCH",
        "metrics": [
            
            
            
            
            "payment_processed_amount"
        ],
        "delta": true
    }
]'

API response

{
    "queryData": [
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 150000,
            "payment_processed_amount_usd": 1782,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": 0,
            "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_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "currency": "INR",
            "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,
            "time_range": {
                "start_time": "2024-10-10T18:30:00.000Z",
                "end_time": "2024-10-18T08:24:00.000Z"
            },
            "time_bucket": "2024-10-10 18:30:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 1794006540,
            "payment_processed_amount_usd": 1794006540,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": 0,
            "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_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "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,
            "time_range": {
                "start_time": "2024-10-10T18:30:00.000Z",
                "end_time": "2024-10-18T08:24:00.000Z"
            },
            "time_bucket": "2024-10-10 18:30:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 6540,
            "payment_processed_amount_usd": 7118,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": 0,
            "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_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "currency": "EUR",
            "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,
            "time_range": {
                "start_time": "2024-10-10T18:30:00.000Z",
                "end_time": "2024-10-18T08:24:00.000Z"
            },
            "time_bucket": "2024-10-10 18:30:00"
        }
    ],
    "metaData": [
        {
            "total_payment_processed_amount": 1794163080,
            "total_payment_processed_amount_usd": 1794015440,
            "total_payment_processed_amount_without_smart_retries": 0,
            "total_payment_processed_amount_without_smart_retries_usd": 0,
            "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
        }
    ]
}

Testing for various other scenarios

by tweaking development.toml we can create these scenarios

[forex_api]
call_delay = 30
local_fetch_retry_count = 5
local_fetch_retry_delay = 1000
api_timeout = 20000
api_key = "YOUR PRIMARY API KEY HER" # set this value to anything else to invalidate it
fallback_api_key = "YOUR FALLBACK API KEY HER" # set this value to anything else to invalidate it
redis_lock_timeout = 2600

by setting call_delay to 30s we can check for the fetch cycle and redis updates.

  1. When primary api isn't working (invalidating the primary api key)
Screenshot 2024-10-29 at 12 08 11 AM

API response : 200

  1. when both keys are invalidated
Screenshot 2024-10-29 at 12 10 32 AM Screenshot 2024-10-29 at 12 32 15 AM

API response : 500

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

@maverox maverox self-assigned this Oct 23, 2024
@maverox maverox requested review from a team as code owners October 23, 2024 19:46
@maverox maverox added C-feature Category: Feature request or enhancement A-Analytics labels Oct 23, 2024
@maverox maverox added the Rust Pull requests that update Rust code label Oct 23, 2024
tsdk02
tsdk02 previously approved these changes Oct 25, 2024
@tsdk02 tsdk02 self-requested a review October 28, 2024 11:12
- fallback api doesnt return a USD factor of 1 inside the rates field
like the primary api's response, which was causing different response
when using fall_back api for fetching exchange rates.
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Nov 5, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 5, 2024
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Nov 6, 2024
Merged via the queue into main with commit 01c5216 Nov 6, 2024
24 of 25 checks passed
@Gnanasundari24 Gnanasundari24 deleted the currency-conversion-analytics branch November 6, 2024 09:51
bsayak03 pushed a commit that referenced this pull request Nov 26, 2024
…y aggregation (#6418)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Analytics C-feature Category: Feature request or enhancement Rust Pull requests that update Rust code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat(analytics): implement currency conversion to power multi-currency aggregation
5 participants