Skip to content

Conversation

Sakilmostak
Copy link
Contributor

@Sakilmostak Sakilmostak commented Apr 9, 2025

Type of Change

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

Description

  • In list payment method for merchant, list both mandate and non-mandate payment methods unless it is zero mandate flow
  • If the setup_future_usage is off_session for a payment method, downgrade it to on_session for that payment method
  • Add config for the zero mandates (being used in list payment method for merchant)
  • Add setup_future_usage field to payment_attempt to keep track of it for every attempt made

Below contains the new filtering logic:
image

Below represents the PaymentType for each payment_method_type during list call based the following parameters:
image

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
Added setup_future_usage column to payment_attempt table
  • This PR modifies application configuration/environment variables
Added filter config for zero_mandates.
This represent the combination of payment_method, payment_method_type and connector for which zero_mandate flow is present

Motivation and Context

How did you test it?

Testing Payment Method List for Merchant:

Curls:

  1. Create Payment
curl --location '{{baseUrl}}/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: {{api_key}}' \
--data-raw '{
    "amount": 10,
    "currency": "USD",
    "confirm": false,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "customer_id": "{{customer_id}}",
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://duck.com",
    "billing": {
        "address": {
            "city": "test",
            "country": "HR",
            "line1": "here is some \n there is some \n none is some? \n ",
            "line2": "there",
            "line3": "anywhere",
            "zip": "560095",
            "state": "Varaždin County",
            "first_name": "S@k!l",
            "last_name": "M*st@k"
        }
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX"
        }
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
   "setup_future_usage": "off_session",
}'
  1. Payment Method List for Merchant
curl --location '{{baseUrl}}/account/payment_methods?client_secret={{client_secret}}' \
--header 'Accept: application/json' \
--header 'api-key: {{api_key}}'

Scenarios:
Case 1: Non-zero amount and setup_future_usage as on_session
Result:

  • Payment Method List should have all the payment method type selected by merchant

Case 2: Non-zero amount and setup_future_usage as off_session
Result:

  • Payment Method List should have all the payment method type selected by merchant

Case 3: Zero amount and setup_future_usage as on_session
Result:

  • Payment Method List should have all the payment method type selected by merchant

Case 4: Zero amount and setup_future_usage as off_session
Result:

  • Payment Method List should filter the payment method type based on whether zero mandate is supported
Testing setup_future_usage downgrade logic:

Curls:
Payment Create+Confirm:

