1

Has anyone added a customer email address to the PDF invoice in a recent version of Magento, there is a nice example for an older version from Elgentos here:

How do I add a customer's email to the sales invoice?

I am pretty new to Magento, but I can see the module needs registering in a different way etc for recent versions and I am unsure if it can even be taken across.

ChrisC
  • 46
  • 7

4 Answers4

1

Firstly, a little bit of theory. The following model's function getPdf renders invoice's data:

vendor/magento/module-sales/Model/Order/Pdf/Invoice.php

To be more specific, the function insertOrder of the parent's class

vendor/magento/module-sales/Model/Order/Pdf/AbstractPdf.php

adds customer's data to the final PDF.

So, in order to write a customer's email in the Invoice's pdf, we can do the following:

1) Create di.xml inside of your module's etc directory:

<?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="YourVendor\YourModule\Model\Order\Pdf\Invoice" />
</config>

2) Create the model YourVendor\YourModule\Model\Order\Pdf\Invoice:

<?php
namespace YourVendor\YourModule\Model\Order\Pdf;

class Invoice extends \Magento\Sales\Model\Order\Pdf\Invoice
{
    protected function insertOrder(&$page, $obj, $putOrderId = true)
    {
        parent::insertOrder($page, $obj, $putOrderId);

        /**
         * Here we add the customer's email to the pdf
         */
        $order = $obj;
        $x = 450;
        $y = 705;
        $page->drawText($order->getShippingAddress()->getEmail(), $x, $y, 'UTF-8');
    }
}

3) Flush the cache.

That's it! Now, when you print your invoice, you'll see a neat customer's email writing at the top of the PDF.

You can move the writing wherever you like by changing x and y values.

Note: I've just tested my code in M2 CE 2.2.6, it works nicely there.

  • Thank you so much for the proposed solution Nikita, but I would really like a solution that extended the customer address, in that way all the customers contact data would be grouped together and the framing would adjust to the extra data. – ChrisC Oct 15 '18 at 11:56
  • Okay, Chris, I'll provide you updates a little bit later tonight – Nikita Abrashnev Oct 15 '18 at 16:34
  • Chris - please try now. I've updated the email's position to be inside of the shipping address box. – Nikita Abrashnev Oct 15 '18 at 19:22
  • Nikita - does this work in production mode? I don't see any changes when trying the code. Don't you need to create a module like this example: (https://magento.stackexchange.com/questions/122287/how-to-create-simple-module-in-magento-2) – ChrisC Oct 22 '18 at 14:37
  • @ChrisC - yep, you do need to create a new module. My example is based on creation of a new module, then creating di.xml and a new model in it. You never have to change files in the vendor directory manually. – Nikita Abrashnev Oct 22 '18 at 14:45
  • All works now thanks, I had to change the co-ordinates as the logo and address moved things about. This is a good temporary solution, but any changes to address or logo can throw the email address into a undesirable area. I am going to try and work on looking at extending the address field, that way everything should be in the correct place. – ChrisC Oct 22 '18 at 15:42
1

I know its bad form to post an answer to your own question, but it may help others who wish to add the email to the address.

Add di.xml in modules app/code/myvendorname/mymodulename/etc directory:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Customer\Block\Address\Renderer\DefaultRenderer"
 type="myvendorname\mymodulename\Block\Address\Renderer\DefaultRenderer"/> 
</config>

Add module.xml to the same directory:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="mymodulename" setup_version="1.0.0">
</module>
</config>

Add registration.php to the app/code/myvendorname/mymodulename directory:

<?php 
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'mymodulename',
__DIR__
);

Add DefaultRenderer.php to app/code/myvendorname/mymodulename/Block/Address/Renderer/

<?php
namespace myvendorname/mymodulename\Block\Address\Renderer;

use Magento\Customer\Model\Address\Mapper; use Magento\Customer\Model\Metadata\ElementFactory;

class DefaultRenderer extends \Magento\Customer\Block\Address\Renderer\DefaultRenderer {

protected $_customerMetadataService;

public function __construct( \Magento\Framework\View\Element\Context $context, ElementFactory $elementFactory, \Magento\Directory\Model\CountryFactory $countryFactory, \Magento\Customer\Api\AddressMetadataInterface $metadataService, Mapper $addressMapper, \Magento\Customer\Api\CustomerMetadataInterface $customerMetadataService, array $data = [] ) { parent::__construct($context, $elementFactory, $countryFactory, $metadataService, $addressMapper, $data); $this->_customerMetadataService = $customerMetadataService; }

/**

  • {@inheritdoc}
  • @SuppressWarnings(PHPMD.CyclomaticComplexity)
  • @SuppressWarnings(PHPMD.NPathComplexity)

*/ public function renderArray($addressAttributes, $format = null) { switch ($this->getType()->getCode()) { case 'html': $dataFormat = ElementFactory::OUTPUT_FORMAT_HTML; break; case 'pdf': $dataFormat = ElementFactory::OUTPUT_FORMAT_PDF; break; case 'oneline': $dataFormat = ElementFactory::OUTPUT_FORMAT_ONELINE; break; default: $dataFormat = ElementFactory::OUTPUT_FORMAT_TEXT; break; }

$attributesMetadata = $this->_addressMetadataService->getAllAttributesMetadata(); if (null !== $this->_customerMetadataService->getAttributeMetadata('email')) { $attributesMetadata[] = $this->_customerMetadataService->getAttributeMetadata('email'); }

$data = []; foreach ($attributesMetadata as $attributeMetadata) { if (!$attributeMetadata->isVisible()) { continue; } $attributeCode = $attributeMetadata->getAttributeCode(); if ($attributeCode == 'country_id' && isset($addressAttributes['country_id'])) { $data['country'] = $this->_countryFactory->create()->loadByCode( $addressAttributes['country_id'] )->getName(); } elseif ($attributeCode == 'region' && isset($addressAttributes['region'])) { $data['region'] = __($addressAttributes['region']); } elseif (isset($addressAttributes[$attributeCode])) { $value = $addressAttributes[$attributeCode]; $dataModel = $this->_elementFactory->create($attributeMetadata, $value, 'customer_address'); $value = $dataModel->outputValue($dataFormat); if ($attributeMetadata->getFrontendInput() == 'multiline') { $values = $dataModel->outputValue(ElementFactory::OUTPUT_FORMAT_ARRAY); // explode lines foreach ($values as $k => $v) { $key = sprintf('%s%d', $attributeCode, $k + 1); $data[$key] = $v; } } $data[$attributeCode] = $value; } } if ($this->getType()->getEscapeHtml()) { foreach ($data as $key => $value) { $data[$key] = $this->escapeHtml($value); } } $format = $format !== null ? $format : $this- >getFormatArray($addressAttributes); return $this->filterManager->template($format, ['variables' => $data]); } }

After the usual upgrade process you can then add email to your pdf address template in the Magento backend:

 {{depend email}}Email: {{var email}}{{/depend}}
Litsher - Nathan
  • 312
  • 1
  • 18
ChrisC
  • 46
  • 7
0

I tried your solution ChrisC, but I get an error in console after uploading the plugin:

[Symfony\Component\Console\Exception\CommandNotFoundException] There are no commands defined in the "cache" namespace.

If it works on your Magento, can you maybe provide the plugin files e.g. on Github? Would appreciate it! Thanks!

Joris
  • 43
  • 6
0

ChrisC's solution worked great for me, thanks.

After Joris suggested, I added a github repository:
https://github.com/ljr95/magento2-module-CustomerEmailAddressTemplate

Hopefully, this will help someone else.

ljr95
  • 11
  • 3