edisonneza / jspdf-invoice-template Goto Github PK
View Code? Open in Web Editor NEWPDF template created to generate invoices based on props object. Using jsPDF library.
Home Page: https://edisonneza.github.io/jspdf-invoice-template
PDF template created to generate invoices based on props object. Using jsPDF library.
Home Page: https://edisonneza.github.io/jspdf-invoice-template
Hi again,
While I love your package I was trying to get off the load from browser and create background functions using Google Cloud Functions to generate new Invoices and thus update the Invoice URL in database.
The problem I am facing with my test script is that I get this error
Error: Automatic publicPath is not supported in this browser
My function is nothing fancy, a simple exppressjs route
app.get('/generateInvoice', (req, res) => {
const jsPDFInvoiceTemplate = require("jspdf-invoice-template");
const props = {
outputType: 'blob',
...otherProps
}
const pdfCreated = jsPDFInvoiceTemplate(props);
const blob = pdfCreated.blob
res.send(blob)
})
This is working perfectly in Browser but when I try on Cloud Function I got that error.
Error: Automatic publicPath is not supported in this browser
at /home/besnik/Desktop/Nap Inc/functions/node_modules/jspdf-invoice-template/dist/index.js:2:351320
at /home/besnik/Desktop/Nap Inc/functions/node_modules/jspdf-invoice-template/dist/index.js:2:351462
at /home/besnik/Desktop/Nap Inc/functions/node_modules/jspdf-invoice-template/dist/index.js:2:352242
at /home/besnik/Desktop/Nap Inc/functions/node_modules/jspdf-invoice-template/dist/index.js:2:81
at Object.<anonymous> (/home/besnik/Desktop/Nap Inc/functions/node_modules/jspdf-invoice-template/dist/index.js:2:221)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Module.require (internal/modules/cjs/loader.js:974:19)
If I could manage to make it work, I would share the function here as well for others :)
Cheers,
I am getting this error when I try to use this on NodeJS (ExpressJS)
"Error: Automatic publicPath is not supported in this browser"
I followed the documentation and imported jspdf-invoice-template, but getting below error
ERROR in ./node_modules/jspdf-invoice-template/src/index.js 90:22
Module parse failed: Unexpected token (90:22)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| orientationLandscape: props.orientationLandscape || false,
| logo: {
src: props.logo?.src || "",
| width: props.logo?.width || "",
| height: props.logo?.height || "",
Please let me know what i am missing?
Hi!
I like your template, but i want to create a little bit different template for my website like in video. Do you know where to do that? Any video link?
hi,
Thanks for the great work.
I'm trying to prepend a signature image at the bottom, and able to get it work when save locally
var img = resizeBase64(imageURL, 128, 128);
var props = {
outputType: "blob",
returnJsPDFDocObject: true,
...
const pdfObject = jsPDFInvoiceTemplate(props);
pdfObject.jsPDFDocObject.addImage(img, "jpeg", 10, 250);
pdfObject.jsPDFDocObject.save(`${newFileName}.pdf`); // this works correctly, with the image at the bottom.
var blob = pdfObject.blob;
var path = `pdfs/${newFileName}.pdf`;
const pdfRef = ref(storage, path);
uploadBytes(pdfRef, blob) // blob here seems still refer to the original PDF, not the one with addImage
.then(() => {
toast.success("PDF uploaded successfully");
})
.catch(() => {
toast.error("PDF upload failed");
});
However the PDF on the firebase is missing the image (it's the original PDF) , I suspect the way I use blob maybe incorrect, could you advise?
Shqipe thnx for this :)
I really appreciate what you have done here, that saved me a lot of time!!
I have 1 question though:
Looking forward to receive back,
thnx in advance
Cheers
I created an arrow function called PdfObject, which loops through an array and calls the jsPDFInvoiceTemplate. However, I also put a use state hook (a hook), and I try to set some state and modify the values. However, I get the
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
const PdfObject = () => {
const [newState, setNewState] = useState(
{..some value})
array.forEach((item) => {
setNewState(...)
var props = {
...
}
//Calls The PDF generation
jsPDFInvoiceTemplate(props)
})
}
jspdf-invoice-template/src/index.js
Line 484 in fb3bffe
jspdf-invoice-template/src/index.js
Line 489 in fb3bffe
Would we be correct in assuming that these magic numbers for 183mm and 270mm are directly proportional to the A4 dimensions for sizing?
both are 27mm below A4 paper dimensions 210mm 270mm
My first impression is that the y-coord (currentHeight
) potentially near the end of page should wrap to the next page.
Appears to be a hard-coded 27mm condition which may equate to about three lines of text?
Printable "safe area" aesthetic adjustments?
--
There are other number constants used to adjust as well throughout the code, I thought I would suggest this as one of the more accessible places to refactor
Hello,
When I'm using this template, it keeps generating two files every time I download it, save it, or open it in a new URL. Maybe you are calling a function or variable twice in your code? BTW, great project and keep the work up!
jspdf-invoice-template/src/index.js
Line 209 in fb3bffe
doc.text(docWidth - 10, currentHeight, param.business.address, "right");
Multiple usages of .text() in this (undocumented?) order still appear to work
Dynamic js library is forgiving and the types are often not up to date either; however, I believe the documented types and .text() function signature implementation desire the text variable as the first parameter
Unless I am looking at a different utility, as the end result appears to still work!
https://github.com/MrRio/jsPDF/blob/cef97fb34eda41a8704c9f3983e680919a328ce4/src/jspdf.js#L3421
API.__private__.text = API.text = function(text, x, y, options, transform) {
jspdf
types index.d.ts
text(
text: string | string[],
x: number,
y: number,
options?: TextOptionsLight,
transform?: number | any
): jsPDF;
I am currently refactoring while customising in TypeScript and will see what happens
Also decomposing into separate files.
Hey there, thanks a lot for creating this template! 👍
My use case is running this on a Node.js server (well, a single script for now 😅), and I ran into the issue that Node.js can't create new Image()
objects since it's missing the DOM/window references.
I wanted to share the quick fix I applied on my end, it's a bit rough, so I didn't open a PR for it:
if (param.logo.src) {
var imageHeader;
if(typeof window === "undefined") {
imageHeader = param.logo.src;
} else {
imageHeader = new Image();
imageHeader.src = param.logo.src;
}
//doc.text(htmlDoc.sessionDateText, docWidth - (doc.getTextWidth(htmlDoc.sessionDateText) + 10), currentHeight);
doc.addImage(
imageHeader,
10 + param.logo.margin.left,
currentHeight - 5 + param.logo.margin.top,
param.logo.width,
param.logo.height
);
}
This enables me to pass either a base64-encoded image, or an Uint8Array
in Node.js, essentially exposing the first argument of the doc.addImage()
function.
Property defauft doesn't exit on type 'Props'
var pdfObject = jsPDFInvoiceTemplate.default(props);
Hi Edison, thank you for this!
I would like we had a boolean option to compress the PDF.
Can we add / customize fields like tax no, transport cost, etc similar to how you have provided in the table?
Thanks for this amazing library!
After updating from angular v12 to v13, we started to face this issue:
Error: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'webpackChunkjsPDFInvoiceTemplate')
TypeError: Cannot read properties of undefined (reading 'webpackChunkjsPDFInvoiceTemplate')
Does it tell much?
Is there any solution?
Hi, thank you for the great work. I can see that you have defined 6 columns for the table. I am just wondering if there is any easy way to remove the "item number" and "unit" ? It seems that these 6 columns are hard coded in the index.js file isn't it?
I followed the installation correctly but still have this issue of Uncaught TypeError: t is undefined index.js:2:340710 below is my code
const generatePdf = () => {
var pdfObject = jsPDFInvoiceTemplate.default(props);
console.log(pdfObject)
var props = {
outputType: jsPDFInvoiceTemplate.OutputType.Save,
returnJsPDFDocObject: true,
fileName: "Invoice 2021",
orientationLandscape: false,
logo: {
src: "https://raw.githubusercontent.com/edisonneza/jspdf-invoice-template/demo/images/logo.png",
type: 'PNG', //optional, when src= data:uri (nodejs case)
width: 53.33, //aspect ratio = width/height
height: 26.66,
margin: {
top: 0, //negative or positive num, from the current position
left: 0 //negative or positive num, from the current position
}
},
stamp: {
inAllPages: true, //by default = false, just in the last page
src: "https://raw.githubusercontent.com/edisonneza/jspdf-invoice-template/demo/images/qr_code.jpg",
type: 'JPG', //optional, when src= data:uri (nodejs case)
width: 20, //aspect ratio = width/height
height: 20,
margin: {
top: 0, //negative or positive num, from the current position
left: 0 //negative or positive num, from the current position
}
},
business: {
name: "Business Name",
address: "Albania, Tirane ish-Dogana, Durres 2001",
phone: "(+355) 069 11 11 111",
email: "[email protected]",
email_1: "[email protected]",
website: "www.example.al",
},
contact: {
label: "Invoice issued for:",
name: "Client Name",
address: "Albania, Tirane, Astir",
phone: "(+355) 069 22 22 222",
email: "[email protected]",
otherInfo: "www.website.al",
},
invoice: {
label: "Invoice #: ",
num: 19,
invDate: "Payment Date: 01/01/2021 18:12",
invGenDate: "Invoice Date: 02/02/2021 10:17",
headerBorder: false,
tableBodyBorder: false,
header: [
{
title: "#",
style: {
width: 10
}
},
{
title: "Title",
style: {
width: 30
}
},
{
title: "Description",
style: {
width: 80
}
},
{ title: "Price"},
{ title: "Quantity"},
{ title: "Unit"},
{ title: "Total"}
],
table: Array.from(Array(10), (item, index)=>([
index + 1,
"There are many variations ",
"Lorem Ipsum is simply dummy text dummy text ",
200.5,
4.5,
"m2",
400.5
])),
additionalRows: [{
col1: 'Total:',
col2: '145,250.50',
col3: 'ALL',
style: {
fontSize: 14 //optional, default 12
}
},
{
col1: 'VAT:',
col2: '20',
col3: '%',
style: {
fontSize: 10 //optional, default 12
}
},
{
col1: 'SubTotal:',
col2: '116,199.90',
col3: 'ALL',
style: {
fontSize: 10 //optional, default 12
}
}],
invDescLabel: "Invoice Note",
invDesc: "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary.",
},
footer: {
text: "The invoice is created on a computer and is valid without the signature and stamp.",
},
pageEnable: true,
pageLabel: "Page ",
};
}
The package.json
specifies the ISC License, however the Readme.md only includes a part of the relevant legal text.
https://en.wikipedia.org/wiki/ISC_license#License_terms
Especially the following part is missing
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
I am trying to use this lib instead of plain jsPDF lib.
But it is known as error window not defined.
When configuring the props for the jsPDFInvoiceTemplate, is it possible to use a data URL for the source in a logo?
var props = {
logo: {
src: '',
type: 'JPEG', //optional, when src= data:uri (nodejs case)
width: 80, //aspect ratio = width/height
height: 30,
margin: {
top: 0, //negative or positive num, from the current position
left: 0, //negative or positive num, from the current position
},
},
}
In the src, I want to add a data URL rather than a URL link. Thanks!
I was wondering how to add table background color , header color or text color ?
Usually, we must call printing on other window/tab. This is not a good way if we design a POS-point of sale systems or SPA, cause UX issue.
I propose this:
//1. Define props and :
const propsInvoicePdf = {
outputType: 'bloburl', //OutputType.DataUriString,
onJsPDFDocCreation: (doc: jsPDF) => {
doc.addFont("assets/fonts/Inter-Bold.ttf", "Inter", "Bold");
doc.addFont("assets/fonts/Inter-Regular.ttf", "Inter", "normal");
doc.autoPrint(); // <<------- 1st Trick AUTO Print Here-------------- !!
},
jsPDFDocObject: jsPDF,
returnJsPDFDocObject: true,
// other data props
}
const module = await import("jspdf-invoice-template");
jsPDFInvoiceTemplate = module.default;
pdfCreated = jsPDFInvoiceTemplate(propsInvoicePdf);
//2. Event handling for Edge/Firefox/Chrome/Safari
export const printOnSamePage = async sURL => {
var oHiddFrame = document.createElement("iframe");
oHiddFrame.style.position = 'fixed';
oHiddFrame.style.width = '1px';
oHiddFrame.style.height = '1px';
oHiddFrame.style.opacity = '0.01';
const isSafari = /^((?!chrome|android).)*safari/i.test(window.navigator.userAgent);
if (isSafari) {
// fallback in safari
oHiddFrame.onload = () => {
try {
oHiddFrame.contentWindow.document.execCommand('print', false, null);
} catch (e) {
oHiddFrame.contentWindow.print();
}
};
}
oHiddFrame.src = sURL;
document.body.appendChild(oHiddFrame);
await printPromise;
}
async function doPdfPrint(){
var pdfObject = pdfCreated.jsPDFDocObject;
const sUrl = pdfObject.output('bloburl');
printOnSamePage(sUrl)
.catch ( error => {
// Fallback printing method if need
//pdfObject.autoPrint();
//pdfObject.output('dataurlnewwindow');
})
}
This is well-running and tested solution. I hope that @edisonneza you can embedded it into your lib smoothly.
I am currently facing an issue where I am unable to add the currency symbol to both the price and the total values in my data table. The intended outcome is to display the prices and their corresponding totals with the appropriate currency symbol (₹ for Indian Rupees) using the HTML entity code ₹. Despite attempting to concatenate the currency symbol with the numeric values, the symbol does not appear as expected.
Really nice template, you saved me a bunch of time!! A few tweaks are needed to run on node.js for me but great work, thanks
Hi @edisonneza
thanks for your package, it is very useful
I suggest the feature of adding a stamp as an image below the rows
Can you enhance the footer?
Instead of only the text to a maybe 3-4 line height text with styling and font sizes?
Often you need to put legal information on an invoice like tax-numbers and stuff like this.
Also the text then should adjustable in the row or table with an option to align it left, center, right.
That would be awesome!
Example:
https://www.whmcs-deutschland.eu/wcf/index.php?attachment/204-rechnung-762-page-001-jpg/
maybe like this:
footer?: {
* text?: string,
* },
* footer1?: {
* text?: string,
* align?: string,
* style?: { width?: number },
* margin?: {
* bottom?: number,
* left?: number
* }
* },
* footer2?: {
* text?: string,
* align?: string,
* style?: { width?: number },
* margin?: {
* bottom?: number,
* left?: number
* }
* },
* footer3?: {
* text?: string,
* align?: string,
* style?: { width?: number },
* margin?: {
* bottom?: number,
* left?: number
* }
* },
//...
if (param.pageEnable) {
// current state:
//doc.text(docWidth / 2, docHeight - 10, param.footer.text, "left");
//added here also with the margin.
doc.text(docWidth / 2, docHeight - 10, param.footer1.text, param.footer1.align);
doc.text(docWidth / 2, docHeight - 10, param.footer2.text, param.footer2.align);
doc.text(docWidth / 2, docHeight - 10, param.footer3.text, param.footer3.align);
doc.setPage(i);
doc.text(
param.pageLabel + " " + i + " / " + doc.getNumberOfPages(),
docWidth - 20,
doc.internal.pageSize.height - 6
);
}
```
Hi this code works in Node 18 to generate the datauri string.
var pdfCreated = jsPDFInvoiceTemplate.default({
...invoiceObject,
outputType: OutputType.DataUriString,
returnJsPDFDocObject: true,
fileName: "Invoice 2024",
orientationLandscape: false,
compress: true
});
console.log(pdfCreated.dataUriString);
How to save this directly as pdf? I think there is a function but I dont get it.
Thanks!
Hello, I have an issue where when I loop through an array of items, the output type of "Save" can only download the different pdfs 10 times. So, if I have 20 items in the array, it can only download 10 of them. However, if I have 4 items in the array, it can download all 4 because it's less than 10. Idk if this is an issue with the jspdf save function since when I do OutputType of DataUrlNewWindow, it can open all 20 jsPDFInvoiceTemplate in the browser. I want to be able to use the output type of Save and download all the pdfs in the for loop
Code example:
//Loop through each item and generate PDF for each vendor
array.forEach((item) => {
quoteCounter++
var props = {
outputType: OutputType.Save,
returnJsPDFDocObject: true,
fileName: `Quote #${quoteCounter} ${vendor.slice(0, 3).toUpperCase()}`,
...
}
jsPDFInvoiceTemplate(props)
})
Hi Edison,
First of all, many thanks for your package. Really a timesaver!
Is there a way I add custom styling (font-family, size, colors, weights) or integrate with Bootstrap?
I think it could be a good idea to give the possibility to add multiple table. For example some information's cannot have the same column designation name.
Hi, I'm using jspdf-invoice-template. I am passing dynamic array from invoice, but it is taking empty.
Originally posted by @tayyab-developer in #13 (comment)
The types of 'invoice.header' are incompatible between these types.
Type '({ title: string; style: { width: number; }; } | { title: string; style?: undefined; })[]' is not assignable to type 'string[]'.
This source header definition is expecting string[]
Source code (zip)
Snippet from above source
invDate?: string,
* invGenDate?: string,
* headerBorder?: boolean,
* tableBodyBorder?: boolean,
* header?: string[],
* table?: any,
* invTotalLabel?: string,
* invTotal?: string,
I get the exception for this
header: [
{
title: "#",
style: {
width: 10
}
},
{
title: "Title",
style: {
width: 30
}
},
{
TypeError: Cannot read property 'bind' of undefined
Hi. In Vue 3 I faced this error, I was able to fix it by replacing
jsPDFInvoiceTemplate.default(props);
with
jsPDFInvoiceTemplate(props);
Hi may I know this package can use Japanese language for pdf file such as for column. example quantity word to Japanese. Thank you
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.