Skip to content

Conversation

@bsayak03
Copy link
Contributor

@bsayak03 bsayak03 commented Dec 5, 2025

Type of Change

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

Description

This PR is for consuming card_holder_name separately in .csv for Payment Methods Batch Migration API.

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. CIT payment using card
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_LvweBOgJijFMwOLIj0XP63og3xc0aW4RqcVO2fEm2nJpIAruU82tAOeeemExNNyU' \
--data-raw '{
    "amount": 2500,
    "currency": "USD",
    "connector": [
        "adyen"
    ],
    "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "customer_id": "mmm11",
    "setup_future_usage": "off_session",
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    "amount_to_capture": 2500,
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://duck.com",
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4917610000000000",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_cvc": "737",
            "card_holder_name": "joseph Doe",
            "card_network": "Visa"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph1",
            "last_name": "Doe1"
        },
        "phone": {
            "number": "9123456789",
            "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": "9123456789",
            "country_code": "+91"
        }
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
        
        
    },
        "browser_info": {
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "en-US",
        "color_depth": 32,
        "screen_height": 1117,
        "screen_width": 1728,
        "time_zone": -330,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "127.0.0.1"
    }
}'

Response :

{
    "payment_id": "pay_zhUIhXWbOjjKgwC4g3H9",
    "merchant_id": "merchant_1764928634",
    "status": "succeeded",
    "amount": 2500,
    "net_amount": 2500,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 2500,
    "connector": "adyen",
    "client_secret": "pay_zhUIhXWbOjjKgwC4g3H9_secret_6TDtwWPa5khYIWb10vrq",
    "created": "2025-12-05T13:09:45.402Z",
    "currency": "USD",
    "customer_id": "mmm11",
    "customer": {
        "id": "mmm11",
        "name": "John Doe",
        "email": "[email protected]",
        "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": "0000",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "491761",
            "card_extended_bin": null,
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "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",
            "origin_zip": null
        },
        "phone": {
            "number": "9123456789",
            "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": "joseph1",
            "last_name": "Doe1",
            "origin_zip": null
        },
        "phone": {
            "number": "9123456789",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://duck.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "error_reason": 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": "mmm11",
        "created_at": 1764940185,
        "expires": 1764943785,
        "secret": "epk_ff5f4a2fa72e4278ae8825536c4487f5"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": "P75BVRCDWJNHSXT5",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "gateway_system": "direct"
    },
    "reference_id": "pay_zhUIhXWbOjjKgwC4g3H9_1",
    "payment_link": null,
    "profile_id": "pro_TcGME9szuUbalulKwG2A",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_1TgyIIWpQKa6PmcykD01",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-12-05T13:24:45.402Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-US",
        "time_zone": -330,
        "ip_address": "127.0.0.1",
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        "color_depth": 32,
        "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_channel": null,
    "payment_method_id": "pm_rdWc22pKCaYWS7ckdeTX",
    "network_transaction_id": "030831077993765",
    "payment_method_status": "active",
    "updated": "2025-12-05T13:09:47.291Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "extended_authorization_last_applied_at": null,
    "request_extended_authorization": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": "C48CF85TD6PV7VV5",
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null,
    "enable_partial_authorization": null,
    "enable_overcapture": null,
    "is_overcapture_enabled": null,
    "network_details": null,
    "is_stored_credential": null,
    "mit_category": null,
    "billing_descriptor": null,
    "tokenization": null,
    "partner_merchant_identifier_details": null
}

Note : Take details from this response and make a .csv for NTID

Step 2: Delete PM entry using API

curl --location --request DELETE 'http://localhost:8080/payment_methods/pm_rdWc22pKCaYWS7ckdeTX' \
--header 'api-key: dev_LvweBOgJijFMwOLIj0XP63og3xc0aW4RqcVO2fEm2nJpIAruU82tAOeeemExNNyU'

Response :

{
    "payment_method_id": "pm_rdWc22pKCaYWS7ckdeTX",
    "deleted": true
}

Step 3 : Enable connector_agnostic in Business Profile API :

curl --location 'http://localhost:8080/account/merchant_1764928634/business_profile/pro_TcGME9szuUbalulKwG2A' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_LvweBOgJijFMwOLIj0XP63og3xc0aW4RqcVO2fEm2nJpIAruU82tAOeeemExNNyU' \
--data '{
    "is_connector_agnostic_mit_enabled": true
}'

Response :

