lyra / plugin-magento

An open source plugin that links Magento based e-commerce websites to PayZen secure payment gateway developed by Lyra Network.
https://lyra.com/fr/guides/magento/
Open Software License 3.0
10 stars 12 forks source link

Un-cancelling an order should also reset cancelled amounts on order and order items #37

Closed OLTC-fperrin closed 3 months ago

OLTC-fperrin commented 4 months ago

Hello,

We've been implementing payment orders (link by email in our case) to use with our Point of Sales module.

So when creating the link through the API we add the metadata field update_order => 1 which translate to the param vads_ext_info_update_order => 1 being sent in the request to /lyra/payment/check

If the client already tried to pay and was refused the order is cancelled (which is normal) but the second attempt is accepted, we fall into the else in Controller/Processor/CheckProcessor.php:130

The order is in cancelled status, the payment is accepted and we have update_order as ext_info (which, I believe, was introduced in v2.7.0); so we get into the if on line 138 where you un-cancel order items.

This is fine but we also need to reset the cancelled amounts (base_total_canceled, base_subtotal_canceled, base_tax_canceled, etc...)

Here is the patch I'm applying for now:

--- a/Controller/Processor/CheckProcessor.php   (revision d9d012f097d7c91e070126df5a2283e7fb7b9430)
+++ b/Controller/Processor/CheckProcessor.php   (date 1713446419571)
@@ -139,9 +139,22 @@
                 // Un-cancel order items.
                 $orderItems = $order->getAllItems();
                 foreach ($orderItems as $item) {
+                    $item->setTaxCanceled(0);
+                    $item->setDiscountTaxCompensationCanceled(0);
                     $item->setData("qty_canceled",0)->save();
                 }

+                $order->setSubtotalCanceled(0);
+                $order->setBaseSubtotalCanceled(0);
+                $order->setTaxCanceled(0);
+                $order->setBaseTaxCanceled(0);
+                $order->setShippingCanceled(0);
+                $order->setBaseShippingCanceled(0);
+                $order->setDiscountCanceled(0);
+                $order->setBaseDiscountCanceled(0);
+                $order->setTotalCanceled(0);
+                $order->setBaseTotalCanceled(0);
+
                 // Save order and optionally create invoice.
                 $this->paymentHelper->registerOrder($order, $response);

Is that something you might consider adding in a future release ?

Thank you

nberhouche commented 4 months ago

Hello,

Thank you for bringing this issue to our attention. We'll look into it as soon as possible, and if our tests are conclusive, we could probably add it to the plugin code.

Best regards

OLTC-fperrin commented 4 months ago

looking into this issue of un-cancelling an order, I think the stock should also be updated. Either by using an event or by injecting the \Magento\CatalogInventory\Api\StockManagementInterface and calling registerProductsSale with the appropriate quantities If I managed to find a good solution I'll post it here

OLTC-fperrin commented 4 months ago

Ok, so I used the event checkout_submit_all_after which seems to work just fine in my case since most observers that deal with inventory usually check $quote->getInventoryProcessed() to know if we need to process inventory. Since this data (inventory_processed) is not saved in the database but only in the DataObject in session, it comes back with null and the inventory is processed. I'm not entirely sure this is the best approach but it worked fine in all my tests

Here is my diff so far:

--- a/Controller/Processor/CheckProcessor.php
+++ b/Controller/Processor/CheckProcessor.php
@@ -56,6 +56,16 @@
      */
     protected $creditmemoService;

+    /**
+     * @var \Magento\Framework\Event\ManagerInterface
+     */
+    protected $eventManager;
+
+    /**
+     * @var \Magento\Quote\Model\QuoteRepository
+     */
+    protected $quoteRepository;
+
     /**
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Store\Model\App\Emulation $emulation
@@ -74,7 +84,9 @@
         \Magento\Sales\Model\OrderFactory $orderFactory,
         \Lyranetwork\Lyra\Model\Api\Form\ResponseFactory $lyraResponseFactory,
         \Magento\Sales\Model\Order\CreditmemoFactory $creditmemoFactory,
-        \Magento\Sales\Model\Service\CreditmemoService $creditmemoService
+        \Magento\Sales\Model\Service\CreditmemoService $creditmemoService,
+        \Magento\Framework\Event\ManagerInterface $eventManager,
+        \Magento\Quote\Model\QuoteRepository $quoteRepository
     ) {
         $this->storeManager = $storeManager;
         $this->emulation = $emulation;
@@ -84,6 +96,8 @@
         $this->lyraResponseFactory = $lyraResponseFactory;
         $this->creditmemoFactory = $creditmemoFactory;
         $this->creditmemoService = $creditmemoService;
+        $this->eventManager = $eventManager;
+        $this->quoteRepository = $quoteRepository;
     }

     public function execute(
@@ -139,12 +153,33 @@
                 // Un-cancel order items.
                 $orderItems = $order->getAllItems();
                 foreach ($orderItems as $item) {
+                    $item->setTaxCanceled(0);
+                    $item->setDiscountTaxCompensationCanceled(0);
                     $item->setData("qty_canceled",0)->save();
                 }

+                $order->setSubtotalCanceled(0);
+                $order->setBaseSubtotalCanceled(0);
+                $order->setTaxCanceled(0);
+                $order->setBaseTaxCanceled(0);
+                $order->setShippingCanceled(0);
+                $order->setBaseShippingCanceled(0);
+                $order->setDiscountCanceled(0);
+                $order->setBaseDiscountCanceled(0);
+                $order->setTotalCanceled(0);
+                $order->setBaseTotalCanceled(0);
+
                 // Save order and optionally create invoice.
                 $this->paymentHelper->registerOrder($order, $response);

+                $this->eventManager->dispatch(
+                    'checkout_submit_all_after',
+                    [
+                        'order' => $order,
+                        'quote' => $this->quoteRepository->get($order->getQuoteId())
+                    ]
+                );
+
                 // Display notification URL confirmation message.
                 return 'payment_ok';
             } elseif ($response->isAcceptedPayment() && in_array($order->getStatus(), $successStatuses)) {

You might want to move all of this into the paymentHelper which already have the cancelOrder function.

Hope this help, can't wait to see what you come up with

nberhouche commented 4 months ago

Thank you so much for you suggestion, it's very helpful.

nberhouche commented 4 months ago

Hello there,

You suggestion has been included in v2.8.7 of the module which has been released last week.

Best regards