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(connector): [FISERV, HELCIM] Add amount conversion framework to Fiserv, Helcim #7336

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

itsharshvb
Copy link

@itsharshvb itsharshvb commented Feb 21, 2025

Type of Change

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

Description

added MinorUnit for amount conversion for Fiserv
added FloatMajorUnit for amount conversion for Helcim

Additional Changes

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

Motivation and Context

fixes #6256 and #6019

How did you test it?

Tested through postman:

  • Create a MCA for fiserv:
  • Create a Payment with fiserv:

request:

{
    "amount": 10000,
    "currency": "USD",
    "amount_to_capture": 10000,
    "confirm": true,
    "profile_id": {{profile_id}},
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "no_three_ds",
    "setup_future_usage": "on_session",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "[email protected]",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "customer_id": "customer123",
    "phone_country_code": "+1",
    "description": "Its my first payment request",
    "return_url": "https://google.com",
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": { 
        "card": {
            "card_number": "4147463011110083",
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "joseph Doe",
            "card_cvc": "123"
        }
    },
    "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": "9999999999",
            "country_code": "+91"
        },
        "email": "[email protected]"
    },
    "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": "9999999999",
            "country_code": "+91"
        },
        "email": "[email protected]"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "order_details": [
        {
            "product_name": "Apple iphone 15",
            "quantity": 1,
            "amount": 6540,
            "account_name": "transaction_processing"
        }
    ],
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "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": "128.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"
        }
    },
    //Some connectors like Apple Pay, Airwallex and Noon might require some additional information, find more in the doc.
    "connector_metadata": {
        "noon": {
            "order_category": "pay"
        }
    },
    "payment_link": false,
    "payment_link_config": {
        "theme": "",
        "logo": "",
        "seller_name": "",
        "sdk_layout": "",
        "display_sdk_only": false,
        "enabled_saved_payment_method": false
    },
    "payment_type": "normal", 
    "request_incremental_authorization": false,
    "merchant_order_reference_id": "test_ord",
    "session_expiry": 900 
}

response: - The payment should be succeeded

{
    "payment_id": "pay_9mnPycKv5V2w9aNCHyO8",
    "merchant_id": "merchant_1740127595",
    "status": "succeeded",
    "amount": 10000,
    "net_amount": 10000,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 10000,
    "connector": "fiserv",
    "client_secret": "pay_9mnPycKv5V2w9aNCHyO8_secret_X4CTRqm4Ldyx6L7s2OPa",
    "created": "2025-02-21T08:46:50.624Z",
    "currency": "USD",
    "customer_id": "customer123",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "[email protected]",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "0083",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "414746",
            "card_extended_bin": null,
            "card_exp_month": "10",
            "card_exp_year": "25",
            "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"
        },
        "phone": {
            "number": "9999999999",
            "country_code": "+91"
        },
        "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": "9999999999",
            "country_code": "+91"
        },
        "email": "[email protected]"
    },
    "order_details": [
        {
            "brand": null,
            "amount": 6540,
            "category": null,
            "quantity": 1,
            "tax_rate": null,
            "product_id": null,
            "product_name": "Apple iphone 15",
            "product_type": null,
            "sub_category": null,
            "product_img_link": null,
            "product_tax_code": null,
            "total_tax_amount": null,
            "requires_shipping": null
        }
    ],
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "9999999999",
    "return_url": "https://google.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,
    "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": "customer123",
        "created_at": 1740127610,
        "expires": 1740131210,
        "secret": "epk_a6328125a3ad471d88ef13493272c1cc"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "6f2fdeb7a1884bc0957c0f977644c30c",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": {
        "apple_pay": null,
        "airwallex": null,
        "noon": {
            "order_category": "pay"
        }
    },
    "feature_metadata": null,
    "reference_id": "CHG015117c1ffa76779d655a830730d7add1a",
    "payment_link": null,
    "profile_id": "pro_IxmWaGQVX320n30wDNuM",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_o2Tw2yV2oWr4vEC5b22q",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-02-21T09:01:50.623Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "128.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": "2025-02-21T08:46:54.326Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": "test_ord",
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": "manual"
}
  • Create a MCA for helcim:
  • Create a Payment with helcim:
{
    "amount": 100,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "amount_to_capture": 100,
    "customer_id": "helcim",
    "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://google.com",
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "5413330089099130",
            "card_exp_month": "01",
            "card_exp_year": "28",
            "card_holder_name": "joseph Doe",
            "card_cvc": "100"
        }
    },
    "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"
    },
    "browser_info": {
        "color_depth": 24,
        "java_enabled": true,
        "java_script_enabled": true,
        "language": "en-US",
        "screen_height": 1080,
        "screen_width": 1920,
        "time_zone": 123,
        "ip_address": "192.168.1.1",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
        "os_type": "Windows",
        "os_version": "10",
        "device_model": "Desktop"
    },
    "order_details": [{
        "product_name":"something",
        "quantity": 4, 
        "amount" : 400
    }]
}

response: - The payment should be succeeded

{
    "payment_id": "pay_TORNbtguEZUEleC3kYt5",
    "merchant_id": "merchant_1740386925",
    "status": "succeeded",
    "amount": 100,
    "net_amount": 100,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 100,
    "connector": "helcim",
    "client_secret": "pay_TORNbtguEZUEleC3kYt5_secret_PLV79VNxPEreoif4WfRh",
    "created": "2025-02-24T08:49:05.760Z",
    "currency": "USD",
    "customer_id": "helcim",
    "customer": {
        "id": "helcim",
        "name": "John Doe",
        "email": "[email protected]",
        "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": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "9130",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "541333",
            "card_extended_bin": null,
            "card_exp_month": "01",
            "card_exp_year": "28",
            "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"
        },
        "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": [
        {
            "brand": null,
            "amount": 400,
            "category": null,
            "quantity": 4,
            "tax_rate": null,
            "product_id": null,
            "product_name": "something",
            "product_type": null,
            "sub_category": null,
            "product_img_link": null,
            "product_tax_code": null,
            "total_tax_amount": null,
            "requires_shipping": null
        }
    ],
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.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,
    "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": "helcim",
        "created_at": 1740386945,
        "expires": 1740390545,
        "secret": "epk_79d58a8d4ee84ef7bd0e66d4ffa2d471"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "32476974",
    "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_TORNbtguEZUEleC3kYt5_1",
    "payment_link": null,
    "profile_id": "pro_1daddCjtZeUez131YwqB",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_b16Kuzg7hY5sPy9NgQUV",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-02-24T09:04:05.759Z",
    "fingerprint": null,
    "browser_info": {
        "os_type": "Windows",
        "language": "en-US",
        "time_zone": 123,
        "ip_address": "192.168.1.1",
        "os_version": "10",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
        "color_depth": 24,
        "device_model": "Desktop",
        "java_enabled": true,
        "screen_width": 1920,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 1080,
        "java_script_enabled": true
    },
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-02-24T08:49:09.053Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": "manual"
}

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

@itsharshvb itsharshvb requested review from a team as code owners February 21, 2025 08:52
Copy link

semanticdiff-com bot commented Feb 21, 2025

@itsharshvb itsharshvb added A-connector-integration Area: Connector integration C-refactor Category: Refactor labels Feb 21, 2025
@itsharshvb itsharshvb linked an issue Feb 21, 2025 that may be closed by this pull request
2 tasks
@itsharshvb itsharshvb changed the title [REFACTOR]: [FISERV] Add amount conversion framework to Fiserv refactor: [FISERV] Add amount conversion framework to Fiserv Feb 21, 2025
@itsharshvb itsharshvb changed the title refactor: [FISERV] Add amount conversion framework to Fiserv refactor(connector): [FISERV, HELCIM] Add amount conversion framework to Fiserv, Helcim Feb 24, 2025
@itsharshvb itsharshvb linked an issue Feb 24, 2025 that may be closed by this pull request
2 tasks

impl Fiserv {
pub fn new() -> &'static Self {
&Self {
amount_converter: &MinorUnitForConnector,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
amount_converter: &MinorUnitForConnector,
amount_converter: &FloatMajorUnitForConnector,

According to the doc, the amount accepted by the connector is in FloatMajorUnit. Please make the necessary changes accordingly at all relevant places for the Fiserv connector.

@@ -23,22 +23,14 @@ use crate::{

#[derive(Debug, Serialize)]
pub struct FiservRouterData<T> {
pub amount: String,
pub amount: MinorUnit,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
pub amount: MinorUnit,
pub amount: FloatMajorUnit,

@@ -89,8 +81,7 @@ pub struct GooglePayToken {

#[derive(Default, Debug, Serialize)]
pub struct Amount {
#[serde(serialize_with = "utils::str_to_f32")]
total: String,
total: MinorUnit,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
total: MinorUnit,
total: FloatMajorUnit,

pub router_data: T,
}

impl<T> TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for FiservRouterData<T> {
impl<T> TryFrom<(MinorUnit, T)> for FiservRouterData<T> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
impl<T> TryFrom<(MinorUnit, T)> for FiservRouterData<T> {
impl<T> TryFrom<(FloatMajorUnit, T)> for FiservRouterData<T> {

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-refactor Category: Refactor
Projects
None yet
2 participants