curl --location '{{baseUrl}}/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: ••••••' \
--data-raw '{
    "amount": 141,
    "currency": "EUR",
    "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "customer_id": "StripeCustomer",
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+1",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
    "payment_method": "gift_card",
    "payment_method_type": "givex",
    "payment_method_data": {
        "gift_card": {
            "givex": {
                "number": "{{gift_card_number}}",
                "cvc": "{{gift_card_cvc}}"
            }
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "GB",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "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": "127.0.0.1"
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "GB",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "setup_future_usage": "off_session"
}'

Scenarios:
Case 1: Create a payment with cards for Adyen with setup_future_usage as off_session
Result:

  • The response should contain payment_method_id and setup_future_usage as off_session
    Reason:
  • Since card for adyen support mandates, the filter allowed for the creation of mandate

Case 2: Create a payment with gift cards for Adyen with setup_future_usage as off_session
Result:

  • In response, setup_future_usage should be on_session with payment_method_id as null
    Reason:
  • setup_future_usage is downgraded to on_session since mandate is not supported by gift card for adyen

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

@Sakilmostak Sakilmostak added C-feature Category: Feature request or enhancement M-database-changes Metadata: This PR involves database schema changes A-payment-methods Area: Payment Methods labels Apr 9, 2025
@Sakilmostak Sakilmostak added this to the April 2025 Release milestone Apr 9, 2025
@Sakilmostak Sakilmostak self-assigned this Apr 9, 2025
@Sakilmostak Sakilmostak requested review from a team as code owners April 9, 2025 11:36
Copy link

semanticdiff-com bot commented Apr 9, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/core/payment_methods/cards.rs  2% smaller
  crates/router/src/configs/defaults/payment_connector_required_fields.rs  1% smaller
  config/config.example.toml Unsupported file format
  config/deployments/integration_test.toml Unsupported file format
  config/deployments/production.toml Unsupported file format
  config/deployments/sandbox.toml Unsupported file format
  config/development.toml Unsupported file format
  config/docker_compose.toml Unsupported file format
  crates/diesel_models/src/payment_attempt.rs  0% smaller
  crates/diesel_models/src/schema.rs  0% smaller
  crates/diesel_models/src/user/sample_data.rs  0% smaller
  crates/hyperswitch_domain_models/src/payments/payment_attempt.rs  0% smaller
  crates/router/src/configs/secrets_transformers.rs  0% smaller
  crates/router/src/configs/settings.rs  0% smaller
  crates/router/src/core/payments/flows/authorize_flow.rs  0% smaller
  crates/router/src/core/payments/helpers.rs  0% smaller
  crates/router/src/core/payments/operations/payment_create.rs  0% smaller
  crates/router/src/core/payments/operations/payment_response.rs  0% smaller
  crates/router/src/core/payments/retry.rs  0% smaller
  crates/router/src/core/payments/transformers.rs  0% smaller
  crates/router/src/types/storage/payment_attempt.rs  0% smaller
  crates/router/src/utils/user/sample_data.rs  0% smaller
  crates/storage_impl/src/mock_db/payment_attempt.rs  0% smaller
  crates/storage_impl/src/payments/payment_attempt.rs  0% smaller
  migrations/2025-04-09-074315_add_setup_future_usage_to_payment_attempt/down.sql Unsupported file format
  migrations/2025-04-09-074315_add_setup_future_usage_to_payment_attempt/up.sql Unsupported file format
  v2_migrations/2025-01-13-081847_drop_v1_columns/up.sql Unsupported file format

Copy link
Contributor

@kashif-m kashif-m left a comment

Choose a reason for hiding this comment

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

Looks good, added some nits and comments

kashif-m
kashif-m previously approved these changes Apr 10, 2025
Copy link
Contributor

@kashif-m kashif-m left a comment

Choose a reason for hiding this comment

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

Looks good 👍

@Sakilmostak Sakilmostak requested a review from a team as a code owner April 15, 2025 13:00
tsdk02
tsdk02 previously approved these changes Apr 15, 2025
@@ -4500,6 +4500,7 @@ impl AttemptType {
extended_authorization_applied: None,
capture_before: None,
card_discovery: None,
setup_future_usage: old_payment_attempt.setup_future_usage,
Copy link
Member

Choose a reason for hiding this comment

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

In retry is this use the old attempts setup future usage or this should be none and calculate actual future usage while doing the next attempt

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For each new payment_attempt of retry, the setup_future_usage will be picked from payment_intent since retry calls call_connector_service on every attempt meaning the downgrade logic is ran everytime.

kashif-m
kashif-m previously approved these changes Apr 16, 2025
@Sakilmostak Sakilmostak removed the request for review from a team April 16, 2025 09:42
@likhinbopanna likhinbopanna added this pull request to the merge queue Apr 17, 2025
Merged via the queue into main with commit d061e0a Apr 17, 2025
16 of 20 checks passed
@likhinbopanna likhinbopanna deleted the pml_config_change branch April 17, 2025 12:09
pixincreate added a commit that referenced this pull request Apr 21, 2025
…acilitapay-pix-pmt

* 'main' of github.com:juspay/hyperswitch: (21 commits)
  refactor(required_fields): move pm required fields to pm crate (#7539)
  fix(connector): [noon] address `next_action_url` being `null` for cards in 3ds payment (#7832)
  refactor(middleware): add middleware to record metrics for request count and duration (#7803)
  chore(version): 2025.04.18.0
  chore(postman): update Postman collection files
  fix(connector): [globalpay] handle edge case where currency comes as empty upon payment decline (#7812)
  refactor(cypress-v2): change `Authorization` and `payment_methods_enabled` for v2 cypress tests (#7805)
  fix(connector): [Cybersource] send type selection indicator for co-batch cards (#7828)
  feat(payment_method): add logic for setup_future_usage downgrade and add filter based on zero mandate config (#7775)
  refactor(accounts): move dashboard_metadata table to accounts_schema and point v2 to v1 dashboard_metadata (#7793)
  chore(analytics): opensearch client creation based on config (#7810)
  ci(postman): update assertion error message for nmi collection (#7765)
  feat: add primary key not null query to generic filter function (#7785)
  chore(version): 2025.04.17.0
  chore: change payment method files ownership to `hyperswitch-payment-methods` (#7808)
  feat(vsaas): modify api key auth to support vsaas cases (#7593)
  ci(cypress): verify mandate id to be `null` if payment id not `succeeded` (#7749)
  feat(connector): [chargebee] consumes required fields to support transaction monitoring (#7774)
  ci(configs): remove vault private key from configs (#7825)
  chore(version): 2025.04.16.0
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-payment-methods Area: Payment Methods C-feature Category: Feature request or enhancement M-database-changes Metadata: This PR involves database schema changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants