Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

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
Appearance settings

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

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

Merged
likhinbopanna merged 22 commits intomainfromrefunds-create-core-flow
Apr 21, 2025

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

hrithikesh026
hrithikesh026 previously approved these changesApr 11, 2025
jarnura
jarnura previously approved these changesApr 13, 2025
#[cfg(feature = "v2")]
impl ApiEventMetric for RefundsCreateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
None
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we returningNone here?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

We are going to take this up later in separate implementation.

tsdk02 reacted with thumbs up emoji
tsdk02
tsdk02 previously approved these changesApr 15, 2025
@likhinbopannalikhinbopanna added this pull request to themerge queueApr 17, 2025
@github-merge-queuegithub-merge-queuebot removed this pull request from themerge queue due to failed status checksApr 17, 2025
@likhinbopannalikhinbopanna added this pull request to themerge queueApr 21, 2025
Merged via the queue intomain with commiteabef32Apr 21, 2025
16 of 20 checks passed
@likhinbopannalikhinbopanna deleted the refunds-create-core-flow branchApril 21, 2025 09:19
pixincreate added a commit that referenced this pull requestApr 22, 2025
…acilitapay-pix-pmt* 'main' of github.com:juspay/hyperswitch:  fix(connector): revert noon-paypal (#7864)  refactor(cypress): do not update `card_expiry` while updating card info (#7834)  feat(vsaas): add processor_merchant_id and created_by column in payment_intents and payments_attempts for v1 (#7768)  chore(dynamic-fields): remove billing details as required fields for Worldpay connector (#7853)  feat(dynamic_routing): integration of elimination routing for core flows (#6816)  chore(version): 2025.04.22.0  revert: fix(connector): [noon] address `next_action_url` being `null` for cards in 3ds payment (#7859)  feat(dynamic_routing): add open router integration for success based routing (#7795)  feat(refunds_v2): Add refund create core flow (#7619)  fix(core): [CARD TESTING GUARD] Added Card Testing Guard Config response in case of NULL (#7478)
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@hrithikesh026hrithikesh026hrithikesh026 approved these changes

@su-shivanshmathursu-shivanshmathursu-shivanshmathur approved these changes

@jarnurajarnurajarnura left review comments

@tsdk02tsdk02tsdk02 left review comments

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.
6 participants
@AmeyWale@jarnura@hrithikesh026@tsdk02@su-shivanshmathur@likhinbopanna

[8]ページ先頭

©2009-2025 Movatter.jp