1

I wan to edit the totals of Invoice print in PDF format. If it was HTML page than its easy to inspect it. But I can't find where i can adjust the widht of a cell.

As you can see the Discount text is overlapping. The file involved in printing is this. enter image description here

And here the code of my printing php file

app/code/Catwalk/InvoicePdf/Model/Order/Pdf/Items/Invoice/DefaultInv.php

 <?php

namespace Catwalk\InvoicePdf\Model\Order\Pdf\Items\Invoice;

use Magento\Catalog\Model\Product;
use Magento\Sales\Model\Order\Pdf\Items\Invoice\DefaultInvoice;

class DefaultInv extends DefaultInvoice
{
    protected $product;
    protected $_assetRepo;
    protected $_storeManager;
    protected $dirctory;
    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Tax\Helper\Data $taxData,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\Framework\Filter\FilterManager $filterManager,
        \Magento\Framework\Stdlib\StringUtils $string,
        Product $_product,
        \Magento\Framework\View\Asset\Repository $assetRepo,
        \ Magento\Framework\App\Filesystem\DirectoryList  $dirctory,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \
        Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = []
    )
    {
        $this->product = $_product;
        $this->dirctory = $dirctory;
        $this->_storeManager = $storeManager;
        $this->_assetRepo = $assetRepo;
        parent::__construct($context, $registry, $taxData, $filesystem, $filterManager, $string, $resource, $resourceCollection, $data);
    }

    /**
     * Draw item line
     *
     * @return void
     */
    public function draw()
    {
        $order = $this->getOrder();
        $item = $this->getItem();
        $pdf = $this->getPdf();
        $page = $this->getPage();
        $lines = [];

        $productImage = $this->getProductImage($item, $page);
        // draw Product name
        $lines[0] = [['text' => $this->string->split($item->getName(), 35, true, true), 'feed' => 35]];
        $lines[0][] = array(
            'text'  => $productImage,
            'is_image'  => 1,
            'feed'  => 210
        );
        // draw SKU
        $lines[0][] = [
            'text' => $this->string->split($this->getSku($item), 17),
            'feed' => 290,
            'align' => 'right',
        ];

        // draw QTY
        $lines[0][] = ['text' => $item->getQty() * 1, 'feed' => 435, 'align' => 'right'];

        // draw item Prices
        $i = 0;
        $prices = $this->getItemPricesForDisplay();
        $feedPrice = 355;
        $feedSubtotal = $feedPrice + 160;
        foreach ($prices as $priceData) {
            if (isset($priceData['label'])) {
                // draw Price label
                $lines[$i][] = ['text' => $priceData['label'], 'feed' => $feedPrice, 'align' => 'right'];
                // draw Subtotal label
                $lines[$i][] = ['text' => $priceData['label'], 'feed' => $feedSubtotal, 'align' => 'right'];
                $i++;
            }
            // draw Price
            $lines[$i][] = [
                'text' => $priceData['price'],
                'feed' => $feedPrice,
                'font' => 'bold',
                'align' => 'right',
            ];
            // draw Subtotal
            $lines[$i][] = [
                'text' => $priceData['subtotal'],
                'feed' => $feedSubtotal,
                'font' => 'bold',
                'align' => 'right',
            ];
            $i++;
        }

        // draw Tax
        $lines[0][] = [
            'text' => $order->formatPriceTxt($item->getTaxAmount()),
            'feed' => 465,
            'font' => 'bold',
            'align' => 'right',
        ];

        // custom options
        $options = $this->getItemOptions();
        if ($options) {
            foreach ($options as $option) {
                // draw options label
                $lines[][] = [
                    'text' => $this->string->split($this->filterManager->stripTags($option['label']), 40, true, true),
                    'font' => 'italic',
                    'feed' => 35,
                ];

                if ($option['value']) {
                    if (isset($option['print_value'])) {
                        $printValue = $option['print_value'];
                    } else {
                        $printValue = $this->filterManager->stripTags($option['value']);
                    }
                    $values = explode(', ', $printValue);
                    foreach ($values as $value) {
                        $lines[][] = ['text' => $this->string->split($value, 30, true, true), 'feed' => 40];
                    }
                }
            }
        }

        $lineBlock = ['lines' => $lines, 'height' => 20];

        $page = $pdf->drawLineBlocks($page, [$lineBlock], ['table_header' => true],1);
        $this->setPage($page);
    }

    /*
    * Return Value of custom attribute
    * */
    private function getProductImage($item,  &$page)
    {
        $productId = $item->getOrderItem()->getProductId();
        $product = $this->product->load($productId);
        $image = $product->getSmallImage();
        $filePath = null;
        $extension = strtolower(pathinfo($image, PATHINFO_EXTENSION));

        if (!is_null($image) && $extension !== "gif") {
            $imagePath = '/catalog/product'.$image;
            $media = $this->dirctory->getPath(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
            $filePath = $media.$imagePath;
            if (!file_exists($filePath)) {
                $filePath = $this->getProductPlaceholderPath();
            }
        } else {
            $filePath = $this->getProductPlaceholderPath();
        }

        if (!file_exists($filePath)) {
           return null;
        }

        return $filePath;
    }
    public function getProductPlaceholderPath()
    {
        $placeholderPath = $this->_assetRepo->createAsset('Magento_Catalog::images/product/placeholder/small_image.jpg')->getPath();
        $staticPath = $this->dirctory->getPath('static');
        return $staticPath . '/' . $placeholderPath;
    }
}

line 77

 $lines[$i][] = ['text' => $priceData['label'], 'feed' => $feedPrice, 'align' => 'right'];

I want to give more width to this total section, to adjust bigger text values enter image description here

3 Answers 3

3

Your totals are left aligned, which is the issue here. When you change them to right alignment (which is default for Magento 2.4.5-p1) it will fix your problem.

In order to change the totals you have to overwrite \Magento\Sales\Model\Order\Pdf\AbstractPdf::insertTotals so in case of an invoice you will have to overwrite \Magento\Sales\Model\Order\Pdf\Invoice via preference.

In your new class extend \Magento\Sales\Model\Order\Pdf\Invoice and add the method insertTotals:

    /**
     * Insert totals to pdf page
     *
     * @param  \Zend_Pdf_Page $page
     * @param  \Magento\Sales\Model\AbstractModel $source
     * @return \Zend_Pdf_Page
     */
    protected function insertTotals($page, $source)
    {
        $order = $source->getOrder();
        $totals = $this->_getTotalsList();
        $lineBlock = ['lines' => [], 'height' => 15];
        foreach ($totals as $total) {
            $total->setOrder($order)->setSource($source);

            if ($total->canDisplay()) {
                $total->setFontSize(10);
                foreach ($total->getTotalsForDisplay() as $totalData) {
                    $lineBlock['lines'][] = [
                        [
                            'text' => $totalData['label'],
                            'feed' => 475, // you can decrease the offset to increase the width
                            'align' => 'right', // this will fix your issue
                            'font_size' => $totalData['font_size'],
                            'font' => 'bold',
                        ],
                        [
                            'text' => $totalData['amount'],
                            'feed' => 565,
                            'align' => 'right',
                            'font_size' => $totalData['font_size'],
                            'font' => 'bold'
                        ],
                    ];
                }
            }
        }

        $this->y -= 20;
        $page = $this->drawLineBlocks($page, [$lineBlock]);
        return $page;
    }

You can see the 'align' key within the array, you can change it as you need.

If you want to keep the left alignment you have the option to change the value for the 'feed' key, which defines the x offset of the text. You must decrease the value to increase the width of the "column".

I made some screenshots to show you the differences:
feed=475, align=left which is your case align_left

feed=475, align=right align_right

feed=400, align=left align_left_with_decreased_offset

Generally I would recommend using the right alignment because then you are not bound by the length of the label. If you keep align left and your label length increases you will run into the same problem again.

4
  • Hi Daniel, I want to give more width to this total section, to adjust bigger text labels. May 16, 2023 at 13:46
  • Oups didn't saw this answer Sry Daniel.
    – Claims
    May 16, 2023 at 15:13
  • Hi @SanaullahAhmad, this should answer your question already but I made some improvements to clarify how it works.
    – Daniel
    May 16, 2023 at 16:35
  • 1
    Thank @Daniel yes its working now. May 17, 2023 at 11:13
1

If you look at the method drawLineBlocks you will see she is called in AbstractPdf this class has two properties which are x and y so if you want to change their values you need to extends these methods from AbstractPdf...but it's quite annoying to do as kinda all objects like page have their own x and y. You can check methods like insertOrder in that class where you can see how it's really done

1

I'm going to go with a completely different answer to everyone else, honestly I don't know why the invoice rendering system in Magento 2 is still so antiquated. I had to customise the invoice for a client recently and I decided to install eadesignro/module-pdfgenerator from https://github.com/EaDesgin/magento2-pdf-generator2. Normally I hate installing using anything other than composer packages but this did just what I needed.

Some issues however:

  • I could not install it using composer in Magento Commerce (certainly you will also encounter with open-source edition) 2.4.5-p1 as we are running on php 8.1 so installed in app/code,
  • The html-to-pdf library (mpdf/mpdf) was causing issue so I replaced with dompdf/dompdf ^2.0.

I updated Eadesigndev\Pdfgenerator\Helper::eaPDFSettings() to look like:

$oldErrorReporting = error_reporting();

$pdf = new Dompdf(['is_remote_enabled' => true]);
// When developing locally we use a self-signed cert and need to disable the security checks
if ($this->appState->getMode() === State::MODE_DEVELOPER) {
    $context = stream_context_create([
        'ssl' => [
           'allow_self_signed'=> true,
           'verify_peer' => false,
           'verify_peer_name' => false,
        ]
    ]);
    $pdf->setHttpContext($context);
}
//@codingStandardsIgnoreLine
$pdf->loadHtml(html_entity_decode($parts['body']));
$pdf->render();
$pdfToOutput = $pdf->output();

error_reporting($oldErrorReporting);

return $pdfToOutput;

NOTE: Only use is_remote_enabled can open vulnerabilities if risks are not correctly managed. (audit admin user account, set ACL permissions correctly, etc). I also set the ssl values due to local testing and as you can see this is bypassed in prod mode for security reasons. I also added use Magento\Framework\App\State to my __construct() and added Dompdf\Dompdf to my includes.

The module essentially allows you to use the email template format in M2 for generating PDF invoices.

Hope it helps.

If this is the correct answer please mark it "accepted" as it makes it easier for others with the same issue to find the answer.

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.