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.