A plugin for generating customizable PDF invoices for orders. Supports incremental invoice numbering, credit invoices, and customizable Handlebars templates.

In v4 the field invoice.isCreditInvoice was changed from a getter to a physical database column. To populate the column you need to:
isCreditInvoice where all values are 'false'.UPDATE invoice SET isCreditInvoice = 1 WHERE orderTotals LIKE '%total":-%'; to set the value to 'true' for invoices that have a negative total.yarn add @pinelab/pinelab-invoice-pluginvendure-config.ts:AllowInvoicesPermissionSales > Invoices to see all generated invoices. The order detail page will have generated invoices for that order only.Settings > Invoices to enable invoice generation and edit the invoice handlebars template.Enable invoice generation for the current channel on order placement. Invoices are generated on order placement.Preview button to view a sample PDF invoice.Puppeteer bundles its own Chromium binary, which is downloaded during npm install. This can be unreliable in containerized environments: the download may silently fail on certain base images, behind proxies, or in air-gapped CI. When the bundled binary is missing at runtime, invoice generation fails with Could not find Chrome.
The recommended approach is to install system Chrome and tell Puppeteer to use it via the PUPPETEER_EXECUTABLE_PATH env var. This is more reliable, produces smaller images, and avoids the postinstall download entirely.
Note:
--no-sandboxis required when running Chrome as root inside a container. The plugin passes this flag by default. If you run as a non-root user, you can remove it viapuppeteerLaunchOptions.
You can customize how Puppeteer launches Chrome in two ways. Both are fully backward compatible — when neither is set, the plugin uses its defaults (headless: true, args: ['--no-sandbox']).
Option 1: Plugin config (recommended for most cases)
Any Puppeteer launch option can be passed here. The plugin merges your options over its defaults (your values win).
Option 2: PUPPETEER_EXECUTABLE_PATH env var
This env var is Puppeteer's standard convention. It takes the highest precedence — even over executablePath set in puppeteerLaunchOptions. This is useful for overriding the Chrome path per environment (e.g. different paths in CI vs production) without changing code.
Add the following link to your email template:
https://<your server>/invoices/e2e-default-channel/C7YH7WME4LTQNFRZ?email=hayden.zieme12@hotmail.com.
When the customer clicks the link, the server will check if the ordercode, channelCode and customer emailaddress
match with the requested order. If so, it will return the invoice.
This link will always return the first invoice generated for an order. If invoices were recreated via the Admin UI, you can specify the invoice number in the url.
On the order detail page you can click the button recreate invoice to generate a new invoice based on the current state of the order.
By default, this will first create a credit invoice, then a new invoice. A credit invoice basically voids the previous invoice before generating a new one.
To send emails when new invoices are created, you can listen for InvoiceCreatedEvents:
Credit invoices use the same template as regular invoices, so make sure to handle credit invoice data. Checkout the default template for an example on how to use it for credit invoices.
Credit invoices will receive additional data with the default loadDataFn(). This data is needed to create valid credit invoices:
To disable the credit invoice behaviour:
By default, the plugin uses TypeOrm's text to store the invoice template in the DB. This might not be enough, for example when you'd like to add base64 encoded images to your invoices. This will result in the error ER_DATA_TOO_LONG: Data too long for column 'templateString'. You can specify your DB engine with an env variable, and the plugin will resolve the correct column type:
Don't forget to run a DB migration: This will delete any data in the templateString column!
Checkout https://orkhan.gitbook.io/typeorm/docs/entities for available databases and column types.
This plugin also includes a strategy for storing invoices in Google Storage:
yarn add @google-cloud/storage
The strategy will use the projectId and credentials in from your environment, which is useful for Google Cloud Run or Cloud Functions.
However, if you want to run it locally or on a custom environment, you need to pass a keyFile to the plugin. This is needed to generate signedUrls, which are used to give customers temporary access to a file on Storage. More info about locally using signedUrls: https://github.com/googleapis/nodejs-storage/issues/360
This plugin also includes a strategy for storing invoices on Amazon S3.
yarn add aws-sdk
Implement your own strategy for storing invoices by implementing one of these interfaces:
RemoteStorageStrategy for storing PDF files on an external platform like Google Cloud or S3. It redirects the user to
a public/authorized URL for the user to download the invoice PDF.
LocalFileStrategy streams the invoice through the Vendure service to the user.
Implement a custom loadDataFn to pass custom data into your template or generate custom invoice numbers:
Make sure to return the data needed for credit invoices when shouldGenerateCreditInvoice is defined.
You can access this data in your HTML template using Handlebars.js:
You can automatically export each created invoice to an accounting platform by including an accounting strategy in the plugin. See one of the examples below for more details.
This strategy exports each invoice to Xero (UK only). To get started:
accounting.transactions,accounting.contacts and accounting.settings.read.npm install xero-node to install the Xero NodeJS client.If you are getting { error: 'invalid_client' } during startup, you might have to recreate your Xero app on https://developer.xero.com/app/manage.
You can implement your own export strategy to export invoices to your custom accounting platform. Take a look at the included XeroUKExportStrategy as an example.
migrateInvoices(queryRunner) to the bottom of the up function in your migration file, like soLocalFileStrategy.streamFile() and streamMultiple() now check file existence before streaming and attach error handlers to prevent unhandled stream errors.google-chrome-stable and set PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable. See the README for a working Dockerfile.puppeteerLaunchOptions config option for passing custom options to puppeteer.launch() (e.g. executablePath, args, timeout).PUPPETEER_EXECUTABLE_PATH env var support to override the Chrome binary path without code changes.src/ui/). The plugin now exclusively uses the React Dashboard via @vendure/dashboard.getMostRecentInvoiceForOrder to return the latest invoice instead of the oldest one.isCreditInvoice as column in the DB in an Invoiceinvoice.isCreditInvoiceFor. This is only populated for invoices generated with V4.Regenerate invoice as warning button when order total differs from the latest invoice total ( see #485)defaultTemplate as reference.