{
    "merchant_id": "merchant_1764928634",
    "profile_id": "pro_TcGME9szuUbalulKwG2A",
    "profile_name": "US_default",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "PDLi8t2lqmytxr9YBcV4ktE4wdssarCkDTsgtzhYRY65lYDfg6andZIAqjgRmKTr",
    "redirect_to_merchant_with_http_post": false,
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": "https://webhook.site/bbacbe31-872a-4626-b348-a6e961e64e2f",
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true,
        "payment_statuses_enabled": null,
        "refund_statuses_enabled": null,
        "payout_statuses_enabled": null
    },
    "metadata": null,
    "routing_algorithm": null,
    "intent_fulfillment_time": 900,
    "frm_routing_algorithm": null,
    "payout_routing_algorithm": null,
    "applepay_verified_domains": null,
    "session_expiry": 900,
    "payment_link_config": null,
    "authentication_connector_details": null,
    "use_billing_as_payment_method_billing": true,
    "extended_card_info_config": null,
    "collect_shipping_details_from_wallet_connector": false,
    "collect_billing_details_from_wallet_connector": false,
    "always_collect_shipping_details_from_wallet_connector": false,
    "always_collect_billing_details_from_wallet_connector": false,
    "is_connector_agnostic_mit_enabled": true,
    "payout_link_config": null,
    "outgoing_webhook_custom_http_headers": null,
    "tax_connector_id": null,
    "is_tax_connector_enabled": false,
    "is_network_tokenization_enabled": false,
    "is_auto_retries_enabled": false,
    "max_auto_retries_enabled": null,
    "always_request_extended_authorization": null,
    "is_click_to_pay_enabled": false,
    "authentication_product_ids": null,
    "card_testing_guard_config": {
        "card_ip_blocking_status": "disabled",
        "card_ip_blocking_threshold": 3,
        "guest_user_card_blocking_status": "disabled",
        "guest_user_card_blocking_threshold": 10,
        "customer_id_blocking_status": "disabled",
        "customer_id_blocking_threshold": 5,
        "card_testing_guard_expiry": 3600
    },
    "is_clear_pan_retries_enabled": false,
    "force_3ds_challenge": false,
    "is_debit_routing_enabled": false,
    "merchant_business_country": null,
    "is_pre_network_tokenization_enabled": false,
    "acquirer_configs": null,
    "is_iframe_redirection_enabled": null,
    "merchant_category_code": null,
    "merchant_country_code": null,
    "dispute_polling_interval": null,
    "is_manual_retry_enabled": null,
    "always_enable_overcapture": null,
    "is_external_vault_enabled": "skip",
    "external_vault_connector_details": null,
    "billing_processor_id": null,
    "is_l2_l3_enabled": false
}

Step 4 : Run batch migrations API

curl --location 'http://localhost:8080/payment_methods/migrate-batch' \
--header 'api-key: test_admin' \
--form 'file=@"/Users/sayak.b/Downloads/update_sample.csv"' \
--form 'merchant_id="merchant_1764928634"' \
--form 'merchant_connector_ids="mca_1TgyIIWpQKa6PmcykD01"'

Response :

[
    {
        "line_number": 1,
        "payment_method_id": "pm_M76U28gqVs22DWDAkCk3",
        "payment_method": "card",
        "payment_method_type": "credit",
        "customer_id": "mmm11",
        "migration_status": "Success",
        "card_number_masked": "222240XXXXXX0005",
        "card_migrated": true,
        "network_token_migrated": false,
        "connector_mandate_details_migrated": null,
        "network_transaction_id_migrated": true
    }
]

Step 5 : Payouts create using pm_id

