One of the interaction with the Customers involve sending mails, including pdf files.
For example, for every order you do on a Shop as a Customer we expect to receive an Invoice.
Working on what make a shop an unique experience, as a Developer you will be asked to customize every PDF files that PrestaShop can produce.
You can alter the rendering using the provided data or push the PDF Rendering to its best, introducing your very own information that will made your PDF files amazing.
All PDF generated by PrestaShop are using Smarty templates and TCPDF as PDF rendering engine.
You will find all theses templates in the pdf
folder, for each use case
managed natively by the Core.
You can alter the Core files OR override them by copying them on themes/<your-theme>/pdf
folder.
Delivery Slips are available in Orders > Delivery Slips
section of the Back Office.
The following files are used to generate the PDF file:
pdf
├── delivery-slip.addresses-tab.tpl
├── delivery-slip.payment-tab.tpl
├── delivery-slip.product-tab.tpl
├── delivery-slip.style-tab.tpl
├── delivery-slip.summary-tab.tpl
└── delivery-slip.tpl
Invoices are available in Orders > Invoices
section of the Back Office and in Orders List
section of the Customer Back Office.
The following files are used to generate the PDF file:
pdf
├── invoice.addresses-tab.tpl
├── invoice-b2b.tpl
├── invoice.note-tab.tpl
├── invoice.payment-tab.tpl
├── invoice.product-tab.tpl
├── invoice.shipping-tab.tpl
├── invoice.style-tab.tpl
├── invoice.summary-tab.tpl
├── invoice.tax-tab.tpl
├── invoice.total-tab.tpl
└── invoice.tpl
Order (or Merchandise) Returns are available in Orders > Merchandise Returns
section of the Back Office.
The following files are used to generate the PDF file:
pdf
├── order-return.addresses-tab.tpl
├── order-return.conditions-tab.tpl
├── order-return.product-tab.tpl
├── order-return.summary-tab.tpl
└── order-return.tpl
Order Slips are available in Orders > Order Slips
section of the Back Office.
pdf
├── order-slip.payment-tab.tpl
├── order-slip.product-tab.tpl
├── order-slip.summary-tab.tpl
├── order-slip.total-tab.tpl
└── order-slip.tpl
Since 1.7, Supply Orders are not available anymore in the Back Office but you can still “trigger” the generation of the PDF files.
pdf
├── supply-order.addresses-tab.tpl
├── supply-order-footer.tpl
├── supply-order-header.tpl
├── supply-order.product-tab.tpl
├── supply-order.tax-tab.tpl
├── supply-order.total-tab.tpl
└── supply-order.tpl
These files are used by most of the previous files:
pdf
├── footer.tpl
├── header.tpl
└── pagination.tpl
{* /themes/your-theme/pdf/invoice.style-tab.tpl *}
{assign var=color_header value="#25B9D7"}
{assign var=color_border value="#3ED2F0"}
{assign var=color_border_lighter value="#DFF5F9"}
{assign var=color_line_even value="#FAFBFC"}
{assign var=color_line_odd value="#6C868E"}
{assign var=font_size_text value="12pt"}
{assign var=font_size_header value="12pt"}
{assign var=font_size_product value="12pt"}
{assign var=height_header value="25px"}
{assign var=table_padding value="7px"}
You will get an Invoice would look like this:
A dynamic hook allows you to alter or add more information that will become available in the previous templates.
There is the list of available Template Classes in the Core:
HTMLTemplateDeliverySlip
HTMLTemplateInvoice
HTMLTemplateOrderReturn
HTMLTemplateOrderSlip
HTMLTemplateSupplyOrderForm
If your shop is available for the European Union, the GDPR module must be installed.
This means you can generate another PDF thanks to the class named HTMLTemplatePSGDPRModule
. This PDF will contain all the Customer Information.
To guess the hook for each template, we can look at the HTMLTemplate
abstract Class:
<?php
// l. 160
$template = ucfirst(str_replace('HTMLTemplate', '', get_class($this)));
$hook_name = 'displayPDF' . $template;
Concept | Hook name |
---|---|
Invoice | displayPDFInvoice |
Invoice | displayInvoiceLegalFreeText |
Delivery Slip | displayPDFDeliverySlip |
Order Return | displayPDFOrderReturn |
Order Slip | displayPDFOrderSlip |
Supply Order | displayPDFSupplyOrderForm |
GDPR Archive | displayPDFPSGDPRModule |
In modules/your-module/your-module.php
:
<?php
public function hookDisplayPDFInvoice($hookArgs)
{
$customer = $this->context->customer;
$hookArgs['object']->is_birthday = $this->isBirthday($customer->birthday);
}
// Naive implementation: don't do that.
private function isBirthDay(string $customerBirthday)
{
return date('y-m-d') == $customerBirthday;
}
In themes/your-theme/pdf/invoice.note-tab.tpl
:
{* ... keep the content ... *}
{if $order_invoice->is_birthday}
<tr>
<td colspan="12">
{l s='Happy Birthday !' d='Modules.YourModule.Pdf' pdf='true'}
</td>
</tr>
{/if}
You will get an Invoice would look like this:
For each of these templates, Smarty variables are available.
There is the list of the variables available:
{lastname}
{firstname}
{id_order}
{order_name}
{delivery_block_txt}
{invoice_block_txt}
{delivery_block_html}
{invoice_block_html}
{delivery_company}
{delivery_firstname}
{delivery_lastname}
{delivery_address1}
{delivery_address2}
{delivery_city}
{delivery_postal_code}
{delivery_country}
{delivery_state}
{delivery_phone}
{delivery_other}
{invoice_company}
{invoice_vat_number}
{invoice_firstname}
{invoice_lastname}
{invoice_address2}
{invoice_address1}
{invoice_city}
{invoice_postal_code}
{invoice_country}
{invoice_state}
{invoice_phone}
{invoice_other}
{order_name}
{date}
{carrier}
{payment}
{products}
{total_paid}
{total_products}
{total_discounts}
{total_shipping}
{total_wrapping}
{total_tax_paid}
They are set in the PaymentModule:validateOrder
function.
dump
them and figure out what they provide.As always, you can hook into this email workflow and while there are multiples hooks that can fit this specific needs, the best one is named actionGetExtraMailTemplateVars
.
Once you get the right hook, you will be able to alter or add extra variables:
<?php
// your-module/your-module.php
public function install()
{
...
$this->registerHook('actionGetExtraMailTemplateVars');
}
public function hookActionGetExtraMailTemplateVars($hookArgs)
{
dump($hookArgs);
// Adapted from PrestaShop Email Manager Module
$hookArgs['extra_template_vars']['{password}'] = '*******';
}
Assume that the .tpl
files in the pdf
folder have been copied from the Core
mycustompdfgenerator
├── pdf
├── delivery-slip.addresses-tab.tpl
├── delivery-slip.product-tab.tpl
├── delivery-slip.style-tab.tpl
├── delivery-slip.tpl
├── footer.tpl
├── header.tpl
├── mycustompdfgenerator.php
├── logo.png
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class MyCustomPdfGenerator extends Module
{
public function __construct()
{
$this->name = 'mycustompdfgenerator';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'Firstname Lastname';
$this->need_instance = 0;
$this->ps_versions_compliancy = [
'min' => '1.7',
'max' => _PS_VERSION_
];
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('My module');
$this->description = $this->l('Description of my module.');
$this->confirmUninstall = $this->l('Are you sure you want to uninstall?');
}
public function generatePDF(array $params): void
{
$myOrderObject = new Order((int) $params['id_order']);
$myCustomSlipVarsForPdfContent = $this->myContentDatasPresenter($myOrderObject);
$myCustomSlipVarsForPdfFooter = $this->myFooterDatasPresenter($myOrderObject);
$myCustomSlipVarsForPdfHeader = $this->myHeaderDatasPresenter($myOrderObject);
$pdfGen = new PDFGenerator(false, 'P');
$pdfGen->setFontForLang(Context::getContext()->language->iso_code);
$pdfGen->startPageGroup();
$pdfGen->createHeader($this->getHeader($myCustomSlipVarsForPdfHeader));
$pdfGen->createFooter($this->getFooter($myCustomSlipVarsForPdfFooter));
$pdfGen->createContent($this->getPdfContent($myCustomSlipVarsForPdfContent));
$pdfGen->writePage();
$pdfGen->render('my_custom_pdf.pdf', 'D');
}
/**
* Returns the template's HTML content.
*
* @return string HTML content
*/
public function getPdfContent(array $myCustomSlipVarsForPdfContent): string
{
$this->context->smarty->assign($myCustomSlipVarsForPdfContent);
$tpls = array(
'style_tab' => $this->context->smarty->fetch(__DIR__.'/pdf/delivery-slip.style-tab.tpl'),
'addresses_tab' => $this->context->smarty->fetch(__DIR__.'/pdf/delivery-slip.addresses-tab.tpl'),
'product_tab' => $this->context->smarty->fetch(__DIR__.'/pdf/delivery-slip.product-tab.tpl'),
);
$this->context->smarty->assign($tpls);
return $this->context->smarty->fetch(__DIR__.'/pdf/delivery-slip.tpl');
}
/**
* Returns the template's HTML footer.
*
* @return string HTML footer
*/
public function getFooter(array $myCustomSlipVarsForPdfFooter): string
{
$this->context->smarty->assign($myCustomSlipVarsForPdfFooter);
return $this->context->smarty->fetch(__DIR__.'/pdf/footer.tpl');
}
/**
* Returns the template's HTML header.
*
* @return string HTML header
*/
public function getHeader(array $myCustomSlipVarsForPdfHeader): string
{
$this->context->smarty->assign($myCustomSlipVarsForPdfHeader);
return $this->context->smarty->fetch(__DIR__.'/pdf/header.tpl');
}
/**
* Format your order data here for pdf content : ['tpl_var_name'=>'tpl_value']
*
* @return array
*/
public function myContentDatasPresenter(Order $myOrderObject): array
{
// TODO : implement it
}
/**
* Format your order data here for pdf footer : ['tpl_var_name'=>'tpl_value']
*
* @return array
*/
public function myFooterDatasPresenter(Order $myOrderObject): array
{
// TODO : implement it
}
/**
* Format your order data here for pdf header : ['tpl_var_name'=>'tpl_value']
*
* @return array
*/
public function myHeaderDatasPresenter(Order $myOrderObject): array
{
// TODO : implement it
}
}
$myModuleOrderPdfGenerator = Module::getInstanceByName('mycustompdfgenerator');
$myModuleOrderPdfGenerator->generatePDF([
'id_order'=>666
]);