How To

How to Change Order PDF Format in Magento 2

In an E-commerce Businesses, order emails & E-Documents provide evidence that products or services are sold to the customers. However, for tax purposes, it is essential to record and maintain all sales details. In this digital world, things changed with a time where store owners manually kept track of everything. Instead, now it’s easier to rely on Various CMS’s that automate the whole process & save times, efforts by going green.

In Magento 2, managing all these things are as easy as pie. Once an order is placed by customer all you can quickly generate an invoice, shipment, credit memo, and order pdf just by clicking a button. Also, it sends an email notification to both store customer and admin. Besides all of these things, Magento provides an option to generate and download order PDF that holds complete information of the buyer, seller as well as a product that has been sold. Because every business is different, the store owner has to modify all these E-Documents according to their business needs, after all, it served as evidence and provides legal protection for both parties. So, we are back with another blog series that will help you expand default Magento Order PDF by adding some more useful elements to pdf.

Here, we have added PAN number of the admin below every Invoice number and displayed buyer PAN Number with Billing & Shipping Address inside PDF. To do the same follow these pretty steps that will help you to change order PDF Format in Magento 2.

To do the same, first we need to override model of invoice PDF inside our custom extension folder.
app\code\Vendor\Extension\etc\adminhtml\di.xml

<pre class="lang:default decode:true">
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
 
   <preference for="Magento\Sales\Model\Order\Pdf\Invoice" type="Vendor\Extension\Model\Order\Pdf\Invoice" />
</config>
</pre>

Now you need to create model file named ‘invoice.php’ and paste below code inside that file.
app\code\Vendor\Extension\Model\Order\Pdf\Invoice.php

<pre class="lang:default decode:true">
<?php
namespace Vendor\Extension\Model\Order\Pdf;
class Invoice extends \Magento\Sales\Model\Order\Pdf\Invoice
{     
    protected function insertOrder(&$page, $obj, $putOrderId = true)
    {
        if ($obj instanceof \Magento\Sales\Model\Order) {
            $shipment = null;
            $order = $obj;
        } elseif ($obj instanceof \Magento\Sales\Model\Order\Shipment) {
            $shipment = $obj;
            $order = $shipment->getOrder();
        }
        $customerId = $order->getCustomerId();
        $this->y = $this->y ? $this->y : 815;
        $top = $this->y;
 
        $page->setFillColor(new \Zend_Pdf_Color_GrayScale(0.45));
        $page->setLineColor(new \Zend_Pdf_Color_GrayScale(0.45));
        $page->drawRectangle(25, $top, 570, $top - 200);
        $page->setFillColor(new \Zend_Pdf_Color_GrayScale(1));
        $this->setDocHeaderCoordinates([25, $top, 570, $top - 55]);
        $this->_setFontRegular($page, 10);
 
        if ($putOrderId) {
            $page->drawText(__('Order # ') . $order->getRealOrderId(), 35, $top -= 30, 'UTF-8');
        }
        $page->drawText(
            __('Order Date:: ') .
         $this->_localeDate->formatDate(
                $this->_localeDate->scopeDate(
                 $order->getStore(),
                 $order->getCreatedAt(),
                 true
                ),
                \IntlDateFormatter::MEDIUM,
             false
            ),
            35,
            $top -= 15,
            'UTF-8'
        );
                 
      $page->drawText(__('Tax Invoice/Bill of Supply/Cash Memo'), 325, $top +=30 , 'UTF-8');
      $page->drawText(__('PAN NUMBER : AMPD2354680') 325, $top -= 15, 'UTF-8');
             $top -= 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, $top, 275, $top - 25);
             $page->drawRectangle(275, $top, 570, $top - 25);
 
        /* Calculate blocks info */ 
        /* Billing Address */        $billingAddress = $this->_formatAddress($this->addressRenderer->format($order->getBillingAddress(), 'pdf'));
        $billingAddress[]="Buyer PAN  Number :".$order->getBuyerPanNumber(); 
                     
        /* Payment */        $paymentInfo = $this->_paymentData->getInfoBlock($order->getPayment())->setIsSecureMode(true)->toPdf();
        $paymentInfo = htmlspecialchars_decode($paymentInfo, ENT_QUOTES);
        $payment = explode('{{pdf_row_separator}}', $paymentInfo);
        foreach ($payment as $key => $value) {
            if (strip_tags(trim($value)) == '') {
                unset($payment[$key]);
            }
        }
        reset($payment);
 
         if (!$order->getIsVirtual()) {
            /* Shipping Address */            $shippingAddress = $this->_formatAddress($this->addressRenderer->format($order->getShippingAddress(), 'pdf'));
            $shippingAddress[]="Buyer PAN Number :".$order->getBuyerPanNumber(); 
            $shippingMethod = $order->getShippingDescription();
        }
 
        $page->setFillColor(new \Zend_Pdf_Color_GrayScale(0));
        $this->_setFontBold($page, 12);
        $page->drawText(__('Sold to:'), 35, $top - 15, 'UTF-8');
 
        if (!$order->getIsVirtual()) {
            $page->drawText(__('Ship to:'), 285, $top - 15, 'UTF-8');
        } else {
            $page->drawText(__('Payment Method:'), 285, $top - 15, 'UTF-8');
        }
 
        $addressesHeight = $this->_calcAddressHeight($billingAddress);
        if (isset($shippingAddress)) {
            $addressesHeight = max($addressesHeight, $this->_calcAddressHeight($shippingAddress));
        }
 
        $page->setFillColor(new \Zend_Pdf_Color_GrayScale(1));
        $page->drawRectangle(25, $top - 25, 570, $top - 33 - $addressesHeight);
        $page->setFillColor(new \Zend_Pdf_Color_GrayScale(0));
        $this->_setFontRegular($page, 10);
        $this->y = $top - 40;
        $addressesStartY = $this->y;
 
        foreach ($billingAddress as $value) {
            if ($value !== '') {
                $text = [];
                foreach ($this->string->split($value, 45, true, true) as $_value) {
                 $text[] = $_value;
                }
                foreach ($text as $part) {
                    $page->drawText(strip_tags(ltrim($part)), 35, $this->y, 'UTF-8');
                 $this->y -= 15;
                }
            }
        }
 
        $addressesEndY = $this->y;
 
        if (!$order->getIsVirtual()) {
            $this->y = $addressesStartY;
            foreach ($shippingAddress as $value) {
                if ($value !== '') {
                 $text = [];
                 foreach ($this->string->split($value, 45, true, true) as $_value) {
                     $text[] = $_value;
                 }
                 foreach ($text as $part) {
                        $page->drawText(strip_tags(ltrim($part)), 285, $this->y, 'UTF-8');
                     $this->y -= 15;
                 }
                }
            }
 
            $addressesEndY = min($addressesEndY, $this->y);
            $this->y = $addressesEndY;
 
            $page->setFillColor(new \Zend_Pdf_Color_Rgb(0.93, 0.92, 0.92));
            $page->setLineWidth(0.5);
            $page->drawRectangle(25, $this->y, 275, $this->y - 25);
            $page->drawRectangle(275, $this->y, 570, $this->y - 25);
 
            $this->y -= 15;
            $this->_setFontBold($page, 12);
            $page->setFillColor(new \Zend_Pdf_Color_GrayScale(0));
            $page->drawText(__('Payment Method'), 35, $this->y, 'UTF-8');
            $page->drawText(__('Shipping Method:'), 285, $this->y, 'UTF-8');
 
            $this->y -= 10;
            $page->setFillColor(new \Zend_Pdf_Color_GrayScale(1));
 
            $this->_setFontRegular($page, 10);
            $page->setFillColor(new \Zend_Pdf_Color_GrayScale(0));
 
            $paymentLeft = 35;
            $yPayments = $this->y - 15;
        } else {
            $yPayments = $addressesStartY;
            $paymentLeft = 285;
        }
 
        foreach ($payment as $value) {
            if (trim($value) != '') {
                //Printing "Payment Method" lines
                $value = preg_replace('/<br[^>]*>/i', "\n", $value);
                foreach ($this->string->split($value, 45, true, true) as $_value) {
                    $page->drawText(strip_tags(trim($_value)), $paymentLeft, $yPayments, 'UTF-8');
                 $yPayments -= 15;
                }
            }
        }
 
        if ($order->getIsVirtual()) {
            // replacement of Shipments-Payments rectangle block
            $yPayments = min($addressesEndY, $yPayments);
            $page->drawLine(25, $top - 25, 25, $yPayments);
            $page->drawLine(570, $top - 25, 570, $yPayments);
            $page->drawLine(25, $yPayments, 570, $yPayments);
 
            $this->y = $yPayments - 15;
        } else {
            $topMargin = 15;
            $methodStartY = $this->y;
            $this->y -= 15;
 
            foreach ($this->string->split($shippingMethod, 45, true, true) as $_value) {
                $page->drawText(strip_tags(trim($_value)), 285, $this->y, 'UTF-8');
                $this->y -= 15;
            }
 
            $yShipments = $this->y;
            $totalShippingChargesText = "(" . __(
                 'Total Shipping Charges'
                ) . " " . $order->formatPriceTxt(
                    $order->getShippingAmount()
                ) . ")";
 
            $page->drawText($totalShippingChargesText, 285, $yShipments - $topMargin, 'UTF-8');
            $yShipments -= $topMargin + 10;
 
            $tracks = [];
            if ($shipment) {
                $tracks = $shipment->getAllTracks();
         }
            if (count($tracks)) {
                $page->setFillColor(new \Zend_Pdf_Color_Rgb(0.93, 0.92, 0.92));
                $page->setLineWidth(0.5);
                $page->drawRectangle(285, $yShipments, 510, $yShipments - 10);
                $page->drawLine(400, $yShipments, 400, $yShipments - 10);             
 
                $this->_setFontRegular($page, 9);
                $page->setFillColor(new \Zend_Pdf_Color_GrayScale(0));
               
                $page->drawText(__('Title'), 290, $yShipments - 7, 'UTF-8');
                $page->drawText(__('Number'), 410, $yShipments - 7, 'UTF-8');
 
                $yShipments -= 20;
                $this->_setFontRegular($page, 8);
                foreach ($tracks as $track) {
                 $maxTitleLen = 45;
                 $endOfTitle = strlen($track->getTitle()) > $maxTitleLen ? '...' : '';
                 $truncatedTitle = substr($track->getTitle(), 0, $maxTitleLen) . $endOfTitle;
                 $page->drawText($truncatedTitle, 292, $yShipments, 'UTF-8');
                    $page->drawText($track->getNumber(), 410, $yShipments, 'UTF-8');
                 $yShipments -= $topMargin - 5;
                }
            } else {
                $yShipments -= $topMargin - 5;
            }
 
            $currentY = min($yPayments, $yShipments);
 
            // replacement of Shipments-Payments rectangle block
            $page->drawLine(25, $methodStartY, 25, $currentY);
            //left
            $page->drawLine(25, $currentY, 570, $currentY);
            //bottom
            $page->drawLine(570, $currentY, 570, $methodStartY);
         $this->_drawFooter($page);
            //right
 
            $this->y = $currentY;
            $this->y -= 15;
        }
 }
    protected function _drawHeader(\Zend_Pdf_Page $page)
 {
        /* Add table head */        $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, 670, $this->y - 15);
        $this->y -= 10;
        $page->setFillColor(new \Zend_Pdf_Color_RGB(0, 0, 0));
 
        //columns headers
    $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' => __('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;
 }
    public function getPdf($invoices = [])
 {
        $this->_beforeGetPdf();
        $this->_initRenderer('invoice');
 
        $pdf = new \Zend_Pdf();
        $this->_setPdf($pdf);
        $style = new \Zend_Pdf_Style();
        $this->_setFontBold($style, 10);
 
        foreach ($invoices as $invoice) {
            if ($invoice->getStoreId()) {
                $this->_localeResolver->emulate($invoice->getStoreId());
                $this->_storeManager->setCurrentStore($invoice->getStoreId());
            }
            $page = $this->newPage();
            $order = $invoice->getOrder();
            /* Add image */            $this->insertLogo($page, $invoice->getStore());
            /* Add address */            $this->insertAddress($page, $invoice->getStore());
            /* Add head */            $this->insertOrder(
                $page,
                $order,
                $this->_scopeConfig->isSetFlag(
                    self::XML_PATH_SALES_PDF_INVOICE_PUT_ORDER_ID,
                    \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
                 $order->getStoreId()
                )
            );
            /* Add document text and number */            $this->insertDocumentNumber($page, __('Invoice # ') . $invoice->getIncrementId());
            /* Add table */            $this->_drawHeader($page);
            /* Add body */            foreach ($invoice->getAllItems() as $item) {
                if ($item->getOrderItem()->getParentItem()) {
                 continue;
                }
                /* Draw item */                $this->_drawItem($item, $page, $order);
                $page = end($pdf->pages);
            }
            /* Add totals */            $this->insertTotals($page, $invoice);
 
            if ($invoice->getStoreId()) {
                $this->_localeResolver->revert();
            }
                                 
        }
                     
        $this->_afterGetPdf();
        return $pdf;
 }
         
protected function _drawFooter(\Zend_Pdf_Page $page)
{
        $this->_setFontRegular($page, 10);
        $this->y -= 10;
        $page->setFillColor(new \Zend_Pdf_Color_RGB(0, 0, 0));    
 }
 
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 _setFontRegular($object, $size = 7)
 {
        $font = \Zend_Pdf_Font::fontWithPath(
        $this->_rootDirectory->getAbsolutePath('lib/internal/DejavuSans/ttf/DejaVuSans.ttf')
        );
        $object->setFont($font, $size);
        return $font;
 }
 protected function _setFontBold($object, $size = 7)
 {
        $font = \Zend_Pdf_Font::fontWithPath(
            $this->_rootDirectory->getAbsolutePath('lib/internal/DejavuSans/ttf/DejaVuSans.ttf')
        );
        $object->setFont($font, $size);
        return $font;
 }
          protected function _setFontItalic($object, $size = 7)
 {
        $font = \Zend_Pdf_Font::fontWithPath(
            $this->_rootDirectory->getAbsolutePath('lib/internal/DejavuSans/ttf/DejaVuSans.ttf')
        );
        $object->setFont($font, $size);
        return $font;
 }      
}
</pre>

And that’s it! We have successfully added PAN number to order PDF as we needed. You can use this code according to your need for adding or one or more elements to your Order PDF.

If you need any help regarding this code, simply leave a comment below and don’t forget to smash that stars if you found this blog helpful.

Happy Coding!

Click to rate this post!
[Total: 11 Average: 4.6]
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.🏏

View Comments

  • ParseError: syntax error, unexpected '<' in /var/www/html/magento240/app/code/Vendor/Extension/Model/Order/Pdf/Invoice.php:59 Stack trace: #0 /var/www/html/magento240/vendor/composer/ClassLoader.php(322):

Recent Posts

Magento 2: Add Quantity Increment and Decrement on Category Page

Hello Magento Friends, In this blog, we will discuss about adding quantity increment and decrement…

1 day ago

How to Integrate ChatGPT with Laravel Application?

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

4 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…

7 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…

7 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…

1 week 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…

1 week ago