# mageme/module-eu-withdrawal

> Magento 2 implementation scaffolding for the EU consumer-withdrawal workflow under Art. 11a Directive 2011/83/EU (as amended by 2023/2673): guided storefront flow (find order, select items, confirm), durable-medium receipt email, 22-locale Annex I content. NOT legal advice — see README disclaimer; merchant is responsible for compliance verification.

`composer require mageme/module-eu-withdrawal`

Canonical URL: https://packagento.com/mageme/module-eu-withdrawal

## At a glance

- **Vendor**: mageme (https://packagento.com/mageme.md)
- **Latest version**: 1.0.7 — released 2026-06-21
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/mageme/module-eu-withdrawal and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require mageme/module-eu-withdrawal:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Magento 2 implementation scaffolding for the EU consumer-withdrawal workflow under Art. 11a Directive 2011/83/EU (as amended by 2023/2673): guided storefront flow (find order, select items, confirm), durable-medium receipt email, 22-locale Annex I content. NOT legal advice — see README disclaimer; merchant is responsible for compliance verification.

## README

> EU withdrawal button for Magento 2 — the consumer right-of-withdrawal flow
> required by 19 June 2026 under Article 11a of the
> [Consumer Rights Directive (2011/83/EU)](https://eur-lex.europa.eu/eli/dir/2011/83/oj) as amended
> by [Directive (EU) 2023/2673](https://eur-lex.europa.eu/eli/dir/2023/2673/oj).

[![Latest Version](https://img.shields.io/packagist/v/mageme/module-eu-withdrawal.svg?style=flat-square)](https://packagist.org/packages/mageme/module-eu-withdrawal)
[![Downloads](https://img.shields.io/packagist/dt/mageme/module-eu-withdrawal.svg?style=flat-square)](https://packagist.org/packages/mageme/module-eu-withdrawal)
[![Magento](https://img.shields.io/badge/Magento-2.4.4%20–%202.4.9-EE672F.svg?style=flat-square)](https://magento.com)
[![PHP](https://img.shields.io/badge/PHP-8.1%20%7C%208.2%20%7C%208.3%20%7C%208.4%20%7C%208.5-777BB4.svg?style=flat-square)](https://php.net)
[![License](https://img.shields.io/badge/license-MageMe%20EULA-blue.svg?style=flat-square)](https://mageme.com/license/)

The Magento 2 withdrawal button your EU storefront needs before the 19 June 2026 deadline — a storefront-ready, guided flow (find order → select items → review & confirm) with durable-medium receipt emails and Annex I content in 22 EU locales, on Luma, Hyvä, and Breeze.

It adds only the legal withdrawal step required under Art. 11a, and works alongside your existing RMA / refund process rather than replacing it.

**[Documentation](https://docs.mageme.com)** · **[Get Pro features](https://mageme.com/magento-2-withdrawal-button-extension.html)**

![Withdrawal button on the order page — shown automatically once the order is delivered](https://mageme.com/media/extensions/eu-withdrawal/order-view.png)

---

### What it does

- **Storefront withdrawal flow** — guided form (find order → select items → review & confirm) for guests and registered customers at `/withdraw-contract/`
- **Annex I in 22 EU locales** — verbatim EUR-Lex translations where available, theme-overridable per locale
- **Durable-medium receipt** — confirmation email with a frozen snapshot of the legal text shown to the consumer
- **Admin grid and workflow** — filterable request list, mass actions, status state machine, CSV export
- **Article 16 exclusions** — preset list configurable per category, with merchant override

### Screenshots

**Storefront — guided withdrawal flow** (find order → select items → review & confirm):

![Storefront withdrawal flow — select items to withdraw with per-item quantity](https://mageme.com/media/extensions/eu-withdrawal/storefront-flow.png)

**Admin — manage withdrawal requests** (status workflow, jurisdictions, refund totals, CSV export):

![Admin withdrawal requests grid](https://mageme.com/media/extensions/eu-withdrawal/admin-grid.png)

**Durable-medium receipt email** — the confirmation sent to the consumer with a frozen snapshot of the legal text they accepted. *(The SHA-256 integrity-hash card and one-click verification shown here are a [Pro](https://mageme.com/magento-2-withdrawal-button-extension.html) add-on.)*

![Durable-medium withdrawal receipt email; the SHA-256 integrity-hash card shown is a Pro add-on](https://mageme.com/media/extensions/eu-withdrawal/receipt-email.png)

### Free vs Pro

| Feature                                                    | Free | [Pro](https://mageme.com/magento-2-withdrawal-button-extension.html) |
|------------------------------------------------------------|:----:|:-------------------------------------------:|
| Storefront withdrawal flow                                 | Yes  |                     Yes                     |
| Annex I — 22 EU locales                                    | Yes  |                     Yes                     |
| Durable-medium receipt email                               | Yes  |                     Yes                     |
| Admin grid + status workflow                               | Yes  |                     Yes                     |
| Article 16 exclusion presets                               | Yes  |                     Yes                     |
| **Receipt verification** — SHA-256 cryptographic audit     |  —   |                     Yes                     |
| **Annex I forensic snapshot** — immutable per-request copy |  —   |                     Yes                     |
| **Hash-chain audit log** — DB-backed, tamper-evident       |  —   |                     Yes                     |
| **Magic-link guest access** — one-click tokenised URL      |  —   |                     Yes                     |
| **Seal-photo evidence** — optional intact-seal photos      |  —   |                     Yes                     |

→ **[Compare tiers and pricing](https://mageme.com/magento-2-withdrawal-button-extension.html)**

### Install

```bash
composer require mageme/module-eu-withdrawal
bin/magento module:enable MageMe_EUWithdrawal
bin/magento setup:upgrade
bin/magento cache:flush
```

After installation, enable the module at **Stores → Configuration → MageMe Extensions → EU Withdrawal**.

→ **[Full installation guide and configuration reference](https://docs.mageme.com/eu-withdrawal/install)**

On **Luma** and **Breeze** (Swissup) storefronts the base module works out of the box — no extra package required. Only **Hyvä** themes need the companion module below.

#### Hyvä storefront

If your storefront runs on a Hyvä theme, install the theme companion alongside this module — it ports the
customer-facing withdrawal flow and order-view integrations to Tailwind + Alpine.js:

```bash
composer require mageme/module-eu-withdrawal-hyva
bin/magento module:enable Hyva_MageMeEUWithdrawal
bin/magento setup:upgrade
```

If you also run **Hyvä Checkout**, add the checkout companion as well — it re-implements the pre-contract Annex I block
and the digital-content waiver step (Art. 16(m)) for Hyvä Checkout's Magewire runtime:

_(README truncated for .md surface. Full README on https://packagento.com/mageme/module-eu-withdrawal.)_

## Changelog

+ New: Restrict by Customer Group - optionally hide the self-service withdrawal flow from selected customer groups (e.g. your B2B / wholesale groups), while guests and consumers keep it
+ New: a new "If delivery is never confirmed" setting decides whether orders that reached a delivered status without a recorded delivery date stay open or are treated as not eligible (default)
+ New: Statuses Excluded From Withdrawal - choose order statuses (such as a legacy import status) that should never be offered for withdrawal
+ New: submitting a withdrawal request now adds a note with the requested refund to the related order's timeline
- Fix: the refund amount shown in the order-timeline notes and the durable-medium receipt now reflects the full amount instead of the shipping portion only
* Other: the checkout pre-contractual withdrawal information now follows the country and customer-group scope, so it shows only where the self-service withdrawal applies

### 1.0.6

+ New: the withdrawal-CTA order and shipment emails can now be selected directly from the Sales Emails template dropdown - no need to clone a template first
+ New: approving, denying or cancelling a request now adds a short note to the related order's timeline (refund amount, denial reason, or who cancelled), so the outcome is visible on the order itself
+ New: a drop-in "Withdraw from contract" link block for custom themes, so the link can be placed anywhere in the storefront
- Fix: status emails now send guests to the withdrawal page instead of a login page they cannot use
- Fix: the "Show Footer Link" setting now hides the storefront footer link when it is turned off
- Fix: the withdrawal form no longer errors on themes that do not include the optional photo-evidence step
* Other: the submission notification email now lists all of its available variables in the admin template editor

### 1.0.5

+ New: Item Selection setting - the withdrawal form can run in "Full order" mode where the request always covers all returnable items
+ New: Extension points for the Pro photo evidence step on the withdrawal form
+ New: Country Scope setting - optionally limit the self-service withdrawal flow to customers in selected countries
- Fix: final confirmation button now renders the legally required "Confirm withdrawal" label in the customer's language instead of "Submit return request"
- Fix: request creation no longer fails when a third-party extension dispatches the request-created event without eligibility data
- Fix: the "Withdraw from contract" link in order and shipment emails now renders when the email is resent from the admin or sent by a background job
- Fix: an order now stays available for withdrawal through the whole of its final eligible day
- Fix: a logged-in customer opening a withdrawal link for an order that is not their own is now turned away
* Other: Removed the redundant Eligibility column from the items table on the admin withdrawal request page.

### 1.0.4

- Fix: The digital-content waiver step no longer fails to save when the billing address is set during checkout.
* Other: Removed a non-functional Privacy & Retention settings group.
* Other: Internal cleanup, dead-code removal and a more robust order-lookup rate limiter.
* Other: Module permissions now appear under the Sales section in admin role permissions (thanks to Ole Schäfer).

### 1.0.3

- Fix: The refund total now matches the order total when a payment-method discount, gift card or other order-level adjustment applies — such orders previously could not be withdrawn or showed an inflated refund.
- Fix: The refund total shown right after submitting a withdrawal now includes the shipping refund.
- Fix: Corrected the German translation of the "Withdraw from contract" label.

### 1.0.2

_(Changelog truncated for .md surface. Full history on https://packagento.com/mageme/module-eu-withdrawal.)_

## Recent Versions

| Version | Released |
|---|---|
| 1.0.7 | 2026-06-21 |
| 1.0.6 | 2026-06-18 |
| 1.0.5 | 2026-06-17 |
| 1.0.4 | 2026-06-11 |
| 1.0.3 | 2026-06-08 |
| 1.0.2 | 2026-06-04 |
| 1.0.1 | 2026-06-03 |
| 1.0.0 | 2026-06-01 |

## Dependencies

### Require

| Package | Constraint |
|---|---|
| mageme/module-core | ^2.0 |
| php | ~8.1.0\|\|~8.2.0\|\|~8.3.0\|\|~8.4.0\|\|~8.5.0 |

## Quality

Latest release (1.0.7) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | Pass |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 348 | 1 error, 347 warnings (ruleset: Magento2) — 39 auto-fixable with phpcbf |
| PHPMD | Warning | 142 | 142 rule violations (MissingImport:62, NPathComplexity:20, UnusedFormalParameter:18, CyclomaticComplexity:16, ExcessiveClassComplexity:8) |
| Cpd | Warning | 2 | 2 duplicated chunks spanning 82 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Info | 1 | valid; 1 advisory note (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 20 | 20 | – | – |
| 2.4.8 | – | 20 | 20 | – |
| 2.4.9 | – | – | 18 | 18 |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["mageme/module-eu-withdrawal"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

mageme is a Magento 2 vendor on Packagento. See https://packagento.com/mageme.md for their full catalogue.

