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

fix(router): update nick_name only if card_token.card_holder_name is non empty and populate additional card_details from payment_attempt if not present in the locker #6308

Merged
merged 2 commits into from
Oct 14, 2024

Conversation

sai-harsha-vardhan
Copy link
Contributor

@sai-harsha-vardhan sai-harsha-vardhan commented Oct 14, 2024

Type of Change

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

Description

nick_name and card_network are not populated in card details for saved card flow with netcetera

  1. nick_name should be updated with card_token data (card_holder_name) only if it's not none and non empty string
  2. additional card details should be populated from payment_attempt (additional payment data) after fetching from temp locker

update nick_name only if card_token.card_holder_name is non empty and populate additional card_details from payment_attempt if not present in the locker

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?

Tested Manually

  1. Do a saved card external 3ds payment with Netcetera and try to do customer payment method list to see nick_name and card_network being populated in card details

Create CURL

curl --location '{{BASE_URL}}/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: {{API_KEY}}' \
--data-raw '{
    "request_external_three_ds_authentication": true,
    "request_incremental_authorization": false,
    "amount": 123,
    "currency": "USD",
    "confirm": false,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "customer_id": "stripecustomer1",
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "authentication_type": "three_ds",
    "return_url": "https://google.com/",
    "setup_future_usage": "off_session",
    "mandate_data": {
        "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "125.0.0.1",
                "user_agent": "amet irure esse"
            }
        },
        "mandate_type": {
            "multi_use": {
                "amount": 1000,
                "currency": "USD",
                "start_date": "2023-04-21T00:00:00Z",
                "end_date": "2023-05-21T00:00:00Z",
                "metadata": {
                    "frequency": "13"
                }
            }
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "CA",
            "zip": "94122",
            "country": "US",
            "first_name": "John",
            "last_name": "Doe"
        },
         "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "CA",
            "zip": "94122",
            "country": "US",
            "first_name": "John",
            "last_name": "Doe"
        },
         "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
      "connector_metadata": {
        "noon": {
            "order_category": "pay"
        }
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {},
    "order_details": [
        {
            "product_name": "Apple iphone 15",
            "quantity":1,
            "amount": 0,
            "account_name": "transaction_processing"
        }
    ],
    "routing": {
        "type": "single",
        "data": "cybersource",
        "timestamp": 1728906164
    },
    "shipping_cost": 100
}'

Response

{
    "payment_id": "pay_RgRay79tJE6XrnnYhUoh",
    "merchant_id": "merchant_1728289111",
    "status": "requires_payment_method",
    "amount": 123,
    "net_amount": 223,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "pay_RgRay79tJE6XrnnYhUoh_secret_IDJcGnf9foz8yJJUQ5V8",
    "created": "2024-10-14T11:39:53.033Z",
    "currency": "USD",
    "customer_id": "stripecustomer1",
    "customer": {
        "id": "stripecustomer1",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": {
        "update_mandate_id": null,
        "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "125.0.0.1",
                "user_agent": "amet irure esse"
            }
        },
        "mandate_type": {
            "multi_use": {
                "amount": 1000,
                "currency": "USD",
                "start_date": "2023-04-21T00:00:00.000Z",
                "end_date": "2023-05-21T00:00:00.000Z",
                "metadata": {
                    "frequency": "13"
                }
            }
        }
    },
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "CA",
            "first_name": "John",
            "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": "CA",
            "first_name": "John",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": [
        {
            "brand": null,
            "amount": 0,
            "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": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "stripecustomer1",
        "created_at": 1728905993,
        "expires": 1728909593,
        "secret": "epk_7ce03d90da4d42f59dafbdc3264805ef"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": {},
    "connector_metadata": {
        "apple_pay": null,
        "airwallex": null,
        "noon": {
            "order_category": "pay"
        }
    },
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_0W1FrymADX9vzJ4kAifW",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-10-14T11:54:53.033Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-10-14T11:39:53.088Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}

Confirm CURL

curl --location 'localhost:8080/payments/pay_RgRay79tJE6XrnnYhUoh/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_5LPv674cWuRSlDpmLyQWKFKkR9bmLGUiLnH5IxLFfQCbbV2zEdFwkHQ47YN4cZ06' \
--data '{
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
                "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "John Doe",
            "card_cvc": "737",
            "nick_name": "doe"
        }
    },
    "payment_method": "card",
    "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": "125.0.0.1"
    },
    "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "125.0.0.1",
                "user_agent": "amet irure esse"
            }
        }
}'

Response

