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(connector): [Novalnet] add Recurring payment flow for cards #5921

Merged
merged 7 commits into from
Sep 19, 2024

Conversation

cookieg13
Copy link
Contributor

@cookieg13 cookieg13 commented Sep 17, 2024

Type of Change

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

Description

Implemented Card Mandates for Novalnet (3DS)

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?

Could not run cypress tests since we don't have support for 3ds mandates cypress tests. cc: @likhinbopanna

Create Call CIT

curl --location --request POST 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_4wQJ6bOm7gz2rtzoxpzcPVElkrNRAuxWXLdaxjFPEezFltFwcs96AOennIrHraCK' \
--data-raw '{
    "amount": 20000,
    "currency": "EUR",
    "confirm": false,
    "capture_method": "manual",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "three_ds",
    "return_url": "https://google.com",
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "setup_future_usage": "off_session",
    "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"
        }
    }
}'

Confirm Call CIT

curl --location --request POST 'http://localhost:8080/payments/pay_yNIU3yUwlo3IPhvJrTfY/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_4wQJ6bOm7gz2rtzoxpzcPVElkrNRAuxWXLdaxjFPEezFltFwcs96AOennIrHraCK' \
--data-raw '{
    "confirm": true,
    "customer_id": "StripeCustomer",
    "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"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "online",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "127.0.0.1",
            "user_agent": "amet irure esse"
        }
    },
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4000 0000 0000 1091",
            "card_exp_month": "12",
            "card_exp_year": "2025",
            "card_holder_name": "Max Mustermann",
            "card_cvc": "123"
        },
        "billing": {
            "address": {
                "line1": "1467",
                "line2": "CA",
                "line3": "CA",
                "city": "Musterhausen",
                "state": "California",
                "zip": "12345",
                "country": "DE",
                "first_name": "Max",
                "last_name": "Mustermann"
            },
            "email": "test@novalnet.de",
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            }
        }
    }
}'

Confirm Response CIT

{
    "payment_id": "pay_yNIU3yUwlo3IPhvJrTfY",
    "merchant_id": "merchant_1726485581",
    "status": "requires_customer_action",
    "amount": 20000,
    "net_amount": 20000,
    "amount_capturable": 20000,
    "amount_received": null,
    "connector": "novalnet",
    "client_secret": "pay_yNIU3yUwlo3IPhvJrTfY_secret_TGnLOTuvXSwexeuGfGzv",
    "created": "2024-09-17T07:29:59.670Z",
    "currency": "EUR",
    "customer_id": "StripeCustomer",
    "customer": {
        "id": "StripeCustomer",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "manual",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1091",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "400000",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "2025",
            "card_holder_name": null,
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": {
            "address": {
                "city": "Musterhausen",
                "country": "DE",
                "line1": "1467",
                "line2": "CA",
                "line3": "CA",
                "zip": "12345",
                "state": "California",
                "first_name": "Max",
                "last_name": "Mustermann"
            },
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            },
            "email": "test@novalnet.de"
        }
    },
    "payment_token": null,
    "shipping": {
        "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": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "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": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": {
        "type": "redirect_to_url",
        "redirect_to_url": "http://localhost:8080/payments/redirect/pay_yNIU3yUwlo3IPhvJrTfY/merchant_1726485581/pay_yNIU3yUwlo3IPhvJrTfY_1"
    },
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_nLolcnhU7DUrn1VoSrxJ",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_4JNPgjOIPC53n1fZIzTE",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T07:44:59.670Z",
    "fingerprint": null,
    "browser_info": {
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "user_agent": null,
        "color_depth": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "java_script_enabled": null
    },
    "payment_method_id": "pm_afIt4ybmy7fOw9ZNK9XY",
    "payment_method_status": null,
    "updated": "2024-09-17T07:30:08.062Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null
}

MIT Call

curl --location --request POST 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_4wQJ6bOm7gz2rtzoxpzcPVElkrNRAuxWXLdaxjFPEezFltFwcs96AOennIrHraCK' \
--data-raw '{
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_4mGZxyLtnuMtTqfwnOrj"
    },
    "authentication_type": "three_ds",
    "customer": {
        "id": "StripeCustomer",
        "email": "guest@example.com"
    },
    "description": "This is the test payment made through Mule API",
    "currency": "EUR",
    "amount": 126,
    "confirm": true,
    "capture_method": "automatic",
    "off_session": true,
    "metadata": {
        "businessUnit": "ZG_GL_Group",
        "country": "US",
        "clientId": "N/A",
        "productName": "Travel insurance",
        "orderReference": "order-040724-001"
    },
    "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,
        "ip_address": "103.77.139.95",
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true
    }
}'

MIT Response

{
    "payment_id": "pay_HQolMJe2OXdWE8zvomqz",
    "merchant_id": "merchant_1726485581",
    "status": "succeeded",
    "amount": 126,
    "net_amount": 126,
    "amount_capturable": 0,
    "amount_received": 126,
    "connector": "novalnet",
    "client_secret": "pay_HQolMJe2OXdWE8zvomqz_secret_Wr5QBrFXaGV7wN2K4tC5",
    "created": "2024-09-17T08:40:09.301Z",
    "currency": "EUR",
    "customer_id": "StripeCustomer",
    "customer": {
        "id": "StripeCustomer",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "This is the test payment made through Mule API",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": true,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1091",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "400000",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "2025",
            "card_holder_name": "Max Mustermann",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": null,
    "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": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "StripeCustomer",
        "created_at": 1726562409,
        "expires": 1726566009,
        "secret": "epk_c80377110ad64514baf0858f2ac645f7"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "15032100030113398",
    "frm_message": null,
    "metadata": {
        "country": "US",
        "clientId": "N/A",
        "productName": "Travel insurance",
        "businessUnit": "ZG_GL_Group",
        "orderReference": "order-040724-001"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "15032100030113398",
    "payment_link": null,
    "profile_id": "pro_nLolcnhU7DUrn1VoSrxJ",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_4JNPgjOIPC53n1fZIzTE",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T08:55:09.301Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "103.77.139.95",
        "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_4mGZxyLtnuMtTqfwnOrj",
    "payment_method_status": "active",
    "updated": "2024-09-17T08:40:13.451Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null
}

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

@cookieg13 cookieg13 requested a review from a team as a code owner September 17, 2024 09:30
Copy link

semanticdiff-com bot commented Sep 17, 2024

Review changes with SemanticDiff.

Analyzed 4 of 4 files.

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

Filename Status
✔️ crates/router/src/configs/defaults.rs Analyzed
✔️ crates/hyperswitch_connectors/src/utils.rs 0.13% smaller
✔️ crates/hyperswitch_connectors/src/connectors/novalnet.rs 18.39% smaller
✔️ crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs 50.01% smaller

@cookieg13 cookieg13 force-pushed the novalnetRecurringPayments branch from 6d66813 to 97c87dc Compare September 17, 2024 09:36
@cookieg13 cookieg13 force-pushed the novalnetRecurringPayments branch from 97c87dc to 9af2865 Compare September 17, 2024 09:51
@cookieg13 cookieg13 changed the title Novalnet recurring payments feat(connector): [Novalnet] add Recurring payment flow for cards Sep 17, 2024
@cookieg13 cookieg13 self-assigned this Sep 17, 2024
@cookieg13 cookieg13 added A-connector-integration Area: Connector integration C-feature Category: Feature request or enhancement S-waiting-on-review Status: This PR has been implemented and needs to be reviewed labels Sep 17, 2024
@cookieg13 cookieg13 requested a review from a team as a code owner September 17, 2024 12:56
@cookieg13 cookieg13 force-pushed the novalnetRecurringPayments branch from e6e2f03 to ebdfa80 Compare September 17, 2024 13:42
srujanchikke
srujanchikke previously approved these changes Sep 17, 2024
@cookieg13 cookieg13 force-pushed the novalnetRecurringPayments branch 3 times, most recently from 5944263 to ff2dcff Compare September 19, 2024 07:23
@pixincreate pixincreate removed the request for review from a team September 19, 2024 09:07
@cookieg13 cookieg13 force-pushed the novalnetRecurringPayments branch from ff2dcff to 3130d94 Compare September 19, 2024 09:20
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Sep 19, 2024
Merged via the queue into main with commit 6a6ce17 Sep 19, 2024
12 of 14 checks passed
@Gnanasundari24 Gnanasundari24 deleted the novalnetRecurringPayments branch September 19, 2024 14:00
@SanchithHegde SanchithHegde removed the S-waiting-on-review Status: This PR has been implemented and needs to be reviewed label Sep 22, 2024
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 C-feature Category: Feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants