Sitemap

Magento 2 — How to delete Creditmemo?

5 min readNov 15, 2020

--

hellomage.com

Before we go into the methods to delete a credit-memo, let's have a look at the credit memo tables first, as well as the Important tables that keep the refunded data.

Main credit memo tables.

Important tables that store refunded data.

Table 1: sales_order_item

qty_refunded
tax_refunded
base_tax_refunded
discount_tax_compensation_refunded
base_discount_tax_compensation_refunded
amount_refunded
base_amount_refunded
discount_refunded
base_discount_refunded

Table 2: sales_order

base_total_refunded
total_refunded
base_subtotal_refunded
subtotal_refunded
base_tax_refunded
tax_refunded
base_discount_tax_compensation_refunded
discount_tax_compensation_refunded
base_shipping_refunded
shipping_refunded
base_shipping_tax_refunded
shipping_tax_refunded
adjustment_positive
base_adjustment_positive
adjustment_negative
base_adjustment_negative
discount_refunded
base_discount_refunded

If the refund transaction was done by “online” mode, the below fields in sales_order has to be corrected.

total_online_refunded
base_total_online_refunded

If the refund transaction was done by “offline” mode, the below fields in sales_order has to be corrected.

total_offline_refunded
base_total_offline_refunded

Let’s write the code

First thing is to get the credit memo ID and using that, get the credit memo object. when we developing this as a module, we used to pass the credit memo ID either to the controller, or maybe we might use a console command with credit memo ID as an argument. In any case, we have to get the credit memo ID to get the object.

Below is the controller execute function. I have used a button inside the credit memo detail page that points to the below controller action.

You can see more about defining route and controller here

<?php

namespace HelloMage\DeleteCreditmemo\Controller\Adminhtml\Delete;

use Exception;
use HelloMage\DeleteCreditmemo\Model\Creditmemo\Delete;
use Magento\Backend\App\Action;
use Magento\Sales\Api\CreditmemoRepositoryInterface;

// our controller

/**
* Class
Creditmemo
*
@package HelloMage\DeleteCreditmemo\Controller\Adminhtml\Delete
*/
class Creditmemo extends Action
{
/**
*
@var CreditmemoRepositoryInterface
*/
protected $creditmemoRepository;

/**
*
@var Delete
*/
protected $delete;

/**
*
Creditmemo constructor.
*
@param Action\Context $context
*
@param CreditmemoRepositoryInterface $creditmemoRepository
*
@param Delete $delete
*/
public function __construct(
Action\Context $context,
CreditmemoRepositoryInterface $creditmemoRepository,
Delete $delete
) {
$this->creditmemoRepository = $creditmemoRepository;
$this->delete = $delete;
parent::__construct($context);
}
public function execute()
{
// getting creditmemo id from request
$creditmemoId = $this->getRequest()
->getParam('creditmemo_id');

// using creditmemo repository, loading object
$creditmemo = $this->creditmemoRepository
->get($creditmemoId);

// fetching order-id from creditmemo object
$orderId = $creditmemo->getOrderId();

try {
// below is the function perform delete operation
$this->delete->deleteCreditmemo($creditmemoId);
$this->messageManager
->addSuccessMessage(__('Successfully deleted creditmemo #%1.', $creditmemo->getIncrementId()));
} catch (Exception $e) {
$this->messageManager->addErrorMessage(__('Error delete creditmemo #%1.', $creditmemo->getIncrementId()));
}
$resultRedirect = $this->resultRedirectFactory->create();

// redirecting to relative order page
$resultRedirect->setPath('sales/order/view', ['order_id' => $orderId]);

return $resultRedirect;
}
}

So, let's create a class called “Delete

<?php

namespace HelloMage\DeleteCreditmemo\Model\Creditmemo;

use Exception;
use Magento\Sales\Api\CreditmemoRepositoryInterface;
use Magento\Sales\Model\Order;

/**
*
Class Delete
*
@package HelloMage\DeleteCreditmemo\Model\Creditmemo
*/
class Delete
{
/**
*
@var CreditmemoRepositoryInterface
*/
protected $creditmemoRepository;

/**
*
@var Order
*/
protected $order;

/**
*
Delete constructor.
*
@param Order $order
*
@param CreditmemoRepositoryInterface $creditmemoRepository
*/
public function __construct(
Order $order,
CreditmemoRepositoryInterface $creditmemoRepository
) {
$this->order = $order;
$this->creditmemoRepository = $creditmemoRepository;
}

/**
*
@param $creditmemoId
*
@return \Magento\Sales\Model\Order
*
@throws \Exception
*/
public function deleteCreditmemo($creditmemoId)
{
// delete operations.
}
}