{
    "payment_id": "pay_RgRay79tJE6XrnnYhUoh",
    "merchant_id": "merchant_1728289111",
    "status": "requires_customer_action",
    "amount": 123,
    "net_amount": 223,
    "amount_capturable": 223,
    "amount_received": null,
    "connector": "cybersource",
    "client_secret": "pay_RgRay79tJE6XrnnYhUoh_secret_IDJcGnf9foz8yJJUQ5V8",
    "created": "2024-10-14T11:39:53.033Z",
    "currency": "USD",
    "customer_id": "stripecustomer1",
    "customer": {
        "id": "stripecustomer1",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "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": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1111",
            "card_type": "DEBIT",
            "card_network": "Visa",
            "card_issuer": null,
            "card_issuing_country": "OMAN",
            "card_isin": "411111",
            "card_extended_bin": null,
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": "token_0U1KHbVHBHcFZND2vOm5",
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "CA",
            "first_name": "John",
            "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": "CA",
            "first_name": "John",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": [
        {
            "brand": null,
            "amount": 0,
            "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": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": {
        "type": "three_ds_invoke",
        "three_ds_data": {
            "three_ds_authentication_url": "http://localhost:8080/payments/pay_RgRay79tJE6XrnnYhUoh/3ds/authentication",
            "three_ds_authorize_url": "http://localhost:8080/payments/pay_RgRay79tJE6XrnnYhUoh/merchant_1728289111/authorize/cybersource",
            "three_ds_method_details": {
                "three_ds_method_key": "threeDSMethodData",
                "three_ds_method_data_submission": true,
                "three_ds_method_data": "eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS8zZHMtbWV0aG9kLW5vdGlmaWNhdGlvbi11cmwiLCJ0aHJlZURTU2VydmVyVHJhbnNJRCI6IjUzZjBkZDAxLTc5MTItNGY2NS1hZTBkLTY3OGJiYjZmYjdhZiJ9",
                "three_ds_method_url": "https://3dss-pp-prev-ndm.acquiring.test.netcetera.com/acs/3ds-method"
            },
            "poll_config": {
                "poll_id": "external_authentication_pay_RgRay79tJE6XrnnYhUoh",
                "delay_in_secs": 2,
                "frequency": 5
            },
            "message_version": "2.2.0",
            "directory_server_id": "A000000003"
        }
    },
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "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": {},
    "connector_metadata": {
        "apple_pay": null,
        "airwallex": null,
        "noon": {
            "order_category": "pay"
        }
    },
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_0W1FrymADX9vzJ4kAifW",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": {
        "authentication_flow": null,
        "electronic_commerce_indicator": null,
        "status": "pending",
        "ds_transaction_id": "53f0dd01-7912-4f65-ae0d-678bbb6fb7af",
        "version": "2.2.0",
        "error_code": null,
        "error_message": null
    },
    "external_3ds_authentication_attempted": true,
    "expires_on": "2024-10-14T11:54:53.033Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "125.0.0.1",
        "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": null,
    "payment_method_status": null,
    "updated": "2024-10-14T11:40:12.398Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}

Customer PML CURL

curl --location '{{BASE_URL}}/customers/payment_methods?client_secret={{CLIENT_SECRET}}' \
--header 'Accept: application/json' \
--header 'api-key: {{PUBLISHABLE_KEY}}'

Response

{
  "customer_payment_methods": [
    {
      "payment_token": "token_gQiGZNCz66gIS1i1vQvy",
      "payment_method_id": "pm_01JCgYWXwBXoLyWBlPRK",
      "customer_id": "stripecustomer1",
      "payment_method": "card",
      "payment_method_type": null,
      "payment_method_issuer": null,
      "payment_method_issuer_code": null,
      "recurring_enabled": true,
      "installment_payment_enabled": false,
      "payment_experience": [
        "redirect_to_url"
      ],
      "card": {
        "scheme": "Visa",
        "issuer_country": "OMAN",
        "last4_digits": "1111",
        "expiry_month": "03",
        "expiry_year": "2030",
        "card_token": null,
        "card_holder_name": "John Doe",
        "card_fingerprint": null,
        "nick_name": "doe",
        "card_network": "Visa",
        "card_isin": "411111",
        "card_issuer": null,
        "card_type": "DEBIT",
        "saved_to_locker": true
      },
      "metadata": null,
      "created": "2024-10-14T11:40:39.515Z",
      "bank": null,
      "surcharge_details": null,
      "requires_cvv": false,
      "last_used_at": "2024-10-14T11:40:39.515Z",
      "default_payment_method_set": false,
      "billing": {
        "address": {
          "city": "San Fransico",
          "country": "US",
          "line1": "1467",
          "line2": "Harrison Street",
          "line3": "Harrison Street",
          "zip": "94122",
          "state": "CA",
          "first_name": "John",
          "last_name": "Doe"
        },
        "phone": {
          "number": "8056594427",
          "country_code": "+91"
        },
        "email": null
      }
    }
  ],
  "is_guest_customer": false
}

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

@sai-harsha-vardhan sai-harsha-vardhan added A-core Area: Core flows C-bug Category: Bug labels Oct 14, 2024
@sai-harsha-vardhan sai-harsha-vardhan self-assigned this Oct 14, 2024
@sai-harsha-vardhan sai-harsha-vardhan requested review from a team as code owners October 14, 2024 12:42
Copy link

semanticdiff-com bot commented Oct 14, 2024

Review changes with SemanticDiff.

Analyzed 2 of 2 files.

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

Filename Status
✔️ crates/router/src/core/payment_methods.rs Analyzed
✔️ crates/router/src/core/payments/helpers.rs 14.31% smaller


updated_card.nick_name = name_on_card;
if let Some(name) = name_on_card.clone() {
Copy link
Contributor

Choose a reason for hiding this comment

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

clone not required

Suggested change
if let Some(name) = name_on_card.clone() {
if let Some(ref name) = name_on_card {


updated_card.nick_name = name_on_card;
if let Some(name) = name_on_card.clone() {
if !name.peek().is_empty() {
Copy link
Contributor

Choose a reason for hiding this comment

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

should we do trim here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-core Area: Core flows C-bug Category: Bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants