Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

feat(refunds_v2): Add refund create core flow#7619

Open
AmeyWale wants to merge19 commits intomain
base:main
Choose a base branch
Loading
fromrefunds-create-core-flow

Conversation

AmeyWale
Copy link
Contributor

@AmeyWaleAmeyWale commentedMar 25, 2025
edited
Loading

Type of Change

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

Description

This PR is a part of v2 implementation of refunds. This PR contains refunds create core flow, i.e we can be able to create refunds for payments in v2.

Important
We are movingrefunds/transformers.rs andrefunds/validator.rs to a separate location because of accessibility
to both v1 and v2 refund code.

Additional Changes

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

Motivation and Context

Merging this PR would add support for creating refunds for payments in v2 apis.

How did you test it?

  • Create Payment Intent api call
curl --location 'http://localhost:8080/v2/payments/create-intent' \--header 'api-key: xyz' \--header 'Content-Type: application/json' \--header 'x-profile-id: pro_' \--header 'Authorization: api-key=xyz' \--data-raw '{    "amount_details": {        "order_amount": 100,        "currency": "USD"    },    "capture_method":"automatic",    "authentication_type": "no_three_ds",    "billing": {        "address": {            "first_name": "John",            "last_name": "Dough"        },        "email": "example@example.com"    },    "shipping": {        "address": {            "first_name": "John",            "last_name": "Dough",            "city": "Karwar",            "zip": "581301",            "state": "Karnataka"        },        "email": "example@example.com"    }}'
  • Response from the above call
{"id":"12345_pay_0195d13dd6497c12a3b187039fc4b71e","status":"requires_payment_method","amount_details": {"order_amount":100,"currency":"USD","shipping_cost":null,"order_tax_amount":null,"external_tax_calculation":"skip","surcharge_calculation":"skip","surcharge_amount":null,"tax_on_surcharge":null  },"client_secret":"12345_pay_0195d13dd6497c12a3b187039fc4b71e_secret_0195d13dd6547a938bfe7b97b36203a5","profile_id":"pro_TujgCYCsvWvO6YNsRAmC","merchant_reference_id":null,"routing_algorithm_id":null,"capture_method":"automatic","authentication_type":"no_three_ds","billing": {"address": {"city":null,"country":null,"line1":null,"line2":null,"line3":null,"zip":null,"state":null,"first_name":"John","last_name":"Dough"    },"phone":null,"email":"example@example.com"  },"shipping": {"address": {"city":"Karwar","country":null,"line1":null,"line2":null,"line3":null,"zip":"581301","state":"Karnataka","first_name":"John","last_name":"Dough"    },"phone":null,"email":"example@example.com"  },"customer_id":null,"customer_present":"present","description":null,"return_url":null,"setup_future_usage":"on_session","apply_mit_exemption":"Skip","statement_descriptor":null,"order_details":null,"allowed_payment_method_types":null,"metadata":null,"connector_metadata":null,"feature_metadata":null,"payment_link_enabled":"Skip","payment_link_config":null,"request_incremental_authorization":"default","expires_on":"2025-03-26T07:12:25.588Z","frm_metadata":null,"request_external_three_ds_authentication":"Skip"}
  • Confirm Intent API call
curl --location 'http://localhost:8080/v2/payments/12345_pay_0195d13dd6497c12a3b187039fc4b71e/confirm-intent' \--header 'x-client-secret: 12345_pay_0195d13dd6497c12a3b187039fc4b71e_secret_0195d13dd6547a938bfe7b97b36203a5' \--header 'x-profile-id: pro_TujgCYCsvWvO6YNsRAmC' \--header 'Content-Type: application/json' \--header 'Authorization: publishable-key=pk_dev_58559cdf90434adcb0b92eeb6a8b633f,client-secret=12345_pay_0195d13dd6497c12a3b187039fc4b71e_secret_0195d13dd6547a938bfe7b97b36203a5' \--data '{    "payment_method_data": {        "card": {            "card_number": "4242424242424242",            "card_exp_month": "09",            "card_exp_year": "25",            "card_holder_name": "John Doe",            "card_cvc": "100"        }    },    "payment_method_type": "card",    "payment_method_subtype": "credit"}'
  • Response from the above call
{"id":"12345_pay_0195d13dd6497c12a3b187039fc4b71e","status":"succeeded","amount": {"order_amount":100,"currency":"USD","shipping_cost":null,"order_tax_amount":null,"external_tax_calculation":"skip","surcharge_calculation":"skip","surcharge_amount":null,"tax_on_surcharge":null,"net_amount":100,"amount_to_capture":null,"amount_capturable":0,"amount_captured":100  },"customer_id":null,"connector":"stripe","client_secret":"12345_pay_0195d13dd6497c12a3b187039fc4b71e_secret_0195d13dd6547a938bfe7b97b36203a5","created":"2025-03-26T06:57:25.588Z","payment_method_data": {"billing":null  },"payment_method_type":"card","payment_method_subtype":"credit","connector_transaction_id":"pi_3R6ntzD5R7gDAGff0MYUxZFn","connector_reference_id":null,"merchant_connector_id":"mca_FhEKUEAUdgv7mVCs3A9U","browser_info":null,"error":null,"shipping":null,"billing":null,"attempts":null,"connector_token_details": {"token":"pm_1R6ntzD5R7gDAGff07DogD0c","connector_token_request_reference_id":"oMf8ppmFul0oTqI6Zl"  },"payment_method_id":null,"next_action":null,"return_url":"https://google.com/success","authentication_type":"no_three_ds","authentication_type_applied":"no_three_ds"}
  • Create refund for a successful payment
curl --location 'http://localhost:8080/v2/refunds' \--header 'X-Profile-Id: pro_TujgCYCsvWvO6YNsRAmC' \--header 'Content-Type: application/json' \--header 'api-key: dev_kksGlKY14xNypCzsrJIXFCzL3t2j5kUs7ChmloPryJsdRy2RWYljonzPCxJSDmuZ' \--data '{    "payment_id":"12345_pay_0195d13dd6497c12a3b187039fc4b71e",    "merchant_reference_id":"1742972385",    "reason":"Paid by mistake",    "metadata":{        "foo":"bar"    }}'
  • Response from the above call
{"id":"12345_ref_0195d13dfedb7790bc1a84be825e64d5","payment_id":"12345_pay_0195d13dd6497c12a3b187039fc4b71e","merchant_reference_id":"1742972256","amount":100,"currency":"USD","status":"succeeded","reason":"Paid by mistake","metadata": {"foo":"bar"  },"error_details": {"code":"","message":""  },"created_at":"2025-03-26T06:57:35.993Z","updated_at":"2025-03-26T06:57:36.981Z","connector":"stripe","profile_id":"pro_TujgCYCsvWvO6YNsRAmC","merchant_connector_id":"mca_FhEKUEAUdgv7mVCs3A9U","connector_refund_reference_id":"12345_ref_0195d13dfedb7790bc1a84be825e64d5"}
  • Trying the same refund again will give us this response
{"error":{"type":"invalid_request","message":"The refund amount exceeds the amount captured","code":"IR_13"}}
  • What if the payment was failed and we try to refund it. (Invalid card number in confirm intent call)
curl --location 'http://localhost:8080/v2/payments/12345_pay_0195d142100474c3bcb32e40935e290d/confirm-intent' \--header 'x-client-secret: 12345_pay_0195d142100474c3bcb32e40935e290d_secret_0195d14210127d30b524ec0e063b3c0a' \--header 'x-profile-id: pro_TujgCYCsvWvO6YNsRAmC' \--header 'Content-Type: application/json' \--header 'Authorization: publishable-key=pk_dev_58559cdf90434adcb0b92eeb6a8b633f,client-secret=12345_pay_0195d142100474c3bcb32e40935e290d_secret_0195d14210127d30b524ec0e063b3c0a' \--data '{    "payment_method_data": {        "card": {            "card_number": "4242424242424242",            "card_exp_month": "01",            "card_exp_year": "25",            "card_holder_name": "John Doe",            "card_cvc": "100"        }    },    "payment_method_type": "card",    "payment_method_subtype": "credit"}'
  • Response from the above call
{"id":"12345_pay_0195d142100474c3bcb32e40935e290d","status":"failed","amount": {"order_amount":100,"currency":"USD","shipping_cost":null,"order_tax_amount":null,"external_tax_calculation":"skip","surcharge_calculation":"skip","surcharge_amount":null,"tax_on_surcharge":null,"net_amount":100,"amount_to_capture":null,"amount_capturable":0,"amount_captured":null  },"customer_id":null,"connector":"stripe","client_secret":"12345_pay_0195d142100474c3bcb32e40935e290d_secret_0195d14210127d30b524ec0e063b3c0a","created":"2025-03-26T07:02:02.514Z","payment_method_data": {"billing":null  },"payment_method_type":"card","payment_method_subtype":"credit","connector_transaction_id":null,"connector_reference_id":null,"merchant_connector_id":"mca_FhEKUEAUdgv7mVCs3A9U","browser_info":null,"error": {"code":"invalid_expiry_month","message":"invalid_expiry_month","unified_code":null,"unified_message":null  },"shipping":null,"billing":null,"attempts":null,"connector_token_details":null,"payment_method_id":null,"next_action":null,"return_url":"https://google.com/success","authentication_type":"no_three_ds","authentication_type_applied":"no_three_ds"}
  • Trying to refund failed payment
curl --location 'http://localhost:8080/v2/refunds' \--header 'X-Profile-Id: pro_TujgCYCsvWvO6YNsRAmC' \--header 'Content-Type: application/json' \--header 'api-key: dev_kksGlKY14xNypCzsrJIXFCzL3t2j5kUs7ChmloPryJsdRy2RWYljonzPCxJSDmuZ' \--data '{    "payment_id":"12345_pay_0195d142100474c3bcb32e40935e290d",    "merchant_reference_id":"1742972638",    "reason":"Paid by mistake",    "metadata":{        "foo":"bar"    }}'
  • Response from the above call
{"error": {"type":"invalid_request","message":"This Payment could not be refund because it has a status of failed. The expected state is succeeded, partially_captured","code":"IR_14"  }}

Error case responses

  • Connector NotImplemented Error (501)
{    "error": {        "type": "invalid_request",        "message": "get_url method is not implemented",        "code": "IR_00"    }}
  • Connector NotSupported Error (400)
{    "error": {        "type": "invalid_request",        "message": "Payment method type not supported",        "code": "IR_19",        "reason": "Refund is not supported by Stripe"    }}

Checklist

  • I formatted the codecargo +nightly fmt --all
  • I addressed lints thrown bycargo clippy
  • I reviewed the submitted code
  • I added unit tests for my changes where possible

@AmeyWaleAmeyWale requested review froma team ascode ownersMarch 25, 2025 09:38
@semanticdiff-comSemanticDiff.com
Copy link

semanticdiff-combot commentedMar 25, 2025
edited
Loading

Review changes with  SemanticDiff

Changed Files
FileStatus
  crates/router/src/lib.rs  82% smaller
  crates/router/src/core/refunds.rs  45% smaller
  crates/router/src/types/api/refunds.rs  41% smaller
  crates/openapi/src/openapi_v2.rs  26% smaller
  api-reference-v2/openapi_spec.json  14% smaller
  crates/api_models/src/refunds.rs  12% smaller
  crates/router/src/core/utils.rs  10% smaller
  crates/api_models/src/events/refund.rs  8% smaller
  crates/api_models/Cargo.tomlUnsupported file format
  crates/common_utils/src/types.rs  0% smaller
  crates/diesel_models/src/query/payment_attempt.rs  0% smaller
  crates/diesel_models/src/query/refund.rs  0% smaller
  crates/diesel_models/src/refund.rs  0% smaller
  crates/hyperswitch_domain_models/src/payments.rs  0% smaller
  crates/hyperswitch_domain_models/src/payments/payment_attempt.rs  0% smaller
  crates/openapi/Cargo.tomlUnsupported file format
  crates/router/Cargo.tomlUnsupported file format
  crates/router/src/core.rs  0% smaller
  crates/router/src/core/refunds_v2.rs  0% smaller
  crates/router/src/core/utils/refunds_transformers.rs  0% smaller
  crates/router/src/core/utils/refunds_validator.rs  0% smaller
  crates/router/src/db/kafka_store.rs  0% smaller
  crates/router/src/db/refund.rs  0% smaller
  crates/router/src/routes.rs  0% smaller
  crates/router/src/routes/app.rs  0% smaller
  crates/router/src/routes/refunds.rs  0% smaller
  crates/storage_impl/src/mock_db/payment_attempt.rs  0% smaller
  crates/storage_impl/src/payments/payment_attempt.rs  0% smaller

@AmeyWaleAmeyWale self-assigned thisMar 25, 2025
@AmeyWaleAmeyWale linked an issueMar 25, 2025 that may beclosed by this pull request
@hyperswitch-bothyperswitch-botbot added the M-api-contract-changesMetadata: This PR involves API contract changes labelMar 25, 2025
hrithikesh026
hrithikesh026 previously approved these changesApr 2, 2025
hrithikesh026
hrithikesh026 previously approved these changesApr 2, 2025
hrithikesh026
hrithikesh026 previously approved these changesApr 11, 2025
Copy link
Contributor

@hrithikesh026hrithikesh026 left a comment

Choose a reason for hiding this comment

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

LGTM

use api_models::{enums::Connector, refunds::RefundErrorDetails};
use common_utils::{
id_type,
types::{ConnectorTransactionId, MinorUnit},
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
types::{ConnectorTransactionId,MinorUnit},
typesascommon_types,

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@jarnurajarnurajarnura approved these changes

@hrithikesh026hrithikesh026hrithikesh026 approved these changes

At least 2 approving reviews are required to merge this pull request.

Assignees

@AmeyWaleAmeyWale

Labels
api-v2M-api-contract-changesMetadata: This PR involves API contract changes
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

[FEATURE]: Add refunds create core flow for v2 apis.
3 participants
@AmeyWale@jarnura@hrithikesh026

[8]ページ先頭

©2009-2025 Movatter.jp