diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 00000000..60b7a9bb
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,132 @@
+# Copilot Instructions
+
+These instructions apply to code reviews on pull requests in this repository.
+
+## Project Context
+
+This is PayPlug's official Sylius plugin. PayPlug is a Payment Service Provider (PSP). The plugin integrates PayPlug's payment processing into Sylius via multiple payment methods: standard card (PayPlug), Oney financing, Bancontact, Scalapay, Apple Pay, and American Express.
+
+**Stack**: PHP 8.2+, Sylius 2.0+, Symfony 6.4+, Payum, `payplug/payplug-php ^4.0`
+
+## Intentional Patterns — Do Not Flag as Issues
+
+- **`sleep(10)` in `NotifyAction`** — intentional, prevents a race condition between the IPN webhook and the user redirect. Never suggest removing it.
+- **No direct SDK calls** — `PayPlugApiClient` is the only allowed entry point to the PayPlug PHP SDK. Any direct call to SDK classes bypasses this and is a bug.
+- **Dual architecture** — Sylius 2.1+ uses a command/response provider model alongside legacy Payum actions. Both coexist intentionally.
+- **Card saving condition** — a card is only saved when the PayPlug API response includes `metadata['customer_id']`. Absence of this guard is a bug.
+- **`payment_context.cart`** — required in the PayPlug API payload for Oney and Scalapay payments. Missing it causes API rejection.
+- **Distributed lock in `NotifyAction`** — Symfony Lock is used on payment ID to prevent concurrent webhook processing. Do not flag as over-engineering.
+
+## Code Review Dimensions
+
+### Security
+- SQL injection, XSS, CSRF
+- Authentication and authorization flaws
+- Secrets or credentials committed in code
+- Insecure deserialization, path traversal, SSRF
+- Direct calls to PayPlug PHP SDK classes instead of going through `PayPlugApiClient`
+- Webhook payloads must be verified via `PayPlugApiClient::treat()` before any processing — never act on raw `php://input` directly
+- Card data (PAN, CVV, raw card numbers) must never appear in logs, error messages, or stored fields
+- API secret keys must never appear in logs, exception messages, or HTTP responses
+- Payment amounts must be validated server-side — never trust a client-submitted amount
+- `redirect_url` values must come from the PayPlug API response, never constructed from user input (open redirect risk)
+
+### Performance
+- N+1 queries (especially in Sylius entity traversal)
+- Unnecessary memory allocations
+- Algorithmic complexity (O(n²) in hot paths)
+- Missing database indexes
+- Unbounded queries or loops
+- Resource leaks
+
+### Correctness
+- Edge cases: empty input, null, overflow
+- Race conditions and concurrency issues
+- Error handling and propagation
+- Off-by-one errors, type safety
+- `declare(strict_types=1)` must be present in every PHP file
+- For new payment gateways (PPRO pattern): verify the full implementation checklist is covered (gateway factory, form type, resolver decorator, refund provider, templates, service definitions, translations)
+- Amount unit: Payum works in the smallest currency unit (cents). Any conversion must be explicit — silently mixing units is a payment amount bug
+- EUR-only enforcement must happen before the API call, not after
+- `factory_name` must be stored alongside `redirect_url` in payment details — missing it allows a stale redirect from one gateway to be reused when retrying with a different one
+- Refund amounts must not exceed the remaining refundable amount on the payment
+- State machine transition names must match Sylius/Payum constants exactly; Oney adds a custom `oney_request_payment` transition that is easy to misspell or omit
+
+### Maintainability
+- Naming clarity, single responsibility, duplication
+- Test coverage: PHPUnit in `tests/PHPUnit/`, Behat in `features/`
+- Documentation for non-obvious logic only — do not flag missing comments on self-explanatory code
+- PHPStan level max compliance; suppressions must go in `ruleset/phpstan-baseline.neon`
+- ECS coding standard based on `sylius-labs/coding-standard`
+- Translations must be complete in all three locales (`en`, `fr`, `it`) — partial translation is a regression
+- New services must be registered in both `config/services.yaml` (command/response providers) and the relevant `config/services/*.xml` file (Payum factory or API client) — registering only one side causes runtime failures
+
+### Headless Compliance
+
+In a headless Sylius setup the frontend is a decoupled SPA or mobile app — it cannot follow server-side HTTP redirects. Any shop-facing response that performs a redirect instead of returning JSON breaks the headless flow.
+
+- Shop-facing controllers and response providers must return a `JsonResponse` containing a `redirect_url` field rather than a `RedirectResponse`. The client is responsible for performing the redirect.
+- Known existing offenders (do not flag these as new issues, but flag any new code that replicates the same pattern):
+ - `src/OrderPay/Provider/CaptureHttpResponseProvider.php` — returns `RedirectResponse($data['redirect_url'])`
+ - `src/Controller/OneClickAction.php` — returns `RedirectResponse` on all exit paths
+- Admin-facing controllers (`src/Action/Admin/`) are exempt — headless compliance only applies to the shop payment flow.
+- If a new controller or response provider in the shop flow returns `RedirectResponse`, flag it as a headless compliance issue.
+
+## Output Format
+
+Structure the review comment exactly as follows:
+
+### 1. What's Good
+
+A bullet list of positive observations — things done well, non-obvious correct decisions, solid patterns.
+
+---
+
+### 2. Summary table
+
+A markdown table with two columns: **Dimension** and **Rating**. One row per review dimension. Use emoji inline with the rating text:
+
+| Dimension | Rating |
+|---|---|
+| Security | ✅ Fine |
+| Correctness | ⚠️ Medium (short reason) |
+| Performance | ✅ Fine |
+| Maintainability | ⚠️ Low (short reason) |
+
+Severity scale:
+- ✅ **Fine** — no issues
+- ⚠️ **Low / Medium** — should be fixed but not blocking
+- ❌ **High / Critical** — must be fixed before merge
+
+---
+
+### 3. Closing one-liner
+
+A single sentence summarising what needs to be addressed before merge (or that the PR is ready if nothing critical).
+
+---
+
+### 4. Individual findings (one section per issue)
+
+Each finding follows this exact structure:
+
+**Heading:** `[Dimension] [emoji] [Severity]` — e.g. `Security ⚠️ Medium`
+
+**Subtitle (bold):** short title followed by the file path and line number as a markdown link — e.g. `**Path traversal in getPayment** (PaymentClient.php:290)`
+
+**Code block:** the relevant snippet from the diff showing the problem.
+
+**Explanation paragraph:** what the risk is and why it matters. Be concrete.
+
+**Fix line:** start with `Fix:` in bold, then a brief description, followed by a code block showing the suggested fix.
+
+Lead with Critical/High findings. Omit the findings section entirely if there are no issues.
+
+## Iterative Reviews
+
+When reviewing a new commit on a PR that already has open review threads:
+
+- **Resolve threads** for issues that have been addressed in the new commit — do not leave them open if the fix is present.
+- **Do not re-open or re-comment** on issues that were already resolved in a previous round.
+- Only open new threads for issues that are genuinely new or that remain unresolved.
+- If a previous finding was partially addressed, update the thread with what still needs attention rather than opening a duplicate.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a9caf7c4..b1616306 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -3,8 +3,8 @@ name: CI
'on':
pull_request:
branches:
- - test-develop-ci
- - test-master-ci
+ - develop
+ - master
paths-ignore:
- README.md
@@ -14,12 +14,14 @@ jobs:
sylius-matrix:
needs: [quality]
- if: github.base_ref == 'test-develop-ci'
+ if: github.base_ref == 'develop'
uses: payplug/template-ci/.github/workflows/sylius_phpunit.yml@main
+ with:
+ symfony-versions: '["7.3"]'
sonarcloud:
- if: always() && !failure() && !cancelled() && github.base_ref == 'test-develop-ci'
- needs: sylius-matrix
+ if: always() && !failure() && !cancelled() && github.base_ref == 'develop'
+ needs: [sylius-matrix]
uses: payplug/template-ci/.github/workflows/sonarcloud.yml@main
with:
project-name: 'github-payplug-payplug-syliuspayplugplugin'
diff --git a/config/services.yaml b/config/services.yaml
index 116676f0..7db6a5fe 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -139,6 +139,26 @@ services:
- name: sylius.payment_request.provider.http_response
gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\ScalapayGatewayFactory::FACTORY_NAME
+ ## Wero Payplug Gateway ##
+ payplug_sylius_payplug_plugin.command_provider.payplug_wero:
+ class: Sylius\Bundle\PaymentBundle\CommandProvider\ActionsCommandProvider
+ arguments:
+ - !tagged_locator
+ tag: payplug_sylius_payplug_plugin.command_provider.payplug_wero
+ index_by: 'action'
+ tags:
+ - name: sylius.payment_request.command_provider
+ gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory::FACTORY_NAME
+ payplug_sylius_payplug_plugin.provider.order_pay.http_response.payplug_wero:
+ class: Sylius\Bundle\PaymentBundle\Provider\ActionsHttpResponseProvider
+ arguments:
+ - !tagged_locator
+ tag: payplug_sylius_payplug_plugin.http_response_provider.payplug_wero
+ index_by: action
+ tags:
+ - name: sylius.payment_request.provider.http_response
+ gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory::FACTORY_NAME
+
## Apple Pay Payplug Gateway ##
payplug_sylius_payplug_plugin.command_provider.payplug_apple_pay:
diff --git a/config/services/client.xml b/config/services/client.xml
index 22917bdf..3f2d3391 100644
--- a/config/services/client.xml
+++ b/config/services/client.xml
@@ -62,5 +62,14 @@
method="create"/>
payplug_scalapay
+
+
+
+ payplug_wero
+
diff --git a/config/services/gateway.xml b/config/services/gateway.xml
index dd174517..475c0a26 100644
--- a/config/services/gateway.xml
+++ b/config/services/gateway.xml
@@ -55,5 +55,13 @@
+
+
+
+ PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory
+
+
diff --git a/config/twig_hooks/admin.yaml b/config/twig_hooks/admin.yaml
index ba1e2403..ebd1c960 100644
--- a/config/twig_hooks/admin.yaml
+++ b/config/twig_hooks/admin.yaml
@@ -33,6 +33,9 @@ sylius_twig_hooks:
'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_scalapay': &scalapayGateway
live_checkbox: *liveCheckbox
+ 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_wero': &weroGateway
+ live_checkbox: *liveCheckbox
+
'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug':
<<: *payplugGateway
renew_oauth: &renewOAuth
@@ -53,3 +56,6 @@ sylius_twig_hooks:
'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_scalapay':
<<: *scalapayGateway
renew_oauth: *renewOAuth
+ 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_wero':
+ <<: *weroGateway
+ renew_oauth: *renewOAuth
diff --git a/config/twig_hooks/shop.yaml b/config/twig_hooks/shop.yaml
index 5ffe2826..36252bfd 100644
--- a/config/twig_hooks/shop.yaml
+++ b/config/twig_hooks/shop.yaml
@@ -47,3 +47,6 @@ sylius_twig_hooks:
'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_scalapay':
scalapay:
template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_scalapay.html.twig'
+ 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_wero':
+ wero:
+ template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_wero.html.twig'
diff --git a/public/assets/wero/logo.svg b/public/assets/wero/logo.svg
new file mode 100644
index 00000000..a1b9d520
--- /dev/null
+++ b/public/assets/wero/logo.svg
@@ -0,0 +1,41 @@
+
+
+
diff --git a/ruleset/phpstan-baseline.neon b/ruleset/phpstan-baseline.neon
index 2ebc3b8c..abca980f 100644
--- a/ruleset/phpstan-baseline.neon
+++ b/ruleset/phpstan-baseline.neon
@@ -1366,6 +1366,12 @@ parameters:
count: 1
path: ../src/Resolver/ScalapayPaymentMethodsResolverDecorator.php
+ -
+ message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Resolver\\WeroPaymentMethodsResolverDecorator\:\:getSupportedMethods\(\) should return array\ but returns array\.$#'
+ identifier: return.type
+ count: 1
+ path: ../src/Resolver/WeroPaymentMethodsResolverDecorator.php
+
-
message: '#^Call to method apply\(\) on an unknown class SM\\StateMachine\\StateMachineInterface\.$#'
identifier: class.notFound
diff --git a/src/Command/Provider/CapturePaymentRequestCommandProvider.php b/src/Command/Provider/CapturePaymentRequestCommandProvider.php
index 8d0be621..bb507e7e 100644
--- a/src/Command/Provider/CapturePaymentRequestCommandProvider.php
+++ b/src/Command/Provider/CapturePaymentRequestCommandProvider.php
@@ -35,6 +35,10 @@
'payplug_sylius_payplug_plugin.command_provider.payplug_scalapay',
['action' => PaymentRequestInterface::ACTION_CAPTURE],
)]
+#[AutoconfigureTag(
+ 'payplug_sylius_payplug_plugin.command_provider.payplug_wero',
+ ['action' => PaymentRequestInterface::ACTION_CAPTURE],
+)]
final class CapturePaymentRequestCommandProvider implements PaymentRequestCommandProviderInterface
{
public function supports(PaymentRequestInterface $paymentRequest): bool
diff --git a/src/Command/Provider/NotifyPaymentRequestCommandProvider.php b/src/Command/Provider/NotifyPaymentRequestCommandProvider.php
index 55f16fb8..4ef91b6a 100644
--- a/src/Command/Provider/NotifyPaymentRequestCommandProvider.php
+++ b/src/Command/Provider/NotifyPaymentRequestCommandProvider.php
@@ -33,6 +33,10 @@
'payplug_sylius_payplug_plugin.command_provider.payplug_scalapay',
['action' => PaymentRequestInterface::ACTION_NOTIFY],
)]
+#[AutoconfigureTag(
+ 'payplug_sylius_payplug_plugin.command_provider.payplug_wero',
+ ['action' => PaymentRequestInterface::ACTION_NOTIFY],
+)]
final class NotifyPaymentRequestCommandProvider implements PaymentRequestCommandProviderInterface
{
public function supports(PaymentRequestInterface $paymentRequest): bool
diff --git a/src/Command/Provider/StatusPaymentRequestCommandProvider.php b/src/Command/Provider/StatusPaymentRequestCommandProvider.php
index a0475641..37676e9b 100644
--- a/src/Command/Provider/StatusPaymentRequestCommandProvider.php
+++ b/src/Command/Provider/StatusPaymentRequestCommandProvider.php
@@ -34,6 +34,10 @@
'payplug_sylius_payplug_plugin.command_provider.payplug_scalapay',
['action' => PaymentRequestInterface::ACTION_STATUS],
)]
+#[AutoconfigureTag(
+ 'payplug_sylius_payplug_plugin.command_provider.payplug_wero',
+ ['action' => PaymentRequestInterface::ACTION_STATUS],
+)]
final class StatusPaymentRequestCommandProvider implements PaymentRequestCommandProviderInterface
{
public function __construct(private RequestStack $requestStack)
diff --git a/src/Creator/PayPlugPaymentDataCreator.php b/src/Creator/PayPlugPaymentDataCreator.php
index 89d882c0..9b437e68 100644
--- a/src/Creator/PayPlugPaymentDataCreator.php
+++ b/src/Creator/PayPlugPaymentDataCreator.php
@@ -20,6 +20,7 @@
use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Gateway\ScalapayGatewayFactory;
+use PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory;
use Sylius\Component\Core\Model\AddressInterface;
use Sylius\Component\Core\Model\CustomerInterface;
use Sylius\Component\Core\Model\OrderInterface;
@@ -355,6 +356,7 @@ private function addPaymentMethodFieldToDetails(ArrayObject $details, string $ga
ApplePayGatewayFactory::FACTORY_NAME => ApplePayGatewayFactory::PAYMENT_METHOD_APPLE_PAY,
AmericanExpressGatewayFactory::FACTORY_NAME => AmericanExpressGatewayFactory::PAYMENT_METHOD_AMERICAN_EXPRESS,
ScalapayGatewayFactory::FACTORY_NAME => ScalapayGatewayFactory::PAYMENT_METHOD_SCALAPAY,
+ WeroGatewayFactory::FACTORY_NAME => WeroGatewayFactory::PAYMENT_METHOD_WERO,
];
// match function is only supported by php 8. so can not use it here.
foreach ($paymentMethods as $name => $method) {
diff --git a/src/Gateway/Form/Type/WeroGatewayConfigurationType.php b/src/Gateway/Form/Type/WeroGatewayConfigurationType.php
new file mode 100644
index 00000000..39d1a035
--- /dev/null
+++ b/src/Gateway/Form/Type/WeroGatewayConfigurationType.php
@@ -0,0 +1,25 @@
+ 'payplug_wero',
+ 'label' => 'payplug_sylius_payplug_plugin.ui.wero_gateway_label',
+ 'priority' => 90,
+ ],
+)]
+final class WeroGatewayConfigurationType extends AbstractGatewayConfigurationType
+{
+ protected string $gatewayFactoryTitle = WeroGatewayFactory::FACTORY_TITLE;
+
+ protected string $gatewayFactoryName = WeroGatewayFactory::FACTORY_NAME;
+
+ protected string $gatewayBaseCurrencyCode = WeroGatewayFactory::BASE_CURRENCY_CODE;
+}
diff --git a/src/Gateway/WeroGatewayFactory.php b/src/Gateway/WeroGatewayFactory.php
new file mode 100644
index 00000000..aaa3f536
--- /dev/null
+++ b/src/Gateway/WeroGatewayFactory.php
@@ -0,0 +1,14 @@
+ PaymentRequestInterface::ACTION_CAPTURE],
)]
+#[AutoconfigureTag(
+ 'payplug_sylius_payplug_plugin.http_response_provider.payplug_wero',
+ ['action' => PaymentRequestInterface::ACTION_CAPTURE],
+)]
class CaptureHttpResponseProvider implements HttpResponseProviderInterface
{
public function supports(RequestConfiguration $requestConfiguration, PaymentRequestInterface $paymentRequest): bool
diff --git a/src/PaymentProcessing/RefundPaymentProcessor.php b/src/PaymentProcessing/RefundPaymentProcessor.php
index b6d74a0f..4f9bb13b 100644
--- a/src/PaymentProcessing/RefundPaymentProcessor.php
+++ b/src/PaymentProcessing/RefundPaymentProcessor.php
@@ -14,6 +14,7 @@
use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Gateway\ScalapayGatewayFactory;
+use PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Repository\RefundHistoryRepositoryInterface;
use Psr\Log\LoggerInterface;
use Sylius\Component\Core\Model\PaymentInterface;
@@ -126,6 +127,7 @@ private function prepare(PaymentInterface $payment): void
ApplePayGatewayFactory::FACTORY_NAME,
AmericanExpressGatewayFactory::FACTORY_NAME,
ScalapayGatewayFactory::FACTORY_NAME,
+ WeroGatewayFactory::FACTORY_NAME,
], true)
) {
return;
diff --git a/src/Provider/WeroSupportedRefundPaymentMethodsProviderDecorator.php b/src/Provider/WeroSupportedRefundPaymentMethodsProviderDecorator.php
new file mode 100644
index 00000000..82870068
--- /dev/null
+++ b/src/Provider/WeroSupportedRefundPaymentMethodsProviderDecorator.php
@@ -0,0 +1,15 @@
+decorated->getSupportedMethods($subject);
+
+ /** @var OrderInterface $order */
+ $order = $subject->getOrder();
+ $billingCountryCode = $order->getBillingAddress()?->getCountryCode();
+
+ return $this->supportedMethodsProvider->provide(
+ $supportedMethods,
+ WeroGatewayFactory::FACTORY_NAME,
+ $subject->getAmount() ?? 0,
+ $billingCountryCode,
+ );
+ }
+
+ public function supports(BasePaymentInterface $subject): bool
+ {
+ return $this->decorated->supports($subject);
+ }
+}
diff --git a/src/Validator/PaymentMethodValidator.php b/src/Validator/PaymentMethodValidator.php
index 34b826e2..1ce571aa 100644
--- a/src/Validator/PaymentMethodValidator.php
+++ b/src/Validator/PaymentMethodValidator.php
@@ -15,6 +15,7 @@
use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsCanSavePaymentMethod;
use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsOneyEnabled;
use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\PayplugPermission;
+use PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Validator\ConstraintViolationListInterface;
@@ -48,6 +49,7 @@ public function process(PaymentMethodInterface $paymentMethod): void
AmericanExpressGatewayFactory::FACTORY_NAME => $this->processAmex($paymentMethod),
ApplePayGatewayFactory::FACTORY_NAME => $this->processApplePay($paymentMethod),
ScalapayGatewayFactory::FACTORY_NAME => $this->processScalapay($paymentMethod),
+ WeroGatewayFactory::FACTORY_NAME => $this->processWero($paymentMethod),
default => throw new \InvalidArgumentException('Unsupported payment method'),
};
@@ -113,4 +115,11 @@ private function processScalapay(PaymentMethodInterface $paymentMethod): Constra
return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS);
}
+
+ private function processWero(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface
+ {
+ $constraintList = [new IsCanSavePaymentMethod()];
+
+ return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS);
+ }
}
diff --git a/templates/shop/integrated/index.html.twig b/templates/shop/integrated/index.html.twig
index 61a4b1d2..6afd94b9 100644
--- a/templates/shop/integrated/index.html.twig
+++ b/templates/shop/integrated/index.html.twig
@@ -1,6 +1,6 @@
-{% set initRouteParam = {'paymentMethodId': paymentMethod.id} %}
+{% set init_route_param = {'paymentMethodId': paymentMethod.id} %}
{% if order is defined and order.getCheckoutCompletedAt is not null and order.tokenValue is not null %}
- {% set initRouteParam = initRouteParam|merge({'orderToken': order.tokenValue}) %}
+ {% set init_route_param = init_route_param|merge({'orderToken': order.tokenValue}) %}
{% endif %}
@@ -14,7 +14,7 @@
payment_id: '{{ payment.details.payment_id }}',
{% endif %}
routes: {
- init_payment: '{{ path('payplug_sylius_integrated_payment_init', initRouteParam) }}',
+ init_payment: '{{ path('payplug_sylius_integrated_payment_init', init_route_param) }}',
},
cardholder: '{{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.card_holder.title'|trans }}',
pan: '{{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.pan.title'|trans }}',
diff --git a/templates/shop/select_payment/_wero.html.twig b/templates/shop/select_payment/_wero.html.twig
new file mode 100644
index 00000000..59000c28
--- /dev/null
+++ b/templates/shop/select_payment/_wero.html.twig
@@ -0,0 +1,7 @@
+{% set form = hookable_metadata.context.form %}
+
+
diff --git a/tests/PHPUnit/Creator/PayPlugPaymentDataCreatorTest.php b/tests/PHPUnit/Creator/PayPlugPaymentDataCreatorTest.php
index 144af170..4b545215 100644
--- a/tests/PHPUnit/Creator/PayPlugPaymentDataCreatorTest.php
+++ b/tests/PHPUnit/Creator/PayPlugPaymentDataCreatorTest.php
@@ -12,6 +12,7 @@
use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory;
+use PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Component\Core\Model\AddressInterface;
@@ -439,6 +440,23 @@ public function testCreate_bancontactGateway_setsBancontactPaymentMethod(): void
self::assertSame('bancontact', $details['payment_method']);
}
+ // -------------------------------------------------------------------------
+ // create() — Wero gateway (PPRO payment_method field)
+ // -------------------------------------------------------------------------
+
+ /**
+ * Uses the Wero gateway factory (a PPRO method routed through PayPlug).
+ * Verifies the payment_method field is set to the literal string 'wero'.
+ */
+ public function testCreate_weroGateway_setsWeroPaymentMethod(): void
+ {
+ $payment = $this->buildMinimalPaymentWithGateway(WeroGatewayFactory::FACTORY_NAME);
+
+ $details = $this->creator->create($payment);
+
+ self::assertSame('wero', $details['payment_method']);
+ }
+
// -------------------------------------------------------------------------
// create() — phone number in billing / shipping address
// -------------------------------------------------------------------------
diff --git a/tests/PHPUnit/PaymentProcessing/RefundPaymentProcessorTest.php b/tests/PHPUnit/PaymentProcessing/RefundPaymentProcessorTest.php
index d4ba9812..3a2d3763 100644
--- a/tests/PHPUnit/PaymentProcessing/RefundPaymentProcessorTest.php
+++ b/tests/PHPUnit/PaymentProcessing/RefundPaymentProcessorTest.php
@@ -11,6 +11,7 @@
use PayPlug\SyliusPayPlugPlugin\Entity\RefundHistory;
use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Gateway\ScalapayGatewayFactory;
+use PayPlug\SyliusPayPlugPlugin\Gateway\WeroGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\PaymentProcessing\RefundPaymentProcessor;
use PayPlug\SyliusPayPlugPlugin\Repository\RefundHistoryRepositoryInterface;
use PHPUnit\Framework\MockObject\MockObject;
@@ -100,6 +101,23 @@ public function testProcess_scalapayGateway_callsApiRefund(): void
$this->processor->process($payment);
}
+ // -------------------------------------------------------------------------
+ // process() — Wero gateway → refund is processed
+ // -------------------------------------------------------------------------
+
+ /**
+ * Calls process() with a Wero payment; verifies refundPayment() is called,
+ * confirming Wero is included in the supported gateway allow-list.
+ */
+ public function testProcess_weroGateway_callsApiRefund(): void
+ {
+ $payment = $this->buildPayment(WeroGatewayFactory::FACTORY_NAME, ['payment_id' => 'pay_wero']);
+
+ $this->apiClient->expects(self::once())->method('refundPayment')->with('pay_wero');
+
+ $this->processor->process($payment);
+ }
+
// -------------------------------------------------------------------------
// process() — API exception → UpdateHandlingException
// -------------------------------------------------------------------------
diff --git a/translations/messages.en.yml b/translations/messages.en.yml
index 97b5424c..9ffa6acb 100644
--- a/translations/messages.en.yml
+++ b/translations/messages.en.yml
@@ -25,6 +25,7 @@ payplug_sylius_payplug_plugin:
confirm_card_deletion: Are you sure you want to delete this card?
bancontact_gateway_label: Bancontact by Payplug
scalapay_gateway_label: Scalapay by PayPlug
+ wero_gateway_label: Wero by PayPlug
apple_pay_gateway_label: Apple Pay by Payplug
american_express_gateway_label: American Express by Payplug
apple_pay_not_available: Apple Pay is not available on this browser or device.
diff --git a/translations/messages.fr.yml b/translations/messages.fr.yml
index 42193f9b..068fba68 100644
--- a/translations/messages.fr.yml
+++ b/translations/messages.fr.yml
@@ -25,6 +25,7 @@ payplug_sylius_payplug_plugin:
confirm_card_deletion: Êtes-vous sûr(e) de vouloir supprimer cette carte ?
bancontact_gateway_label: Bancontact by Payplug
scalapay_gateway_label: Scalapay by PayPlug
+ wero_gateway_label: Wero by PayPlug
apple_pay_gateway_label: Apple Pay by Payplug
american_express_gateway_label: American Express by Payplug
apple_pay_not_available: Apple Pay n'est pas disponible sur ce navigateur ou appareil.
diff --git a/translations/messages.it.yml b/translations/messages.it.yml
index b9170f12..10459f42 100644
--- a/translations/messages.it.yml
+++ b/translations/messages.it.yml
@@ -25,6 +25,7 @@ payplug_sylius_payplug_plugin:
confirm_card_deletion: Desideri cancellare questa carta?
bancontact_gateway_label: Bancontact by Payplug
scalapay_gateway_label: Scalapay by PayPlug
+ wero_gateway_label: Wero by PayPlug
apple_pay_gateway_label: Apple Pay by Payplug
american_express_gateway_label: American Express by Payplug
apple_pay_not_available: Apple Pay non è disponibile su questo browser o dispositivo.
diff --git a/translations/validators.en.yml b/translations/validators.en.yml
index a5fc5a83..6e75e794 100644
--- a/translations/validators.en.yml
+++ b/translations/validators.en.yml
@@ -33,6 +33,14 @@ payplug_sylius_payplug_plugin:
You don't have access to this feature yet.
To activate Scalapay, please contact us at support@payplug.com
and activate the LIVE mode.
+ payplug_wero:
+ can_not_save_method_with_test_key: |
+ The Wero payment method is not available for the TEST mode.
+ Please activate the LIVE mode.
+ can_not_save_method_no_access: |
+ You don't have access to this feature yet.
+ To activate Wero, please contact us at support@payplug.com
+ and activate the LIVE mode.
payplug_apple_pay:
can_not_save_method_with_test_key: |
The Apple Pay payment method is not available for the TEST mode.
diff --git a/translations/validators.fr.yml b/translations/validators.fr.yml
index 128c6ffb..2c35609a 100644
--- a/translations/validators.fr.yml
+++ b/translations/validators.fr.yml
@@ -32,6 +32,14 @@ payplug_sylius_payplug_plugin:
Vous n'avez pas accès à cette fonctionnalité.
Pour activer Scalapay, contactez-nous à support@payplug.com
et activez le mode LIVE.
+ payplug_wero:
+ can_not_save_method_with_test_key: |
+ Le paiement par Wero n'est pas disponible en mode TEST.
+ Veuillez activer le mode LIVE.
+ can_not_save_method_no_access: |
+ Vous n'avez pas accès à cette fonctionnalité.
+ Pour activer Wero, contactez-nous à support@payplug.com
+ et activez le mode LIVE.
payplug_apple_pay:
can_not_save_method_with_test_key: |
Le paiement par Apple Pay n’est pas disponible en mode TEST.
diff --git a/translations/validators.it.yml b/translations/validators.it.yml
index efaf49df..23f1c2f6 100644
--- a/translations/validators.it.yml
+++ b/translations/validators.it.yml
@@ -32,6 +32,14 @@ payplug_sylius_payplug_plugin:
Non puoi ancora accedere a questa funzionalità.
Per attivare Scalapay, contattaci a support@payplug.com
e attiva la modalità LIVE.
+ payplug_wero:
+ can_not_save_method_with_test_key: |
+ Il metodo di pagamento Wero non è disponibile in modalità TEST.
+ Attiva la modalità LIVE.
+ can_not_save_method_no_access: |
+ Non puoi ancora accedere a questa funzionalità.
+ Per attivare Wero, contattaci a support@payplug.com
+ e attiva la modalità LIVE.
payplug_american_express:
can_not_save_method_with_test_key: |
Il pagamento Apple Pay non è disponibile in modalità TEST.