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

Refactor(core): Inclusion of constraint graph for merchant Payment Method list #4626

Merged
merged 44 commits into from
May 24, 2024

Conversation

prajjwalkumar17
Copy link
Contributor

@prajjwalkumar17 prajjwalkumar17 commented May 13, 2024

Type of Change

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

Description

Adds CGraphing for Merchant Pms with all the possible filters applicable as described below.

Addressed in this PR:

1 Creation of Constraint Graph for Merchant Payment Method List:

Created a Constraint Graph with the following filters/Nodes:

From configs and MCA:

  1. Countries Filter
  2. Currency Filter
  3. Supported for Mandates Filter
  4. Allowed Payment Method Types
  5. Supported for Update Mandates Filter
  6. Capture Method Used

From Req:

  1. Recurring Enabled
  2. Installment Enabled
  3. Amount Based

After Applying all these Filters and creating a Graph for a Merchant MCA with 2 PMT enabled (Credit and Debit) with one connector(Cybersource), We will get a graph equivalent to this

graphviz (3)

Henceforth, we will verify the constraints by constructing Context from our PaymentIntent and PaymentAttempt.
PM List for Merchant curl:

curl --location 'http://127.0.0.1:8080/account/payment_methods?client_secret=pay_RtUquUfJt9sSheQNpqdR_secret_6BOkQMk1fYNq5zCgOdYr' \
--header 'Accept: application/json' \
--header 'api-key: pk_dev_423ae8fdc10d4db0bf28eda1662f51a3' \
--data ''

2 Moka Caching of Pm Filter Graph:

We have even implemented Moka(In memory) Cashing mechanism for our CGraph to minimize the latency. So for every request first the cache value will be checked if present, derived and used else CGraph will be constructed and the cache will be refreshed.
Screenshot 2024-05-23 at 14 54 28

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?

Testing requires creation/refactoring of our configs:
The configs followed are as follows:-

[pm_filters.stripe]
google_pay = { country = "CN" }
apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US,KR,VN,MA,ZA,VA,CL,SV,GT,HN,PA" }

[pm_filters.cybersource]
credit = { not_available_flows = { capture_method = "manual" }, country = "AU, JP, IQ, US", currency = "INR"}
google_pay = { country = "AU,US", currency = "INR" }
debit = { country = "AU,IN, US", currency = "INR" }

Flow followed

Request 1: mca create request (Cybersource)

