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(router): add integrity check for refund refund sync and capture flow with stripe as connector #5187

Conversation

sahkal
Copy link
Contributor

@sahkal sahkal commented Jul 3, 2024

Type of Change

  • New feature
  • Enhancement

Description

With this Pr we are creating integrity check for Refund, Refund Sync and Capture flows

Motivation and Context

This Pr holds the payment in a non-terminal state incase there is any data discrepancy in the above flows.

How did you test it?

Since it is a black box scenario it cannot is tested in sbx, until and unless we have a way to configure dummy connector to send mismatched data.

Local testing are as follows:

Capture Flow integrity checks

[Scenario 1] : Automatic capture

Steps:

Do payment create

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D' \
--data-raw '
{
    "amount": 6540,
    "currency": "USD",
      "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "amount_to_capture": 6540,
    "customer_id": "stripesavecard_1234",
    "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://google.com",
    "setup_future_usage": "on_session",
    "customer_acceptance": {
        "acceptance_type": "offline",
        "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": "4111111111111111",
          "card_exp_month": "03",
          "card_exp_year": "2030",
          "card_holder_name": "joseph Doe",
          "card_cvc": "737"
        }
      },
    "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"
        }
    },
    "routing": {
        "type": "single",
        "data": "stripe"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "session_expiry": 2423545   
}'

have hardcoded the capture amount internally to fail
Screenshot 2024-07-03 at 3 20 50 PM

Now do Sync to

normal sync, to check status and error message at our end.

curl --location 'http://localhost:8080/payments/pay_gRBvgpnuFH1xp1ogV1JU' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D'

Status should be processing and error message should state the kind of error

Response

{
    "payment_id": "pay_kW1mXPEzZmf6QZ54smCE",
    "merchant_id": "merchant_1719479670",
    "status": "processing",
    "amount": 6540,
    "net_amount": 6540,
    "amount_capturable": 6540,
    "amount_received": 6540,
    "connector": "stripe",
    "client_secret": "pay_kW1mXPEzZmf6QZ54smCE_secret_BCTKpfxKFlA7QL2WgWRI",
    "created": "2024-07-03T10:26:16.124Z",
    "currency": "USD",
    "customer_id": "stripesavecard_1234",
    "customer": {
        "id": "stripesavecard_1234",
        "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": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1111",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "411111",
            "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"
        },
        "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": "[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": "Integrity Check Failed! Value mismatched for fields capture_amount",
    "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": false,
    "connector_transaction_id": "pi_3PYQOCCuXDMKrYZe0WmZAbDZ",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_yl0tPMSCxxJlndl0aMHz",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_ejZeqRd80HoTTxvHokwN",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-07-31T11:38:41.124Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_kVzWJzqsyZgiVe49N3rc",
    "payment_method_status": "active",
    "updated": "2024-07-03T10:26:17.975Z",
    "charges": null,
    "frm_metadata": null
}

check if the connector has fixed the data using force sync

curl --location 'http://localhost:8080/payments/pay_gRBvgpnuFH1xp1ogV1JU?force_sync=true' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D'

if the connector has fixed it then it goes to success
Screenshot 2024-07-03 at 3 54 50 PM

[Scenario 2] : Manual capture

Do payment create

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D' \
--data-raw '
{
    "amount": 6540,
    "currency": "USD",
      "confirm": true,
    "capture_method": "manual",
    "capture_on": "2022-09-10T10:11:12Z",
    "amount_to_capture": 456,
    "customer_id": "stripesavecard_1234",
    "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://google.com",
    "setup_future_usage": "on_session",
    "customer_acceptance": {
        "acceptance_type": "offline",
        "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": "4111111111111111",
          "card_exp_month": "03",
          "card_exp_year": "2030",
          "card_holder_name": "joseph Doe",
          "card_cvc": "737"
        }
      },
    "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"
        }
    },
    "routing": {
        "type": "single",
        "data": "stripe"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "session_expiry": 2423545
}'

Try doing manual capture, have hardcoded it to fail

curl --location 'http://localhost:8080/payments/pay_dkGgoeJ2jw54XDbRIkJQ/capture' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D' \
--data '{
  "amount_to_capture": 428
}'
Screenshot 2024-07-03 at 6 11 38 PM

Now, do sync and lets say connector has fixed the data mismatched,
Sync

curl --location 'http://localhost:8080/payments/pay_dkGgoeJ2jw54XDbRIkJQ?force_sync=true' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D'
Screenshot 2024-07-03 at 6 13 56 PM

Refunds

Do payment create

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D' \
--data-raw '
{
    "amount": 6540,
    "currency": "USD",
      "confirm": true,
    "capture_on": "2022-09-10T10:11:12Z",
    "customer_id": "stripesavecard_1234",
    "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://google.com",
    "setup_future_usage": "on_session",
    "customer_acceptance": {
        "acceptance_type": "offline",
        "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": "4111111111111111",
          "card_exp_month": "03",
          "card_exp_year": "2030",
          "card_holder_name": "joseph Doe",
          "card_cvc": "737"
        }
      },
    "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"
        }
    },
    "routing": {
        "type": "single",
        "data": "stripe"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "session_expiry": 2423545 
}'

Status should be 200, with succeeded

Now, do refund

curl --location 'http://localhost:8080/refunds' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D' \
--data '{
    "payment_id": "pay_johXpdvAaZoxsPm7JiwM",
    "amount": 6540,
    "reason": "Customer returned product",
    "refund_type": "instant",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    }
}'

The status code should be 200, with status as manual review along with error message
Screenshot 2024-07-03 at 6 32 06 PM

Now, lets say the merchant tries refund again, but since the refunds was already initiated, we shall get 400 bad request
Screenshot 2024-07-03 at 6 45 48 PM

Now, we do a sync checking if the connector as fixed the data

curl --location 'http://localhost:8080/refunds/ref_tCSzuGnxgTPUvA62hBe6' \
--header 'Accept: application/json' \
--header 'api-key: dev_DZb1asJFT5ywRneS0niZUSrkXAiwGopwoWDKETATbIJqvPm2hj58q1Yrpbhqdb6D'
Screenshot 2024-07-03 at 6 49 20 PM

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code

sahkal and others added 30 commits May 13, 2024 16:50
hrithikesh026
hrithikesh026 previously approved these changes Jul 5, 2024
hrithikesh026
hrithikesh026 previously approved these changes Jul 5, 2024
Narayanbhat166
Narayanbhat166 previously approved these changes Jul 5, 2024
Comment on lines +2930 to +2931
let currency_enum = enums::Currency::from_str(currency.to_uppercase().as_str())
.change_context(errors::ConnectorError::ParsingFailed)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

If this check fails we will throw internal_server_error, and we won't be able to recover the payment without directly altering the DB

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, but this parsing failure should only happen if the currency is not supported by our application and we get that in response, Yes! we wont be able to recover this payment since its a data mismatched issue at connector end! it should be 5xx since if the issue is in hyperswitch end then we shouldn't have let the payment go through in the beginning of the request.

SamraatBansal
SamraatBansal previously approved these changes Jul 5, 2024
): added capture amount to sync data
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Jul 8, 2024
Merged via the queue into main with commit adc760f Jul 8, 2024
13 checks passed
@Gnanasundari24 Gnanasundari24 deleted the 5742-integrity-add-integrity-check-for-refund-refund-sync-and-capture-flow branch July 8, 2024 15:30
@sahkal sahkal restored the 5742-integrity-add-integrity-check-for-refund-refund-sync-and-capture-flow branch July 10, 2024 14:17
@pixincreate pixincreate removed the S-waiting-on-review Status: This PR has been implemented and needs to be reviewed label Jul 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-core Area: Core flows A-framework Area: Framework C-feature Category: Feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants