Magento: PDF Invoices on Customer Dashboard (Working Code)

It’s rather stupid to have the PDF version of invoices on back-end and not the same invoices available on fronted. Why to maintain both the PDF and HTML versions while, at least in Italy, the customer document and the merchant document should be identical?

I like PDFs because a customer can easly save them, print them and send them to other people. So I look for a way to have on Magento customer dashboard (or order list) the same PDF invoice version I can get on administration side.

I was unable to find a ready to use solution even if many commercial modules seem to provide this feature. But is it so hard to do? No it is no! Here the steps!

A module is needed

Ok, this is the worst part: if we need a module, we need to understand Magento modules and particularly the controller concept. I’m not able to deeply explain that, I’m a new bye of Magento, so let me to only show what I did.

I declared a module named Pdf adding a XML to the app/etc/modules: this is required to have the module code loaded by Magento. The file must be named Pdf.xml and it’s content:

1

2

3

4

5

6

7

8

9

<?xml version="1.0"?>

<config>

<modules>

<Pdf>

<active>true</active>

<codePool>local</codePool>

</Pdf>

</modules>

</config>

The I created a controller to have an URL to be called to generate the PDF invoice. The URL will be “/pdf/index/invoice/order_id/x/”. The first part “pdf” identify the module that manage this kind of request, the “index” part is the main controller, the “invoice” part is the specific requested action. The “order_id” and “x” are “parameters used to identify the order for which I’ll print out the invoices.

Yes, I made this thing to print out all invoices for a single order, it’s simpler.

The URL to generate a PDF invoice will be used later in a theme modification so there will be a link for the customer to download the invoice.

Now the hardest part: code the module and write a correct config.xml.

The module home will be “/app/code/local/Pdf”, remember that the module folder name must the same same as the name of the XML seen before. There are many conventions in Magento that a coder must follow and this is a very good thing: keep things clear, uniform and coherent is very important (and usually forgot by PHP coders).

Inside that folder, the sub folder “etc” will contain this config.xml file which declare the controller (and so tells Magento who call when the above URL is used):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<?xml version="1.0"?>

<config>

<modules>

<Pdf>

<version>1.0.0</version>

</Pdf>

</modules>

<frontend>

<routers>

<pdf>

<use>standard</use>

<args>

<module>Pdf</module>

<frontName>pdf</frontName>

</args>

</pdf>

</routers>

</frontend>

</config>

Now, believe me, the URL “/pdf/index/invoices/order_id/x/” will be addressed to our Pdf module. More details with examples on controller can be found here.

The controller

The controller is finally a piece of code that must be named and placed in the right way. Its name will be “IndexController.php”. The “Index” part, as you can note, matches the “index” part of the URL. If one wants to have the URL like “/pdf/batman/invoices/order_id/x/”, the controller will be named “BatmanController.php”.

Note the name of the controller class, which is prefixed with the module name, “Pdf”. The URL part “invoices” is matched by the internal “invoicesAction” method and uses the “PDF generator model” to create the same PDF as in the back-end:

1

$pdf=Mage::getModel('sales/order_pdf_invoice')->getPdf($invoices);

The only custom part I added is a control over the relation between the requested order to print and and cutomer, _canViewOrder(), that I copied from another core controller

Display the PDF invoice link

Now that we have a “service” to get the invoice in PDF format, we need to add a link somewhere on customer area. I decided to modify the “my orders” panel where there is the customer order list.

The involved file is the piece of the template which list the customer orders. The base file is:

/app/design/frontend/base/default/template/sales/order/history.phtml

I noted that my themes does not redefine this file so I copied it on my theme folder using the same folder structure (starting from “template”): that operation override completely this template part. Then I modified it adding a link to the PDF printing service:

That’s all folks! Now you don’t need to pay for PDF invoices on frontend anymore!

Conclusions

I agree, it’s not so simple, but neither too hard to accomplish. Magento is clearly complex and it’s complexity has negative effects on simple thing and positive effects on complex things. My next experiment will be the modification of the PDF invoice generator, which is full PHP code, trying to change it without rewrite it!

Some People (as me) should have 404 errors because config.xml file should be created in /app/code/local/Pdf/etc and by default the name of php controller should be IndexController.php.
Also to permit translation I have added in :
/app/design/frontend/Your_Interface/Your_Theme/template/sales/order/history.phtml following code :
|
<a href="getUrl(‘pdf/index/invoices’, array(‘order_id’ => $_order->getId())) ?>”>__(‘Invoices (PDF)’) ?>

People who get 404 errors don’t have <? php before the .php file content. I encountered the same problem but searched for a solution, there was told to paste <? php before the code. Everything worked like a charm after that!

Thank you for this great tutorial. Unfortunately I’m getting an error I can’t solve.
When I hit the “Invoice (PDF)” link, I’m getting the following error: “Controller file was loaded but class does not exist”. I checked everything three times (at least), but can’t find the mistake. Could you help me out with this code? I’m using Magento 1.7.0.2. Could it be a version problem?