diff --git a/Config/module.xml b/Config/module.xml
index 7ed0c5d..aee6a55 100755
--- a/Config/module.xml
+++ b/Config/module.xml
@@ -17,7 +17,7 @@
en_USfr_FR
- 3.1.0
+ 3.2.0Vincent Lopes-Vicente
diff --git a/EventListener/FormExtend/OrderFormListener.php b/EventListener/FormExtend/OrderFormListener.php
deleted file mode 100755
index 68a9ada..0000000
--- a/EventListener/FormExtend/OrderFormListener.php
+++ /dev/null
@@ -1,81 +0,0 @@
-request = $requestStack->getCurrentRequest();
- }
-
- public function addMultiPaymentField(TheliaFormEvent $event)
- {
- if (!PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_ENABLED)) {
- return;
- }
-
- $event->getForm()->getFormBuilder()
- ->add(
- self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME,
- CheckboxType::class
- );
-
- }
-
- public function checkMultiPaymentSelected(OrderEvent $event)
- {
- $request = $this->request;
- if (null === $request || !$request->hasSession()) {
- return;
- }
-
- $request->getSession()->set(self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME, 0);
- $formData = $request->attributes->get(
- self::THELIA_CUSTOMER_ORDER_PAYMENT_FROM_NAME,
- $request->query->get(
- self::THELIA_CUSTOMER_ORDER_PAYMENT_FROM_NAME,
- $request->request->get(self::THELIA_CUSTOMER_ORDER_PAYMENT_FROM_NAME)
- )
- );
-
- if (!isset($formData[self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME]) || 0 == $formData[self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME]) {
- return;
- }
-
- $request->getSession()->set(self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME, 1);
- }
-
- /**
- * Returns an array of event names this subscriber wants to listen to.
- *
- * @return array The event names to listen to
- *
- * @api
- */
- public static function getSubscribedEvents(): array
- {
- return array(
- TheliaEvents::FORM_AFTER_BUILD.'.'.self::THELIA_CUSTOMER_ORDER_PAYMENT_FROM_NAME => array('addMultiPaymentField', 64),
- TheliaEvents::ORDER_SET_PAYMENT_MODULE => array('checkMultiPaymentSelected', 64)
- );
- }
-}
\ No newline at end of file
diff --git a/EventListener/PaymentOptionListener.php b/EventListener/PaymentOptionListener.php
new file mode 100644
index 0000000..be15c5f
--- /dev/null
+++ b/EventListener/PaymentOptionListener.php
@@ -0,0 +1,114 @@
+ ['addMultiPaymentOption', 128],
+ ];
+ }
+
+ public function addMultiPaymentOption(PaymentModuleOptionEvent $event): void
+ {
+ if ($event->getModule()->getId() !== PayPlugModule::getModuleId()) {
+ return;
+ }
+
+ if (!PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_ENABLED)) {
+ return;
+ }
+
+ $cart = $event->getCart();
+
+ if (null === $cart) {
+ return;
+ }
+
+ $country = $event->getCountry() ?? $this->taxEngine->getDeliveryCountry();
+ $cartAmount = $cart->getTaxedAmount($country);
+
+ if ($cartAmount <= (float) PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MINIMUM)
+ || $cartAmount >= (float) PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MAXIMUM)) {
+ return;
+ }
+
+ $translator = Translator::getInstance();
+ $domain = PayPlugModule::DOMAIN_NAME.'.fo.default';
+
+ $option = (new PaymentModuleOption())
+ ->setCode(self::MULTI_PAYMENT_OPTION_CODE)
+ ->setTitle($translator->trans(
+ 'Pay in %n times without fees.',
+ ['%n' => PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_TIMES)],
+ $domain,
+ ))
+ ->setDescription($translator->trans('You will be asked to save your payment card data.', [], $domain));
+
+ $group = (new PaymentModuleOptionGroup())
+ ->setCode(self::GROUP_CODE)
+ ->setTitle($translator->trans('Payment in instalments', [], $domain))
+ ->setMinimumSelectedOptions(0)
+ ->setMaximumSelectedOptions(1)
+ ->appendPaymentModuleOption($option);
+
+ $event->appendPaymentModuleOptionGroups($group);
+ }
+
+ /**
+ * Whether the buyer ticked the instalment option, while the shop still offers it.
+ */
+ public static function isMultiPaymentChosen(SessionInterface $session): bool
+ {
+ if (!PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_ENABLED)) {
+ return false;
+ }
+
+ $choices = $session->get(self::SESSION_KEY, []);
+
+ if (!\is_array($choices)) {
+ return false;
+ }
+
+ foreach ($choices as $choice) {
+ if (\is_array($choice)
+ && self::GROUP_CODE === ($choice['group'] ?? null)
+ && \is_array($choice['values'] ?? null)
+ && \in_array(self::MULTI_PAYMENT_OPTION_CODE, $choice['values'], true)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/Hook/FrontHookManager.php b/Hook/FrontHookManager.php
deleted file mode 100755
index 3d4dda3..0000000
--- a/Hook/FrontHookManager.php
+++ /dev/null
@@ -1,105 +0,0 @@
-taxEngine = $taxEngine;
- }
-
- public function onOrderInvoiceAfterJsInclude(HookRenderEvent $event)
- {
- $payPlugModuleId = PayPlugModule::getModuleId();
- if (PayPlugModule::getConfigValue(PayPlugConfigValue::PAYMENT_PAGE_TYPE) === "lightbox") {
- $event->add($this->render(
- 'PayPlugModule/order-invoice-after-js-include.html',
- compact('payPlugModuleId')
- ));
- }
- }
-
- public function onOrderInvoicePaymentExtra(HookRenderEvent $event)
- {
- if ((int)$event->getArgument('module') !== PayPlugModule::getModuleId()) {
- return;
- }
-
- $this->displayOneClickPayment($event);
- $this->displayMultiPayment($event);
- }
-
- protected function displayMultiPayment(HookRenderEvent $event)
- {
- if (!PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_ENABLED)) {
- return;
- }
-
- $nTimes = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_TIMES);
- $minimumAmount = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MINIMUM);
- $maximumAmount = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MAXIMUM);
-
- /** @var Country $country */
- $country = $this->taxEngine->getDeliveryCountry();
-
- $request = $this->getRequest();
- if (null === $request || !$request->hasSession()) {
- return;
- }
-
- $cart = $request->getSession()->getSessionCart();
- $cartAmount = $cart->getTaxedAmount($country);
- if ($cartAmount <= $minimumAmount || $cartAmount >= $maximumAmount) {
- return;
- }
-
- $event->add(
- $this->render(
- 'PayPlugModule/multi-payment.html',
- compact("nTimes")
- )
- );
- }
-
- protected function displayOneClickPayment(HookRenderEvent $event)
- {
- if (!PayPlugModule::getConfigValue(PayPlugConfigValue::ONE_CLICK_PAYMENT_ENABLED)) {
- return;
- }
-
- $request = $this->getRequest();
- if (null === $request || !$request->hasSession()) {
- return;
- }
-
- $customerId = $request->getSession()->getCustomerUser()->getId();
-
- $payPlugCard = PayPlugCardQuery::create()
- ->findOneByCustomerId($customerId);
-
- if (null === $payPlugCard) {
- return;
- }
-
- $event->add(
- $this->render(
- 'PayPlugModule/one-click-payment.html',
- [
- 'last4' => $payPlugCard->getLast4()
- ]
- )
- );
- }
-}
\ No newline at end of file
diff --git a/Hook/Theme/PayPlugPaymentThemeHook.php b/Hook/Theme/PayPlugPaymentThemeHook.php
new file mode 100644
index 0000000..c75c5ca
--- /dev/null
+++ b/Hook/Theme/PayPlugPaymentThemeHook.php
@@ -0,0 +1,155 @@
+isLightbox()
+ ? $this->twig->render(self::TEMPLATE_DIR.'lightbox-script.html.twig')
+ : '';
+ }
+
+ if ((int) ($parameters['module'] ?? 0) !== PayPlugModule::getModuleId()) {
+ return '';
+ }
+
+ $last4 = $this->savedCardLast4();
+ $payUrl = $this->isLightbox() ? $this->payUrl() : null;
+
+ if (null === $last4 && null === $payUrl) {
+ return '';
+ }
+
+ // Translated here: the module's front strings are read by the Thelia translator,
+ // the Twig one of the theme does not load them.
+ $translator = Translator::getInstance();
+ $domain = PayPlugModule::DOMAIN_NAME.'.fo.default';
+
+ return $this->twig->render(self::TEMPLATE_DIR.'payment-extra.html.twig', [
+ 'payUrl' => $payUrl,
+ 'savedCard' => null === $last4 ? null : [
+ 'title' => $translator->trans('One click payment is available !', [], $domain),
+ 'notice' => $translator->trans(
+ 'A payment card ending in %last4% is saved on your account: it will be charged as soon as you place the order.',
+ ['%last4%' => $last4],
+ $domain,
+ ),
+ 'deleteLabel' => $translator->trans('Delete this card', [], $domain),
+ 'deleteUrl' => $this->urlGenerator->generate('payplugmodule_delete_card'),
+ ],
+ ]);
+ }
+
+ private function isLightbox(): bool
+ {
+ return 'lightbox' === PayPlugModule::getConfigValue(PayPlugConfigValue::PAYMENT_PAGE_TYPE);
+ }
+
+ /**
+ * The address the order button of the theme leads to, which the lightbox script
+ * takes over. A theme without that route keeps the hosted payment page.
+ */
+ private function payUrl(): ?string
+ {
+ try {
+ return $this->urlGenerator->generate(self::PAY_ROUTE);
+ } catch (RouteNotFoundException) {
+ return null;
+ }
+ }
+
+ /**
+ * The last digits of the card PaymentService will charge, under the same conditions:
+ * one click payment on, a card saved by the customer, not expired.
+ */
+ private function savedCardLast4(): ?string
+ {
+ if (!PayPlugModule::getConfigValue(PayPlugConfigValue::ONE_CLICK_PAYMENT_ENABLED)) {
+ return null;
+ }
+
+ $request = $this->requestStack->getCurrentRequest();
+
+ if (null === $request || !$request->hasSession()) {
+ return null;
+ }
+
+ $session = $request->getSession();
+
+ if (!$session instanceof Session) {
+ return null;
+ }
+
+ $customer = $session->getCustomerUser();
+
+ if (null === $customer) {
+ return null;
+ }
+
+ $card = PayPlugCardQuery::create()->findOneByCustomerId($customer->getId());
+
+ if (null === $card) {
+ return null;
+ }
+
+ $expireDate = date('Y-m', strtotime($card->getExpireYear().'-'.$card->getExpireMonth()));
+
+ if ($expireDate <= date('Y-m')) {
+ return null;
+ }
+
+ return (string) $card->getLast4();
+ }
+}
diff --git a/I18n/frontOffice/default/fr_FR.php b/I18n/frontOffice/default/fr_FR.php
index 6303a0d..f3e94cc 100755
--- a/I18n/frontOffice/default/fr_FR.php
+++ b/I18n/frontOffice/default/fr_FR.php
@@ -1,9 +1,10 @@
'Une carte de paiement finissant par %last4 as été enregitrée précédemment a votre demande. Le paiement de cette commande seras fait automatiquement après un clic sur le bouton "Etape suivante".',
+ 'A payment card ending in %last4% is saved on your account: it will be charged as soon as you place the order.' => 'Une carte de paiement finissant par %last4% est enregistrée sur votre compte : elle sera débitée dès que vous passerez la commande.',
+ 'Delete this card' => 'Supprimer cette carte',
'One click payment is available !' => 'Paiement en un clic disponible !',
'Pay in %n times without fees.' => 'Paiement en %n fois sans frais.',
- 'To clear your payment card details, please click here' => 'Pour supprimer ces informations de paiement, cliquez ici',
- 'You will be asked to save your payment card data.' => 'Ils vous sera demandé d\'enregistrer votre carte bancaire.',
+ 'Payment in instalments' => 'Paiement en plusieurs fois',
+ 'You will be asked to save your payment card data.' => 'Il vous sera demandé d\'enregistrer votre carte bancaire.',
);
diff --git a/PayPlugModule.php b/PayPlugModule.php
index fb28c18..5b49435 100755
--- a/PayPlugModule.php
+++ b/PayPlugModule.php
@@ -12,7 +12,7 @@
namespace PayPlugModule;
-use PayPlugModule\EventListener\FormExtend\OrderFormListener;
+use PayPlugModule\EventListener\PaymentOptionListener;
use PayPlugModule\Model\PayPlugConfigValue;
use PayPlugModule\Service\PaymentService;
use Propel\Runtime\Connection\ConnectionInterface;
@@ -26,7 +26,6 @@
use Thelia\Log\Tlog;
use Thelia\Model\Order;
use Thelia\Module\AbstractPaymentModule;
-use Thelia\Tools\URL;
class PayPlugModule extends AbstractPaymentModule
{
@@ -91,8 +90,7 @@ public function pay(Order $order): ?Response
$request = $this->getRequest();
$isMultiPayment = $request->hasSession()
- ? $request->getSession()->get(OrderFormListener::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME, 0)
- : 0;
+ && PaymentOptionListener::isMultiPaymentChosen($request->getSession());
$orderTotalAmount = $this->getOrderPayTotalAmount($order);
if ($isMultiPayment) {
@@ -109,13 +107,15 @@ public function pay(Order $order): ?Response
PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_ENABLED, false),
PayPlugModule::getConfigValue(PayPlugConfigValue::ONE_CLICK_PAYMENT_ENABLED, false),
$slice,
- $orderTotalAmount
+ $orderTotalAmount,
+ $this->getPaymentSuccessPageUrl($order->getId()),
+ $this->getPaymentFailurePageUrl($order->getId(), null)
);
$forceRedirect = false;
if (true === $payment['isPaid']) {
$forceRedirect = true;
- $payment['url'] = URL::getInstance()->absoluteUrl('/order/placed/'.$order->getId());
+ $payment['url'] = $this->getPaymentSuccessPageUrl($order->getId());
}
if ($this->getRequest()->isXmlHttpRequest()) {
@@ -127,13 +127,14 @@ public function pay(Order $order): ?Response
);
}
} catch (\Exception $exception) {
- if ($this->getRequest()->isXmlHttpRequest()) {
- return new JsonResponse(['error' => $exception->getMessage()], 400);
- }
Tlog::getInstance()->addError(
'Error PayPlugModule::pay() : ' . $exception->getMessage()
);
- return new RedirectResponse(URL::getInstance()->absoluteUrl('error'));
+
+ // The failure page of the shop, for a plain request and for the lightbox
+ // script alike: the script follows the redirection. The provider's message
+ // stays in the log.
+ return new RedirectResponse($this->getPaymentFailurePageUrl($order->getId(), null));
}
return new RedirectResponse($payment['url']);
diff --git a/Service/PaymentService.php b/Service/PaymentService.php
index eccbacc..48b13a4 100755
--- a/Service/PaymentService.php
+++ b/Service/PaymentService.php
@@ -45,13 +45,23 @@ public function sendOrderPayment(
bool $capture,
bool $allowSaveCard,
int $paymentSlice,
- float $totalOrder
+ float $totalOrder,
+ ?string $returnUrl = null,
+ ?string $cancelUrl = null
) {
$paymentEvent = (new PayPlugPaymentEvent())
->buildFromOrder($order,$totalOrder)
->setCapture($capture)
->setAllowSaveCard($allowSaveCard);
+ if (null !== $returnUrl) {
+ $paymentEvent->setHostedPaymentReturnUrl($returnUrl);
+ }
+
+ if (null !== $cancelUrl) {
+ $paymentEvent->setHostedPaymentCancelUrl($cancelUrl);
+ }
+
if (null !== $card = PayPlugCardQuery::create()->findOneByCustomerId($order->getCustomerId())) {
$todayDate = date("Y-m");
$expireDate = date("Y-m", strtotime($card->getExpireYear().'-'.$card->getExpireMonth()));
diff --git a/templates/frontOffice/default/PayPlugModule/lightbox-script.html.twig b/templates/frontOffice/default/PayPlugModule/lightbox-script.html.twig
new file mode 100644
index 0000000..34f8e5b
--- /dev/null
+++ b/templates/frontOffice/default/PayPlugModule/lightbox-script.html.twig
@@ -0,0 +1,64 @@
+{# In the head of the payment pages, in lightbox mode. A click on a link to the address
+ the PayPlug method of the page names (data-pay-url, see payment-extra.html.twig) is
+ sent in the background: the module answers with the PayPlug payment address, opened in
+ the PayPlug lightbox, or with the address to go to (a card already saved, an error).
+ Without the marker — another method chosen — or without the library, the link is
+ followed as usual and the hosted payment page takes over. #}
+
+
diff --git a/templates/frontOffice/default/PayPlugModule/multi-payment.html b/templates/frontOffice/default/PayPlugModule/multi-payment.html
deleted file mode 100755
index 4229e30..0000000
--- a/templates/frontOffice/default/PayPlugModule/multi-payment.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{form_field form=$form field='pay_plug_multi_payment'}
-
-
-
-
- {intl l='You will be asked to save your payment card data.' n={url path='/payplug/card/delete'} d='payplugmodule.fo.default'}
-
-{/form_field}
\ No newline at end of file
diff --git a/templates/frontOffice/default/PayPlugModule/one-click-payment.html b/templates/frontOffice/default/PayPlugModule/one-click-payment.html
deleted file mode 100755
index 60e3146..0000000
--- a/templates/frontOffice/default/PayPlugModule/one-click-payment.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
{intl l='One click payment is available !' d='payplugmodule.fo.default'}
-
- {intl l='A payment card ending by %last4 has been previously saved at your request. Payment for your order will be made immediately after clicking the "Next Step" button.' last4=$last4 d='payplugmodule.fo.default'}
-
- {intl l='To clear your payment card details, please click here' url={url path='/payplug/card/delete'} d='payplugmodule.fo.default'}.
-
diff --git a/templates/frontOffice/default/PayPlugModule/order-invoice-after-js-include.html b/templates/frontOffice/default/PayPlugModule/order-invoice-after-js-include.html
deleted file mode 100755
index 512fa42..0000000
--- a/templates/frontOffice/default/PayPlugModule/order-invoice-after-js-include.html
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/templates/frontOffice/default/PayPlugModule/payment-extra.html.twig b/templates/frontOffice/default/PayPlugModule/payment-extra.html.twig
new file mode 100644
index 0000000..8a7c72a
--- /dev/null
+++ b/templates/frontOffice/default/PayPlugModule/payment-extra.html.twig
@@ -0,0 +1,13 @@
+{# Under the PayPlug method of the payment step, once chosen. In lightbox mode the root
+ carries the address the order button leads to: lightbox-script.html.twig opens the
+ PayPlug form instead of following it. The texts come translated from
+ PayPlugPaymentThemeHook; the classes are those of the Flexy theme. #}
+