How To

Magento 2: How to Add Download Invoice Button in Order Email?

Hello Magento Friends,

In today’s tutorial, I will explain How to Add a “Download Invoice” Button in Magento 2 Order Email.

Once the payment is completed successfully, an order confirmation email is sent to the customer’s email. Order confirmation email helps customers get detailed information about their orders. You can allow users to easily download order invoice from the order confirmation email itself in Magento 2.

Let’s look at the steps to add download invoice button in the order email in Magento 2.

Steps to Add Download Invoice Button in Order Email in Magento 2:

Step 1: Firstly, go to the below file path

app\code\Vendor\Extension\view\frontend\layout\sales_email_order_items.xml

Then add the code as follows

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" label="Email Order Items List" design_abstraction="custom">
    <body>
        <referenceBlock name="items">
            <action method="setTemplate">
                <argument name="template" translate="true" xsi:type="string">Vendor_Extension::email/items.phtml</argument>
            </action>
        </referenceBlock>       
    </body>
</page>

Step 2: Next, move to the file path as given below

app\code\Vendor\Extension\view\frontend\templates\email\items.phtml

And embed the below code

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
// phpcs:disable Magento2.Templates.ThisInTemplate

/** @var $block \Magento\Sales\Block\Order\Email\Items */?>
<?php $_order = $block->getOrder() ?>
<?php if ($_order) : ?>
    <?php $_items = $_order->getAllItems(); ?>
        <?php foreach ($_items as $_item) : ?>
            <?php if (!$_item->getParentItem()) : ?>
                    <?= $block->getItemHtml($_item) ?>
            <?php endif; ?>
        <?php endforeach; ?>
        <tr>
            <td style="font-size: 18px;font-weight: bold;border-bottom: 1px solid #ccc;padding-bottom: 10px;font-family: Arial, Helvetica, sans-serif;">
                Order Total
            </td>
        </tr>

        <tr class="order-totals">
            <?= $block->getChildHtml('order_totals') ?>
        </tr>
       <?php if(count($_order->getInvoiceCollection())): 
        $objectManager =  \Magento\Framework\App\ObjectManager::getInstance(); 

        $storeManager = $objectManager->get('\Magento\Store\Model\StoreManagerInterface');
        $store = $storeManager->getStore();
        $baseUrl = $store->getBaseUrl();
        ?>
        <tr>
            <td style="text-align: center;font-family: Arial, Helvetica, sans-serif;">
                <a href="<?= $baseUrl ?>emailcustomisation/invoice/printinvoice/order_id/<?= $_order->getId() ?>" class="download" >Download
                </a>
            </td>
        </tr>
        <?php endif; ?>
    <?php if ($this->helper(\Magento\GiftMessage\Helper\Message::class)
            ->isMessagesAllowed('order', $_order, $_order->getStore())
        && $_order->getGiftMessageId()
    ) : ?>
        <?php $_giftMessage = $this->helper(\Magento\GiftMessage\Helper\Message::class)
            ->getGiftMessage($_order->getGiftMessageId()); ?>
        <?php if ($_giftMessage) : ?>
            <br />
            <table class="message-gift">
                <tr>
                    <td>
                        <h3><?= $block->escapeHtml(__('Gift Message for this Order')) ?></h3>
                        <strong><?= $block->escapeHtml(__('From:')) ?></strong> <?= $block->escapeHtml($_giftMessage->getSender()) ?>
                        <br /><strong><?= $block->escapeHtml(__('To:')) ?></strong> <?= $block->escapeHtml($_giftMessage->getRecipient()) ?>
                        <br /><strong><?= $block->escapeHtml(__('Message:')) ?></strong>
                        <br /><?= $block->escapeHtml($_giftMessage->getMessage()) ?>
                    </td>
                </tr>
            </table>
        <?php endif; ?>
    <?php endif; ?>
<?php endif; ?>

Step 3: Now navigate to the following file path

app\code\Vendor\Extension\etc\frontend\routes.xml

Then add the below code snippet

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="yourrouteid" frontName="yourfrountname">
            <module name="Vendor_Extension" />
        </route>
    </router>
</config>

Step 4: Next, you need to go to the below-mentioned file path

app\code\Vendor\Extension\Controller\Invoice\Printinvoice.php

And include the code as given below

<?php

namespace Vendor\Extension\Controller\Invoice;

use Magento\Framework\App\ResponseInterface;
use Magento\Framework\App\Filesystem\DirectoryList;

class Printinvoice extends \Magento\Framework\App\Action\Action
{
    /**
     * Authorization level of a basic admin session
     *
     * @see _isAllowed()
     */    const ADMIN_RESOURCE = 'Magento_Sales::sales_invoice';

    /**
     * @var \Magento\Framework\App\Response\Http\FileFactory
     */    protected $_fileFactory;

    /**
     * @var \Magento\Backend\Model\View\Result\ForwardFactory
     */    protected $resultForwardFactory;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory
     * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
     */    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\App\Response\Http\FileFactory $fileFactory,
        \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory,
        \Magento\Sales\Model\OrderFactory $order)
    {
        $this->_fileFactory = $fileFactory;
        parent::__construct($context);
        $this->resultForwardFactory = $resultForwardFactory;
        $this->order = $order;
    }

    /**
     * @return ResponseInterface|void
     * @throws \Exception
     */    public function execute()
    {
       $orderId = $this->getRequest()->getParam('order_id');
       $orderdetails = $this->order->create()->load($orderId);
        $invoiceId = 0;
        foreach ($orderdetails->getInvoiceCollection() as $invoice)
        {
            $invoiceId = $invoice->getId();
        }
        if ($invoiceId != 0)
        {
            $invoice = $this->_objectManager->create(
                \Magento\Sales\Api\InvoiceRepositoryInterface::class
            )->get($invoiceId);
            if ($invoice)
            {
                $pdf = $this->_objectManager->create(\Magento\Sales\Model\Order\Pdf\Invoice::class)->getPdf([$invoice]);
                $date = $this->_objectManager->get(
                    \Magento\Framework\Stdlib\DateTime\DateTime::class
                )->date('Y-m-d_H-i-s');
                $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true];

                return $this->_fileFactory->create(
                    'invoice' . $date . '.pdf',
                    $fileContent,
                    DirectoryList::VAR_DIR,
                    'application/pdf'
                );
            }
        }
        else
        {
            return;
            return $this->resultForwardFactory->create()->forward('noroute');
        }
    }
}

Step 5: In this step, move to the following file path

app\code\Vendor\Extension\Model\Order\Pdf\Invoice.php

Then incorporate the following piece of code

<?php

namespace Vendor\Extension\Model\Order\Pdf;

use PHPQRCode\QRcode;

class Invoice extends \Magento\Sales\Model\Order\Pdf\Invoice
{
    protected function _setFontBold($object, $size = 7)
    {
        $font = \Zend_Pdf_Font::fontWithPath($this->getFontPath());
        $object->setFont($font, $size);
        return $font;
    }

    public function newPage(array $settings = [])
    {
        $page = $this->_getPdf()->newPage(\Zend_Pdf_Page::SIZE_A4);
        $this->_getPdf()->pages[] = $page;
        $this->y = 800;
        if (!empty($settings['table_header']))
        {
            $this->_drawHeader($page);
        }
        return $page;
    }

    protected function _drawHeader(\Zend_Pdf_Page $page)
    {
        $this->_setFontRegular($page, 10);
        $page->setFillColor(new \Zend_Pdf_Color_RGB(0.93, 0.92, 0.92));
        $page->setLineColor(new \Zend_Pdf_Color_GrayScale(0.5));
        $page->setLineWidth(0.5);
        $page->drawRectangle(25, $this->y, 570, $this->y - 15);
        $this->y -= 10;
        $page->setFillColor(new \Zend_Pdf_Color_RGB(0, 0, 0));

        $taxableAmountText = $this->string->split('Taxable Amount', 8);
        $lines[0][] = ['text' => __('Products'), 'feed' => 35];
       
        $lines[0][] = ['text' => __('Qty'), 'feed' => 150, 'align' => 'right'];

        $lines[0][] = ['text' => __('Price'), 'feed' => 185, 'align' => 'right'];

        $lines[0][] = ['text' => __('Subtotal'), 'feed' => 235, 'align' => 'right'];
        $lines[0][] = ['text' => __('Discount'), 'feed' => 290, 'align' => 'right'];

        $lines[0][] = ['text' => __('Tax Amt'), 'feed' => 345, 'align' => 'right'];
        $lines[0][] = ['text' => __('Custom'), 'feed' => 400, 'align' => 'right'];
    
        $lines[0][] = ['text' => __('Row Total'), 'feed' => 570, 'align' => 'right'];

        $lineBlock = ['lines' => $lines, 'height' => 5, $this->y];

        $this->drawLineBlocks($page, [$lineBlock], ['table_header' => true]);
        $page->setFillColor(new \Zend_Pdf_Color_GrayScale(0));
        $this->y -= 20;
    }

    protected function _setFontRegular($object, $size = 7)
    {
        $font = \Zend_Pdf_Font::fontWithPath($this->getFontPath());
        $object->setFont($font, $size);
        return $font;
    }

   protected function _drawFooter(\Zend_Pdf_Page $page)
   {
        $this->_setFontRegular($page, 10);
        $this->y -= 10;
        $page->setFillColor(new \Zend_Pdf_Color_RGB(0, 0, 0));
    }
    protected function _setFontItalic($object, $size = 7)
    {
        $font = \Zend_Pdf_Font::fontWithPath($this->getFontPath());
        $object->setFont($font, $size);
        return $font;
    }
}

Step 6: At last, go to the below file path

app\code\Vendor\Extension\Model\Sales\Order\Pdf\Items\Invoice.php

And insert the below fragment of code

<?php
namespace Vendor\Extension\Model\Sales\Order\Pdf\Items;
use Magento\Bundle\Model\Sales\Order\Pdf\Items\Invoice as InvoiceDefualt;
class Invoice extends InvoiceDefualt
{
    public function draw()
    {
   $draw = $this->drawChildrenItems();
          $draw = $this->drawCustomOptions($draw);
  $page = $this->getPdf()->drawLineBlocks($this->getPage(), $draw, ['table_header' => true]);
  $this->setPage($page);
    }
    private function drawChildrenItems(): array
    {
        $this->_setFontRegular();
        $prevOptionId = '';
        $drawItems = [];
        $optionId = 0;
        $lines = [];
        foreach ($this->getChildren($this->getItem()) as $childItem)
        {
            $index = array_key_last($lines) !== null ? array_key_last($lines) + 1 : 0;
            $attributes = $this->getSelectionAttributes($childItem);
            if (is_array($attributes))
            {
                $optionId = $attributes['option_id'];
            }
            if (!isset($drawItems[$optionId]))
            {
                $drawItems[$optionId] = ['lines' => [], 'height' => 15];
            }
            if ($childItem->getOrderItem()->getParentItem() && $prevOptionId !=   $attributes['option_id'])
            {
                $lines[$index][] = [
                    'font' => 'italic',
                    'text' => $this->string->split($attributes['option_label'], 35, true, true),
                    'feed' => 35,
                ];
                $index++;
                $prevOptionId = $attributes['option_id'];
            }
            if ($childItem->getOrderItem()->getParentItem())
            {
                $feed = 30;
                $name = $this->getValueHtml($childItem)."<br /> SKU :".$childItem-   >getSku();
            }
            else
            {
                $feed = 25;
                $name = $childItem->getName();
            }
            $lines[$index][] = ['text' => $this->string->split($name, 15, true, true), 'feed' => $feed];
            if ($this->canShowPriceInfo($childItem))
            {
             $tax = $this->getOrder()->formatPriceTxt($childItem->getTaxAmount());
             $item = $this->getItem();
             $this->_item = $childItem;
             $feedPrice = 140;
             $feedSubtotal = $feedPrice + 185;
             foreach ($this->getItemPricesForDisplay() as $priceData)
             {
                 if (isset($priceData['label']))
                 {
                     // draw Price label
                     $lines[$index][] = ['text' => $priceData['label'], 'feed' => $feedPrice, 'align' => 'right'];

                     // draw Subtotal label
                     $lines[$index][] = ['text' => $priceData['label'], 'feed' => $feedSubtotal, 'align' => 'right'];
                     $index++;
                 }
                 $lines[$index][] = [
                     'text' => round($childItem->getQty(), 2),
                     'feed' => $feedPrice,
                     'font' => 'bold',
                     'align' => 'right',
                 ];
                 // draw Price
                 $lines[$index][] = [
                     'text' => $priceData['price'],
                     'feed' => $feedPrice+40,
                     'font' => 'bold',
                     'align' => 'right',
                 ];
                 // draw Subtotal
                 $lines[$index][] = [
                     'text' => $priceData['subtotal'],
                     'feed' => $feedPrice+90,
                     'font' => 'bold',
                     'align' => 'right',
                 ];
                 $lines[$index][] = [
                     'text' => round($childItem->getDiscountAmount(), 2),
                     'feed' => $feedPrice+130,
                     'font' => 'bold',
                     'align' => 'right',
                 ];

                 $lines[$index][] = [
                     'text' => $tax,
                     'feed' => $feedPrice+200,
                     'font' => 'bold',
                     'align' => 'right',
                 ];
                 $lines[$index][] = [
                 'text' => "Custom",
                 'feed' => $feedPrice+260,
                 'font' => 'bold',
                 'align' => 'right',
                 ];
                 $lines[$index][] = [
                     'text' => $this->getOrder()->formatPriceTxt($childItem->getRowTotal()+$childItem->getTaxAmount()),
                     'feed' => $feedSubtotal+230,
                     'font' => 'bold',
                     'align' => 'right',
                 ];
                 $index++;
             }
             $this->_item = $item;
         }
         /* drawPrices End */        }
        $drawItems[$optionId]['lines'] = $lines;
        return $drawItems;
    }
  
    private function drawCustomOptions(array $draw): array
    {
        $options = $this->getItem()->getOrderItem()->getProductOptions();
        if ($options && isset($options['options']))
        {
            foreach ($options['options'] as $option)
            {
                $lines = [];
                $lines[][] = [
                    'text' => $this->string->split(
                        $this->filterManager->stripTags($option['label']),
                        40,
                        true,
                        true
                    ),
                    'font' => 'italic',
                    'feed' => 35,
                ];
                if ($option['value'])
                {
                    $text = [];
                    $printValue = $option['print_value'] ?? $this->filterManager->stripTags($option['value']);
                    $values = explode(', ', $printValue);
                    foreach ($values as $value)
                    {
                        foreach ($this->string->split($value, 30, true, true) as $subValue)
                        {
                            $text[] = $subValue;
                        }
                    }
                    $lines[][] = ['text' => $text, 'feed' => 40];
                }
                $draw[] = ['lines' => $lines, 'height' => 15];
            }
        }
        return $draw;
    }
}

Step 7: Finally, run the below commands

php bin/magento cache:flush
php bin/magento setup:di:compile

Conclusion:

With the help of the above-given steps, you can easily add download invoice button to order emails and improve the user experience. If you have difficulty in the above steps, let me know through the comment box. Share the article with your friends and stay in touch with us for more solutions.

Happy Coding!

Click to rate this post!
[Total: 4 Average: 5]
Dhiren Vasoya

Dhiren Vasoya is a Director and Co-founder at MageComp, Passionate 🎖️ Certified Magento Developer👨‍💻. He has more than 9 years of experience in Magento Development and completed 850+ projects to solve the most important E-commerce challenges. He is fond❤️ of coding and if he is not busy developing then you can find him at the cricket ground, hitting boundaries.🏏

Recent Posts

How to Integrate ChatGPT with Laravel Application?

In this guide, we'll explore how to integrate ChatGPT, an AI-powered chatbot, with a Laravel…

2 days ago

What are Net Sales? How to Calculate Your Net Sales?

In the world of business, understanding financial metrics is crucial for making informed decisions and…

4 days ago

Magento 2 Extensions Digest April 2024 (New Release & Updates)

Welcome to the MageComp Monthly Digest, where we bring you the latest updates, releases, and…

4 days ago

The ABCs of Geofencing: Definition, Features and Uses

In this era, businesses are always on the lookout for ways to engage with their…

5 days ago

How to Delete Product Variant in a Shopify Remix App using GraphQL Mutations?

Managing a Shopify store efficiently involves keeping your product catalog organized. This includes removing outdated…

6 days ago

6 Innovative Tools Revolutionizing E-Commerce Operations

E-commerce has transformed the way consumers shop for products and services and interact with businesses.…

1 week ago