7

I need to create credit memo and online refund programmatically in magento 2. I referred programmatic creation of credit memo in magento 1.x here. Any help for magento 2?

1

6 Answers 6

13

Finally discovered the solution, to create credit memo with online refund from custom code. Use this code in your custom model and call the function where ever you want.

public __construct(
    \Magento\Sales\Model\Order $order,
    \Magento\Sales\Model\Order\CreditmemoFactory $creditmemoFactory,
    \Magento\Sales\Model\Order\Invoice $invoice,
    \Magento\Sales\Model\Service\CreditmemoService $creditmemoService,
    array $data = []
) {
    parent::__construct($data);
    $this->order = $order;
    $this->creditmemoFactory = $creditmemoFactory;
    $this->creditmemoService = $creditmemoService;
    $this->invoice = $invoice; 
}

public function refundCode()
{
    $order = $this->order;
    $order->load(10);

    $invoices = $order->getInvoiceCollection();
    foreach ($invoices as $invoice) {
        $invoiceincrementid = $invoice->getIncrementId();
    }

    $invoiceobj = $this->invoice->loadByIncrementId($invoiceincrementid);
    $creditmemo = $this->creditmemoFactory->createByOrder($order);

    // Don't set invoice if you want to do offline refund
    $creditmemo->setInvoice($invoiceobj);

    $this->creditmemoService->refund($creditmemo); 
}
5
  • How to pass here an array of specific items?
    – zhartaunik
    Commented Mar 21, 2017 at 7:52
  • Hi @zhartaunik do we have combination of your code & zhartaunik's answer in Refund it automatically includes Shipping Fee. How to avoid that?
    – Jackson
    Commented Apr 3, 2017 at 3:23
  • Doesn't work in 2.1.6 and 2.1.7 - throws an error "We don't have enough information to save the parent transaction ID" Commented Jun 16, 2017 at 19:16
  • How to change order status from closed to cancel when credit memo is created? Commented Oct 24, 2018 at 16:11
  • do you know how to return to stock for an item?
    – leo
    Commented Jun 29, 2021 at 16:36
5

Here some function which can be helpful to you

Create a creditmemo from an order:

\Magento\Sales\Model\Order\CreditmemoFactory::createByOrder

Refund a creditmemo:

\Magento\Sales\Model\Service\CreditmemoService::refund
0
5

Magento 2.1.3

/**
 * @var \Magento\Sales\Model\Order\CreditmemoFactory
 */
protected $refundOrder;

/**
 * @var \Magento\Sales\Model\Order\Creditmemo\ItemCreationFactory
 */
protected $itemCreationFactory;

public function __construct(
    \Magento\Sales\Model\RefundOrder $refundOrder,
    \Magento\Sales\Model\Order\Creditmemo\ItemCreationFactory $itemCreationFactory
) {
    $this->refundOrder = $refundOrder;
    $this->itemCreationFactory = $itemCreationFactory;
}

public function execute()
{
    $creditmemoItem = $this->itemCreationFactory->create();
    $creditmemoItem->setQty(1)
          ->setOrderItemId(22);
    $itemIdsToRefund[] = $creditmemoItem;

    $this->refundOrder->execute(
        $order->getId(),
        $itemIdsToRefund
    );
}

Runs as clockwork

4
  • Can i get refund related table fields bz i want to create csv template for data migration. Commented Jul 22, 2017 at 13:50
  • How can I pass invoice id for same? Commented Oct 26, 2018 at 10:32
  • can we refund amout to storecredit ?
    – devhs
    Commented Mar 25, 2021 at 11:05
  • Doesn't seem to be anyway to do an online refund using Magento\Sales\Model\RefundOrder. It will always be offline.
    – Rooster242
    Commented May 10, 2021 at 22:37
1

To do a partial credit memo against an invoice, you need to do something like this:

/** @var RefundInvoiceInterface $refundInvoice */
$refundInvoice = $objectManager->get("\Magento\Sales\Api\RefundInvoiceInterface");

$items = []; // If items is empty array, the entire invoice will be refunded.

/** @var \Magento\Sales\Model\Order\Invoice\Item $item */
foreach ($invoice->getAllItems() as $item) {

    // Note that the simple and configurable products are returned in getAllItems(). The function getVisibleItems() does not work, so we need this check:
    if($item->getOrderItem()->getProductType() == \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE) {
        continue;
    }

    $qtyToReturn = 1; // Select out many you want to refund
    $creditmemoItemCreation = new \Magento\Sales\Model\Order\Creditmemo\ItemCreation();
    $items[] = $creditmemoItemCreation->setQty($qtyToReturn)->setOrderItemId($item->getOrderItemId());
}

// If you don't want to refund shipping, or to make adjustment refunds, use the CreationArguments (otherwise, you can leave these next two lines out)
$creditMemoCreationArguments = new CreationArguments();
$creditMemoCreationArguments->setShippingAmount(0);

$refundInvoice->execute($invoice->getId(), $items, true, true, false, null, $creditMemoCreationArguments);
1
  • Seems to possibly be something missing, where does $invoice get defined? It also seems like the $items array gets overwritten...
    – joeybab3
    Commented Jun 21, 2021 at 23:29
0

Try below one

$objectManager = \Magento\Framework\App\ObjectManager::getInstance(); /* Instance of object manager */


$incrementId = "100075273"; /*Increment Id */

$collection = $objectManager->create('Magento\Sales\Model\Order'); 
$order = $collection->loadByIncrementId($incrementId);

$invoice = $objectManager->create('Magento\Sales\Model\Order\Invoice');

$creditMemoFacory = $objectManager->create('Magento\Sales\Model\Order\CreditmemoFactory');
$creditmemoService = $objectManager->create('Magento\Sales\Model\Service\CreditmemoService');

try {
    $invoices = $order->getInvoiceCollection();
    foreach ($invoices as $invoice) {
        $invoiceincrementid = $invoice->getIncrementId();
    }

if(isset($invoiceincrementid)){
    $invoiceobj = $invoice->loadByIncrementId($invoiceincrementid);
    $creditmemo = $creditMemoFacory->createByOrder($order);

// Don't set invoice if you want to do offline refund
$creditmemo->setInvoice($invoiceobj);

$creditmemoService->refund($creditmemo); 

echo "CreditMemo Succesfully Created For Order: ".$incrementId;

} else {
    echo "CreditMemo Cannot Be Created For Order: ".$incrementId; /*if order has 0 amount or something wrong happened**/
}

} catch (\Exception $e) {
   echo "Creditmemo Not Created". $e->getMessage();
}
1
  • How to do a partial refund ?
    – devhs
    Commented Mar 30, 2021 at 6:37
0

That's how I got it working on Magento 2.3. All you need to pass is just the Order object.

<?php

namespace Vender\Package\Model\Order\Processor;

use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\CreditmemoFactory;
use Magento\Sales\Model\Order\Invoice;
use Magento\Sales\Model\Service\CreditmemoService;


class CustomClass
{
    protected $creditMemoFactory;
    protected $creditMemoService;
    protected $invoice;


    public function __construct (
        CreditmemoFactory $creditMemoFactory,
        CreditmemoService $creditMemoService,
        Invoice $invoice
    ) {
        $this->creditMemoFactory = $creditMemoFactory;
        $this->creditMemoService = $creditMemoService;
        $this->invoice = $invoice;
    }


    /**
     * @param OrderInterface $order
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    protected function refund(OrderInterface $order): void
    {
        $invoices = $order->getInvoiceCollection();

        if (count($invoices) == 0) {
            throw new \Exception(__('No Invoices found for Refund. Magento_ID: %2',
                $order->getIncrementId()));
        }

        foreach ($invoices as $invoice) {
            $invoice = $this->invoice->loadByIncrementId($invoice->getIncrementId());
            $creditMemo = $this->creditMemoFactory->createByOrder($order);

            // Don't set invoice if you want to do offline refund
            $creditMemo->setInvoice($invoice);
            $creditMemo->setCustomerNote(__('Your Order %1 has been Refunded back in your account',
                $order->getIncrementId()));
            $creditMemo->setCustomerNoteNotify(false);
            $creditMemo->addComment(__('Order has been Refunded'));

            $order->addCommentToStatusHistory(__('Order has been Refunded Successfully'));

            $this->creditMemoService->refund($creditMemo);
        }
    }
}


I hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.