diff --git a/config/services/client.xml b/config/services/client.xml index 4e2053e8..73148c93 100644 --- a/config/services/client.xml +++ b/config/services/client.xml @@ -90,14 +90,5 @@ method="create"/> payplug_wero - - - - payplug_uhf - diff --git a/config/twig_hooks/admin.yaml b/config/twig_hooks/admin.yaml index 50544202..faff9e66 100644 --- a/config/twig_hooks/admin.yaml +++ b/config/twig_hooks/admin.yaml @@ -19,12 +19,18 @@ sylius_twig_hooks: one_click: template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/one_click.html.twig' priority: 0 - integrated_payment: - template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/integrated_payment.html.twig' + hosted_fields_mode: + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/hosted_fields_mode.html.twig' priority: 0 + hf_identifier: + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/hf_identifier.html.twig' + priority: -1 + hf_sub_merchant_id: + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/hf_sub_merchant_id.html.twig' + priority: -2 deferred_capture: template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/deferred_capture.html.twig' - priority: 0 + priority: -3 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_oney': &oneyGateway live_checkbox: *liveCheckbox fees_for: @@ -44,15 +50,6 @@ sylius_twig_hooks: 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_wero': &weroGateway live_checkbox: *liveCheckbox - 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_uhf': &uhfGateway - live_checkbox: *liveCheckbox - one_click: - template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/one_click.html.twig' - priority: 0 - hf_identifier_default: &hfIdentifierDefault - template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/hf_identifier_default.html.twig' - priority: -1 - 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug': <<: *payplugGateway renew_oauth: &renewOAuth @@ -76,6 +73,3 @@ sylius_twig_hooks: 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_wero': <<: *weroGateway renew_oauth: *renewOAuth - 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_uhf': - <<: *uhfGateway - renew_oauth: *renewOAuth diff --git a/config/twig_hooks/shop.yaml b/config/twig_hooks/shop.yaml index ffa22870..36252bfd 100644 --- a/config/twig_hooks/shop.yaml +++ b/config/twig_hooks/shop.yaml @@ -50,6 +50,3 @@ sylius_twig_hooks: 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_wero': wero: template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_wero.html.twig' - 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_uhf': - uhf: - template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_payplug_uhf.html.twig' diff --git a/features/shop/hosted_fields_payment_method.feature b/features/shop/hosted_fields_payment_method.feature index 01a36834..7f22142b 100644 --- a/features/shop/hosted_fields_payment_method.feature +++ b/features/shop/hosted_fields_payment_method.feature @@ -2,25 +2,25 @@ Feature: Paying with Hosted Fields during checkout In order to buy products As a Customer - I want to see Hosted Fields as a distinct payment method at checkout + I want to see Hosted Fields when the merchant enabled it on the PayPlug payment method Background: Given the store operates on a single channel in "United States" And that channel also allows to shop using the "EUR" currency And there is a user "john@bitbag.pl" identified by "password123" And I changed my currency to "EUR" - And the store has a payment method "PayPlug Hosted Fields" with a code "payplug_hosted_fields" and PayPlug Hosted Fields payment gateway + And the store has a payment method "PayPlug" with a code "payplug" and PayPlug Hosted Fields payment gateway And This secret Key is valid And the store ships everywhere for free And the store has "DHL" shipping method with "$0.00" fee And I am logged in as "john@bitbag.pl" @ui - Scenario: I can see and select the Hosted Fields payment method + Scenario: I can see and select the PayPlug payment method with Hosted Fields enabled Given the store has a product "PHP T-Shirt" priced at "€50.00" And I added product "PHP T-Shirt" to the cart And I chose "DHL" shipping method Then I should be on the checkout payment step - And I should be able to select "PayPlug Hosted Fields" payment method - And I select "PayPlug Hosted Fields" payment method + And I should be able to select "PayPlug" payment method + And I select "PayPlug" payment method And I should see the "#card-container" element on the page diff --git a/src/EventSubscriber/PostPaymentSelectEventSubscriber.php b/src/EventSubscriber/PostPaymentSelectEventSubscriber.php index d013f5b0..47701bbf 100644 --- a/src/EventSubscriber/PostPaymentSelectEventSubscriber.php +++ b/src/EventSubscriber/PostPaymentSelectEventSubscriber.php @@ -5,7 +5,7 @@ namespace PayPlug\SyliusPayPlugPlugin\EventSubscriber; use Doctrine\ORM\EntityManagerInterface; -use PayPlug\SyliusPayPlugPlugin\Gateway\UhfGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use PayPlug\SyliusPayPlugPlugin\PaymentProcessing\HostedFieldsPaymentProcessorInterface; use Sylius\Abstraction\StateMachine\StateMachineInterface; use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent; @@ -194,7 +194,10 @@ private function handleHostedFieldsToken(Request $request, PaymentInterface $las private function isHostedFieldsEnabled(PaymentInterface $payment): bool { - return UhfGatewayFactory::FACTORY_NAME === $payment->getMethod()?->getGatewayConfig()?->getFactoryName(); + $gatewayConfig = $payment->getMethod()?->getGatewayConfig(); + + return PayPlugGatewayFactory::FACTORY_NAME === $gatewayConfig?->getFactoryName() && + true === ($gatewayConfig->getConfig()[PayPlugGatewayFactory::HOSTED_FIELDS] ?? false); } private function getRequestField(Request $request, string $field): string diff --git a/src/Gateway/Form/Extension/PayPlugGatewayConfigurationTypeExtension.php b/src/Gateway/Form/Extension/PayPlugGatewayConfigurationTypeExtension.php index a6c47a2a..273617ad 100644 --- a/src/Gateway/Form/Extension/PayPlugGatewayConfigurationTypeExtension.php +++ b/src/Gateway/Form/Extension/PayPlugGatewayConfigurationTypeExtension.php @@ -9,12 +9,21 @@ use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Contracts\Translation\TranslatorInterface; final class PayPlugGatewayConfigurationTypeExtension extends AbstractTypeExtension { + public function __construct(private TranslatorInterface $translator) + { + } + /** * @inheritdoc */ @@ -29,12 +38,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help_html' => true, 'required' => false, ]) - ->add(PayPlugGatewayFactory::INTEGRATED_PAYMENT, CheckboxType::class, [ - 'block_name' => 'payplug_checkbox', - 'label' => 'payplug_sylius_payplug_plugin.form.integrated_payment_enable', - 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, - 'required' => false, - ]) ->add(PayPlugGatewayFactory::DEFERRED_CAPTURE, CheckboxType::class, [ 'block_name' => 'payplug_checkbox', 'label' => 'payplug_sylius_payplug_plugin.form.deferred_capture_enable', @@ -43,6 +46,49 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help_html' => true, 'required' => false, ]) + ->add(PayPlugGatewayFactory::DISPLAY_MODE_FIELD, ChoiceType::class, [ + 'mapped' => false, + 'required' => false, + 'expanded' => true, + 'placeholder' => 'payplug_sylius_payplug_plugin.form.redirected_payment_enable', + 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, + 'choices' => [ + 'payplug_sylius_payplug_plugin.form.integrated_payment_enable' => PayPlugGatewayFactory::DISPLAY_MODE_INTEGRATED_PAYMENT, + 'payplug_sylius_payplug_plugin.ui.hosted_fields_option' => PayPlugGatewayFactory::DISPLAY_MODE_HOSTED_FIELDS, + ], + ]) + ->add(PayPlugGatewayFactory::HF_IDENTIFIER, TextType::class, [ + 'label' => 'payplug_sylius_payplug_plugin.ui.hf_identifier_label', + 'required' => false, + 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, + ]) + ->add(PayPlugGatewayFactory::HF_SUB_MERCHANT_ID, PasswordType::class, [ + 'label' => 'payplug_sylius_payplug_plugin.ui.hf_sub_merchant_id_label', + 'required' => false, + 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, + ]) + ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event): void { + $rawData = $event->getData(); + if (!is_array($rawData)) { + return; + } + + $submitted = $rawData[PayPlugGatewayFactory::HF_SUB_MERCHANT_ID] ?? ''; + if (!is_scalar($submitted) || '' !== trim((string) $submitted)) { + return; + } + + // PasswordType keeps its default `always_empty` (never echoes the stored secret + // back into the rendered `value` attribute), so a blank submission means "left + // untouched", not "clear it" - same convention as a change-password form. Restore + // the previously persisted value instead of letting a blank field wipe it out. + $previousData = $event->getForm()->getData(); + $previousValue = is_array($previousData) ? ($previousData[PayPlugGatewayFactory::HF_SUB_MERCHANT_ID] ?? null) : null; + if (is_string($previousValue) && '' !== $previousValue) { + $rawData[PayPlugGatewayFactory::HF_SUB_MERCHANT_ID] = $previousValue; + $event->setData($rawData); + } + }) ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { $data = $event->getData(); // phpstan check @@ -52,6 +98,48 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $data['payum.http_client'] = '@payplug_sylius_payplug_plugin.api_client.payplug'; $event->setData($data); }) + // DISPLAY_MODE_FIELD's pre-selection must happen on POST_SET_DATA, not PRE_SET_DATA: + // it's `mapped => false`, and Symfony's DataMapper::mapDataToForms() runs right after + // PRE_SET_DATA dispatches (as part of the same parent setData() call), resetting every + // unmapped child back to its configured (null) default — silently wiping out a + // setData() call made from PRE_SET_DATA. POST_SET_DATA fires after that reset, so + // nothing overwrites it afterward. + ->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event): void { + $data = $event->getData(); + if (!is_array($data)) { + return; + } + + $event->getForm()->get(PayPlugGatewayFactory::DISPLAY_MODE_FIELD)->setData( + PayPlugGatewayFactory::resolveDisplayMode($data), + ); + }) + ->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event): void { + $form = $event->getForm(); + $submittedData = [ + PayPlugGatewayFactory::DISPLAY_MODE_FIELD => $form->get(PayPlugGatewayFactory::DISPLAY_MODE_FIELD)->getData(), + PayPlugGatewayFactory::HF_IDENTIFIER => $form->get(PayPlugGatewayFactory::HF_IDENTIFIER)->getData(), + PayPlugGatewayFactory::HF_SUB_MERCHANT_ID => $form->get(PayPlugGatewayFactory::HF_SUB_MERCHANT_ID)->getData(), + ]; + + foreach (PayPlugGatewayFactory::missingHostedFieldsRequirements($submittedData) as $field) { + $messageKey = PayPlugGatewayFactory::HF_IDENTIFIER === $field + ? 'payplug_sylius_payplug_plugin.form.account_id_required' + : 'payplug_sylius_payplug_plugin.form.submerchant_id_required'; + + $form->get($field)->addError(new FormError($this->translator->trans($messageKey))); + } + }) + ->addEventListener(FormEvents::SUBMIT, function (FormEvent $event): void { + $data = $event->getData(); + if (!is_array($data)) { + return; + } + + $displayMode = $event->getForm()->get(PayPlugGatewayFactory::DISPLAY_MODE_FIELD)->getData(); + $displayMode = is_string($displayMode) ? $displayMode : null; + $event->setData(array_merge($data, PayPlugGatewayFactory::resolveDisplayModeFlags($displayMode))); + }) ; } diff --git a/src/Gateway/Form/Extension/UhfGatewayConfigurationTypeExtension.php b/src/Gateway/Form/Extension/UhfGatewayConfigurationTypeExtension.php deleted file mode 100644 index e4f95e90..00000000 --- a/src/Gateway/Form/Extension/UhfGatewayConfigurationTypeExtension.php +++ /dev/null @@ -1,47 +0,0 @@ -add(UhfGatewayFactory::HF_IDENTIFIER_DEFAULT, TextType::class, [ - 'label' => 'payplug_sylius_payplug_plugin.ui.hf_identifier_default_label', - 'required' => true, - 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, - 'constraints' => [ - new NotBlank([]), - ], - ]) - ->add(UhfGatewayFactory::ONE_CLICK, CheckboxType::class, [ - 'block_name' => 'payplug_checkbox', - 'label' => 'payplug_sylius_payplug_plugin.form.one_click_enable', - 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, - 'help' => 'payplug_sylius_payplug_plugin.form.one_click_help', - 'help_html' => true, - 'required' => false, - ]) - ; - } - - public static function getExtendedTypes(): iterable - { - return [UhfGatewayConfigurationType::class]; - } -} diff --git a/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php b/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php index 80fce24a..168ebfbb 100644 --- a/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php +++ b/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php @@ -69,6 +69,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void if (!$dataFormChannels instanceof Collection) { return; } + + $rawData = $event->getData(); + if (!\is_array($rawData) || !$this->shouldValidateBaseCurrency($rawData)) { + return; + } + + $flashedMessages = []; /** @var ChannelInterface $dataFormChannel */ foreach ($dataFormChannels as $key => $dataFormChannel) { $baseCurrency = $dataFormChannel->getBaseCurrency(); @@ -77,15 +84,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void } $baseCurrencyCode = $baseCurrency->getCode(); if ($this->gatewayBaseCurrencyCode !== $baseCurrencyCode) { - $message = $this->translator->trans( - 'payplug_sylius_payplug_plugin.form.base_currency_not_euro', - [ - '#channel_code#' => $dataFormChannel->getCode(), - '#payment_method#' => $this->gatewayFactoryTitle, - ], - ); + $message = $this->baseCurrencyViolationMessage($dataFormChannel); $formChannels->get((string) $key)->addError(new FormError($message)); - $this->requestStack->getSession()->getFlashBag()->add('error', $message); + if (!\in_array($message, $flashedMessages, true)) { + $flashedMessages[] = $message; + $this->requestStack->getSession()->getFlashBag()->add('error', $message); + } } } }) @@ -119,4 +123,36 @@ private function checkCreationRequirements( /* @phpstan-ignore-next-line */ $form->getParent()->getParent()->get('enabled')->addError(new FormError($message)); } + + /** + * Hook for subtypes to scope the base-currency-per-channel restriction below. + * Default: always enforced, preserving today's behavior for every gateway that doesn't + * override this (Bancontact, American Express, Scalapay, Wero, Oney...). + * + * @see baseCurrencyViolationMessage() Companion hook customizing the message this guards. + * + * @param array $rawFormData Raw PRE_SUBMIT data of the gateway config form. + */ + protected function shouldValidateBaseCurrency(array $rawFormData): bool + { + return true; + } + + /** + * Hook for subtypes to customize the currency-violation message. Default matches today's + * generic wording, used by every gateway subtype that doesn't override it (Bancontact, + * American Express, Scalapay, Wero, Oney...). + * + * @see shouldValidateBaseCurrency() Companion hook scoping when this message is used. + */ + protected function baseCurrencyViolationMessage(ChannelInterface $channel): string + { + return $this->translator->trans( + 'payplug_sylius_payplug_plugin.form.base_currency_not_euro', + [ + '#channel_code#' => $channel->getCode(), + '#payment_method#' => $this->gatewayFactoryTitle, + ], + ); + } } diff --git a/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php b/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php index f9056fdf..1344b3d1 100644 --- a/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php +++ b/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php @@ -5,6 +5,7 @@ namespace PayPlug\SyliusPayPlugPlugin\Gateway\Form\Type; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; +use Sylius\Component\Core\Model\ChannelInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; #[AutoconfigureTag( @@ -22,4 +23,25 @@ final class PayPlugGatewayConfigurationType extends AbstractGatewayConfiguration protected string $gatewayFactoryName = PayPlugGatewayFactory::FACTORY_NAME; protected string $gatewayBaseCurrencyCode = PayPlugGatewayFactory::BASE_CURRENCY_CODE; + + /** + * Only `integrated_payment` requires every associated channel to be EUR; the redirected + * and `hosted_fields` display modes both work in any currency. + * + * @param array $rawFormData + */ + protected function shouldValidateBaseCurrency(array $rawFormData): bool + { + return PayPlugGatewayFactory::DISPLAY_MODE_INTEGRATED_PAYMENT === ($rawFormData[PayPlugGatewayFactory::DISPLAY_MODE_FIELD] ?? null); + } + + /** + * shouldValidateBaseCurrency() above only ever lets this fire for `integrated_payment` mode + * (redirected/hosted_fields both return false there), so this message can be specific to + * that mode rather than the generic per-gateway wording. + */ + protected function baseCurrencyViolationMessage(ChannelInterface $channel): string + { + return $this->translator->trans('payplug_sylius_payplug_plugin.form.integrated_payment_currency_incompatible'); + } } diff --git a/src/Gateway/Form/Type/UhfGatewayConfigurationType.php b/src/Gateway/Form/Type/UhfGatewayConfigurationType.php deleted file mode 100644 index c7d0b9ef..00000000 --- a/src/Gateway/Form/Type/UhfGatewayConfigurationType.php +++ /dev/null @@ -1,25 +0,0 @@ - 'payplug_uhf', - 'label' => 'payplug_sylius_payplug_plugin.ui.uhf_gateway_label', - 'priority' => 80, - ], -)] -final class UhfGatewayConfigurationType extends AbstractGatewayConfigurationType -{ - protected string $gatewayFactoryTitle = UhfGatewayFactory::FACTORY_TITLE; - - protected string $gatewayFactoryName = UhfGatewayFactory::FACTORY_NAME; - - protected string $gatewayBaseCurrencyCode = UhfGatewayFactory::BASE_CURRENCY_CODE; -} diff --git a/src/Gateway/PayPlugGatewayFactory.php b/src/Gateway/PayPlugGatewayFactory.php index 99cb0e41..21826092 100644 --- a/src/Gateway/PayPlugGatewayFactory.php +++ b/src/Gateway/PayPlugGatewayFactory.php @@ -16,4 +16,85 @@ final class PayPlugGatewayFactory extends AbstractGatewayFactory public const INTEGRATED_PAYMENT = 'integratedPayment'; public const DEFERRED_CAPTURE = 'deferredCapture'; + + public const HOSTED_FIELDS = 'hostedFields'; + + public const HF_IDENTIFIER = 'hfIdentifier'; + + public const HF_SUB_MERCHANT_ID = 'hfSubMerchantId'; + + // Unmapped admin form field driving INTEGRATED_PAYMENT/HOSTED_FIELDS below + public const DISPLAY_MODE_FIELD = 'hostedFieldsMode'; + + public const DISPLAY_MODE_INTEGRATED_PAYMENT = 'integrated_payment'; + + public const DISPLAY_MODE_HOSTED_FIELDS = 'hosted_fields'; + + /** + * Derives the admin form radio's initial selection from persisted config. + * Hosted Fields wins if both flags are somehow true, since only it carries the + * mandatory Account ID / SubMerchant ID fields the merchant would otherwise lose sight of. + */ + public static function resolveDisplayMode(array $config): ?string + { + if (true === ($config[self::HOSTED_FIELDS] ?? false)) { + return self::DISPLAY_MODE_HOSTED_FIELDS; + } + if (true === ($config[self::INTEGRATED_PAYMENT] ?? false)) { + return self::DISPLAY_MODE_INTEGRATED_PAYMENT; + } + + return null; + } + + /** + * Derives the two persisted booleans from the submitted radio value. + * Always returns both keys explicitly (rather than only the "true" one) so that switching + * away from a previously-selected mode clears the stale flag instead of leaving it behind. + * + * @return array{integratedPayment: bool, hostedFields: bool} + */ + public static function resolveDisplayModeFlags(?string $displayMode): array + { + return [ + self::INTEGRATED_PAYMENT => self::DISPLAY_MODE_INTEGRATED_PAYMENT === $displayMode, + self::HOSTED_FIELDS => self::DISPLAY_MODE_HOSTED_FIELDS === $displayMode, + ]; + } + + /** + * @param array $rawFormData Display-mode/HF-identifier/HF-sub-merchant-id + * values as submitted (assembled from the config + * form's already-submitted child forms at + * POST_SUBMIT, not PRE_SUBMIT's raw payload). + * + * @return list Config keys (HF_IDENTIFIER / HF_SUB_MERCHANT_ID) that are blank + * while hosted_fields is selected; empty if hosted_fields isn't selected + * or both fields are filled. + */ + public static function missingHostedFieldsRequirements(array $rawFormData): array + { + if (self::DISPLAY_MODE_HOSTED_FIELDS !== ($rawFormData[self::DISPLAY_MODE_FIELD] ?? null)) { + return []; + } + + $missing = []; + if (self::isBlank($rawFormData[self::HF_IDENTIFIER] ?? '')) { + $missing[] = self::HF_IDENTIFIER; + } + if (self::isBlank($rawFormData[self::HF_SUB_MERCHANT_ID] ?? '')) { + $missing[] = self::HF_SUB_MERCHANT_ID; + } + + return $missing; + } + + private static function isBlank(mixed $value): bool + { + if (!is_scalar($value)) { + return true; + } + + return '' === trim((string) $value); + } } diff --git a/src/Gateway/UhfGatewayFactory.php b/src/Gateway/UhfGatewayFactory.php deleted file mode 100644 index 772de381..00000000 --- a/src/Gateway/UhfGatewayFactory.php +++ /dev/null @@ -1,16 +0,0 @@ -isSaveCardAllowed(...)), new TwigFunction('is_payplug_test_mode_enabled', $this->isTest(...)), + new TwigFunction('payplug_hosted_fields_company_id', $this->hostedFieldsCompanyId(...)), + new TwigFunction('payplug_display_mode', $this->displayMode(...)), ]; } + /** + * @param array $config + */ + public function displayMode(array $config): ?string + { + return PayPlugGatewayFactory::resolveDisplayMode($config); + } + public function isSaveCardAllowed(PaymentMethodInterface $paymentMethod): bool { return $this->canSaveCardChecker->isAllowed($paymentMethod); @@ -37,4 +48,12 @@ public function isTest(PaymentMethodInterface $paymentMethod): bool return !(bool) $client->getAccount()['is_live']; } + + public function hostedFieldsCompanyId(PaymentMethodInterface $paymentMethod): string + { + $client = $this->apiClientFactory->createForPaymentMethod($paymentMethod); + $companyId = $client->getAccount()['company_ref'] ?? ''; + + return \is_string($companyId) ? $companyId : ''; + } } diff --git a/src/Validator/PaymentMethodValidator.php b/src/Validator/PaymentMethodValidator.php index 558b4513..2a9b0d49 100644 --- a/src/Validator/PaymentMethodValidator.php +++ b/src/Validator/PaymentMethodValidator.php @@ -12,7 +12,6 @@ use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\ScalapayGatewayFactory; -use PayPlug\SyliusPayPlugPlugin\Gateway\UhfGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsCanSavePaymentMethod; use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsOneyEnabled; use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\PayplugPermission; @@ -51,7 +50,6 @@ public function process(PaymentMethodInterface $paymentMethod): void ApplePayGatewayFactory::FACTORY_NAME => $this->processDefault($paymentMethod), ScalapayGatewayFactory::FACTORY_NAME => $this->processDefault($paymentMethod), WeroGatewayFactory::FACTORY_NAME => $this->processDefault($paymentMethod), - UhfGatewayFactory::FACTORY_NAME => $this->processUhf($paymentMethod), default => throw new \InvalidArgumentException('Unsupported payment method'), }; @@ -70,31 +68,19 @@ private function processPayplug(PaymentMethodInterface $paymentMethod): Constrai $config = $paymentMethod->getGatewayConfig()?->getConfig() ?? []; $constraintList = [new IsCanSavePaymentMethod()]; - if (true === $config[PayPlugGatewayFactory::ONE_CLICK]) { + if (true === ($config[PayPlugGatewayFactory::ONE_CLICK] ?? false)) { $constraintList[] = new PayplugPermission(Permission::CAN_SAVE_CARD); } - if (true === $config[PayPlugGatewayFactory::DEFERRED_CAPTURE]) { + if (true === ($config[PayPlugGatewayFactory::DEFERRED_CAPTURE] ?? false)) { $constraintList[] = new PayplugPermission(Permission::CAN_CREATE_DEFERRED_PAYMENT); } - if (true === $config[PayPlugGatewayFactory::INTEGRATED_PAYMENT]) { + if (true === ($config[PayPlugGatewayFactory::INTEGRATED_PAYMENT] ?? false)) { $constraintList[] = new PayplugPermission(Permission::CAN_USE_INTEGRATED_PAYMENTS); } return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS); } - private function processUhf(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface - { - $config = $paymentMethod->getGatewayConfig()?->getConfig() ?? []; - $constraintList = [new IsCanSavePaymentMethod()]; - - if (true === ($config[UhfGatewayFactory::ONE_CLICK] ?? false)) { - $constraintList[] = new PayplugPermission(Permission::CAN_SAVE_CARD); - } - - return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS); - } - private function processOney(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface { $constraintList = [new IsOneyEnabled()]; diff --git a/templates/admin/payment_method/form/hf_identifier_default.html.twig b/templates/admin/payment_method/form/hf_identifier.html.twig similarity index 84% rename from templates/admin/payment_method/form/hf_identifier_default.html.twig rename to templates/admin/payment_method/form/hf_identifier.html.twig index 08bcf7ff..0942b7be 100644 --- a/templates/admin/payment_method/form/hf_identifier_default.html.twig +++ b/templates/admin/payment_method/form/hf_identifier.html.twig @@ -1,4 +1,4 @@ -{% set form = hookable_metadata.context.form.gatewayConfig.config.hfIdentifierDefault %} +{% set form = hookable_metadata.context.form.gatewayConfig.config.hfIdentifier %}
{{ form_row(form) }} diff --git a/templates/admin/payment_method/form/hf_sub_merchant_id.html.twig b/templates/admin/payment_method/form/hf_sub_merchant_id.html.twig new file mode 100644 index 00000000..1f2d5696 --- /dev/null +++ b/templates/admin/payment_method/form/hf_sub_merchant_id.html.twig @@ -0,0 +1,5 @@ +{% set form = hookable_metadata.context.form.gatewayConfig.config.hfSubMerchantId %} + +
+ {{ form_row(form) }} +
diff --git a/templates/admin/payment_method/form/integrated_payment.html.twig b/templates/admin/payment_method/form/hosted_fields_mode.html.twig similarity index 80% rename from templates/admin/payment_method/form/integrated_payment.html.twig rename to templates/admin/payment_method/form/hosted_fields_mode.html.twig index 26c8c373..f63517fd 100644 --- a/templates/admin/payment_method/form/integrated_payment.html.twig +++ b/templates/admin/payment_method/form/hosted_fields_mode.html.twig @@ -1,5 +1,5 @@ -{% set form = hookable_metadata.context.form.gatewayConfig.config.integratedPayment %} +{% set form = hookable_metadata.context.form.gatewayConfig.config.hostedFieldsMode %}
{{ form_row(form) }} -
\ No newline at end of file +
diff --git a/templates/shop/hosted_fields/index.html.twig b/templates/shop/hosted_fields/index.html.twig index 4136effd..1a8c2970 100644 --- a/templates/shop/hosted_fields/index.html.twig +++ b/templates/shop/hosted_fields/index.html.twig @@ -1,10 +1,8 @@ -{% set config = paymentMethod.gatewayConfig.config %} -