Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2c0981a
Use state machine in PaymentWebhookController
TheMilek Apr 21, 2026
289db82
Add comment about 200 responses
TheMilek Apr 21, 2026
97265af
Use state machine in PaymentWebhookController (#339)
TheMilek Apr 22, 2026
a2dc1fe
Omit cardToken and method from off-session recurring charge
michalkaczmarek-bitbag Jun 11, 2026
00ec842
ECS
michalkaczmarek-bitbag Jun 12, 2026
50e1676
[Integration Mollie 3] Omit cardToken and method from off-session rec…
TheMilek Jun 16, 2026
a789926
Refactor migration flow - moved to SubscriptionPlugin
michalkaczmarek-bitbag Jun 30, 2026
e806494
[Integration Mollie 11] add lazy migration - mollie side (#343)
TheMilek Jun 30, 2026
1c2bfd3
Add deprecation notices to Mollie subscription admin UI
TheMilek Jun 29, 2026
7834ea1
Add deprecation notices to Mollie subscription admin UI (#344)
TheMilek Jun 30, 2026
cf0e420
fix repo methods
michalkaczmarek-bitbag Jun 30, 2026
387cc18
fix repo methods (#345)
TheMilek Jun 30, 2026
393328d
Deprecate Mollie subscription and recurring payment classes
TheMilek Jun 30, 2026
c70faa9
Skip cancellation of migrated Mollie subscriptions
TheMilek Jun 30, 2026
db97cf5
Add findMigrated to Mollie subscription repository
TheMilek Jun 30, 2026
06c723b
Mollie subscription deprecation (#346)
TheMilek Jun 30, 2026
e52bb44
Filter migrated and processing subscriptions in Mollie subscription r…
TheMilek Jun 30, 2026
b03cdb5
Filter migrated and processing subscriptions in Mollie subscription r…
TheMilek Jun 30, 2026
6a4f6d1
Integration subscriptions (#348)
TheMilek Jun 30, 2026
70e74a2
Return default options when country code is null in payment methods r…
Wojdylak Jul 6, 2026
17a8d0f
Drop non-Mollie order test case incompatible with resolver return type
Wojdylak Jul 6, 2026
7400f14
Return default options when country code is null in payment methods r…
TheMilek Jul 6, 2026
8bb6f15
add iterator to repo method
michalkaczmarek-bitbag Jul 7, 2026
b9be2e3
Validate webhook payment against order and fix IDOR order token/PII leak
TheMilek Jul 7, 2026
153c754
Validate webhook payment against order and fix IDOR order token/PII l…
TheMilek Jul 7, 2026
ebbe6d6
Validate webhook payment against order and fix IDOR order token/PII leak
TheMilek Jul 7, 2026
01316b3
Validate webhook payment against order and fix IDOR order token/PII l…
TheMilek Jul 7, 2026
c47ef18
Resolve conflicts between 3.2 and 3.3
TheMilek Jul 7, 2026
ab939bb
[UPMERGE] 3.2 -> 3.3 (#353)
TheMilek Jul 7, 2026
c08e65d
fix query for iterable method in query
michalkaczmarek-bitbag Jul 7, 2026
34a1fd0
Merge branch 'Sylius:3.3' into bugfix/integration-with-subscription-p…
michalkaczmarek-bitbag Jul 7, 2026
335cb75
add iterator to repo method (#350)
TheMilek Jul 9, 2026
7783c46
Validate QR shop endpoints via session instead of order token
TheMilek Jul 9, 2026
184fbfc
Validate QR shop endpoints via session instead of order token (#358)
TheMilek Jul 9, 2026
40e6d44
[UPMERGE] 3.2 -> 3.3 (#359)
TheMilek Jul 9, 2026
1d0aef3
Validate QR shop endpoints via session and complete QR payments from …
TheMilek Jul 9, 2026
b14d123
Validate QR shop endpoints via session and complete QR payments from …
TheMilek Jul 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions UPGRADE-3.2.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
# UPGRADE FROM 3.2.4 TO 3.2.5

1. Run `yarn install` and `yarn build` to rebuild the shop assets. The bundled
`assets/shop/js/mollie/app.js` has changed and the shop will not work correctly until it is
rebuilt.

2. The QR-code and thank-you shop endpoints no longer use the order `tokenValue` introduced in
3.2.4. Ownership is now proven through the shop session, so both endpoints again accept
`?orderId=` and validate it against the session:

- `GET /{_locale}/get-code` serves the current session cart and rejects a foreign `orderId`
with `HTTP 404`; its JSON response returns `orderId`.
- `GET /{_locale}/thank-you` expects `?orderId=`, validates it against the session, and
returns `HTTP 404` when it is missing or does not match.

If you have overridden `app.js` or link to these endpoints yourself, switch back from
`orderToken` to `orderId`.

# UPGRADE FROM 3.2.3 TO 3.2.4

1. The shop payment webhook now verifies that the Mollie payment belongs to the referenced
order before applying its status. Requests whose Mollie payment id does not match the id
stored for the order are acknowledged with `HTTP 200` and ignored.

1. The thank-you and QR-code shop endpoints no longer accept a raw integer `orderId`; they now
use the order's non-guessable `orderToken` (`tokenValue`):

- `GET /{_locale}/thank-you` expects `?orderToken=` instead of `?orderId=` and returns
`HTTP 404` when the token is missing or unknown.
- `GET /{_locale}/get-code` expects `?orderToken=`, serves only the current session cart, and
returns `orderToken` in its JSON response.

The bundled `assets/shop/js/mollie/app.js` has been updated accordingly. If you have
overridden that file or link to these endpoints yourself, switch from `orderId` to
`orderToken`.

1. Run `yarn install` and `yarn build`.

# UPGRADE FROM 3.1 TO 3.2

1. Mollie menu section has been removed
Expand Down
75 changes: 75 additions & 0 deletions UPGRADE-3.3.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
# UPGRADE FROM 3.3.1 TO 3.3.2

1. Run `yarn install` and `yarn build` to rebuild the shop assets. The bundled
`assets/shop/js/mollie/app.js` has changed and the shop will not work correctly until it is
rebuilt.

2. The QR-code and thank-you shop endpoints no longer use the order `tokenValue` introduced in
3.3.1. Ownership is now proven through the shop session, so both endpoints again accept
`?orderId=` and validate it against the session:

- `GET /{_locale}/get-code` serves the current session cart and rejects a foreign `orderId`
with `HTTP 404`; its JSON response returns `orderId`.
- `GET /{_locale}/thank-you` expects `?orderId=`, validates it against the session, and
returns `HTTP 404` when it is missing or does not match.

If you have overridden `app.js` or link to these endpoints yourself, switch back from
`orderToken` to `orderId`.

3. QR-code payments can be paid while their order is still in the `cart` state, because the order
is placed only after the payment completes. The payment state machine does not allow completing
a payment from `cart`, so as a workaround the shop payment webhook applies the paid status
directly in that case, otherwise QR-code orders would stay unpaid.

# UPGRADE FROM 3.3.0 TO 3.3.1

1. The shop payment webhook now verifies that the Mollie payment belongs to the referenced
order before applying its status. Requests whose Mollie payment id does not match the id
stored for the order are acknowledged with `HTTP 200` and ignored.

1. The thank-you and QR-code shop endpoints no longer accept a raw integer `orderId`; they now
use the order's non-guessable `orderToken` (`tokenValue`):

- `GET /{_locale}/thank-you` expects `?orderToken=` instead of `?orderId=` and returns
`HTTP 404` when the token is missing or unknown.
- `GET /{_locale}/get-code` expects `?orderToken=`, serves only the current session cart, and
returns `orderToken` in its JSON response.

The bundled `assets/shop/js/mollie/app.js` has been updated accordingly. If you have
overridden that file or link to these endpoints yourself, switch from `orderId` to
`orderToken`.

1. Run `yarn install` and `yarn build`.

# UPGRADE FROM 3.2 TO 3.3

1. `Sylius\MolliePlugin\EventListener\ShipmentShipEventListener` and the `sylius_mollie.listener.shipment_ship` service
Expand All @@ -6,3 +49,35 @@
(`sylius_mollie.listener.workflow.shipment.ship`, listening on `workflow.sylius_shipment.completed.ship`)
will become the sole listener responsible for notifying Mollie about shipments - covering both admin UI and API contexts.
Currently, the workflow listener only handles API requests; admin UI shipments are still handled by the old listener.

2. **Important update for projects using Mollie subscriptions!**

Starting with Mollie Plugin 4.0, the subscription and recurring payment feature will be removed from the
open-source Mollie integration. Standard Mollie payments will not be affected.

As of 3.3, the subscription and recurring payment classes are marked as `@deprecated` and will be removed in 4.0.

For migration details, please check the
[dedicated blog post](https://sylius.com/blog/important-update-for-projects-using-mollie-subscriptions/)
or [contact the Sylius team](https://sylius.com/contact/).

3. A nullable `migrated_at` column has been added to the `mollie_subscription` table. Run the Doctrine migrations
after upgrading:

```bash
bin/console doctrine:migrations:migrate
```

To support the transition to 4.0, two interfaces gained methods used by the migration process. If you provide
your own implementations, add them (note that both interfaces are themselves deprecated and will be removed in
4.0):

`Sylius\MolliePlugin\Repository\MollieSubscriptionRepositoryInterface`:
- `findScheduledSubscriptionsForMigration(): array`
- `iterateToMigrate(int $batchSize): iterable`
- `findMigrated(int $limit): array`

`Sylius\MolliePlugin\Entity\MollieSubscriptionInterface`:
- `getMigratedAt(): ?\DateTime`
- `setMigratedAt(?\DateTimeInterface $migratedAt): void`
- `isMigrated(): bool`
12 changes: 7 additions & 5 deletions assets/shop/js/mollie/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ const {Mollie} = window;

document.addEventListener('DOMContentLoaded', function () {
const mollieData = document.querySelector('.online-online-payment__container');
if (!mollieData) {
return;
}

let disableValidationMollieComponents = false;
let selectedValue = false;
let orderId = null;
let qrCodeInterval = null;

showQrCodePopUp();

if (!mollieData) {
return;
}

const orderTotalRow = document.getElementById('sylius-shop-checkout-summary-order-total');
const initialOrderTotal = orderTotalRow ? orderTotalRow.textContent : null;
const cardActiveClass = 'online-payment__item--active';
Expand Down Expand Up @@ -239,8 +243,6 @@ document.addEventListener('DOMContentLoaded', function () {
}
}

showQrCodePopUp();

function createPopup(qrCode, qrCodeMethod) {
// Create popup container
var popupContainer = document.createElement('div');
Expand Down
1 change: 1 addition & 0 deletions config/doctrine/MollieSubscription.orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<field name="state" column="state" nullable="false" type="string"/>
<field name="createdAt" column="created_at" nullable="false" type="datetime"/>
<field name="startedAt" column="started_at" nullable="true" type="datetime"/>
<field name="migratedAt" column="migrated_at" nullable="true" type="datetime"/>
<field name="recentFailedPaymentsCount" column="recent_failed_payments_count" nullable="false" type="integer">
<options>
<option name="default">0</option>
Expand Down
2 changes: 2 additions & 0 deletions config/services/controller/shop.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="sylius.repository.payment" />
<argument type="service" id="sylius_mollie.logger.mollie_logger_action" />
<argument type="service" id="sylius_abstraction.state_machine"/>
<argument type="service" id="doctrine.orm.default_entity_manager"/>
</service>

<service id="sylius_mollie.controller.shop.page_redirect" class="Sylius\MolliePlugin\Controller\Shop\PageRedirectController">
Expand Down
4 changes: 4 additions & 0 deletions config/twig_hooks/admin/mollie_subscription/index.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
sylius_twig_hooks:
hooks:
'sylius_mollie.admin.subscription.index.content.header.title_block':
deprecation_notice:
template: '@SyliusMolliePlugin/admin/mollie_subscription/index/content/header/title_block/deprecation_notice.html.twig'
priority: -10
'sylius_mollie.admin.subscription.index.content.header.title_block.actions':
cancel:
template: '@SyliusAdmin/shared/crud/common/content/header/title_block/actions/cancel.html.twig'
Expand Down
3 changes: 3 additions & 0 deletions config/twig_hooks/admin/product_variant/create.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ sylius_twig_hooks:
priority: -100

'sylius_admin.product_variant.create.content.form.sections.mollie':
deprecation_notice:
template: '@SyliusMolliePlugin/admin/product_variant/form/sections/mollie/deprecation_notice.html.twig'
priority: 200
header:
template: '@SyliusMolliePlugin/admin/product_variant/form/sections/mollie/header.html.twig'
priority: 100
Expand Down
3 changes: 3 additions & 0 deletions config/twig_hooks/admin/product_variant/update.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ sylius_twig_hooks:
priority: -100

'sylius_admin.product_variant.update.content.form.sections.mollie':
deprecation_notice:
template: '@SyliusMolliePlugin/admin/product_variant/form/sections/mollie/deprecation_notice.html.twig'
priority: 200
header:
template: '@SyliusMolliePlugin/admin/product_variant/form/sections/mollie/header.html.twig'
priority: 100
Expand Down
5 changes: 5 additions & 0 deletions src/Cloner/SubscriptionOrderCloner.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
use Sylius\MolliePlugin\Model\AdjustmentInterface;
use Webmozart\Assert\Assert;

/**
* @deprecated since Mollie 3.3 and will be removed in 4.0.
*
* @see https://github.com/Sylius/MolliePlugin/blob/3.3/UPGRADE-3.3.md for migration details
*/
final class SubscriptionOrderCloner implements SubscriptionOrderClonerInterface
{
public function __construct(
Expand Down
5 changes: 5 additions & 0 deletions src/Cloner/SubscriptionOrderClonerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
use Sylius\MolliePlugin\Entity\MollieSubscriptionInterface;
use Sylius\MolliePlugin\Entity\OrderInterface;

/**
* @deprecated since Mollie 3.3 and will be removed in 4.0.
*
* @see https://github.com/Sylius/MolliePlugin/blob/3.3/UPGRADE-3.3.md for migration details
*/
interface SubscriptionOrderClonerInterface
{
public function clone(
Expand Down
5 changes: 5 additions & 0 deletions src/Console/Command/BeginProcessingSubscriptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Stopwatch\Stopwatch;

/**
* @deprecated since Mollie 3.3 and will be removed in 4.0.
*
* @see https://github.com/Sylius/MolliePlugin/blob/3.3/UPGRADE-3.3.md for migration details
*/
class BeginProcessingSubscriptions extends Command
{
public const COMMAND_NAME = 'mollie:subscription:begin-processing';
Expand Down
5 changes: 5 additions & 0 deletions src/Console/Command/ProcessSubscriptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
use Symfony\Component\Stopwatch\Stopwatch;
use Webmozart\Assert\Assert;

/**
* @deprecated since Mollie 3.3 and will be removed in 4.0.
*
* @see https://github.com/Sylius/MolliePlugin/blob/3.3/UPGRADE-3.3.md for migration details
*/
class ProcessSubscriptions extends Command
{
public const COMMAND_NAME = 'mollie:subscription:process';
Expand Down
35 changes: 26 additions & 9 deletions src/Controller/Shop/PageRedirectController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@
namespace Sylius\MolliePlugin\Controller\Shop;

use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Order\Repository\OrderRepositoryInterface;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\RouterInterface;

class PageRedirectController
{
private const ORDER_COMPLETED_STATE = 'completed';

private const QR_ORDER_ID_SESSION_KEY = 'sylius_mollie_qr_order_id';

public function __construct(
private readonly RouterInterface $router,
private readonly OrderRepositoryInterface $orderRepository,
Expand All @@ -33,19 +36,33 @@ public function __construct(
public function thankYouAction(Request $request, SessionInterface $session): RedirectResponse
{
$orderId = $request->get('orderId');
$session->set('sylius_order_id', $orderId);
$thankYouPageUrl = $this->router->generate('sylius_shop_order_thank_you');

if (null === $orderId || '' === $orderId ||
(string) $session->get(self::QR_ORDER_ID_SESSION_KEY) !== (string) $orderId) {
throw new NotFoundHttpException('Order not found.');
}

/** @var OrderInterface|null $order */
$order = $this->orderRepository->findOneBy(['id' => $orderId]);
$payment = $order->getLastPayment();
$orderToken = $order->getTokenValue();

if ($payment?->getState() === self::ORDER_COMPLETED_STATE) {
return new RedirectResponse($thankYouPageUrl);
if (null === $order) {
throw new NotFoundHttpException('Order not found.');
}

$session->set('sylius_order_id', $order->getId());

if ($order->getLastPayment()?->getState() === self::ORDER_COMPLETED_STATE) {
return new RedirectResponse($this->router->generate('sylius_shop_order_thank_you'));
}

$tokenValue = $order->getTokenValue();

if (null === $tokenValue) {
throw new NotFoundHttpException('Order not found.');
}
$cartSummaryUrl = $this->router->generate('sylius_shop_order_show', ['tokenValue' => $orderToken]);

return new RedirectResponse($cartSummaryUrl);
return new RedirectResponse(
$this->router->generate('sylius_shop_order_show', ['tokenValue' => $tokenValue]),
);
}
}
Loading
Loading