curl --location 'http://127.0.0.1:8080/account/merchant_1716536756/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
    "connector_type": "fiz_operations",
    "business_country": "US",
    "business_label": "default",
    "connector_name": "cybersource",
    "connector_account_details": {
        "auth_type": "SignatureKey",
        "api_key": "xxxx",
        "api_secret": "xxxxx",
        "key1": "juspay_us_sandbox"
    },
    "test_mode": true,
    "disabled": false,
    "payment_methods_enabled": [
        {
            "payment_method": "card",
            "payment_method_types": [
                {
                    "payment_method_type": "debit",
                    "payment_experience": null,
                    "card_networks": [
                        "Visa",
                        "Mastercard"
                    ],
                    "accepted_currencies": {
                        "type": "enable_only",
                        "list": [
                            "INR"
                        ]
                    },
                    "accepted_countries": {
                        "type": "enable_only",
                        "list": [
                            "JP",
                            "US"
                        ]
                    },
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "credit",
                    "payment_experience": null,
                    "card_networks": [
                        "Visa",
                        "Mastercard"
                    ],
                    "accepted_currencies": {
                        "type": "all_accepted"
                    },
                    "accepted_countries": {
                        "type": "enable_only",
                        "list": [
                            "JP",
                            "US"
                        ]
                    },
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        }
    ],
    "connector_webhook_details": {
        "merchant_secret": "chethanaaaa"
    }
}'

Request 2: mca create request (Stripe)

curl --location 'http://127.0.0.1:8080/account/merchant_1716536756/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
    "connector_type": "fiz_operations",
    "connector_name": "stripe",
    "business_country": "US",
    "business_label": "default",
    "connector_account_details": {
        "auth_type": "HeaderKey",
        "api_key": "{{connector_api_key}}"
    },
    "test_mode": false,
    "disabled": false,
    "payment_methods_enabled": [
        {
            "payment_method": "pay_later",
            "payment_method_types": [
                {
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "payment_experience": "redirect_to_url",
                    "payment_method_type": "affirm"
                }
            ]
        },
        {
            "payment_method": "pay_later",
            "payment_method_types": [
                {
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "payment_experience": "redirect_to_url",
                    "payment_method_type": "klarna"
                }
            ]
        },
        {
            "payment_method": "bank_redirect",
            "payment_method_types": [
                {
                    "payment_method_type": "ideal",
                    "payment_experience": null,
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "eps",
                    "payment_experience": null,
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "bank_debit",
            "payment_method_types": [
                {
                    "payment_method_type": "sepa",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "bank_transfer",
            "payment_method_types": [
                {
                    "payment_method_type": "sepa",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "card",
            "payment_method_types": [
                {
                    "payment_method_type": "credit",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "card_networks": [
                        "AmericanExpress",
                        "Discover",
                        "Interac",
                        "JCB",
                        "Mastercard",
                        "Visa",
                        "DinersClub",
                        "UnionPay",
                        "RuPay"
                    ]
                }
            ]
        },
        {
            "payment_method": "card",
            "payment_method_types": [
                {
                    "payment_method_type": "debit",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "card_networks": [
                        "AmericanExpress",
                        "Discover",
                        "Interac",
                        "JCB",
                        "Mastercard",
                        "Visa",
                        "DinersClub",
                        "UnionPay",
                        "RuPay"
                    ]
                }
            ]
        },
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "apple_pay",
                    "payment_experience": "invoke_sdk_client",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "google_pay",
                    "payment_experience": "invoke_sdk_client",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "we_chat_pay",
                    "payment_experience": "invoke_sdk_client",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        }
    ],
    "metadata": {
        "google_pay": {
            "allowed_payment_methods": [
                {
                    "type": "CARD",
                    "parameters": {
                        "allowed_auth_methods": [
                            "PAN_ONLY",
                            "CRYPTOGRAM_3DS"
                        ],
                        "allowed_card_networks": [
                            "AMEX",
                            "DISCOVER",
                            "INTERAC",
                            "JCB",
                            "MASTERCARD",
                            "VISA"
                        ]
                    },
                    "tokenization_specification": {
                        "type": "PAYMENT_GATEWAY",
                        "parameters": {
                            "gateway": "example",
                            "gateway_merchant_id": "{{gateway_merchant_id}}"
                        }
                    }
                }
            ],
            "merchant_info": {
                "merchant_name": "PK"
            }
        }
    }
}'

Request 3: Payment Create Request (with capture_method = manual)

curl --location 'http://127.0.0.1:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_ee3RmaC8hkDWCibMrIk8AVzIzn1mK0yrQq5dJImuhr61np4mMHcRlGNFATZp0rcQ' \
--data-raw '
{
    "amount": 6540,
    "currency": "INR",
    "confirm": false,
    "capture_method": "manual",
    "capture_on": "2022-09-10T10:11:12Z",
    "amount_to_capture": 6540,
    "customer_id": "cus26",
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
    "setup_future_usage": "on_session",
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "127.0.0.1",
            "user_agent": "amet irure esse"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "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"
    },
    "routing": {
        "type": "single",
        "data": "stripe"
    }
}
'

Request 3: List Merchant Payment Methods

curl --location 'http://127.0.0.1:8080/account/payment_methods?client_secret=pay_pjPrnplx4iezrnZVq9OP_secret_G0Oc8N6SoTMKJpfYMEqZ' \
--header 'Accept: application/json' \
--header 'api-key: pk_dev_a5ea68aa142c4bb8ad07d0570166d26a' \
--data ''

Response
Google pay won't come as we have added in configs allowed country as CN
Payment Type Card(Credit) also won't come as the configs for credit has not_available_flows = manual

{
    "redirect_url": "https://google.com/success",
    "currency": "INR",
    "payment_methods": [
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "apple_pay",
                    "payment_experience": [
                        {
                            "payment_experience_type": "invoke_sdk_client",
                            "eligible_connectors": [
                                "stripe"
                            ]
                        }
                    ],
                    "card_networks": null,
                    "bank_names": null,
                    "bank_debits": null,
                    "bank_transfers": null,
                    "required_fields": {},
                    "surcharge_details": null,
                    "pm_auth_connector": null
                },
                {
                    "payment_method_type": "we_chat_pay",
                    "payment_experience": [
                        {
                            "payment_experience_type": "invoke_sdk_client",
                            "eligible_connectors": [
                                "stripe"
                            ]
                        }
                    ],
                    "card_networks": null,
                    "bank_names": null,
                    "bank_debits": null,
                    "bank_transfers": null,
                    "required_fields": {},
                    "surcharge_details": null,
                    "pm_auth_connector": null
                }
            ]
        },
        {
            "payment_method": "pay_later",
            "payment_method_types": [
                {
                    "payment_method_type": "affirm",
                    "payment_experience": [
                        {
                            "payment_experience_type": "redirect_to_url",
                            "eligible_connectors": [
                                "stripe"
                            ]
                        }
                    ],
                    "card_networks": null,
                    "bank_names": null,
                    "bank_debits": null,
                    "bank_transfers": null,
                    "required_fields": {},
                    "surcharge_details": null,
                    "pm_auth_connector": null
                }
            ]
        },
        {
            "payment_method": "card",
            "payment_method_types": [
                {
                    "payment_method_type": "debit",
                    "payment_experience": null,
                    "card_networks": [
                        {
                            "card_network": "Visa",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "cybersource",
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "JCB",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "UnionPay",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "AmericanExpress",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "Discover",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "Interac",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "RuPay",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "DinersClub",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "stripe"
                            ]
                        },
                        {
                            "card_network": "Mastercard",
                            "surcharge_details": null,
                            "eligible_connectors": [
                                "cybersource",
                                "stripe"
                            ]
                        }
                    ],
                    "bank_names": null,
                    "bank_debits": null,
                    "bank_transfers": null,
                    "required_fields": {
                        "billing.address.last_name": {
                            "required_field": "payment_method_data.billing.address.last_name",
                            "display_name": "card_holder_name",
                            "field_type": "user_full_name",
                            "value": "Doe"
                        },
                        "billing.address.first_name": {
                            "required_field": "payment_method_data.billing.address.first_name",
                            "display_name": "card_holder_name",
                            "field_type": "user_full_name",
                            "value": "joseph"
                        },
                        "billing.address.city": {
                            "required_field": "payment_method_data.billing.address.city",
                            "display_name": "city",
                            "field_type": "user_address_city",
                            "value": "San Fransico"
                        },
                        "payment_method_data.card.card_number": {
                            "required_field": "payment_method_data.card.card_number",
                            "display_name": "card_number",
                            "field_type": "user_card_number",
                            "value": null
                        },
                        "payment_method_data.card.card_cvc": {
                            "required_field": "payment_method_data.card.card_cvc",
                            "display_name": "card_cvc",
                            "field_type": "user_card_cvc",
                            "value": null
                        },
                        "billing.address.zip": {
                            "required_field": "payment_method_data.billing.address.zip",
                            "display_name": "zip",
                            "field_type": "user_address_pincode",
                            "value": "94122"
                        },
                        "payment_method_data.card.card_exp_year": {
                            "required_field": "payment_method_data.card.card_exp_year",
                            "display_name": "card_exp_year",
                            "field_type": "user_card_expiry_year",
                            "value": null
                        },
                        "payment_method_data.card.card_exp_month": {
                            "required_field": "payment_method_data.card.card_exp_month",
                            "display_name": "card_exp_month",
                            "field_type": "user_card_expiry_month",
                            "value": null
                        },
                        "email": {
                            "required_field": "email",
                            "display_name": "email",
                            "field_type": "user_email_address",
                            "value": null
                        },
                        "billing.address.line1": {
                            "required_field": "payment_method_data.billing.address.line1",
                            "display_name": "line1",
                            "field_type": "user_address_line1",
                            "value": "1467"
                        },
                        "billing.address.state": {
                            "required_field": "payment_method_data.billing.address.state",
                            "display_name": "state",
                            "field_type": "user_address_state",
                            "value": "California"
                        },
                        "billing.address.country": {
                            "required_field": "payment_method_data.billing.address.country",
                            "display_name": "country",
                            "field_type": {
                                "user_address_country": {
                                    "options": [
                                        "ALL"
                                    ]
                                }
                            },
                            "value": "US"
                        }
                    },
                    "surcharge_details": null,
                    "pm_auth_connector": null
                }
            ]
        },
        {
            "payment_method": "bank_debit",
            "payment_method_types": [
                {
                    "payment_method_type": "sepa",
                    "payment_experience": null,
                    "card_networks": null,
                    "bank_names": null,
                    "bank_debits": {
                        "eligible_connectors": [
                            "stripe"
                        ]
                    },
                    "bank_transfers": null,
                    "required_fields": {
                        "billing.address.first_name": {
                            "required_field": "payment_method_data.billing.address.first_name",
                            "display_name": "billing_first_name",
                            "field_type": "user_billing_name",
                            "value": "joseph"
                        }
                    },
                    "surcharge_details": null,
                    "pm_auth_connector": null
                }
            ]
        },
        {
            "payment_method": "bank_transfer",
            "payment_method_types": [
                {
                    "payment_method_type": "sepa",
                    "payment_experience": null,
                    "card_networks": null,
                    "bank_names": null,
                    "bank_debits": null,
                    "bank_transfers": {
                        "eligible_connectors": [
                            "stripe"
                        ]
                    },
                    "required_fields": null,
                    "surcharge_details": null,
                    "pm_auth_connector": null
                }
            ]
        }
    ],
    "mandate_payment": null,
    "merchant_name": "Prajjwal",
    "show_surcharge_breakup_screen": false,
    "payment_type": "normal"
}

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

@prajjwalkumar17 prajjwalkumar17 self-assigned this May 13, 2024
@prajjwalkumar17 prajjwalkumar17 marked this pull request as draft May 13, 2024 07:09
@prajjwalkumar17 prajjwalkumar17 changed the title Refac/cg inclusion pm Refactor(core): Inclusion of constraint graph for merchant Payment Method list May 13, 2024
@prajjwalkumar17 prajjwalkumar17 requested a review from a team as a code owner May 23, 2024 06:29
crates/router/src/core/payment_methods/cards.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/cards.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/cards.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/cards.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/cards.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/utils.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/utils.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/utils.rs Outdated Show resolved Hide resolved
crates/router/src/core/payment_methods/utils.rs Outdated Show resolved Hide resolved
Comment on lines +3000 to +3008
payment_attempt
.and_then(|inner| inner.capture_method)
.and_then(|capture_method| {
(capture_method == common_enums::CaptureMethod::Manual).then(|| {
context_values.push(dir::DirValue::CaptureMethod(
common_enums::CaptureMethod::Manual,
));
})
});
Copy link
Member

Choose a reason for hiding this comment

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

Moreover will using then in above code will produce some latency or something. Just curious to know why it should be converted to an if.

Using functional style code like this is more appropriate when your code is supposed to return a value (that's what the function signatures of and_then() and then() denote. Here we're not returning a value, we're performing an action with side effects, which is non-functional i.e. imperative, hence an if would be more suitable.

@likhinbopanna likhinbopanna added this pull request to the merge queue May 24, 2024
Merged via the queue into main with commit 2cabb0b May 24, 2024
13 checks passed
@likhinbopanna likhinbopanna deleted the refac/cg_inclusion_pm branch May 24, 2024 12:19
pixinwork pushed a commit that referenced this pull request May 29, 2024
…actor

* 'main' of github.com:juspay/hyperswitch: (39 commits)
  Fix(Cypress): Fixing 3DS payment failure in headless mode (#4807)
  feat(users): Add redis in Begin and Verify TOTP and create a new API that updates TOTP (#4765)
  refactor(connector): [Klarna] Refactor Authorize call and configs for prod (#4750)
  fix: implement StrongEq for Vec<u8> (#4795)
  refactor(core): move router data response and request models to hyperswitch domain models crate (#4789)
  chore(version): 2024.05.29.0
  refactor: retrieve extended card info config during business profile get call (#4784)
  refactor(payment_methods): add support for passing ttl to locker entries (#4690)
  feat(connector): [CRYPTOPAY] Pass network details in payment request (#4779)
  fix: include client columns in payment attempts response struct (#4761)
  fix(docker-compose): fix docker compose syntax (#4782)
  feat(connector): [Iatapay] add upi qr support (#4728)
  docs(analytics): Add documentation for setting up data services and enabling data features in control center (#4741)
  chore(version): 2024.05.28.0
  feat(connector): [AUTHORIZEDOTNET] Implement non-zero mandates (#4758)
  feat(core): [Paypal] Add session_token flow for Paypal sdk (#4697)
  chore(version): 2024.05.27.0
  chore: add missing migrations for recently added currencies (#4760)
  Refactor(core): Inclusion of constraint graph for merchant Payment Method list (#4626)
  chore(version): 2024.05.24.1
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-constraint-graph Area: Constraint Graph A-core Area: Core flows C-refactor Category: Refactor
Projects
None yet
4 participants