so, the delete operations include the following.

  1. load the credit memo object by its ID.
  2. load credit memo items.
  3. from the credit memo object, get the order object, and ordered items.
  4. match the ordered items against credit memo items and adjust ordered item refund field values ( Table 1: sales_order_item ).
  5. adjust the sale order refund field values ( Table 2: sales_order ).
  6. delete credit memo.
  7. save order.
  1. load the credit memo object by its ID.
$creditmemo = $this->creditmemoRepository->get($creditmemoId);

2. load credit memo items.

$creditmemoItems = $creditmemo->getAllItems();

3. from the credit memo object, get the order object, and ordered items.

$orderId = $creditmemo->getOrder()->getId();
$order = $this->order->load($orderId);
$orderItems = $order->getAllItems();

4. match the ordered items against credit memo items and adjust ordered item refund field values ( Table 1: sales_order_item ).

// comparing ordered items against credit memo itemsforeach ($orderItems as $item) {foreach ($creditmemoItems as $creditmemoItem) {if ($creditmemoItem->getOrderItemId() == $item->getItemId()) {// adjusting qty_refunded
$item->setQtyRefunded($item->getQtyRefunded() - $creditmemoItem->getQty());
// adjusting tax_refunded
$item->setTaxRefunded($item->getTaxRefunded() - $creditmemoItem->getTaxAmount());
// adjusting base_tax_refunded
$item->setBaseTaxRefunded($item->getBaseTaxRefunded() - $creditmemoItem->getBaseTaxAmount());
$discountTaxItem = $item->getDiscountTaxCompensationRefunded();
$discountTaxCredit = $creditmemoItem->getDiscountTaxCompensationAmount();
// adjusting discount_tax_compensation_refunded
$item->setDiscountTaxCompensationRefunded($discountTaxItem - $discountTaxCredit);
$baseDiscountItem = $item->getBaseDiscountTaxCompensationRefunded();
$baseDiscountCredit = $creditmemoItem->getBaseDiscountTaxCompensationAmount();
// adjusting base_discount_tax_compensation_refunded
$item->setBaseDiscountTaxCompensationRefunded($baseDiscountItem - $baseDiscountCredit);
// adjusting amount_refunded
$item->setAmountRefunded($item->getAmountRefunded() - $creditmemoItem->getRowTotal());
// adjusting base_amount_refunded
$item->setBaseAmountRefunded($item->getBaseAmountRefunded() - $creditmemoItem->getBaseRowTotal());
// adjusting discount_refund
$item->setDiscountRefunded($item->getDiscountRefunded() - $creditmemoItem->getDiscountAmount());
// adjusting base_discount_refunded
$item->setBaseDiscountRefunded($item->getBaseDiscountRefunded() - $creditmemoItem->getBaseDiscountAmount());
}
}}

6. adjust the sale order refund field values ( Table 2: sales_order ).

// adjusting base_total_refunded
$order->setBaseTotalRefunded($order->getBaseTotalRefunded() - $creditmemo->getBaseGrandTotal());
// adjusting total_refunded
$order->setTotalRefunded($order->getTotalRefunded() - $creditmemo->getGrandTotal());
// adjusting base_subtotal_refunded
$order->setBaseSubtotalRefunded($order->getBaseSubtotalRefunded() - $creditmemo->getBaseSubtotal());
// adjusting subtotal_refunded
$order->setSubtotalRefunded($order->getSubtotalRefunded() - $creditmemo->getSubtotal());
// adjusting base_tax_refunded
$order->setBaseTaxRefunded($order->getBaseTaxRefunded() - $creditmemo->getBaseTaxAmount());
// adjusting tax_refunded
$order->setTaxRefunded($order->getTaxRefunded() - $creditmemo->getTaxAmount());
// adjusting base_discount_tax_compensation_refunded
$order->setBaseDiscountTaxCompensationRefunded($order->getBaseDiscountTaxCompensationRefunded() - $creditmemo->getBaseDiscountTaxCompensationAmount()
);
// adjusting discount_tax_compensation_refunded
$order->setDiscountTaxCompensationRefunded($order->getDiscountTaxCompensationRefunded() - $creditmemo->getDiscountTaxCompensationAmount());
// adjusting base_shipping_refunded
$order->setBaseShippingRefunded($order->getBaseShippingRefunded() - $creditmemo->getBaseShippingAmount());
// adjusting shipping_refunded
$order->setShippingRefunded($order->getShippingRefunded() - $creditmemo->getShippingAmount());
// adjusting base_shipping_tax_refunded
$order->setBaseShippingTaxRefunded($order->getBaseShippingTaxRefunded() - $creditmemo->getBaseShippingTaxAmount());
// adjusting shipping_tax_refunded
$order->setShippingTaxRefunded($order->getShippingTaxRefunded() - $creditmemo->getShippingTaxAmount());
// adjusting adjustment_positive
$order->setAdjustmentPositive($order->getAdjustmentPositive() - $creditmemo->getAdjustmentPositive());
// adjusting base_adjustment_positive
$order->setBaseAdjustmentPositive($order->getBaseAdjustmentPositive() - $creditmemo->getBaseAdjustmentPositive());
// adjusting adjustment_negative
$order->setAdjustmentNegative($order->getAdjustmentNegative() - $creditmemo->getAdjustmentNegative());
// adjusting base_adjustment_negative
$order->setBaseAdjustmentNegative($order->getBaseAdjustmentNegative() - $creditmemo->getBaseAdjustmentNegative());
// adjusting discount_refunded
$order->setDiscountRefunded($order->getDiscountRefunded() - $creditmemo->getDiscountAmount());
// adjusting base_discount_refunded
$order->setBaseDiscountRefunded($order->getBaseDiscountRefunded() - $creditmemo->getBaseDiscountAmount());
// if credit memo refund done in online mode
if ($creditmemo->getDoTransaction()) {
// adjusting total_online_refunded
$order->setTotalOnlineRefunded($order->getTotalOnlineRefunded() - $creditmemo->getGrandTotal());
// adjusting base_total_online_refunded
$order->setBaseTotalOnlineRefunded($order->getBaseTotalOnlineRefunded() - $creditmemo->getBaseGrandTotal());
} else {// if credit memo refund done in offline mode// adjusting total_offline_refunded
$order->setTotalOfflineRefunded($order->getTotalOfflineRefunded() - $creditmemo->getGrandTotal());
// adjusting base_total_offline_refunded
$order->setBaseTotalOfflineRefunded($order->getBaseTotalOfflineRefunded() - $creditmemo->getBaseGrandTotal());
}

Once adjustment on credit memo depended field values done, we can go with deleting credit memo. we have the creditmemoRepository already on the constructor and the object is also loaded. use below to delete a credit memo.

// delete creditmemo
$this->creditmemoRepository->delete($creditmemoData);

An alternative way to delete a credit memo.

// using resource connection load the tables.$connection = $this->resource->getConnection(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION);$creditmemoGridTable = $connection->getTableName($this->data->getTableName('sales_creditmemo_grid'));$creditmemoTable = $connection->getTableName($this->data->getTableName('sales_creditmemo'));// deleting creditmemo$connection->rawQuery('DELETE FROM `'.$creditmemoGridTable.'` WHERE entity_id='.$creditmemoId);$connection->rawQuery('DELETE FROM `'.$creditmemoTable.'` WHERE entity_id='.$creditmemoId);

Finally, we have to save the order. This adjusts the order state

// checking whether the order state needs to be processing.if ($order->hasShipments() || $order->hasInvoices() || $order->hasCreditmemos()) {// if there a shipment, invoice or creditmemo, then the order state must be in PROCESSING.$order->setState(\Magento\Sales\Model\Order::STATE_PROCESSING)
->setStatus($order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_PROCESSING))->save();

} elseif (!$order->canInvoice() && !$order->canShip() && !$order->hasCreditmemos()) {
// if there is no room for invoice, shipment and creditmemo, then the order must consider as COMPLETE.$order->setState(\Magento\Sales\Model\Order::STATE_COMPLETE)
->setStatus($order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_COMPLETE))
->save();
} else {// if none of the above, the state must be NEW/PENFING.$order->setState(\Magento\Sales\Model\Order::STATE_NEW)
->setStatus($order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_NEW))
->save();
}

--

--

No responses yet