curl --location 'http://localhost:8080/payouts/create' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_LvweBOgJijFMwOLIj0XP63og3xc0aW4RqcVO2fEm2nJpIAruU82tAOeeemExNNyU' \
--data-raw '{
    "payout_method_id": "pm_M76U28gqVs22DWDAkCk3",
    "amount": 1,
    "currency": "USD",
    "customer_id": "mmm11",
    
    "connector": [
        "adyenplatform"
    ],
    "confirm": true,
    "auto_fulfill": true,
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "zip": "94122",
            "country": "FR",
            "first_name": "khfhkfhkj",
            "last_name": "bjkfnjkfnDoe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": "[email protected]"
    }
}'
{
    "payout_id": "payout_s4IhfzScd8G6d3AkWwBi",
    "merchant_id": "merchant_1764928634",
    "merchant_order_reference_id": null,
    "amount": 1,
    "currency": "USD",
    "connector": "adyenplatform",
    "payout_type": "card",
    "payout_method_data": {
        "card": {
            "card_issuer": null,
            "card_network": null,
            "card_type": null,
            "card_issuing_country": null,
            "bank_code": null,
            "last4": "0000",
            "card_isin": "491761",
            "card_extended_bin": null,
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe"
        }
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "FR",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": null,
            "first_name": "khfhkfhkj",
            "last_name": "bjkfnjkfnDoe",
            "origin_zip": null
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": "[email protected]"
    },
    "auto_fulfill": true,
    "customer_id": "mmm11",
    "customer": {
        "id": "mmm11",
        "name": "John Doe",
        "email": "[email protected]",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "client_secret": "payout_payout_s4IhfzScd8G6d3AkWwBi_secret_9pkWiFVnm6G6uCzHXA6a",
    "return_url": null,
    "business_country": null,
    "business_label": null,
    "description": null,
    "entity_type": "Individual",
    "recurring": false,
    "metadata": {},
    "merchant_connector_id": "mca_pR1uNIJR64F09ZNehwcF",
    "status": "initiated",
    "error_message": null,
    "error_code": null,
    "profile_id": "pro_TcGME9szuUbalulKwG2A",
    "created": "2025-12-05T13:28:15.983Z",
    "connector_transaction_id": "38E99869810SBDFS",
    "priority": null,
    "payout_link": null,
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "unified_code": null,
    "unified_message": null,
    "payout_method_id": "pm_M76U28gqVs22DWDAkCk3"
}
"{\"amount\":{\"currency\":\"USD\",\"value\":1},\"balanceAccountId\":\"XXXXXXX\",\"category\":\"card\",\"counterparty\":{\"card\":{\"cardHolder\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"postalCode\":\"94122\",\"city\":\"San Fransico\",\"country\":\"FR\"},\"firstName\":\"joseph\",\"lastName\":\"Doe\",\"fullName\":null,\"email\":\"[email protected]\",\"reference\":\"merchant_1764928634_mmm11\",\"type\":\"individual\"},\"cardIdentification\":{\"number\":\"4917610000000000\",\"expiryMonth\":\"03\",\"expiryYear\":\"2030\",\"issueNumber\":null,\"startMonth\":null,\"startYear\":null}}},\"reference\":\"payout_s4IhfzScd8G6d3AkWwBi_1\",\"referenceForBeneficiary\":\"payout_s4IhfzScd8G6d3AkWwBi_1\"}"

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

@bsayak03 bsayak03 requested a review from a team as a code owner December 5, 2025 09:46
@semanticdiff-com
Copy link

semanticdiff-com bot commented Dec 5, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/api_models/src/payment_methods.rs  28% smaller

@bsayak03 bsayak03 self-assigned this Dec 5, 2025
Copy link
Contributor

@mrudulvajpayee4935 mrudulvajpayee4935 left a comment

Choose a reason for hiding this comment

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

Please test below flows after migrated raw card details and NTI.

  1. MIT using migrated raw card and NTI.
  2. Payout to adyen platform using migrated raw card.

@codecov
Copy link

codecov bot commented Dec 5, 2025

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@0c7f82b). Learn more about missing BASE report.

Files with missing lines Patch % Lines
crates/api_models/src/payment_methods.rs 0.00% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #10551   +/-   ##
=======================================
  Coverage        ?    6.46%           
=======================================
  Files           ?     1251           
  Lines           ?   311970           
  Branches        ?        0           
=======================================
  Hits            ?    20163           
  Misses          ?   291807           
  Partials        ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bsayak03 bsayak03 requested a review from a team as a code owner December 5, 2025 10:56
.map(AdyenTestingData::try_from)
.transpose()?;
let test_holder_name = testing_data.and_then(|test_data| test_data.holder_name);
let holder_name = Some(
Copy link
Contributor

Choose a reason for hiding this comment

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

Won't this throw an error unnecessarily even if test_holder_name is present?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct, putting it inside a match case now

.map(AdyenTestingData::try_from)
.transpose()?;
let test_holder_name = testing_data.and_then(|test_data| test_data.holder_name);
let holder_name = match item
Copy link
Contributor

@mrudulvajpayee4935 mrudulvajpayee4935 Dec 5, 2025

Choose a reason for hiding this comment

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

lets keep existing flows as it is, this change is not required, card holder name is being migrated for payouts case in adyen platform.

.ok_or_else(missing_field_err("mandate_id"))?,
),
holder_name: test_holder_name,
holder_name,
Copy link
Contributor

Choose a reason for hiding this comment

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

same here

@bsayak03 bsayak03 removed the request for review from a team December 5, 2025 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants