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(core): add payments post_session_tokens flow #6325

Closed
wants to merge 2 commits into from

Conversation

swangi-kumari
Copy link
Contributor

@swangi-kumari swangi-kumari commented Oct 15, 2024

Type of Change

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

Description

hotfix for PR

  1. Add support for a new endpoint post_session_tokens which can be called before the confirm call.

Use Case

  • In PayPal, after the session call, when we click the PayPal button, we need to create an order. Previously, this was done in the /confirm call, and in response, we received the order_id / connector_transaction_id. We would then send this information to the HS SDK, which forwarded it to PayPal. PayPal used this data to render their SDK, allowing the user to log in and modify the shipping address. The user would then click "Complete Purchase," triggering the OnApprove callback, which was handled by the /complete_authorize call.
  • The /confirm call happens at the point of order creation, but we receive the shipping address after that. At that stage, we make a call to TaxJar, and the order's tax amount is added. However, since the /confirm call has already happened, we can't change/update the amount at that point. This was the reason for creating the new flow, where the order creation happens in the /post_session_tokens call, and the /confirm call occurs after tax calculation.
  • After this refactoring, the CreateOrder step will be handled in the /post_session_tokens call, and the OnApprove action will be handled in the /confirm call.
  1. Populate Dynamic Fields for Paypal

Additional Changes

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

Motivation and Context

How did you test it?

  1. Create Merchant Account
curl --location 'http://localhost:8080/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data-raw '{
  "merchant_id": "merchant_1728546485",
  "locker_id": "m0010",
  "merchant_name": "NewAge Retailer",
  "merchant_details": {
    "primary_contact_person": "John Test",
    "primary_email": "[email protected]",
    "primary_phone": "sunt laborum",
    "secondary_contact_person": "John Test2",
    "secondary_email": "[email protected]",
    "secondary_phone": "cillum do dolor id",
    "website": "https://www.example.com",
    "about_business": "Online Retail with a wide selection of organic products for North America",
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US"
    }
  },
  "return_url": "https://google.com/success",
  "webhook_details": {
    "webhook_version": "1.0.1",
    "webhook_username": "ekart_retail",
    "webhook_password": "password_ekart@123",
    "payment_created_enabled": true,
    "payment_succeeded_enabled": true,
    "payment_failed_enabled": true
  },
  "sub_merchants_enabled": false,
  "metadata": {
    "city": "NY",
    "unit": "245"
  },
  "primary_business_details": [
    {
      "country": "US",
      "business": "food"
    }
  ]
}'
  1. Create API Key
curl --location 'http://localhost:8080/api_keys/merchant_1728540504' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
  "name": "API Key 1",
  "description": null,
  "expiration": "2025-09-23T01:02:03.000Z"
}'
  1. Create MCA
curl --location 'http://localhost:8080/account/merchant_1728540504/connectors?=' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
    "connector_type": "payment_processor",
    "connector_name": "paypal",
    "connector_account_details": {
        "auth_type": "BodyKey",
        "api_key": "_",
        "key1": "_"
    },
    "test_mode": false,
    "disabled": false,
    "payment_methods_enabled": [
        {
            "payment_method": "card",
            "payment_method_types": [
                {
                    "payment_method_type": "credit",
                    "card_networks": [
                        "Visa",
                        "Mastercard"
                    ],
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "debit",
                    "card_networks": [
                        "Visa",
                        "Mastercard"
                    ],
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "paypal",
                    "payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": false,
                    "installment_payment_enabled": false
                },
                {
                    "payment_method_type": "paypal",
                    "payment_experience": "invoke_sdk_client",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": false,
                    "installment_payment_enabled": false
                }
                
            ]
        },
        {
            "payment_method": "bank_redirect",
            "payment_method_types": [
                {
                    "payment_method_type": "giropay",
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "payment_experience": "redirect_to_url"
                },
                {
                    "payment_method_type": "ideal",
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "payment_experience": "redirect_to_url"
                },
                {
                    "payment_method_type": "eps",
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "payment_experience": "redirect_to_url"
                },
                {
                    "payment_method_type": "sofort",
                    "recurring_enabled": true,
                    "installment_payment_enabled": true,
                    "payment_experience": "redirect_to_url"
                }
            ]
        }
    ],
     "metadata": {
        "paypal_sdk": {
            "client_id": "___"
        }
    },
    "business_country": "US",
    "business_label": "food"
}'
  1. Create Payment
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_MTxKOCiP8GOiXv955xYCMuW0MUzl1anEbVVkxBBR87wfDUObqYqOsCqpogsFFnCd' \
--data-raw '{
    "amount": 6540,
    "currency": "USD",
    "confirm": false,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "amount_to_capture": 6540,
    "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://duck.com",
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX"
        }
    },
    "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"
    }
}'
  1. Create Session token
curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_10cfee22267a4184a3d45665920788ea' \
--data '{
    "payment_id": "pay_J3IXGvol8nNvUkSRTcwQ",
    "wallets": [],
    "client_secret": "pay_J3IXGvol8nNvUkSRTcwQ_secret_VN76rK4oCqTghQ1kwNcO"
}'

Response

{
    "payment_id": "pay_mcVzUMZws5KmEKbGkZ0g",
    "client_secret": "pay_mcVzUMZws5KmEKbGkZ0g_secret_RMWlmy1jSdlp9VOMX1qc",
    "session_token": [
        {
            "wallet_name": "paypal",
            "connector": "paypal",
            "session_token": "ASKAGh2WXgqfQ5TzjpZzLsfhVGlFbjq5VrV5IOX8KXDD2N_XqkGeYNDkWyr_UXnfhXpEkABdmP284b_2",
            "sdk_next_action": {
                "next_action": "post_session_tokens"
            }
        }
    ]
}

In Response Check for Next action - It should be post_session_tokens

  1. List Payment Methods for merchant - Check for required fields (shipping_details)
curl --location 'http://localhost:8080/account/payment_methods?client_secret=pay_J3IXGvol8nNvUkSRTcwQ_secret_VN76rK4oCqTghQ1kwNcO' \
--header 'Accept: application/json' \
--header 'api-key: pk_dev_10cfee22267a4184a3d45665920788ea'

Response

{
    "redirect_url": "https://google.com/success",
    "currency": "USD",
    "payment_methods": [
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "paypal",
                    "payment_experience": [
                        {
                            "payment_experience_type": "invoke_sdk_client",
                            "eligible_connectors": [
                                "paypal"
                            ]
                        },
                        {
                            "payment_experience_type": "redirect_to_url",
                            "eligible_connectors": [
                                "paypal"
                            ]
                        }
                    ],
                    "card_networks": null,
                    "bank_names": null,
                    "bank_debits": null,
                    "bank_transfers": null,
                    "required_fields": {
                        "shipping.address.country": {
                            "required_field": "shipping.address.country",
                            "display_name": "country",
                            "field_type": {
                                "user_shipping_address_country": {
                                    "options": [
                                        "ALL"
                                    ]
                                }
                            },
                            "value": "US"
                        },
                        "shipping.address.first_name": {
                            "required_field": "shipping.address.first_name",
                            "display_name": "shipping_first_name",
                            "field_type": "user_shipping_name",
                            "value": "PiX"
                        },
                        "shipping.address.zip": {
                            "required_field": "shipping.address.zip",
                            "display_name": "zip",
                            "field_type": "user_shipping_address_pincode",
                            "value": "94122"
                        },
                        "shipping.address.state": {
                            "required_field": "shipping.address.state",
                            "display_name": "state",
                            "field_type": "user_shipping_address_state",
                            "value": "California"
                        },
                        "shipping.address.city": {
                            "required_field": "shipping.address.city",
                            "display_name": "city",
                            "field_type": "user_shipping_address_city",
                            "value": "San Fransico"
                        },
                        "shipping.address.last_name": {
                            "required_field": "shipping.address.last_name",
                            "display_name": "shipping_last_name",
                            "field_type": "user_shipping_name",
                            "value": null
                        },
                        "shipping.address.line1": {
                            "required_field": "shipping.address.line1",
                            "display_name": "line1",
                            "field_type": "user_shipping_address_line1",
                            "value": "1467"
                        }
                    },
                    "surcharge_details": null,
                    "pm_auth_connector": null
                }
            ]
        },
            ],
    "mandate_payment": null,
    "merchant_name": "NewAge Retailer",
    "show_surcharge_breakup_screen": false,
    "payment_type": "normal",
    "request_external_three_ds_authentication": false,
    "collect_shipping_details_from_wallets": false,
    "collect_billing_details_from_wallets": false,
    "is_tax_calculation_enabled": false
}
  1. Create Post Session Tokens for Paypal
curl --location 'http://localhost:8080/payments/pay_J3IXGvol8nNvUkSRTcwQ/post_session_tokens' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_10cfee22267a4184a3d45665920788ea' \
--data '{
    "client_secret": "pay_J3IXGvol8nNvUkSRTcwQ_secret_VN76rK4oCqTghQ1kwNcO",
    "payment_method_type": "paypal",
    "payment_method": "wallet"
}'

Response

 {
    "payment_id": "pay_mcVzUMZws5KmEKbGkZ0g",
    "next_action": {
        "type": "invoke_sdk_client",
        "next_action_data": {
            "next_action": "confirm",
            "order_id": "2KW93090954330301"
        }
    }
}

In Response Check for Next action - It should be confirm

  1. Confirm Request
curl 'http://localhost:8080/payments/pay_6oSZ2utmkjgdOlfrZ53E/confirm' \
-X 'POST' \
-H 'Content-Type: application/json' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Sec-Fetch-Mode: cors' \
-H 'x-payment-confirm-source: sdk' \
-H 'x-client-source: ExpressCheckoutElement' \
-H 'api-key: pk_dev_43922dfcb2694e09929891b0f4f7b6dc' \
-H 'x-browser-version: 605.1.15' \
--data-binary '{"client_secret":"pay_6oSZ2utmkjgdOlfrZ53E_secret_EFrF7Izc98NHygNyG51x","return_url":"http://localhost:9060","retry_action":"manual_retry","shipping":{"address":{"country":"US","state":"California","zip":"94588","first_name":"Jagan","city":"Pleasanton","last_name":"Elavarasan","line1":"4141"}},"payment_method":"wallet","payment_method_type":"paypal","payment_experience":"invoke_sdk_client","connector":["paypal"],"payment_method_data":{"wallet":{"paypal_sdk":{"token":""}}},"browser_info":{"user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Safari/605.1.15","accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","language":"en-US","color_depth":24,"screen_height":1117,"screen_width":1728,"time_zone":-330,"java_enabled":true,"java_script_enabled":true},"payment_type":"normal"}'

Response

    "payment_id": "pay_6oSZ2utmkjgdOlfrZ53E",
    "merchant_id": "merchant_1728844379",
    "status": "succeeded",
    "amount": 2999,
    "net_amount": 2999,
    "amount_capturable": 0,
    "amount_received": 2999,
    "connector": "paypal",
    "client_secret": "pay_6oSZ2utmkjgdOlfrZ53E_secret_EFrF7Izc98NHygNyG51x",
    "created": "2024-10-14T09:09:36.340Z",
    "currency": "USD",
    "customer_id": "hyperswitch_sdk_demo_id",
    "customer": {
        "id": "hyperswitch_sdk_demo_id",
        "name": null,
        "email": "[email protected]",
        "phone": null,
        "phone_country_code": null
    },
    "description": "Hello this is description",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "wallet",
    "payment_method_data": {
        "wallet": {},
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "Pleasanton",
            "country": "US",
            "line1": "4141",
            "line2": "Amsterdam Ave",
            "line3": "alsksoe",
            "zip": "94588",
            "state": "California",
            "first_name": "Jagan",
            "last_name": "Elavarasan"
        },
        "phone": {
            "number": "5551234",
            "country_code": "+1"
        },
        "email": "[email protected]"
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "_",
            "country_code": "+91"
        },
        "email": "[email protected]"
    },
    "order_details": [
        {
            "brand": null,
            "amount": 2999,
            "category": null,
            "quantity": 1,
            "product_id": null,
            "product_name": "Apple iPhone 15",
            "product_type": null,
            "sub_category": null,
            "product_img_link": null,
            "product_tax_code": null,
            "requires_shipping": null
        }
    ],
    "email": "[email protected]",
    "name": null,
    "phone": null,
    "return_url": "http://localhost:9060/",
    "authentication_type": "three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": "invoke_sdk_client",
    "payment_method_type": "paypal",
    "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": "1SV0561343891340C",
    "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_6oSZ2utmkjgdOlfrZ53E_1",
    "payment_link": null,
    "profile_id": "pro_03iBylVoOpuldQsVZKtO",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_frKbF7wxB3Rt7tAFbpJA",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-10-14T09:24:36.340Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-US",
        "time_zone": -330,
        "ip_address": "::1",
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Safari/605.1.15",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1728,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 1117,
        "java_script_enabled": true
    },
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-10-14T09:10:19.289Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}

