How to Create Credit Memo in Magento 2 Programmatically?

As much as store owners would like to have no refunds, this is not entirely possible. Customers may purchase the wrong size, colour, etc., receive incorrect items or change their minds unexpectedly. Merchants too may oversee various order-related details. Thus, a refund policy is a necessity to ensure reliable store-customer relations.

In Magento 2, a refund is referred to as a credit memo. It defines the amount of money a customer is supposed to receive back. Usually, credit memos are created in the admin panel. Yet, you can also do this using code.

So in this article, you'll learn how to create a credit memo in Magento 2 programmatically.

Create Credit Memo Using Dependency Injection 

One of the recommended options to go for is the dependency injection method. The following code will help you create a credit memo programmatically.

<?php

namespace Venodr\MyModule\Model;

use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Sales\Model\RefundOrder;
use Magento\Sales\Model\Order\Creditmemo\ItemCreationFactory;

class CreateCreditMemo
{
 protected $itemCreationFactory;

 protected $orderRepository;

 protected $refundOrder;

 public function __construct(
   ItemCreationFactory $itemCreationFactory,
   OrderRepositoryInterface $orderRepository,
   RefundOrder $refundOrder
 ){
   $this->itemCreationFactory = $itemCreationFactory;
   $this->orderRepository = $orderRepository;
   $this->refundOrder = $refundOrder;
 }

 public function createCreditMemo(int $orderId)
 {
   try {
       $order = $this->orderRepository->get($orderId);
 }
 catch (NoSuchEntityException $e) {
   return ['error' => 1, 'msg' => 'Undefined orderId: ' . $orderId];
 }

 if (!$order->canCreditmemo()) {
     return ['error' => 1, 'msg' => 'Cannot create credit memo for order : ' . $orderId];
 }

 $itemIdsToRefund = [];

 foreach ($order->getAllItems() as $orderItem) {
   $creditMemoItem = $this->itemCreationFactory->create();

$creditMemoItem->setQty($orderItem->getQtyOrdered())->setOrderItemId($orderItem->getId());
      $itemIdsToRefund[] = $creditMemoItem;
 }

 try {
    $this->refundOrder->execute($orderId, $itemIdsToRefund);
 }
 catch (\Exception $e) {
   return ['error' => 1, 'msg' => 'Cannot create credit memo : '];
 }


 return ['success' => 1, 'msg' => 'Refund was created'];
}

}

Create Credit Memo Using Object Manager

As you might know, the Object Manager can hide the real dependencies of the class. However, if you're used to applying this method for your development tasks, you can try to create a credit memo this way.

<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);

use Magento\Framework\App\Bootstrap;
require __DIR__ . '/app/bootstrap.php';

$bootstrap = Bootstrap::create(BP, $_SERVER);

$objectManager = $bootstrap->getObjectManager();

$state = $objectManager->get(Magento\Framework\App\State::class);
$state->setAreaCode('adminhtml');

$itemCreationFactory = $objectManager->create(\Magento\Sales\Model\Order\Creditmemo\ItemCreationFactory::class);
$orderRepository = $objectManager->create(\Magento\Sales\Api\OrderRepositoryInterface::class);
$refundOrder = $objectManager->create(\Magento\Sales\Model\RefundOrder::class);
$orderId = 81;

try {
  $order = $orderRepository->get($orderId);
}
catch (NoSuchEntityException $e) {
 return ['error' => 1, 'msg' => 'Undefined orderId: ' . $orderId];
}

if (!$order->canCreditmemo()) {
   return ['error' => 1, 'msg' => 'Cannot create credit memo for order : ' . $orderId];
}

$itemIdsToRefund = [];

foreach ($order->getAllItems() as $orderItem) {
  $creditMemoItem = $itemCreationFactory->create();

$creditMemoItem->setQty($orderItem->getQtyOrdered())->setOrderItemId($orderItem->getId());
  $itemIdsToRefund[] = $creditMemoItem;
}

try {
   $refundOrder->execute($orderId, $itemIdsToRefund);
}
catch (\Exception $e) {
 return ['error' => 1, 'msg' => 'Cannot create credit memo : '];
}

return ['success' => 1, 'msg' => 'Refund was created'];

A programmatic way of creating credit memos may be useful if you need to manage a bunch of refunds. Thus, handling them promptly will benefit the order processing as a whole. 

However, to optimize the process, you need to take a lot of other aspects into account. You might need to know how to create an order programmatically in the first place. Yet the more you know, the better customer experience you can offer.