From d1271ef5ace0cb7ebbd47b9a7e376e3bb8cf87ae Mon Sep 17 00:00:00 2001 From: Peter Jaap Blaakmeer Date: Wed, 13 Nov 2019 14:53:33 +0100 Subject: [PATCH 01/10] Typos, vertalingen + Engelse ziekte --- i18n/nl_NL.csv | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/i18n/nl_NL.csv b/i18n/nl_NL.csv index 32f684a86f5..253c5dd9bff 100644 --- a/i18n/nl_NL.csv +++ b/i18n/nl_NL.csv @@ -1,16 +1,16 @@ "%1: maximum is set higher than set in Mollie dashboard: %2, please correct.","%1: maximaal is hoger ingesteld dan ingesteld: %2, pas dit aan." -"%1: method not enabled in Mollie Dashboard","%1: method not enabled in Mollie Dashboard" -"API Details","API Gegevens" -"Api key not found","API Sleutel niet gevonden" +"%1: method not enabled in Mollie Dashboard","%1: betaalmethode niet ingeschakeld in Mollie Dashboard" +"API Details","API gegevens" +"Api key not found","API sleutel niet gevonden" "Back to Webshop","Terug naar webwinkel" "Bancontact","Bancontact" "Banktransfer","Banktransfer" "Belfius","Belfius" "Branding","Branding" -"Check the Mollie extension technical requirements by running the self test. In case of a warning or error please contact your Developer or Hosting Company.","Controleer de technische eisen van de Mollie extensie door de zelf test uit te voeren. In het geval van een error of waarschuwing, neem contact op met uw Developer of Hosting Partij." -"Compatibility","Compatibility" +"Check the Mollie extension technical requirements by running the self test. In case of a warning or error please contact your Developer or Hosting Company.","Controleer de technische eisen van de Mollie extensie door de zelf test uit te voeren. In het geval van een error of waarschuwing, neem contact op met uw developer of hostingpartij." +"Compatibility","Compatibiliteit" "Configure the general Mollie Payment Payment status and Payment Icons.","Configureer de algemene Mollie instellingen, statussen en afbeeldingen." -"Credit Card","Credit Card" +"Credit Card","Creditcard" "Customer redirected to Mollie, url: %1","Klant doorgestuurd naar Mollie, url: %1" "Debug requests","Debug verzoeken" "Debug","Debug" @@ -22,10 +22,10 @@ "Invalid return from Mollie.","Ongeldig antwoord van Mollie." "Invalid return, missing order id.","Ongeldig antwoord, ordernummer ontbreekt." "KBC","KBC" -"Live API Key","Live API Sleutel" +"Live API Key","Live API sleutel" "Loading Payment Method...","Betalingsmethode wordt geladen..." -"Maximum Order Total","Maximale Orderwaarde" -"Minimum Order Total","Minimale Orderwaarde" +"Maximum Order Total","Maximale orderwaarde" +"Minimum Order Total","Minimale orderwaarde" "Modus","Modus" "Mollie","Mollie" "New order email sent","Nieuwe order e-mail verstuurd" @@ -40,28 +40,28 @@ "Paysafecard","Paysafecard" "Place Order","Plaats order" "Proceed Payment","Vervolg betaling" -"Select Bank","Selecteer Bank" -"Select Giftcard","Selecteer Cadeaukaart" +"Select Bank","Selecteer bank" +"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" -"Show Icons","Toon Iconen" -"Show Payment Icons on Checkout","Toon Betalingsmethode iconen tijdens afrekenen" +"Show Icons","Toon iconen" +"Show Payment Icons on Checkout","Toon betalingsmethode-iconen tijdens afrekenen" "Sofort","Sofort" "Something went wrong.","Er is iets fout gegaan." "Sort Order","Volgorde" "Status Pending","Status in afwachting" "Status Processing","Status verwerken" -"Test API Key","Test API Sleutel" +"Test API Key","Test API sleutel" "The order was canceled","De order is geannuleerd" "There was an error checking the transaction status.","Er heeft zich een error voorgedaan tijdens het controleren van de transactie status." "The number of days after which the payment should expire. Please note: Minimum is 1 and the maximum is 100.","Het aantal dagen waneer de betaling verloopt. Opmerking: het minimaal is 1 dag en maximaal 100 dagen." "Title","Titel" -"Transaction ID not found","Transactie ID niet geovnden" -"Use Loading Screen","Gebruik Laadscherm" +"Transaction ID not found","Transactie ID niet gevonden" +"Use Loading Screen","Gebruik laadscherm" "Use loading screen before redirect. This will enable mobile users to use the back button.","Gebruik het laadscherm voordat de bezoeker wordt doorgelinkt naar Mollie. Dit zorgt ervoor dat (mobiele) gebruikers de terugbutton kunnen gebruiken" "Version","Versie" "When activated the debug file will be located in: var/log/mollie.log","Indien geactiveerd bevindt de logfile zich in: var/log/mollie.log" @@ -76,14 +76,14 @@ "Force use of base currency for the payment request. Is set to no the selected currency of the storeview will be used for request.","Pas het gebruik van basisvaluta voor het betalingsverzoek toe. Indien ingesteld op nee wordt de geselecteerde valuta van de storeview gebruikt voor de aanvraag. " "Debugging","Debugging" "API Details","API-gegevens" -"Api Test","Api Test" -"Language Payment Page","Taal Betaalpagina" +"Api Test","Api test" +"Language Payment Page","Taal betaalpagina" "Let Mollie automatically detect the language or force the language from the store view.","Laat Mollie de taal automatisch detecteren of forceer een taal voor deze store-view." "Payment of type %1 has been rejected. Decision is based on order and outcome of risk assessment.","Betaling van het type %1 is geweigerd. Deze beslissing is gebaseerd op de bestelling en de uitkomst van de risicobeoordeling." "Warning: we recommend to use a unique payment status for pending Banktransfer payments","Waarschuwing: Wij adviseren om een unieke betaalstatus the hanteren voor bankoverboekingen in de wacht" "Fetching...","Ophalen..." -"Error While Fetching","Error Tijdens Ophalen" -"Fetch Status","Status Ophalen" +"Error While Fetching","Error tijdens ophalen" +"Fetch Status","Status ophalen" "The latest status from Mollie has been retrieved","De laatste status is bij Mollie opgehaald" "The payment-status will updated automatically by default, but in case of any interruption you can use this function to fetch the payment status manually.","De betaal status wordt standaard bijgewerkt. Mocht dit door omstandigheden niet het geval zijn dan kun u deze hier handmatig laten ophalen." "Please make sure the payment surcharge does not exceed %1.","Zorg ervoor dat de betaal fee niet meer bedraagt dan %1." From c45490d961eab771faf50cc78c8d004a6c627975 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Wed, 20 Nov 2019 09:25:31 +0100 Subject: [PATCH 02/10] Fix: When the Terms and Conditions are required, it was not possible to set the payment fee --- .../js/view/checkout/save-payment-method.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/checkout/save-payment-method.js b/view/frontend/web/js/view/checkout/save-payment-method.js index 2a495f3a58f..ef407c5c5a0 100644 --- a/view/frontend/web/js/view/checkout/save-payment-method.js +++ b/view/frontend/web/js/view/checkout/save-payment-method.js @@ -1,4 +1,5 @@ define([ + 'ko', 'uiComponent', 'mage/storage', 'Magento_Checkout/js/model/quote', @@ -6,6 +7,7 @@ define([ 'Magento_Checkout/js/model/totals', 'Magento_Checkout/js/action/get-totals' ], function ( + ko, Component, storage, quote, @@ -54,11 +56,26 @@ define([ var url = resourceUrlManager.getUrl(urls, params); payload.paymentMethod = { - method: method + method: method, + extension_attributes: {} }; payload.billingAddress = quote.billingAddress(); + /** + * Problem: We need to set the payment method, therefor we created this function. The api call requires + * that the agreements are all agreed by before doing any action. That's why we list all agreement ids + * and sent them with the request. In a later point in the checkout this will also be checked. + */ + var config = window.checkoutConfig.checkoutAgreements; + if (config.isEnabled) { + var ids = config.agreements.map( function (agreement) { + return agreement.agreementId; + }); + + payload.paymentMethod.extension_attributes.agreement_ids = ids; + } + totals.isLoading(true); storage.post( url, From f1270c4e9de54665449ac8baf22299cc775a973b Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Wed, 20 Nov 2019 15:08:04 +0100 Subject: [PATCH 03/10] Feature: Allow to mark Payment Link orders manually as paid --- Controller/Adminhtml/Action/MarkAsPaid.php | 130 ++++++++++++++++++ Observer/OrderCancelAfter.php | 7 + Plugin/Sales/Block/Adminhtml/Order/View.php | 70 ++++++++++ .../Sales/Block/Adminhtml/Order/ViewTest.php | 85 ++++++++++++ etc/adminhtml/di.xml | 6 + 5 files changed, 298 insertions(+) create mode 100644 Controller/Adminhtml/Action/MarkAsPaid.php create mode 100644 Plugin/Sales/Block/Adminhtml/Order/View.php create mode 100644 Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php create mode 100644 etc/adminhtml/di.xml diff --git a/Controller/Adminhtml/Action/MarkAsPaid.php b/Controller/Adminhtml/Action/MarkAsPaid.php new file mode 100644 index 00000000000..aafbbee2e72 --- /dev/null +++ b/Controller/Adminhtml/Action/MarkAsPaid.php @@ -0,0 +1,130 @@ +orderRepository = $orderRepository; + $this->orderCreate = $orderCreate; + $this->quoteSession = $quoteSession; + $this->transactionFactory = $transactionFactory; + } + + /** + * This controller recreates the selected order with the checkmo payment method and marks it as completed. The + * original order is then canceled. + * + * {@inheritDoc} + */ + public function execute() + { + $orderId = $this->getRequest()->getParam('order_id'); + + $originalOrder = $this->orderRepository->get($orderId); + $originalOrder->setReordered(true); + + $resultRedirect = $this->resultRedirectFactory->create(); + try { + $order = $this->recreateOrder($originalOrder); + $this->cancelOriginalOrder($originalOrder, $order->getIncrementId()); + $this->save($order, $originalOrder); + + $this->messageManager->addSuccessMessage( + __( + 'We cancelled order %1, created this order and marked it as complete.', + $originalOrder->getIncrementId() + ) + ); + + return $resultRedirect->setPath('sales/order/view', ['order_id' => $order->getEntityId()]); + } catch (\Exception $exception) { + $this->messageManager->addExceptionMessage($exception); + + return $resultRedirect->setPath('sales/order/view', ['order_id' => $originalOrder->getEntityId()]); + } + } + + /** + * @param OrderInterface $originalOrder + * @return OrderInterface + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function recreateOrder(OrderInterface $originalOrder) + { + $this->quoteSession->setOrderId($originalOrder->getEntityId()); + $this->quoteSession->setUseOldShippingMethod(true); + $this->orderCreate->initFromOrder($originalOrder); + $this->orderCreate->setPaymentMethod('checkmo'); + + $order = $this->orderCreate->createOrder(); + $order->setState(Order::STATE_COMPLETE); + $order->setStatus(Order::STATE_COMPLETE); + + return $order; + } + + /** + * @param OrderInterface $originalOrder + * @param string $newIncrementId + */ + private function cancelOriginalOrder(OrderInterface $originalOrder, $newIncrementId) + { + $comment = __('We created a new order with increment ID: %1', $newIncrementId); + $originalOrder->addCommentToStatusHistory($comment); + $originalOrder->cancel(); + } + + /** + * @param OrderInterface $order + * @param OrderInterface $originalOrder + * @throws \Exception + */ + private function save(OrderInterface $order, OrderInterface $originalOrder) + { + $transaction = $this->transactionFactory->create(); + $transaction->addObject($order); + $transaction->addObject($originalOrder); + $transaction->save(); + } +} diff --git a/Observer/OrderCancelAfter.php b/Observer/OrderCancelAfter.php index 157bffddbbd..dbb11b7559c 100644 --- a/Observer/OrderCancelAfter.php +++ b/Observer/OrderCancelAfter.php @@ -52,6 +52,13 @@ public function execute(Observer $observer) /** @var \Magento\Sales\Model\Order $order */ $order = $observer->getEvent()->getorder(); + /** + * When manually marking an order as paid we don't want to communicate to Mollie as it will throw an exception. + */ + if ($order->getReordered()) { + return; + } + if ($this->mollieHelper->isPaidUsingMollieOrdersApi($order)) { $this->mollieModel->cancelOrder($order); } diff --git a/Plugin/Sales/Block/Adminhtml/Order/View.php b/Plugin/Sales/Block/Adminhtml/Order/View.php new file mode 100644 index 00000000000..ed83f8c7f7c --- /dev/null +++ b/Plugin/Sales/Block/Adminhtml/Order/View.php @@ -0,0 +1,70 @@ +url = $url; + $this->orderRepository = $orderRepository; + $this->paymentHelper = $paymentHelper; + } + + public function beforeSetLayout(Subject $subject) + { + $order = $subject->getOrder(); + $instance = $this->paymentHelper->getMethodInstance(Checkmo::PAYMENT_METHOD_CHECKMO_CODE); + + $isAvailable = !$instance->isAvailable(); + if (!$order->canCancel() || + $order->getPayment()->getMethod() != 'mollie_methods_paymentlink' || + !$instance || + $isAvailable + ) { + return; + } + + $message = __('Are you sure you want to do this? ' . + 'This will cancel the current order and create a new one that is marked as payed.'); + $url = $this->url->getUrl('mollie/action/markAsPaid/'); + + $subject->addButton( + 'mollie_payment_mark_as_payed', + [ + 'label' => __('Mark as paid'), + 'onclick' => 'confirmSetLocation(\'' . $message . '\', \'' . $url . '\', {data: {order_id: ' . $subject->getOrderId() . '}})', + ], + 0, + -10 + ); + } +} diff --git a/Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php b/Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php new file mode 100644 index 00000000000..f02a15faa9e --- /dev/null +++ b/Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php @@ -0,0 +1,85 @@ +createMock(Order::class); + $orderMock->method('canCancel')->willReturn(false); + + $subjectMock = $this->createMock(Subject::class); + $subjectMock->method('getOrder')->willReturn($orderMock); + + $subjectMock->expects($this->never())->method('addButton'); + + /** @var View $instance */ + $instance = $this->objectManager->create(View::class); + $instance->beforeSetLayout($subjectMock); + } + + /** + * @magentoDataFixture Magento/Sales/_files/order.php + */ + public function testDoesNotShowsTheButtonWhenNotPaymentLink() + { + $order = $this->loadOrderById('100000001'); + $order->getPayment()->setMethod('checkmo'); + + $subjectMock = $this->createMock(Subject::class); + $subjectMock->method('getOrder')->willReturn($order); + + $subjectMock->expects($this->never())->method('addButton'); + + /** @var View $instance */ + $instance = $this->objectManager->create(View::class); + $instance->beforeSetLayout($subjectMock); + } + + /** + * @magentoDataFixture Magento/Sales/_files/order.php + * @magentoConfigFixture current_store payment/checkmo/active 0 + */ + public function testDoesNotShowsTheButtonWhenCheckmoIsNotAvailable() + { + $order = $this->loadOrderById('100000001'); + $order->getPayment()->setMethod('mollie_methods_paymentlink'); + + $subjectMock = $this->createMock(Subject::class); + $subjectMock->method('getOrder')->willReturn($order); + + $subjectMock->expects($this->never())->method('addButton'); + + /** @var View $instance */ + $instance = $this->objectManager->create(View::class); + $instance->beforeSetLayout($subjectMock); + } + + /** + * @magentoDataFixture Magento/Sales/_files/order.php + * @magentoConfigFixture current_store payment/checkmo/active 1 + */ + public function testShowTheButtonWhenApplicable() + { + $order = $this->loadOrderById('100000001'); + $order->getPayment()->setMethod('mollie_methods_paymentlink'); + + $subjectMock = $this->createMock(Subject::class); + $subjectMock->method('getOrder')->willReturn($order); + + $subjectMock->expects($this->once())->method('addButton'); + + /** @var View $instance */ + $instance = $this->objectManager->create(View::class); + $instance->beforeSetLayout($subjectMock); + } +} diff --git a/etc/adminhtml/di.xml b/etc/adminhtml/di.xml new file mode 100644 index 00000000000..f638006dbb0 --- /dev/null +++ b/etc/adminhtml/di.xml @@ -0,0 +1,6 @@ + + + + + + From 838f02912929b39d29aa272abe1b83aa04895d01 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Thu, 21 Nov 2019 11:21:01 +0100 Subject: [PATCH 04/10] New method: Reorder, on/off method, create invoice and changed status to processing --- Config.php | 20 +++ Controller/Adminhtml/Action/MarkAsPaid.php | 45 ++++--- Model/Methods/Reorder.php | 116 ++++++++++++++++++ Plugin/Sales/Block/Adminhtml/Order/View.php | 12 ++ .../Sales/Block/Adminhtml/Order/ViewTest.php | 27 +++- etc/adminhtml/methods/paymentlink.xml | 25 ++-- etc/config.xml | 9 ++ 7 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 Model/Methods/Reorder.php diff --git a/Config.php b/Config.php index 843e3300fd3..38e096d4d1d 100644 --- a/Config.php +++ b/Config.php @@ -17,6 +17,7 @@ class Config const PAYMENT_KLARNAPAYLATER_PAYMENT_SURCHARGE_TAX_CLASS = 'payment/mollie_methods_klarnapaylater/payment_surcharge_tax_class'; const PAYMENT_KLARNASLICEIT_PAYMENT_SURCHARGE = 'payment/mollie_methods_klarnasliceit/payment_surcharge'; const PAYMENT_KLARNASLICEIT_PAYMENT_SURCHARGE_TAX_CLASS = 'payment/mollie_methods_klarnasliceit/payment_surcharge_tax_class'; + const PAYMENT_PAYMENTLINK_ALLOW_MARK_AS_PAID = 'payment/mollie_methods_paymentlink/allow_mark_as_paid'; /** * @var ScopeConfigInterface @@ -39,6 +40,16 @@ private function getPath($path, $storeId) return $this->config->getValue($path, ScopeInterface::SCOPE_STORE, $storeId); } + /** + * @param $path + * @param $storeId + * @return bool + */ + private function getFlag($path, $storeId) + { + return $this->config->isSetFlag($path, ScopeInterface::SCOPE_STORE, $storeId); + } + public function statusPendingBanktransfer($storeId = null) { return $this->config->getValue( @@ -92,4 +103,13 @@ public function klarnaSliceitPaymentSurchargeTaxClass($storeId = null) { return $this->getPath(static::PAYMENT_KLARNASLICEIT_PAYMENT_SURCHARGE_TAX_CLASS, $storeId); } + + /** + * @param null $storeId + * @return bool + */ + public function paymentlinkAllowMarkAsPaid($storeId = null) + { + return $this->getFlag(static::PAYMENT_PAYMENTLINK_ALLOW_MARK_AS_PAID, $storeId); + } } diff --git a/Controller/Adminhtml/Action/MarkAsPaid.php b/Controller/Adminhtml/Action/MarkAsPaid.php index aafbbee2e72..5a91e9b401b 100644 --- a/Controller/Adminhtml/Action/MarkAsPaid.php +++ b/Controller/Adminhtml/Action/MarkAsPaid.php @@ -8,11 +8,14 @@ use Magento\Backend\App\Action; use Magento\Backend\Model\Session\Quote; +use Magento\Framework\DB\Transaction; use Magento\Framework\DB\TransactionFactory; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\AdminOrder\Create; use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Invoice; +use Magento\Sales\Model\Service\InvoiceService; class MarkAsPaid extends Action { @@ -31,16 +34,27 @@ class MarkAsPaid extends Action */ private $quoteSession; + /** + * @var InvoiceService + */ + private $invoiceService; + /** * @var TransactionFactory */ private $transactionFactory; + /** + * @var Transaction + */ + private $transaction; + public function __construct( Action\Context $context, OrderRepositoryInterface $orderRepository, Create $orderCreate, Quote $quoteSession, + InvoiceService $invoiceService, TransactionFactory $transactionFactory ) { parent::__construct($context); @@ -48,6 +62,7 @@ public function __construct( $this->orderRepository = $orderRepository; $this->orderCreate = $orderCreate; $this->quoteSession = $quoteSession; + $this->invoiceService = $invoiceService; $this->transactionFactory = $transactionFactory; } @@ -66,9 +81,12 @@ public function execute() $resultRedirect = $this->resultRedirectFactory->create(); try { + $this->transaction = $this->transactionFactory->create(); + $order = $this->recreateOrder($originalOrder); + $this->createInvoiceFor($order); $this->cancelOriginalOrder($originalOrder, $order->getIncrementId()); - $this->save($order, $originalOrder); + $this->transaction->save(); $this->messageManager->addSuccessMessage( __( @@ -95,11 +113,14 @@ private function recreateOrder(OrderInterface $originalOrder) $this->quoteSession->setOrderId($originalOrder->getEntityId()); $this->quoteSession->setUseOldShippingMethod(true); $this->orderCreate->initFromOrder($originalOrder); - $this->orderCreate->setPaymentMethod('checkmo'); + $this->orderCreate->setPaymentMethod('mollie_methods_reorder'); $order = $this->orderCreate->createOrder(); - $order->setState(Order::STATE_COMPLETE); - $order->setStatus(Order::STATE_COMPLETE); + $order->setState(Order::STATE_PROCESSING); + $order->setStatus(Order::STATE_PROCESSING); + + $this->transaction->addObject($order); + $this->transaction->addObject($originalOrder); return $order; } @@ -115,16 +136,12 @@ private function cancelOriginalOrder(OrderInterface $originalOrder, $newIncremen $originalOrder->cancel(); } - /** - * @param OrderInterface $order - * @param OrderInterface $originalOrder - * @throws \Exception - */ - private function save(OrderInterface $order, OrderInterface $originalOrder) + private function createInvoiceFor(OrderInterface $order) { - $transaction = $this->transactionFactory->create(); - $transaction->addObject($order); - $transaction->addObject($originalOrder); - $transaction->save(); + $invoice = $this->invoiceService->prepareInvoice($order); + $invoice->setRequestedCaptureCase(Invoice::CAPTURE_OFFLINE); + $invoice->register(); + + $this->transaction->addObject($invoice); } } diff --git a/Model/Methods/Reorder.php b/Model/Methods/Reorder.php new file mode 100644 index 00000000000..088a56e3c60 --- /dev/null +++ b/Model/Methods/Reorder.php @@ -0,0 +1,116 @@ +request = $request; + + parent::__construct( + $context, + $registry, + $extensionFactory, + $customAttributeFactory, + $paymentData, + $scopeConfig, + $logger, + $resource, + $resourceCollection, + $data, + $directory + ); + } + + /** + * @param string $paymentAction + * @param object $stateObject + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Mollie\Api\Exceptions\ApiException + */ + public function initialize($paymentAction, $stateObject) + { + /** @var \Magento\Sales\Model\Order\Payment $payment */ + $payment = $this->getInfoInstance(); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $payment->getOrder(); + $order->setCanSendNewEmailFlag(false); + $order->save(); + } + + public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null) + { + return $this->request->getModuleName() == 'mollie' && $this->request->getActionName() == 'markAsPaid'; + } +} diff --git a/Plugin/Sales/Block/Adminhtml/Order/View.php b/Plugin/Sales/Block/Adminhtml/Order/View.php index ed83f8c7f7c..5eb64883ae9 100644 --- a/Plugin/Sales/Block/Adminhtml/Order/View.php +++ b/Plugin/Sales/Block/Adminhtml/Order/View.php @@ -11,9 +11,15 @@ use Magento\Payment\Helper\Data as PaymentHelper; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Block\Adminhtml\Order\View as Subject; +use Mollie\Payment\Config; class View { + /** + * @var Config + */ + private $config; + /** * @var UrlInterface */ @@ -30,10 +36,12 @@ class View private $paymentHelper; public function __construct( + Config $config, UrlInterface $url, OrderRepositoryInterface $orderRepository, PaymentHelper $paymentHelper ) { + $this->config = $config; $this->url = $url; $this->orderRepository = $orderRepository; $this->paymentHelper = $paymentHelper; @@ -42,6 +50,10 @@ public function __construct( public function beforeSetLayout(Subject $subject) { $order = $subject->getOrder(); + if (!$this->config->paymentlinkAllowMarkAsPaid($order->getStoreId())) { + return; + } + $instance = $this->paymentHelper->getMethodInstance(Checkmo::PAYMENT_METHOD_CHECKMO_CODE); $isAvailable = !$instance->isAvailable(); diff --git a/Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php b/Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php index f02a15faa9e..ddd97027e3d 100644 --- a/Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php +++ b/Test/Integration/Plugin/Sales/Block/Adminhtml/Order/ViewTest.php @@ -12,6 +12,26 @@ class ViewTest extends IntegrationTestCase { + /** + * @magentoConfigFixture current_store payment/mollie_methods_paymentlink/allow_mark_as_paid 0 + */ + public function testDoesNotShowsTheButtonWhenDisabled() + { + $orderMock = $this->createMock(Order::class); + + $subjectMock = $this->createMock(Subject::class); + $subjectMock->method('getOrder')->willReturn($orderMock); + + $subjectMock->expects($this->never())->method('addButton'); + + /** @var View $instance */ + $instance = $this->objectManager->create(View::class); + $instance->beforeSetLayout($subjectMock); + } + + /** + * @magentoConfigFixture current_store payment/mollie_methods_paymentlink/allow_mark_as_paid 1 + */ public function testDoesNotShowsTheButtonWhenWeCantCancel() { $orderMock = $this->createMock(Order::class); @@ -28,6 +48,7 @@ public function testDoesNotShowsTheButtonWhenWeCantCancel() } /** + * @magentoConfigFixture current_store payment/mollie_methods_paymentlink/allow_mark_as_paid 1 * @magentoDataFixture Magento/Sales/_files/order.php */ public function testDoesNotShowsTheButtonWhenNotPaymentLink() @@ -47,9 +68,9 @@ public function testDoesNotShowsTheButtonWhenNotPaymentLink() /** * @magentoDataFixture Magento/Sales/_files/order.php - * @magentoConfigFixture current_store payment/checkmo/active 0 + * @magentoConfigFixture current_store payment/mollie_methods_paymentlink/allow_mark_as_paid 0 */ - public function testDoesNotShowsTheButtonWhenCheckmoIsNotAvailable() + public function testDoesNotShowsTheButtonWhenMollieReorderIsNotAvailable() { $order = $this->loadOrderById('100000001'); $order->getPayment()->setMethod('mollie_methods_paymentlink'); @@ -66,7 +87,7 @@ public function testDoesNotShowsTheButtonWhenCheckmoIsNotAvailable() /** * @magentoDataFixture Magento/Sales/_files/order.php - * @magentoConfigFixture current_store payment/checkmo/active 1 + * @magentoConfigFixture default_store payment/mollie_methods_paymentlink/allow_mark_as_paid 1 */ public function testShowTheButtonWhenApplicable() { diff --git a/etc/adminhtml/methods/paymentlink.xml b/etc/adminhtml/methods/paymentlink.xml index e00dcc111e1..37ac8427e5f 100644 --- a/etc/adminhtml/methods/paymentlink.xml +++ b/etc/adminhtml/methods/paymentlink.xml @@ -27,7 +27,16 @@ 1 - + + Magento\Config\Model\Config\Source\Yesno + payment/mollie_methods_paymentlink/allow_mark_as_paid + + 1 + + + Magento\Config\Model\Config\Source\Yesno @@ -38,7 +47,7 @@ 1 - + Mollie\Payment\Model\Adminhtml\Source\NewStatus payment/mollie_methods_paymentlink/order_status_new @@ -46,7 +55,7 @@ 1 - Magento\Payment\Model\Config\Source\Allspecificcountries @@ -55,7 +64,7 @@ 1 - Magento\Directory\Model\Config\Source\Country @@ -65,7 +74,7 @@ 1 - payment/mollie_methods_paymentlink/min_order_total @@ -73,7 +82,7 @@ 1 - payment/mollie_methods_paymentlink/max_order_total @@ -81,7 +90,7 @@ 1 - validate-number @@ -90,7 +99,7 @@ 1 - validate-digits-range digits-range-1-100 diff --git a/etc/config.xml b/etc/config.xml index 54afbf0e8f7..20956f31719 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -172,6 +172,15 @@ here to pay for your purchase.]]> + + 1 + Mollie\Payment\Model\Methods\Reorder + Mollie: Reorder + {ordernumber} + order + order + 0 + 1 Mollie\Payment\Model\Methods\Giftcard From ed3f551a6671511cdfe3200b37ff5c906da2068b Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Thu, 21 Nov 2019 12:25:54 +0100 Subject: [PATCH 05/10] Bugfix: Partial creditmemos with cart price rules applied would return in an error --- Model/OrderLines.php | 26 +++++++++++++----- Test/Integration/Model/OrderLinesTest.php | 32 +++++++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/Model/OrderLines.php b/Model/OrderLines.php index 75fd942164f..e701c875aec 100644 --- a/Model/OrderLines.php +++ b/Model/OrderLines.php @@ -12,6 +12,7 @@ use Magento\Framework\Model\ResourceModel\AbstractResource; use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\Model\AbstractModel; +use Magento\Sales\Api\Data\CreditmemoInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Item; use Mollie\Payment\Model\ResourceModel\OrderLines\Collection as OrderLinesCollection; @@ -416,12 +417,11 @@ public function getOrderLineByItemId($itemId) } /** - * @param Order\Creditmemo $creditmemo - * @param $addShipping - * + * @param CreditmemoInterface $creditmemo + * @param bool $addShipping * @return array */ - public function getCreditmemoOrderLines($creditmemo, $addShipping) + public function getCreditmemoOrderLines(CreditmemoInterface $creditmemo, $addShipping) { $orderLines = []; @@ -429,9 +429,23 @@ public function getCreditmemoOrderLines($creditmemo, $addShipping) foreach ($creditmemo->getAllItems() as $item) { $orderItemId = $item->getOrderItemId(); $lineId = $this->getOrderLineByItemId($orderItemId)->getLineId(); - if ($lineId) { - $orderLines[] = ['id' => $lineId, 'quantity' => round($item->getQty())]; + if (!$lineId) { + continue; } + + $line = [ + 'id' => $lineId, + 'quantity' => round($item->getQty()), + ]; + + if ($item->getBaseDiscountAmount()) { + $line['amount'] = $this->mollieHelper->getAmountArray( + $creditmemo->getBaseCurrencyCode(), + $item->getBaseRowTotalInclTax() - $item->getBaseDiscountAmount() + ); + } + + $orderLines[] = $line; } $orderId = $creditmemo->getOrderId(); diff --git a/Test/Integration/Model/OrderLinesTest.php b/Test/Integration/Model/OrderLinesTest.php index dc2f55a4716..1f7d93e4859 100644 --- a/Test/Integration/Model/OrderLinesTest.php +++ b/Test/Integration/Model/OrderLinesTest.php @@ -3,6 +3,7 @@ namespace Mollie\Payment\Model; use Magento\Sales\Api\Data\CreditmemoInterface; +use Magento\Sales\Api\Data\CreditmemoItemInterface; use Mollie\Payment\Test\Integration\IntegrationTestCase; class OrderLinesTest extends IntegrationTestCase @@ -91,6 +92,37 @@ public function testGetCreditmemoOrderLinesIncludesTheStoreCredit() $this->assertEquals(1, $line['quantity']); } + public function testCreditmemoUsesTheDiscount() + { + /** @var OrderLines $orderLine */ + $orderLine = $this->objectManager->get(\Mollie\Payment\Model\OrderLinesFactory::class)->create(); + $orderLine->setItemId(999); + $orderLine->setLineId('ord_abc123'); + $orderLine->save(); + + /** @var CreditmemoItemInterface $creditmemoItem */ + $creditmemoItem = $this->objectManager->create(CreditmemoItemInterface::class); + $creditmemoItem->setBaseRowTotalInclTax(45); + $creditmemoItem->setBaseDiscountAmount(9); + $creditmemoItem->setQty(1); + $creditmemoItem->setOrderItemId(999); + + /** @var CreditmemoInterface $creditmemo */ + $creditmemo = $this->objectManager->get(CreditmemoInterface::class); + $creditmemo->setOrderId(999); + $creditmemo->setItems([$creditmemoItem]); + + /** @var OrderLines $instance */ + $instance = $this->objectManager->get(OrderLines::class); + $result = $instance->getCreditmemoOrderLines($creditmemo, false); + + $this->assertCount(1, $result['lines']); + + $line = $result['lines'][0]; + $this->assertEquals('36', $line['amount']['value']); + $this->assertEquals(1, $line['quantity']); + } + private function rollbackCreditmemos() { $collection = $this->objectManager->get(\Mollie\Payment\Model\ResourceModel\OrderLines\Collection::class); From 52db87d284e59dcb36af81b0a92be56f3f5e1d10 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Thu, 21 Nov 2019 15:23:27 +0100 Subject: [PATCH 06/10] Notify customer about the invoice --- Config.php | 10 +++++ Controller/Adminhtml/Action/MarkAsPaid.php | 48 +++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Config.php b/Config.php index 38e096d4d1d..cab021bd7bd 100644 --- a/Config.php +++ b/Config.php @@ -11,6 +11,7 @@ class Config { + const GENERAL_INVOICE_NOTIFY = 'payment/mollie_general/invoice_notify'; const XML_PATH_STATUS_PENDING_BANKTRANSFER = 'payment/mollie_methods_banktransfer/order_status_pending'; const XML_PATH_STATUS_NEW_PAYMENT_LINK = 'payment/mollie_methods_paymentlink/order_status_new'; const PAYMENT_KLARNAPAYLATER_PAYMENT_SURCHARGE = 'payment/mollie_methods_klarnapaylater/payment_surcharge'; @@ -50,6 +51,15 @@ private function getFlag($path, $storeId) return $this->config->isSetFlag($path, ScopeInterface::SCOPE_STORE, $storeId); } + /** + * @param null $storeId + * @return bool + */ + public function sendInvoiceEmail($storeId = null) + { + return $this->getFlag(static::GENERAL_INVOICE_NOTIFY, $storeId); + } + public function statusPendingBanktransfer($storeId = null) { return $this->config->getValue( diff --git a/Controller/Adminhtml/Action/MarkAsPaid.php b/Controller/Adminhtml/Action/MarkAsPaid.php index 5a91e9b401b..ce366aa34d4 100644 --- a/Controller/Adminhtml/Action/MarkAsPaid.php +++ b/Controller/Adminhtml/Action/MarkAsPaid.php @@ -10,15 +10,24 @@ use Magento\Backend\Model\Session\Quote; use Magento\Framework\DB\Transaction; use Magento\Framework\DB\TransactionFactory; +use Magento\Sales\Api\Data\InvoiceInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\AdminOrder\Create; use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Email\Sender\InvoiceSender; use Magento\Sales\Model\Order\Invoice; use Magento\Sales\Model\Service\InvoiceService; +use Mollie\Payment\Config; +use Mollie\Payment\Service\Order\OrderCommentHistory; class MarkAsPaid extends Action { + /** + * @var Config + */ + private $config; + /** * @var OrderRepositoryInterface */ @@ -44,6 +53,16 @@ class MarkAsPaid extends Action */ private $transactionFactory; + /** + * @var InvoiceSender + */ + private $invoiceSender; + + /** + * @var OrderCommentHistory + */ + private $orderCommentHistory; + /** * @var Transaction */ @@ -51,19 +70,25 @@ class MarkAsPaid extends Action public function __construct( Action\Context $context, + Config $config, OrderRepositoryInterface $orderRepository, Create $orderCreate, Quote $quoteSession, InvoiceService $invoiceService, + InvoiceSender $invoiceSender, + OrderCommentHistory $orderCommentHistory, TransactionFactory $transactionFactory ) { parent::__construct($context); + $this->config = $config; $this->orderRepository = $orderRepository; $this->orderCreate = $orderCreate; $this->quoteSession = $quoteSession; $this->invoiceService = $invoiceService; + $this->invoiceSender = $invoiceSender; $this->transactionFactory = $transactionFactory; + $this->orderCommentHistory = $orderCommentHistory; } /** @@ -84,10 +109,12 @@ public function execute() $this->transaction = $this->transactionFactory->create(); $order = $this->recreateOrder($originalOrder); - $this->createInvoiceFor($order); + $invoice = $this->createInvoiceFor($order); $this->cancelOriginalOrder($originalOrder, $order->getIncrementId()); $this->transaction->save(); + $this->sendInvoice($invoice, $order); + $this->messageManager->addSuccessMessage( __( 'We cancelled order %1, created this order and marked it as complete.', @@ -143,5 +170,24 @@ private function createInvoiceFor(OrderInterface $order) $invoice->register(); $this->transaction->addObject($invoice); + + return $invoice; + } + + private function sendInvoice(InvoiceInterface $invoice, OrderInterface $order) + { + /** @var Order\Invoice $invoice */ + if ($invoice->getEmailSent() || !$this->config->sendInvoiceEmail($invoice->getStoreId())) { + return; + } + + try { + $this->invoiceSender->send($invoice); + $message = __('Notified customer about invoice #%1', $invoice->getIncrementId()); + $this->orderCommentHistory->add($order, $message, true); + } catch (\Throwable $exception) { + $message = __('Unable to send the invoice: %1', $exception->getMessage()); + $this->orderCommentHistory->add($order, $message, true); + } } } From 512487d36bd08a95f56e900dfaf8730fa5779480 Mon Sep 17 00:00:00 2001 From: Marvin-Magmodules Date: Tue, 26 Nov 2019 20:24:56 +0100 Subject: [PATCH 07/10] Small fixes --- Controller/Adminhtml/Action/MarkAsPaid.php | 18 +++++++++++++----- Model/Methods/Reorder.php | 8 ++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Controller/Adminhtml/Action/MarkAsPaid.php b/Controller/Adminhtml/Action/MarkAsPaid.php index ce366aa34d4..5a57316fd3e 100644 --- a/Controller/Adminhtml/Action/MarkAsPaid.php +++ b/Controller/Adminhtml/Action/MarkAsPaid.php @@ -110,9 +110,10 @@ public function execute() $order = $this->recreateOrder($originalOrder); $invoice = $this->createInvoiceFor($order); - $this->cancelOriginalOrder($originalOrder, $order->getIncrementId()); + $this->cancelOriginalOrder($originalOrder); $this->transaction->save(); + $this->addCommentHistoryOriginalOrder($originalOrder, $order->getIncrementId()); $this->sendInvoice($invoice, $order); $this->messageManager->addSuccessMessage( @@ -152,15 +153,22 @@ private function recreateOrder(OrderInterface $originalOrder) return $order; } + /** + * @param OrderInterface $originalOrder + */ + private function cancelOriginalOrder(OrderInterface $originalOrder) + { + $originalOrder->cancel(); + } + /** * @param OrderInterface $originalOrder * @param string $newIncrementId */ - private function cancelOriginalOrder(OrderInterface $originalOrder, $newIncrementId) + private function addCommentHistoryOriginalOrder(OrderInterface $originalOrder, $newIncrementId) { $comment = __('We created a new order with increment ID: %1', $newIncrementId); - $originalOrder->addCommentToStatusHistory($comment); - $originalOrder->cancel(); + $this->orderCommentHistory->add($originalOrder, $comment, false); } private function createInvoiceFor(OrderInterface $order) @@ -187,7 +195,7 @@ private function sendInvoice(InvoiceInterface $invoice, OrderInterface $order) $this->orderCommentHistory->add($order, $message, true); } catch (\Throwable $exception) { $message = __('Unable to send the invoice: %1', $exception->getMessage()); - $this->orderCommentHistory->add($order, $message, true); + $this->orderCommentHistory->add($order, $message, false); } } } diff --git a/Model/Methods/Reorder.php b/Model/Methods/Reorder.php index 088a56e3c60..c2fb4cad392 100644 --- a/Model/Methods/Reorder.php +++ b/Model/Methods/Reorder.php @@ -6,7 +6,6 @@ namespace Mollie\Payment\Model\Methods; -use Magento\Directory\Helper\Data as DirectoryHelper; use Magento\Framework\Api\AttributeValueFactory; use Magento\Framework\Api\ExtensionAttributesFactory; use Magento\Framework\App\Config\ScopeConfigInterface; @@ -18,7 +17,6 @@ use Magento\Payment\Helper\Data; use Magento\Payment\Model\Method\AbstractMethod; use Magento\Payment\Model\Method\Logger; -use Mollie\Payment\Model\Mollie; /** * Class Reorder @@ -71,8 +69,7 @@ public function __construct( RequestInterface $request, AbstractResource $resource = null, AbstractDb $resourceCollection = null, - array $data = [], - DirectoryHelper $directory = null + array $data = [] ) { $this->request = $request; @@ -86,8 +83,7 @@ public function __construct( $logger, $resource, $resourceCollection, - $data, - $directory + $data ); } From a99d1ec30770df7245b8d67543085e17d6f36fa1 Mon Sep 17 00:00:00 2001 From: Sebastian Wegerer <32958840+sebus208@users.noreply.github.com> Date: Thu, 28 Nov 2019 15:12:29 +0100 Subject: [PATCH 08/10] Update nl_NL.csv Translated the string "Payment canceled, please try again." --- i18n/nl_NL.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/nl_NL.csv b/i18n/nl_NL.csv index 32f684a86f5..b69c8a4c164 100644 --- a/i18n/nl_NL.csv +++ b/i18n/nl_NL.csv @@ -33,6 +33,7 @@ "Notified customer about invoice #%1","Klant over factuur #%1 genotificeerd" "Order not found","Order niet gevonden" "Payment cancelled, please try again.","Betaling geannuleerd, probeer opnieuw." +"Payment canceled, please try again.","Betaling geannuleerd, probeer opnieuw." "Payment from Applicable Countries","Betaling van toepasbare landen" "Payment from Specific Countries","Betaling uit bepaalde landen" "Paymentmethod not found.","Betalingsmethode niet gevonden." From 041640513c80e94999b4381c18c3248f2353c541 Mon Sep 17 00:00:00 2001 From: Sebastian Wegerer <32958840+sebus208@users.noreply.github.com> Date: Thu, 28 Nov 2019 15:16:35 +0100 Subject: [PATCH 09/10] Update nl_NL.csv Added translation for "Payment canceled, please try again." --- i18n/nl_NL.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/nl_NL.csv b/i18n/nl_NL.csv index b69c8a4c164..181caf17d29 100644 --- a/i18n/nl_NL.csv +++ b/i18n/nl_NL.csv @@ -32,8 +32,8 @@ "No order found for transaction id %1","Geen order gevonden met transactie ID %1" "Notified customer about invoice #%1","Klant over factuur #%1 genotificeerd" "Order not found","Order niet gevonden" -"Payment cancelled, please try again.","Betaling geannuleerd, probeer opnieuw." "Payment canceled, please try again.","Betaling geannuleerd, probeer opnieuw." +"Payment cancelled, please try again.","Betaling geannuleerd, probeer opnieuw." "Payment from Applicable Countries","Betaling van toepasbare landen" "Payment from Specific Countries","Betaling uit bepaalde landen" "Paymentmethod not found.","Betalingsmethode niet gevonden." From b6dc5020a16a77d909790bffe9b9ff8aa6c735da Mon Sep 17 00:00:00 2001 From: Marvin-Magmodules Date: Mon, 2 Dec 2019 19:19:42 +0100 Subject: [PATCH 10/10] Version bump --- composer.json | 2 +- etc/module.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 54bdf2f61e1..2bfc15819e8 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "mollie/magento2", "description": "Mollie Payment Module for Magento 2", - "version": "1.8.0", + "version": "1.9.0", "keywords": [ "mollie", "payment", diff --git a/etc/module.xml b/etc/module.xml index 7318d10c08f..0189845542d 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,4 +1,4 @@ - +