For end to end testing, we need to do the payment via SDK

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

@swangi-kumari swangi-kumari added A-connector-integration Area: Connector integration A-core Area: Core flows C-feature Category: Feature request or enhancement C-refactor Category: Refactor M-api-contract-changes Metadata: This PR involves API contract changes labels Oct 15, 2024
@swangi-kumari swangi-kumari self-assigned this Oct 15, 2024
@swangi-kumari swangi-kumari requested review from a team as code owners October 15, 2024 14:39
Copy link

semanticdiff-com bot commented Oct 15, 2024

Review changes with SemanticDiff.

Analyzed 41 of 42 files.

Overall, the semantic diff is 8% smaller than the GitHub diff.

File Information
Filename Status
✔️ crates/storage_impl/src/payments/payment_attempt.rs Analyzed
✔️ crates/router_env/src/logger/types.rs Analyzed
✔️ crates/router_derive/src/macros/operation.rs Analyzed
✔️ crates/router/src/types.rs 78.0% smaller
✔️ crates/router/src/types/api/payments.rs 90.74% smaller
✔️ crates/router/src/types/api/payments_v2.rs 89.53% smaller
✔️ crates/router/src/services/api.rs Analyzed
✔️ crates/router/src/services/authentication.rs Analyzed
✔️ crates/router/src/routes/app.rs 21.33% smaller
✔️ crates/router/src/routes/lock_utils.rs 82.81% smaller
✔️ crates/router/src/routes/payments.rs Analyzed
✔️ crates/router/src/core/payments.rs 47.84% smaller
✔️ crates/router/src/core/payments/connector_integration_v2_impls.rs Analyzed
✔️ crates/router/src/core/payments/flows.rs Analyzed
✔️ crates/router/src/core/payments/operations.rs 62.76% smaller
✔️ crates/router/src/core/payments/transformers.rs Analyzed
✔️ crates/router/src/core/payments/operations/payment_post_session_tokens.rs Analyzed
✔️ crates/router/src/core/payments/operations/payment_response.rs 9.49% smaller
✔️ crates/router/src/core/payments/flows/post_session_tokens_flow.rs Analyzed
✔️ crates/router/src/core/payments/flows/session_flow.rs Analyzed
✔️ crates/router/src/connector/paypal.rs 15.33% smaller
✔️ crates/router/src/connector/utils.rs Analyzed
✔️ crates/router/src/connector/paypal/transformers.rs 11.38% smaller
✔️ crates/router/src/configs/defaults.rs 8.66% smaller
✔️ crates/openapi/src/openapi.rs Analyzed
✔️ crates/openapi/src/routes/payments.rs Analyzed
✔️ crates/hyperswitch_interfaces/src/types.rs 42.98% smaller
✔️ crates/hyperswitch_interfaces/src/api/payments.rs 35.97% smaller
✔️ crates/hyperswitch_interfaces/src/api/payments_v2.rs 24.12% smaller
✔️ crates/hyperswitch_domain_models/src/router_request_types.rs Analyzed
✔️ crates/hyperswitch_domain_models/src/types.rs 66.25% smaller
✔️ crates/hyperswitch_domain_models/src/router_flow_types/payments.rs Analyzed
✔️ crates/hyperswitch_domain_models/src/payments/payment_attempt.rs Analyzed
✔️ crates/hyperswitch_connectors/src/default_implementations.rs 7.2% smaller
✔️ crates/hyperswitch_connectors/src/default_implementations_v2.rs 32.11% smaller
✔️ crates/diesel_models/src/payment_attempt.rs Analyzed
✔️ crates/api_models/src/payments.rs Analyzed
✔️ crates/api_models/src/events/payment.rs 13.61% smaller
✔️ api-reference-v2/openapi_spec.json Analyzed
✔️ api-reference/mint.json 66.67% smaller
✔️ api-reference/openapi_spec.json Analyzed
api-reference/api-reference/payments/payments--post-session-tokens.mdx Unsupported file format

@swangi-kumari swangi-kumari marked this pull request as draft October 15, 2024 17:23
@swangi-kumari
Copy link
Contributor Author

Completed in 6326

@SanchithHegde SanchithHegde deleted the paypal-flow-refactor branch October 27, 2024 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-connector-integration Area: Connector integration A-core Area: Core flows C-feature Category: Feature request or enhancement C-refactor Category: Refactor M-api-contract-changes Metadata: This PR involves API contract changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant