Node.js – How to create PDF Invoice documents

  • by
node-js-pdf-invoice-sample

In this post we will see how we can create PDF Invoices using PDFKit in Node.js. The invoice pdf document will contain a company logo at the top, seller info, customer info and order product details. This is according to my knowledge and not a real invoice document, just a basic thing. The previous tutorial contains some of the syntax explanation for creating PDF with PDFKit in Node.js.

About PDFKit:

PDFKit is an opensource JavaScript library for Node. It helps in creating multi-page, complicated pdf documents. The library facilitates in adding new pages, adding tables, shapes and images to a document. Also it supports different font families and features like text color, line colors, sizes, transformation etc. You can refer official documentation of PDFKit for more information.

The final PDF created at the end will be like below:

node-js-pdf-invoice-sample

To install PDKit and Nodemon in your project use npm command:

npm install nodemon
npm install pdfkit

We will also use fs module, fs is an inbuilt module.

Add a folder with name images in your project and any image with name companyLogo.png inside it.

Create a new js file with name invoice.js and edit it as below:

invoice.js:

const pdfKit = require('pdfkit');
const fs = require('fs');

let companyLogo = "./images/companyLogo.png";
let fileName = './files/sample-invoice.pdf';
let fontNormal = 'Helvetica';
let fontBold = 'Helvetica-Bold';

let sellerInfo = {
"companyName": "Best Sales Pvt. Ltd.",
"address": "Mumbai Central",
"city": "Mumbai",
"state": "Maharashtra",
"pincode": "400017",
"country": "India",
"contactNo": "+910000000600"
}

let customerInfo = {
"customerName": "Customer ABC",
"address": "R783, Rose Apartments, Santacruz (E)",
"city": "Mumbai",
"state": "Maharashtra",
"pincode": "400054",
"country": "India",
"contactNo": "+910000000787"
}

let orderInfo = {
"orderNo": "15484659",
"invoiceNo": "MH-MU-1077",
"invoiceDate": "11/05/2021",
"invoiceTime": "10:57:00 PM",
"products": [
{
"id": "15785",
"name": "Acer Aspire E573",
"company": "Acer",
"unitPrice": 39999,
"totalPrice": 39999,
"qty": 1
},
{
"id": "15786",
"name": "Dell Magic Mouse WQ1545",
"company": "Dell",
"unitPrice": 2999,
"totalPrice": 5998,
"qty": 2
}
],
"totalValue": 45997
}

function createPdf() {
try {

let pdfDoc = new pdfKit();

let stream = fs.createWriteStream(fileName);
pdfDoc.pipe(stream);

pdfDoc.text("Node.js - PDF Invoice creation using PDFKit library.", 5, 5, { align: "center", width: 600 });
pdfDoc.image(companyLogo, 25, 20, { width: 50, height: 50 });
pdfDoc.font(fontBold).text('PARALLELCODES', 7, 75);
pdfDoc.font(fontNormal).fontSize(14).text('Order Invoice/Bill Receipt', 400, 30, { width: 200 });
pdfDoc.fontSize(10).text('11-MAY-2021 10:24 PM', 400, 46, { width: 200 });

pdfDoc.font(fontBold).text("Sold by:", 7, 100);
pdfDoc.font(fontNormal).text(sellerInfo.companyName, 7, 115, { width: 250 });
pdfDoc.text(sellerInfo.address, 7, 130, { width: 250 });
pdfDoc.text(sellerInfo.city + " " + sellerInfo.pincode, 7, 145, { width: 250 });
pdfDoc.text(sellerInfo.state + " " + sellerInfo.country, 7, 160, { width: 250 });

pdfDoc.font(fontBold).text("Customer details:", 400, 100);
pdfDoc.font(fontNormal).text(customerInfo.customerName, 400, 115, { width: 250 });
pdfDoc.text(customerInfo.address, 400, 130, { width: 250 });
pdfDoc.text(customerInfo.city + " " + customerInfo.pincode, 400, 145, { width: 250 });
pdfDoc.text(customerInfo.state + " " + customerInfo.country, 400, 160, { width: 250 });

pdfDoc.text("Order No:" + orderInfo.orderNo, 7, 195, { width: 250 });
pdfDoc.text("Invoice No:" + orderInfo.invoiceNo, 7, 210, { width: 250 });
pdfDoc.text("Date:" + orderInfo.invoiceDate + " " + orderInfo.invoiceTime, 7, 225, { width: 250 });

pdfDoc.rect(7, 250, 560, 20).fill("#FC427B").stroke("#FC427B");
pdfDoc.fillColor("#fff").text("ID", 20, 256, { width: 90 });
pdfDoc.text("Product", 110, 256, { width: 190 });
pdfDoc.text("Qty", 300, 256, { width: 100 });
pdfDoc.text("Price", 400, 256, { width: 100 });
pdfDoc.text("Total Price", 500, 256, { width: 100 });

let productNo = 1;
orderInfo.products.forEach(element => {
console.log("adding", element.name);
let y = 256 + (productNo * 20);
pdfDoc.fillColor("#000").text(element.id, 20, y, { width: 90 });
pdfDoc.text(element.name, 110, y, { width: 190 });
pdfDoc.text(element.qty, 300, y, { width: 100 });
pdfDoc.text(element.unitPrice, 400, y, { width: 100 });
pdfDoc.text(element.totalPrice, 500, y, { width: 100 });
productNo++;
});

pdfDoc.rect(7, 256 + (productNo * 20), 560, 0.2).fillColor("#000").stroke("#000");
productNo++;

pdfDoc.font(fontBold).text("Total:", 400, 256 + (productNo * 17));
pdfDoc.font(fontBold).text(orderInfo.totalValue, 500, 256 + (productNo * 17));

pdfDoc.end();
console.log("pdf generate successfully");
} catch (error) {
console.log("Error occurred", error);
}
}

createPdf();

The sellerInfo, customerInfo, orderInfo contains required data. The forEach loop will iterate the products and attach it to the PDF document. Here, y-axis point is dynamically assigned. The productNo integer value get increased by 1 on each product addition in the document. Because of this, if you add more products in the order list, it will align automatically on its own.

Run this code using the command:

node ./invoice.js

If you are using nodemon use:

nodemon ./invoice.js

Output:

node-js-pdf-invoice-sample

DOWNLOAD SOURCE CODE

This is a simple code showing how we can create complex PDF files in Node.js using PDFKit library. I have created a PDF order invoice document which may contain 5-10 pages in one of my projects with multiple signatures and images on it using similar code. Let me know your thoughts on this. If you need help, please let me know on my facebook page.


Also see:
Node.js – How to create folder or directory

Node.js – Create, read and write text files.

HTTP module in Node.js

Install Node.js on Windows.