From 179adb10360efc785f2444d4727348c1aa8bb829 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Mon, 19 Oct 2020 16:12:18 +0200 Subject: [PATCH 01/13] Bugfix: Calculate the payment fee over the shipping including tax --- Service/PaymentFee/Types/Percentage.php | 2 +- etc/sales.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Service/PaymentFee/Types/Percentage.php b/Service/PaymentFee/Types/Percentage.php index 8528a5678fa..79b54616bc6 100644 --- a/Service/PaymentFee/Types/Percentage.php +++ b/Service/PaymentFee/Types/Percentage.php @@ -47,7 +47,7 @@ public function calculate(CartInterface $cart, Total $total) { $percentage = $this->config->getPercentage($cart->getPayment()->getMethod(), $cart->getStoreId()); - $shipping = $total->getTotalAmount('shipping'); + $shipping = $total->getShippingInclTax(); $subtotal = $total->getData('subtotal_incl_tax'); if (!$subtotal) { $subtotal = $total->getTotalAmount('subtotal'); diff --git a/etc/sales.xml b/etc/sales.xml index 355b3976918..c50f18ef2fb 100644 --- a/etc/sales.xml +++ b/etc/sales.xml @@ -2,7 +2,7 @@
- +
From 6ebdda4099584f6743102fa8515b74aa9d1fc4b2 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Mon, 2 Nov 2020 13:56:47 +0100 Subject: [PATCH 02/13] Fix: The row total would not be calculated correctly when a discount was applied --- .../Processor/BundleWithoutDynamicPricing.php | 71 +++++++++++++++++++ etc/di.xml | 5 +- 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php diff --git a/Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php b/Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php new file mode 100644 index 00000000000..8a41457be8a --- /dev/null +++ b/Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php @@ -0,0 +1,71 @@ +mollieHelper = $mollieHelper; + } + + public function process($orderLine, OrderInterface $order, OrderItemInterface $orderItem = null): array + { + if ( + !$orderItem || + $orderItem->getProductType() !== Type::TYPE_BUNDLE || + !$orderItem->getProduct() || + $orderItem->getProduct()->getPriceType() != Price::PRICE_TYPE_FIXED + ) { + return $orderLine; + } + + $forceBaseCurrency = (bool)$this->mollieHelper->useBaseCurrency($order->getStoreId()); + $currency = $forceBaseCurrency ? $order->getBaseCurrencyCode() : $order->getOrderCurrencyCode(); + + $discountAmount = $this->getDiscountAmountWithTax($orderItem, $forceBaseCurrency); + if (!$discountAmount) { + return $orderLine; + } + + // Magento provides us with a discount amount without tax, but calculates with tax is this case. So calculate + // the correct amount with tax and recalculate the unit price, total amount vat amount and discount amount. + + $taxPercent = $orderItem->getTaxPercent(); + $discountAmount = $discountAmount + (($discountAmount / 100) * $taxPercent); + $unitPrice = $orderLine['totalAmount']['value'] / $orderItem->getQtyOrdered(); + $newVatAmount = (($unitPrice - $discountAmount) / (100 + $taxPercent)) * $taxPercent; + + $orderLine['unitPrice'] = $this->mollieHelper->getAmountArray($currency, $unitPrice); + $orderLine['totalAmount'] = $this->mollieHelper->getAmountArray($currency, $unitPrice - $discountAmount); + $orderLine['vatAmount'] = $this->mollieHelper->getAmountArray($currency, $newVatAmount); + $orderLine['discountAmount'] = $this->mollieHelper->getAmountArray($currency, $discountAmount); + + return $orderLine; + } + + private function getDiscountAmountWithTax(OrderItemInterface $item, bool $forceBaseCurrency) + { + if ($forceBaseCurrency) { + return abs($item->getBaseDiscountAmount() + $item->getBaseDiscountTaxCompensationAmount()); + } + + return abs($item->getDiscountAmount() + $item->getDiscountTaxCompensationAmount()); + } +} diff --git a/etc/di.xml b/etc/di.xml index f64f69416dd..d64a8034c05 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -95,9 +95,8 @@ - - Mollie\Payment\Service\Order\Lines\Processor\VoucherCategory - + Mollie\Payment\Service\Order\Lines\Processor\VoucherCategory + Mollie\Payment\Service\Order\Lines\Processor\BundleWithoutDynamicPricing From 7a2be8cc3c3bbacbfb06a993cfad1ec470b65793 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Mon, 9 Nov 2020 09:56:49 +0100 Subject: [PATCH 03/13] Fix: Correct handling of 5% tax --- .../Lines/Processor/BundleWithoutDynamicPricing.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php b/Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php index 8a41457be8a..9789f719cd5 100644 --- a/Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php +++ b/Service/Order/Lines/Processor/BundleWithoutDynamicPricing.php @@ -44,11 +44,10 @@ public function process($orderLine, OrderInterface $order, OrderItemInterface $o return $orderLine; } - // Magento provides us with a discount amount without tax, but calculates with tax is this case. So calculate - // the correct amount with tax and recalculate the unit price, total amount vat amount and discount amount. + // Magento provides us with a discount amount without tax, but calculates with tax in this case. So recalculate + // the unit price, total amount and vat amount. $taxPercent = $orderItem->getTaxPercent(); - $discountAmount = $discountAmount + (($discountAmount / 100) * $taxPercent); $unitPrice = $orderLine['totalAmount']['value'] / $orderItem->getQtyOrdered(); $newVatAmount = (($unitPrice - $discountAmount) / (100 + $taxPercent)) * $taxPercent; @@ -63,9 +62,9 @@ public function process($orderLine, OrderInterface $order, OrderItemInterface $o private function getDiscountAmountWithTax(OrderItemInterface $item, bool $forceBaseCurrency) { if ($forceBaseCurrency) { - return abs($item->getBaseDiscountAmount() + $item->getBaseDiscountTaxCompensationAmount()); + return abs($item->getBaseDiscountAmount()); } - return abs($item->getDiscountAmount() + $item->getDiscountTaxCompensationAmount()); + return abs($item->getDiscountAmount()); } } From 67b1b86dda2827aff2b10c7a086390daf12b641d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tjitse=20Efd=C3=A9?= Date: Fri, 13 Nov 2020 09:51:44 +0100 Subject: [PATCH 04/13] Fix second chance disabled setting --- Config.php | 3 +++ .../Controller/Checkout/SecondChanceTest.php | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Config.php b/Config.php index da999d3cd19..3e0ed251b28 100644 --- a/Config.php +++ b/Config.php @@ -199,6 +199,9 @@ public function isSecondChanceEmailEnabled($storeId = null) */ public function automaticallySendSecondChanceEmails($storeId = null) { + if (!$this->isSecondChanceEmailEnabled($storeId)) { + return false; + } return $this->isSetFlag(static::GENERAL_AUTOMATICALLY_SEND_SECOND_CHANCE_EMAILS, $storeId); } diff --git a/Test/Integration/Controller/Checkout/SecondChanceTest.php b/Test/Integration/Controller/Checkout/SecondChanceTest.php index cb67fb709ca..1882b38d426 100644 --- a/Test/Integration/Controller/Checkout/SecondChanceTest.php +++ b/Test/Integration/Controller/Checkout/SecondChanceTest.php @@ -7,13 +7,16 @@ namespace Mollie\Payment\Test\Integration\Controller\Checkout; use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SortOrderFactory; use Magento\Quote\Model\Quote; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\TestFramework\TestCase\AbstractController; +use Mollie\Payment\Cron\SendPendingPaymentReminders; use Mollie\Payment\Service\Order\Reorder; use Mollie\Payment\Service\PaymentToken\Generate; +use PHPUnit\Framework\MockObject\MockObject; class SecondChanceTest extends AbstractController { @@ -90,6 +93,29 @@ public function testRecreatesTheOrder() $this->assertRedirect($this->equalTo('http://example.com')); } + /** + * @magentoConfigFixture default_store payment/mollie_general/enable_second_chance_email 0 + * @magentoConfigFixture default_store payment/mollie_general/automatically_send_second_chance_emails 1 + */ + public function testSecondChanceDisabledAutoSendEnabled() + { + /** @var SortOrderFactory|MockObject $sortOrderFactoryMock */ + $sortOrderFactoryMock = $this->getMockBuilder(SortOrderFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $sortOrderFactoryMock->expects($this->never())->method('create'); + + $this->_objectManager->addSharedInstance( + $sortOrderFactoryMock, + SortOrderFactory::class + ); + + /** @var SendPendingPaymentReminders $sendReminderJob */ + $sendReminderJob = $this->_objectManager->get(SendPendingPaymentReminders::class); + $sendReminderJob->execute(); + } + /** * @param $incrementId * @return OrderInterface From b36266c9e7ecb9c3a1fc4b6eae985be800eb54fe Mon Sep 17 00:00:00 2001 From: Roy Duineveld Date: Fri, 13 Nov 2020 11:24:47 +0100 Subject: [PATCH 05/13] Fix --- etc/webapi.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/webapi.xml b/etc/webapi.xml index d4d82465d34..eacebfda6f7 100644 --- a/etc/webapi.xml +++ b/etc/webapi.xml @@ -26,7 +26,7 @@ - + From 873f9b16b6ae03322cc334497dfcdd33f078d966 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Mon, 16 Nov 2020 10:01:47 +0100 Subject: [PATCH 06/13] Moved test to dedicated test class --- .../Controller/Checkout/SecondChanceTest.php | 26 ------------- .../Cron/SendPendingPaymentRemindersTest.php | 38 +++++++++++++++++++ 2 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 Test/Integration/Cron/SendPendingPaymentRemindersTest.php diff --git a/Test/Integration/Controller/Checkout/SecondChanceTest.php b/Test/Integration/Controller/Checkout/SecondChanceTest.php index 1882b38d426..cb67fb709ca 100644 --- a/Test/Integration/Controller/Checkout/SecondChanceTest.php +++ b/Test/Integration/Controller/Checkout/SecondChanceTest.php @@ -7,16 +7,13 @@ namespace Mollie\Payment\Test\Integration\Controller\Checkout; use Magento\Framework\Api\SearchCriteriaBuilder; -use Magento\Framework\Api\SortOrderFactory; use Magento\Quote\Model\Quote; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\TestFramework\TestCase\AbstractController; -use Mollie\Payment\Cron\SendPendingPaymentReminders; use Mollie\Payment\Service\Order\Reorder; use Mollie\Payment\Service\PaymentToken\Generate; -use PHPUnit\Framework\MockObject\MockObject; class SecondChanceTest extends AbstractController { @@ -93,29 +90,6 @@ public function testRecreatesTheOrder() $this->assertRedirect($this->equalTo('http://example.com')); } - /** - * @magentoConfigFixture default_store payment/mollie_general/enable_second_chance_email 0 - * @magentoConfigFixture default_store payment/mollie_general/automatically_send_second_chance_emails 1 - */ - public function testSecondChanceDisabledAutoSendEnabled() - { - /** @var SortOrderFactory|MockObject $sortOrderFactoryMock */ - $sortOrderFactoryMock = $this->getMockBuilder(SortOrderFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $sortOrderFactoryMock->expects($this->never())->method('create'); - - $this->_objectManager->addSharedInstance( - $sortOrderFactoryMock, - SortOrderFactory::class - ); - - /** @var SendPendingPaymentReminders $sendReminderJob */ - $sendReminderJob = $this->_objectManager->get(SendPendingPaymentReminders::class); - $sendReminderJob->execute(); - } - /** * @param $incrementId * @return OrderInterface diff --git a/Test/Integration/Cron/SendPendingPaymentRemindersTest.php b/Test/Integration/Cron/SendPendingPaymentRemindersTest.php new file mode 100644 index 00000000000..79f6ffd15ab --- /dev/null +++ b/Test/Integration/Cron/SendPendingPaymentRemindersTest.php @@ -0,0 +1,38 @@ +getMockBuilder(SortOrderFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $sortOrderFactoryMock->expects($this->never())->method('create'); + + $this->objectManager->addSharedInstance( + $sortOrderFactoryMock, + SortOrderFactory::class + ); + + /** @var SendPendingPaymentReminders $sendReminderJob */ + $sendReminderJob = $this->objectManager->get(SendPendingPaymentReminders::class); + $sendReminderJob->execute(); + } +} \ No newline at end of file From ec1f00b0acf1e638944bfe3bec800e992169bbc7 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Mon, 16 Nov 2020 14:46:21 +0100 Subject: [PATCH 07/13] Bugfix: Throw a 404 is the order does not exists so we can work around timing issues --- Controller/Checkout/Redirect.php | 4 +++- Controller/Checkout/Webhook.php | 30 ++++++++++++++++++++++++------ Model/Mollie.php | 2 +- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Controller/Checkout/Redirect.php b/Controller/Checkout/Redirect.php index acf7ba0568e..275a9194992 100644 --- a/Controller/Checkout/Redirect.php +++ b/Controller/Checkout/Redirect.php @@ -21,6 +21,7 @@ use Magento\Checkout\Model\Session; use Magento\Framework\View\Result\PageFactory; use Mollie\Payment\Model\Methods\ApplePay; +use Mollie\Payment\Model\Methods\Creditcard; use Mollie\Payment\Model\Methods\Directdebit; use Mollie\Payment\Model\Mollie; @@ -233,7 +234,8 @@ private function startTransaction(Mollie $methodInstance, OrderInterface $order) $redirectUrl = $this->_url->getUrl('checkout/onepage/success/'); } - if (!$redirectUrl && $methodInstance instanceof ApplePay) { + $emptyUrlAllowed = $methodInstance instanceof ApplePay || $methodInstance instanceof Creditcard; + if (!$redirectUrl && $emptyUrlAllowed) { $redirectUrl = $this->_url->getUrl('checkout/onepage/success/'); } diff --git a/Controller/Checkout/Webhook.php b/Controller/Checkout/Webhook.php index c693e274cf5..c637efced20 100644 --- a/Controller/Checkout/Webhook.php +++ b/Controller/Checkout/Webhook.php @@ -65,26 +65,44 @@ public function __construct( public function execute() { if ($this->getRequest()->getParam('testByMollie')) { - $result = $this->resultFactory->create(ResultFactory::TYPE_RAW); - $result->setHeader('content-type', 'text/plain'); - $result->setContents('OK', true); - return $result; + return $this->getOkResponse(); } if ($transactionId = $this->getRequest()->getParam('id')) { + $result = $this->resultFactory->create(ResultFactory::TYPE_JSON); try { if ($orderId = $this->mollieModel->getOrderIdByTransactionId($transactionId)) { $this->mollieModel->processTransaction($orderId, 'webhook'); + + return $this->getOkResponse(); } + + $result->setData([ + 'error' => true, + 'message' => __('There is no order found that belongs to "%1"', $transactionId)->render(), + ]); + $result->setHttpResponseCode(404); + + return $result; } catch (\Exception $e) { $this->mollieHelper->addTolog('error', $e->getMessage()); - $result = $this->resultFactory->create(ResultFactory::TYPE_JSON); - $result->setData('error', true); + $result->setData(['error' => true]); $result->setHttpResponseCode(503); return $result; } } } + + /** + * @return \Magento\Framework\Controller\ResultInterface|\Magento\Framework\View\Result\Layout + */ + private function getOkResponse() + { + $result = $this->resultFactory->create(ResultFactory::TYPE_RAW); + $result->setHeader('content-type', 'text/plain'); + $result->setContents('OK', true); + return $result; + } } diff --git a/Model/Mollie.php b/Model/Mollie.php index 63b31be1df1..d8af2b6ac13 100644 --- a/Model/Mollie.php +++ b/Model/Mollie.php @@ -322,7 +322,7 @@ public function loadMollieApi($apiKey) * @param $storeId * @return MollieApiClient|null */ - public function getMollieApi($storeId) + public function getMollieApi($storeId = null) { $apiKey = $this->mollieHelper->getApiKey($storeId); From ff8c5c3917b5f750da02bbc0cf2d1748863431f8 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Mon, 16 Nov 2020 14:50:48 +0100 Subject: [PATCH 08/13] Bugfix: Check if the record already exists to prevent unique constraint errors --- .../SavePendingOrder.php | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/Observer/MollieStartTransaction/SavePendingOrder.php b/Observer/MollieStartTransaction/SavePendingOrder.php index 511571f7748..5818197aa26 100644 --- a/Observer/MollieStartTransaction/SavePendingOrder.php +++ b/Observer/MollieStartTransaction/SavePendingOrder.php @@ -13,9 +13,15 @@ use Mollie\Payment\Api\Data\PendingPaymentReminderInterfaceFactory; use Mollie\Payment\Api\PendingPaymentReminderRepositoryInterface; use Mollie\Payment\Config; +use Mollie\Payment\Helper\General; class SavePendingOrder implements ObserverInterface { + /** + * @var General + */ + private $mollieHelper; + /** * @var Config */ @@ -32,13 +38,15 @@ class SavePendingOrder implements ObserverInterface private $repository; public function __construct( + General $mollieHelper, Config $config, PendingPaymentReminderInterfaceFactory $reminderFactory, PendingPaymentReminderRepositoryInterface $repository ) { + $this->mollieHelper = $mollieHelper; + $this->config = $config; $this->reminderFactory = $reminderFactory; $this->repository = $repository; - $this->config = $config; } public function execute(Observer $observer) @@ -50,10 +58,24 @@ public function execute(Observer $observer) return; } - /** @var PendingPaymentReminderInterface $reminder */ - $reminder = $this->reminderFactory->create(); - $reminder->setOrderId($order->getEntityId()); + try { + // If this succeeds there already exists a reminder. + $this->repository->getByOrderId($order->getEntityId()); + return; + } catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + // Ignore. + } - $this->repository->save($reminder); + try { + /** @var PendingPaymentReminderInterface $reminder */ + $reminder = $this->reminderFactory->create(); + $reminder->setOrderId($order->getEntityId()); + + $this->repository->save($reminder); + } catch (\Exception $exception) { + $message = 'Got an exception while trying to save a payment reminder: ' . $exception->getMessage(); + $message .= ' - Store ID: ' . $order->getStoreId(); + $this->mollieHelper->addTolog('error', $message); + } } } \ No newline at end of file From a130d70b07bc17c9d81ffa686c4e394cdb35f3fa Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Fri, 20 Nov 2020 11:24:53 +0100 Subject: [PATCH 09/13] Few fixes: - Remove transaction so the move of the payment reminder from pending to sent is not tied to sending the email. - Added extra logging. - Remove pending payment reminders when an order is placed to make sure that there are no emails sent when the order is paid by a non-Mollie payment. - Move from a loop with 10 items to a single run with 500 items. - Delete the pending reminder if it is already marked as sent. --- Cron/SendPendingPaymentReminders.php | 28 +++++----- .../RemovePendingPaymentReminders.php | 53 +++++++++++++++++++ Service/Order/PaymentReminder.php | 37 ++++++------- Service/Order/SecondChanceEmail.php | 7 ++- etc/events.xml | 3 ++ 5 files changed, 94 insertions(+), 34 deletions(-) create mode 100644 Observer/SalesOrderPlaceBefore/RemovePendingPaymentReminders.php diff --git a/Cron/SendPendingPaymentReminders.php b/Cron/SendPendingPaymentReminders.php index e307d25d4ca..38f31b6541c 100644 --- a/Cron/SendPendingPaymentReminders.php +++ b/Cron/SendPendingPaymentReminders.php @@ -70,23 +70,21 @@ public function execute() return; } - do { - /** @var SortOrder $sortOrder */ - $sortOrder = $this->sortOrderFactory->create(); - $sortOrder->setField('entity_id'); - $sortOrder->setDirection(SortOrder::SORT_ASC); + /** @var SortOrder $sortOrder */ + $sortOrder = $this->sortOrderFactory->create(); + $sortOrder->setField('entity_id'); + $sortOrder->setDirection(SortOrder::SORT_ASC); - $delay = $this->config->secondChanceEmailDelay(); - $date = (new \DateTimeImmutable($this->dateTime->gmtDate()))->sub(new \DateInterval('PT' . $delay . 'H')); - $this->builder->addFilter(Order::CREATED_AT, $date, 'lt'); - $this->builder->addSortOrder($sortOrder); - $this->builder->setPageSize(10); + $delay = $this->config->secondChanceEmailDelay(); + $date = (new \DateTimeImmutable($this->dateTime->gmtDate()))->sub(new \DateInterval('PT' . $delay . 'H')); + $this->builder->addFilter(Order::CREATED_AT, $date, 'lt'); + $this->builder->addSortOrder($sortOrder); + $this->builder->setPageSize(200); - $result = $this->paymentReminderRepository->getList($this->builder->create()); + $result = $this->paymentReminderRepository->getList($this->builder->create()); - foreach ($result->getItems() as $item) { - $this->paymentReminder->send($item); - } - } while ($result->getTotalCount()); + foreach ($result->getItems() as $item) { + $this->paymentReminder->send($item); + } } } \ No newline at end of file diff --git a/Observer/SalesOrderPlaceBefore/RemovePendingPaymentReminders.php b/Observer/SalesOrderPlaceBefore/RemovePendingPaymentReminders.php new file mode 100644 index 00000000000..d3602939661 --- /dev/null +++ b/Observer/SalesOrderPlaceBefore/RemovePendingPaymentReminders.php @@ -0,0 +1,53 @@ +config = $config; + $this->deletePaymentReminder = $deletePaymentReminder; + } + + /** + * Remove any pending payment reminders. This is to prevent that payment reminders get send if the order was paid + * by a payment method that is not from Mollie. + * + * @param Observer $observer + */ + public function execute(Observer $observer) + { + /** @var OrderInterface $order */ + $order = $observer->getData('order'); + + if (!$this->config->automaticallySendSecondChanceEmails($order->getStoreId())) { + return; + } + + $this->deletePaymentReminder->byEmail($order->getCustomerEmail()); + } +} \ No newline at end of file diff --git a/Service/Order/PaymentReminder.php b/Service/Order/PaymentReminder.php index fcf316b7716..d1b045cbc06 100644 --- a/Service/Order/PaymentReminder.php +++ b/Service/Order/PaymentReminder.php @@ -6,7 +6,6 @@ namespace Mollie\Payment\Service\Order; -use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; @@ -15,13 +14,14 @@ use Mollie\Payment\Api\Data\SentPaymentReminderInterfaceFactory; use Mollie\Payment\Api\PendingPaymentReminderRepositoryInterface; use Mollie\Payment\Api\SentPaymentReminderRepositoryInterface; +use Mollie\Payment\Logger\MollieLogger; class PaymentReminder { /** - * @var ResourceConnection + * @var MollieLogger */ - private $resourceConnection; + private $logger; /** * @var OrderRepositoryInterface @@ -54,7 +54,7 @@ class PaymentReminder private $deletePaymentReminder; public function __construct( - ResourceConnection $resourceConnection, + MollieLogger $logger, OrderRepositoryInterface $orderRepository, SentPaymentReminderInterfaceFactory $sentPaymentReminderFactory, SentPaymentReminderRepositoryInterface $sentPaymentReminderRepository, @@ -62,39 +62,40 @@ public function __construct( SecondChanceEmail $secondChanceEmail, DeletePaymentReminder $deletePaymentReminder ) { + $this->logger = $logger; $this->orderRepository = $orderRepository; $this->sentPaymentReminderFactory = $sentPaymentReminderFactory; $this->sentPaymentReminderRepository = $sentPaymentReminderRepository; $this->pendingPaymentReminderRepository = $pendingPaymentReminderRepository; $this->secondChanceEmail = $secondChanceEmail; - $this->resourceConnection = $resourceConnection; $this->deletePaymentReminder = $deletePaymentReminder; } public function send(PendingPaymentReminderInterface $pendingPaymentReminder): OrderInterface { - $connection = $this->resourceConnection->getConnection(); - $connection->beginTransaction(); + $order = $this->orderRepository->get($pendingPaymentReminder->getOrderId()); + $this->logger->addInfoLog( + 'info', + sprintf('Preparing to send the payment reminder for order #%s', $order->getIncrementId()) + ); - try { - $order = $this->orderRepository->get($pendingPaymentReminder->getOrderId()); - $this->moveReminderFromPendingToSent($order, $pendingPaymentReminder); - - $this->secondChanceEmail->send($order); + $this->moveReminderFromPendingToSent($order, $pendingPaymentReminder); - $connection->commit(); + $this->logger->addInfoLog( + 'info', + sprintf('Payment reminder record moved to sent table for order #%s', $order->getIncrementId()) + ); - return $order; - } catch (\Exception $exception) { - $connection->rollBack(); + $this->secondChanceEmail->send($order); - throw $exception; - } + return $order; } private function moveReminderFromPendingToSent(OrderInterface $order, PendingPaymentReminderInterface $pendingPaymentReminder): void { if ($this->isAlreadySend($order)) { + // Already sent, so delete the pending payment reminder. + $this->pendingPaymentReminderRepository->delete($pendingPaymentReminder); return; } diff --git a/Service/Order/SecondChanceEmail.php b/Service/Order/SecondChanceEmail.php index 975dfc20716..977b51363fa 100644 --- a/Service/Order/SecondChanceEmail.php +++ b/Service/Order/SecondChanceEmail.php @@ -102,10 +102,15 @@ public function send(OrderInterface $order) $builder->addTo($order->getCustomerEmail(), $customerName); $builder->setTemplateVars($this->getTemplateVars($order)); - $this->logger->addInfoLog('info', 'Sending second chance email for order #' . $order->getIncrementId()); + $this->logger->addInfoLog( + 'info', + sprintf('Sending second chance email for order #%s', $order->getIncrementId()) + ); $transport = $builder->getTransport(); $transport->sendMessage(); + + $this->logger->addInfoLog('info', sprintf('Second chance email for order #%s sent', $order->getIncrementId())); } private function getTemplateVars(OrderInterface $order) diff --git a/etc/events.xml b/etc/events.xml index 37865f0706f..845e94dd120 100644 --- a/etc/events.xml +++ b/etc/events.xml @@ -33,4 +33,7 @@ + + +
From bf4c949c3fee2043484f03bad6e0f984931c14d7 Mon Sep 17 00:00:00 2001 From: Frank Tiggelman Date: Fri, 20 Nov 2020 12:11:22 +0100 Subject: [PATCH 10/13] Removed unused line from CSV --- i18n/de_DE.csv | 1 - i18n/en_US.csv | 1 - i18n/es_ES.csv | 1 - i18n/fr_FR.csv | 1 - i18n/nl_NL.csv | 1 - 5 files changed, 5 deletions(-) diff --git a/i18n/de_DE.csv b/i18n/de_DE.csv index 1c97228dcab..458c3554d37 100644 --- a/i18n/de_DE.csv +++ b/i18n/de_DE.csv @@ -44,7 +44,6 @@ "Select Giftcard","Giftcard Auswählen" "Self Test","Selbsttest" "Send Invoice Email","Rechnungs-E-Mail Senden" -"Set the notification for to Notify the customer with the Invoice","Legen Sie die Benachrichtigung fest, um den Kunden mit der Rechnung zu benachrichtigen" "Set the order status before the customer is redirected to Payment Gateway","Legen Sie den Bestell-Status fest, bevor der Kunde zum Zahlungs-Gateway umgeleitet wird" "Set the order status for Completed Payments","Legen Sie den Bestell-Status für Abgeschlossene Zahlungen fest" "Settings","Einstellungen" diff --git a/i18n/en_US.csv b/i18n/en_US.csv index 2088820e7a9..69594cb381d 100644 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -44,7 +44,6 @@ "Select Giftcard","Select Giftcard" "Self Test","Self Test" "Send Invoice Email","Send Invoice Email" -"Set the notification for to Notify the customer with the Invoice","Set the notification for to Notify the customer with the Invoice" "Set the order status before the customer is redirected to Payment Gateway","Set the order status before the customer is redirected to Payment Gateway" "Set the order status for Completed Payments","Set the order status for Completed Payments" "Settings","Settings" diff --git a/i18n/es_ES.csv b/i18n/es_ES.csv index 360731334be..3680f60e586 100644 --- a/i18n/es_ES.csv +++ b/i18n/es_ES.csv @@ -44,7 +44,6 @@ "Select Giftcard","Seleccione Tarjeta regalo" "Self Test","Autodiagnóstico" "Send Invoice Email","Enviar factura por correo electrónico" -"Set the notification for to Notify the customer with the Invoice","Configurar la notificación para Notificar al cliente con la Factura" "Set the order status before the customer is redirected to Payment Gateway","Establecer el estado del pedido antes de que el cliente sea redirigido a la pasarela de pago" "Set the order status for Completed Payments","Establecer el estado del pedido para Pagos completados" "Settings","Ajustes" diff --git a/i18n/fr_FR.csv b/i18n/fr_FR.csv index b0ca24610fa..60ce790f413 100644 --- a/i18n/fr_FR.csv +++ b/i18n/fr_FR.csv @@ -44,7 +44,6 @@ "Select Giftcard","Choisir une carte-cadeau" "Self Test","Autodiagnostic" "Send Invoice Email","Envoyer une facture par courriel" -"Set the notification for to Notify the customer with the Invoice","Définissez la notification pour Notifier le client avec la facture" "Set the order status before the customer is redirected to Payment Gateway","Définir l'état de la commande avant que le client ne soit redirigé vers la passerelle de paiement" "Set the order status for Completed Payments","Définir le statut de la commande pour les paiements complétés" "Settings","Options" diff --git a/i18n/nl_NL.csv b/i18n/nl_NL.csv index da63b6ffc32..2ce86bb274e 100644 --- a/i18n/nl_NL.csv +++ b/i18n/nl_NL.csv @@ -45,7 +45,6 @@ "Select Giftcard","Selecteer cadeaukaart" "Self Test","Zelftest" "Send Invoice Email","Stuur factuur e-mail" -"Set the notification for to Notify the customer with the Invoice","Stel de notificatie in om klanten te informeren met de factuur" "Set the order status before the customer is redirected to Payment Gateway","Stel de orderstatus in voordat de klant wordt doorgestuurd naar de betaalomgeving" "Set the order status for Completed Payments","Stel de orderstatus in voor afgeronde betalingen" "Settings","Instellingen" From c36c73911926e202081f2380085d0192a3c6596e Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Fri, 20 Nov 2020 12:51:20 +0100 Subject: [PATCH 11/13] Fix: Allow to place a second chance order when the original order is canceled --- Controller/Checkout/SecondChance.php | 34 ++++++++++++++++++++++++--- Service/Order/Reorder.php | 15 +++++++++++- etc/di.xml | 6 +++++ view/frontend/templates/loading.phtml | 1 + 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/Controller/Checkout/SecondChance.php b/Controller/Checkout/SecondChance.php index e798e3e75f5..1868411ed90 100644 --- a/Controller/Checkout/SecondChance.php +++ b/Controller/Checkout/SecondChance.php @@ -10,11 +10,14 @@ use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; +use Mollie\Payment\Api\Data\PaymentTokenInterface; use Mollie\Payment\Api\PaymentTokenRepositoryInterface; use Mollie\Payment\Model\Methods\Paymentlink; use Mollie\Payment\Service\Order\Reorder; +use Mollie\Payment\Service\PaymentToken\Generate; class SecondChance extends Action { @@ -38,18 +41,25 @@ class SecondChance extends Action */ private $paymentlink; + /** + * @var Generate + */ + private $generatePaymentToken; + public function __construct( Context $context, OrderRepositoryInterface $orderRepository, PaymentTokenRepositoryInterface $paymentTokenRepository, Reorder $reorder, - Paymentlink $paymentlink + Paymentlink $paymentlink, + Generate $generatePaymentToken ) { parent::__construct($context); $this->orderRepository = $orderRepository; $this->paymentTokenRepository = $paymentTokenRepository; $this->reorder = $reorder; $this->paymentlink = $paymentlink; + $this->generatePaymentToken = $generatePaymentToken; } public function execute() @@ -88,7 +98,25 @@ private function reorder() } $order = $this->reorder->create($order); - $information = $order->getPayment()->getAdditionalInformation(); - return $this->_redirect($information['checkout_url']); + + $token = $this->getToken($order); + $url = $this->_url->getUrl('mollie/checkout/redirect', ['paymentToken' => $token->getToken()]); + + return $this->_redirect($url); + } + + /** + * @param OrderInterface $order + * @throws \Magento\Framework\Exception\LocalizedException + * @return PaymentTokenInterface|null + */ + private function getToken(OrderInterface $order): PaymentTokenInterface + { + $token = $this->paymentTokenRepository->getByOrder($order); + if ($token) { + return $token; + } + + return $this->generatePaymentToken->forOrder($order); } } diff --git a/Service/Order/Reorder.php b/Service/Order/Reorder.php index 45dbebca505..6e0dd0a449b 100644 --- a/Service/Order/Reorder.php +++ b/Service/Order/Reorder.php @@ -6,6 +6,7 @@ namespace Mollie\Payment\Service\Order; +use Magento\Checkout\Model\Session; use Magento\Framework\DB\Transaction; use Magento\Framework\DB\TransactionFactory; use Magento\Quote\Api\Data\CartInterface; @@ -60,6 +61,11 @@ class Reorder */ private $cart; + /** + * @var Session + */ + private $checkoutSession; + public function __construct( Config $config, Create $orderCreate, @@ -67,7 +73,8 @@ public function __construct( InvoiceSender $invoiceSender, OrderCommentHistory $orderCommentHistory, TransactionFactory $transactionFactory, - CartInterface $cart + CartInterface $cart, + Session $checkoutSession ) { $this->config = $config; $this->orderCreate = $orderCreate; @@ -76,6 +83,7 @@ public function __construct( $this->orderCommentHistory = $orderCommentHistory; $this->transactionFactory = $transactionFactory; $this->cart = $cart; + $this->checkoutSession = $checkoutSession; } public function create(OrderInterface $originalOrder) @@ -89,6 +97,11 @@ public function create(OrderInterface $originalOrder) $this->addCommentHistoryOriginalOrder($originalOrder, $order->getIncrementId()); + $this->checkoutSession->setLastQuoteId($order->getQuoteId()) + ->setLastSuccessQuoteId($order->getQuoteId()) + ->setLastOrderId($order->getId()) + ->setLastRealOrderId($order->getIncrementId()); + return $order; } diff --git a/etc/di.xml b/etc/di.xml index c3a3dfc8460..98589bae741 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -154,4 +154,10 @@ + + + + Magento\Checkout\Model\Session\Proxy + + diff --git a/view/frontend/templates/loading.phtml b/view/frontend/templates/loading.phtml index 519c3200fb1..ab15a9889a6 100644 --- a/view/frontend/templates/loading.phtml +++ b/view/frontend/templates/loading.phtml @@ -3,6 +3,7 @@ * Copyright © 2018 Magmodules.eu. All rights reserved. * See COPYING.txt for license details. */ +/** @var \Mollie\Payment\Block\Loading $block */ ?> getRedirectUrl(); ?>
From b6b63c554e5b10caee9dcb8a31ef5d9abffdbaea Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Fri, 20 Nov 2020 13:21:13 +0100 Subject: [PATCH 12/13] Test fix --- Test/Integration/Controller/Checkout/SecondChanceTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Integration/Controller/Checkout/SecondChanceTest.php b/Test/Integration/Controller/Checkout/SecondChanceTest.php index cb67fb709ca..1ef90e77a39 100644 --- a/Test/Integration/Controller/Checkout/SecondChanceTest.php +++ b/Test/Integration/Controller/Checkout/SecondChanceTest.php @@ -87,7 +87,7 @@ public function testRecreatesTheOrder() $this->getRequest()->setParam('payment_token', $token->getToken()); $this->dispatch('/mollie/checkout/secondChance/'); - $this->assertRedirect($this->equalTo('http://example.com')); + $this->assertRedirect($this->stringContains('mollie/checkout/redirect/paymentToken')); } /** From 89a31aa36cd4a937a971b0393b2b1fbe4477410e Mon Sep 17 00:00:00 2001 From: Marvin-Magmodules Date: Fri, 20 Nov 2020 14:02:45 +0100 Subject: [PATCH 13/13] Version bump --- composer.json | 2 +- etc/config.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index dd3812c46dd..15dd908d213 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "mollie/magento2", "description": "Mollie Payment Module for Magento 2", - "version": "1.18.0", + "version": "1.18.1", "keywords": [ "mollie", "payment", diff --git a/etc/config.xml b/etc/config.xml index 80352719b9b..f9fa6038c87 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -3,7 +3,7 @@ - v1.18.0 + v1.18.1 0 0 test