Skip to content

2021-10-13 - Refund handling

2021-10-13 - Refund handling

INFO

This document represents an architecture decision record (ADR) and has been mirrored from the ADR section in our Shopware 6 repository. You can find the original version here

Context

Shopware offers no way of unified refund handling. This results in every payment extension either implementing it themselves or not at all.

Decision

We want to implement the following structure to offer a unified refund handling for all extension types.

New refund data structure

A payment extension will need to persist its actual captures to use the refund handling. Those captures are bound to a specific OrderTransaction. The capture has an amount, allows saving an external reference.

OrderTransactionCapture

A capture is directly associated with a transaction. This relation is n order_transaction_captures to 1 order_transaction.

Database table

TypeField nameReferences
BINARY(16)id
BINARY(16)transaction_idorder_transaction.id
BINARY(16)state_idstate_machine_state.id
VARCHAR(255) NULLexternal_reference
LONGTEXTamount
LONGTEXT NULLcustom_fields

Entity

TypeProperty name
stringid
stringtransactionId
stringstateId
string/nullexternalReference
floattotalAmount
CalculatedPriceamount
array/nullcustomFields
OrderTransactionEntity/nulltransaction
StateMachineStateEntity/nullstateMachineState
OrderTransactionRefundCollection/nullrefunds

OrderTransactionCaptureRefund

A refund is directly associated with a capture. This relation is n order_transaction_capture_refunds to 1 order_transaction_capture.

Database table

TypeField nameReferences
BINARY(16)id
BINARY(16)capture_idorder_transaction_capture.id
BINARY(16)state_idstate_machine_state.id
VARCHAR(255) NULLreason
LONGTEXTamount
LONGTEXT NULLcustom_fields
VARCHAR(255) NULLexternal_reference

Entity

TypeProperty name
stringid
stringcaptureId
stringstateId
string/nullexternalReference
string/nullreason
floattotalAmount
CalculatedPriceamount
array/nullcustomFields
StateMachineStateEntity/nullstateMachineState
OrderTransactionCaptureEntity/nulltransactionCapture
OrderTransactionCaptureRefundPositionCollection/nullpositions

OrderTransactionCaptureRefundPosition

Refund positions are optional and only there if a refund is position-specific. They relate n order_transaction_capture_refund_positions to 1 order_transaction_capture_refund.

Database table

TypeField nameReferences
BINARY(16)id
BINARY(16)refund_idorder_transaction_capture_refund.id
BINARY(16)line_item_idorder_line_item.id
INT(11)quantity
VARCHAR(255) NULLreason
LONGTEXTrefund_amount
LONGTEXT NULLcustom_fields

Entity

TypeProperty name
stringid
stringrefundId
stringlineItemId
string/nullreason
intquantity
floatrefundPrice
CalculatedPricerefundAmount
array/nullcustomFields
OrderLineItemEntity/nulllineItem
OrderTransactionCaptureRefundEntity/nullorderTransactionCaptureRefund

Changes to existing entities

PaymentMethod

  • Add refundHandlingEnabled computed field if payment method handler implements RefundHandlerInterface

OrderTransaction

  • Add OneToManyAssociation OrderTransactionCaptureCollection captures

OrderLineItem

  • Add OneToManyAssociation OrderTransactionCaptureRefundPositionCollection|null refundPositions

State machine

Add 2 new state machines for OrderTransactionCapture and OrderTransactionCaptureRefund.

OrderTransactionCapture

We want to add the following states to a new order_transaction_capture.state state machine:

  • pending
  • completed
  • failed

OrderTransactionCaptureRefund

We want to add the following states to a new order_transaction_capture_refund.state state machine:

  • open
  • in_progress
  • cancelled
  • failed
  • completed

PaymentRefundHandlerInterface

Add an interface as outlined below:

php
public function refund(string $orderRefundId, Context $context): void;

PaymentRefundProcessor

The PaymentRefundProcessor gets triggered via a corresponding Admin-API action and contains the method processRefund as outlined below:

php
public function processRefund(string $refundId, Context $context): Response;

Apps

The whole refund handling should be available for apps and plugins. The following changes are required to allow apps to handle refunds.

\Shopware\Core\Framework\App\Manifest\Xml\PaymentMethod

Add refundUrl to the manifest PaymentMethod. Also change the xsd accordingly.

AppRefundHandler

Add an AppRefundHandler, which assembles payloads and talks to the app refund endpoint.

Captures and apps

Captures are written over the Admin-API endpoint.