@logicdine/medusa-plugin-invoice
v0.1.0
Published
Invoice generator plugin for Medusa v2 with multi-template support (PDF + HTML), POS receipts, and admin management
Maintainers
Readme
@logicdine/medusa-plugin-invoice
Invoice generator plugin for Medusa v2 with multi-template support, PDF & HTML engines, POS receipt sizes, and full admin management.
Features
- Multiple Invoice Templates - Classic Invoice, Kitchen Order, Packing Slip, POS Receipt, or create your own
- Two Template Engines - Native PDF (pdfmake) with section toggles, or HTML (Handlebars) for full customization
- POS Receipt Support - 80mm and 58mm thermal receipt paper sizes with dynamic height estimation
- Template Preview - Preview templates with sample data (75 items) before saving
- Style Editor - Customize font sizes, colors, bold/italic per style category from the admin UI
- Section Visibility - Toggle company header, addresses, item prices, totals, notes per template
- Title Control - Show header on first page only or repeat on every page
- Auto Invoice on Order - Generates invoice automatically when an order is placed
- Email Notification - Sends invoice PDF as email attachment on order placement
- Stale Invoice Tracking - Marks invoices as stale when orders are updated (edits, returns, exchanges)
- Admin Widget - Invoice list with template selector on order detail page
- Store API - Customers can download their invoices
Prerequisites
- Medusa v2 application (v2.13+)
- PostgreSQL database
- Node.js >= 20
Installation
npm install @logicdine/medusa-plugin-invoice
# or
pnpm add @logicdine/medusa-plugin-invoiceConfiguration
Add the plugin to your medusa-config.ts:
import { defineConfig } from '@medusajs/framework/utils'
export default defineConfig({
// ...
plugins: [
{
resolve: "@logicdine/medusa-plugin-invoice",
},
],
})Run migrations:
npx medusa db:migrateThis creates the required tables and seeds 5 built-in templates.
Built-in Templates
| Template | Type | Page Size | Description | |----------|------|-----------|-------------| | Classic Invoice | PDF | A4 | Full invoice with all sections | | Kitchen Order | PDF | A5 | Items + quantities only, no prices | | Packing Slip | PDF | A4 | Items + shipping address, no prices | | POS Receipt | PDF | 80mm | Compact thermal receipt layout | | HTML Invoice (Example) | HTML | A4 | Handlebars HTML template example |
Admin Pages
Invoice Settings (/app/settings/invoice-config)
Configure company information used across all templates:
- Company name, address, phone, email
- Company logo URL
- Notes/footer text
- Default template selection
Invoice Templates (/app/settings/invoice-templates)
Manage templates:
- View all templates with type, page size, and default indicator
- Create new templates (PDF or HTML type)
- Edit templates with live PDF preview panel
- Toggle section visibility (11 sections)
- Customize styles (font size, color, bold, italic) for PDF templates
- Delete custom templates (built-in templates are protected)
Order Invoice Widget
On each order detail page (order.details.side.before):
- Template selector dropdown
- Generate button
- Invoice list with template name, status, date, and download link
API Endpoints
Admin
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /admin/invoice-config | Get invoice configuration |
| POST | /admin/invoice-config | Update invoice configuration |
| GET | /admin/orders/:id/invoices | List invoices for an order |
| POST | /admin/orders/:id/invoices | Generate invoice (optional template_id in body) |
| GET | /admin/invoices/:id/download | Download invoice PDF |
| GET | /admin/invoice-templates | List all templates |
| POST | /admin/invoice-templates | Create a template |
| GET | /admin/invoice-templates/:id | Get a template |
| PUT | /admin/invoice-templates/:id | Update a template |
| DELETE | /admin/invoice-templates/:id | Delete a template (blocks built-ins) |
| POST | /admin/invoice-templates/:id/preview | Preview a saved template with sample data |
| POST | /admin/invoice-templates/preview | Preview unsaved template config |
Store
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /store/orders/:id/invoices | Download invoice PDF (customer) |
Creating Custom Templates
PDF Template
Create a template with type: "pdf" and configure sections:
{
"name": "My Custom Invoice",
"document_title": "TAX INVOICE",
"type": "pdf",
"page_size": "A4",
"sections": {
"company_header": true,
"company_details": true,
"invoice_metadata": true,
"billing_address": true,
"shipping_address": true,
"items_table": true,
"item_prices": true,
"totals": true,
"notes": true,
"thank_you": true,
"title_every_page": false
},
"styles": {
"companyName": { "fontSize": 20, "color": "#1a365d", "bold": true },
"invoiceTitle": { "fontSize": 28, "color": "#2c3e50" }
}
}HTML Template
Create a template with type: "html" and provide Handlebars HTML:
<div style="font-family: Helvetica, sans-serif;">
<h1>{{config.company_name}}</h1>
<h2>{{documentTitle}}</h2>
<p>Invoice: {{invoiceId}} | Date: {{invoiceDate}}</p>
<p>Order: #{{order.display_id}}</p>
<table>
<tr>
<th>Item</th><th>Qty</th><th>Price</th><th>Total</th>
</tr>
{{#each items}}
<tr>
<td>{{this.title}}</td>
<td>{{this.quantity}}</td>
<td>{{this.unit_price}} {{../currency}}</td>
<td>{{multiply this.unit_price this.quantity}} {{../currency}}</td>
</tr>
{{/each}}
</table>
<p><strong>Total: {{order.total}} {{currency}}</strong></p>
</div>Available Handlebars variables:
order- Full order object (display_id, created_at, total, subtotal, tax_total, etc.)config- Invoice config (company_name, company_address, company_phone, etc.)items- Order line items array (title, quantity, unit_price, variant)invoiceId- Invoice display IDinvoiceDate- Formatted invoice dateorderDate- Formatted order datedocumentTitle- Template document titlebillingAddress- Billing address objectshippingAddress- Shipping address objectcurrency- Currency code (uppercase)
Available Handlebars helpers:
{{multiply a b}}- Multiply two numbers{{uppercase str}}- Convert to uppercase{{formatDate date}}- Format a date string{{padStart val len char}}- Pad a value
Page Sizes
| Value | Dimensions | Use Case |
|-------|-----------|----------|
| A4 | 210 x 297mm | Standard invoices |
| A5 | 148 x 210mm | Kitchen orders, smaller documents |
| LETTER | 8.5 x 11in | US letter size |
| RECEIPT-80MM | 80mm x auto | Standard thermal receipt (most POS) |
| RECEIPT-58MM | 58mm x auto | Narrow thermal receipt |
Receipt sizes use dynamic height estimation based on content — the PDF is always a single page.
Section Visibility
| Section | Description |
|---------|-------------|
| company_header | Logo + company name + document title |
| company_details | Address, phone, email |
| invoice_metadata | Invoice ID, date, order ID, order date |
| billing_address | Bill-to address block |
| shipping_address | Ship-to address block |
| items_table | Order line items table |
| item_prices | Price and total columns in items table |
| totals | Subtotal, tax, shipping, total |
| notes | Footer notes from config |
| thank_you | "Thank you" message |
| title_every_page | Repeat header on every page (vs first page only) |
Events & Subscribers
The plugin listens to these events:
| Event | Action |
|-------|--------|
| order.placed | Generate invoice + send email with PDF attachment |
| order.updated | Mark existing invoices as stale |
| order-edit.confirmed | Mark existing invoices as stale |
| order.exchange_created | Mark existing invoices as stale |
| order.claim_created | Mark existing invoices as stale |
| order.return_received | Mark existing invoices as stale |
Workflows
Exported workflows you can use in custom code:
import {
generateInvoicePdfWorkflow,
markInvoiceStaleWorkflow,
updateInvoiceConfigWorkflow,
createInvoiceTemplateWorkflow,
updateInvoiceTemplateWorkflow,
deleteInvoiceTemplateWorkflow,
} from "@logicdine/medusa-plugin-invoice/workflows"generateInvoicePdfWorkflow
const { result: pdfBuffer } = await generateInvoicePdfWorkflow(container).run({
input: {
order_id: "order_123",
template_id: "inv_tmpl_kitchen", // optional, uses default if omitted
},
})Email Notifications
The plugin sends invoice PDFs as email attachments via Medusa's Notification Module. You need a configured notification provider (e.g. SendGrid, Resend) with an order-placed email template.
License
MIT
