Files
core/src/modules/invoice
2026-04-12 12:50:14 -04:00
..
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00
2026-04-12 12:50:14 -04:00

Invoice Module

Full billing system with clients, items, categories, transactions, and recurrences. Supports Stripe and Interac payments, automatic interest on overdue invoices, email reminders, and PDF generation.


Features

  • Invoices with automatic numbering (CLIENTYEAR##, e.g. 0120250l)
  • Public payment page via secure token (Stripe, Interac, or manual)
  • Statuses: draftsentpartial / overduepaid / cancelled
  • Reusable items catalogued by categories
  • Transactions recorded automatically (Stripe webhook) or manually
  • Recurrences: automatic invoice generation at configurable intervals
  • Interest: automatic interest on overdue invoices (configurable rate and grace period)
  • Email reminders: automatic reminders before and after the due date
  • PDF: invoice and payment receipt
  • Client dashboard: "my invoices" portal for logged-in users

Installation

1. Environment variables

Copy variables from .env.example into your .env:

2. Stripe Webhook Configuration

Get your webhook URL:

  • Production: https://yourdomain.com/zen/api/webhook/stripe
  • Development: http://localhost:3000/zen/api/webhook/stripe

Configure in Stripe Dashboard:

  1. Go to Stripe Dashboard > Developers > Webhooks
  2. Click "Add endpoint"
  3. Enter your webhook URL
  4. Select events:
    • checkout.session.completed
    • payment_intent.succeeded
    • payment_intent.payment_failed
  5. Click "Add endpoint"

Add webhook secret to .env:

  1. Click on the endpoint in Stripe Dashboard
  2. Copy the "Signing secret" (starts with whsec_)
  3. Add to .env: STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx

Test webhook (optional):

stripe listen --forward-to localhost:3000/zen/api/webhook/stripe

3. Database tables

Tables are created automatically with npx zen-db init. For reference, here are the module tables:

Table Description
zen_invoices Invoices
zen_invoice_items Invoice line items
zen_invoice_reminders Sent reminder history
zen_invoice_interac Interac details per client
zen_transactions Received payments
zen_recurrences Recurring billing configurations
zen_items Reusable item catalogue
zen_categories Item categories

This module depends on zen_clients (clients module).


Admin interface

Page URL
Invoice list /admin/invoice/invoices
Create invoice /admin/invoice/invoices/new
Edit invoice /admin/invoice/invoices/edit
Item list /admin/invoice/items
Create item /admin/invoice/items/new
Edit item /admin/invoice/items/edit
Category list /admin/invoice/categories
Create category /admin/invoice/categories/new
Edit category /admin/invoice/categories/edit
Transactions /admin/invoice/transactions
Add transaction /admin/invoice/transactions/new
Recurrences /admin/invoice/recurrences
Create recurrence /admin/invoice/recurrences/new
Edit recurrence /admin/invoice/recurrences/edit

Public pages (no authentication)

URL Description
/invoice/:token Invoice payment page
/invoice/:token/pdf Invoice PDF viewer
/invoice/:token/receipt Payment receipt PDF

Each invoice gets a unique 64-character hex token on creation. This token is the only access method for the client.


Admin API (authentication required)

Invoices

Method Route Description
GET /zen/api/admin/invoices Invoice list (paginated)
GET /zen/api/admin/invoices?id={id} Invoice by ID
POST /zen/api/admin/invoices Create an invoice
PUT /zen/api/admin/invoices?id={id} Update an invoice
DELETE /zen/api/admin/invoices?id={id} Delete an invoice (rejected if paid)

List parameters:

Parameter Default Description
page 1 Current page
limit 20 Results per page
search Text search
status Filter by status
client_id Filter by client
sortBy created_at Sort field
sortOrder DESC ASC or DESC

Invoice statuses:

Status Description
draft Draft — not sent to client
sent Sent — awaiting payment
partial Partially paid
overdue Overdue (past due date)
paid Paid in full
cancelled Cancelled

Items

Method Route Description
GET /zen/api/admin/items Item list
GET /zen/api/admin/items?id={id} Item by ID
POST /zen/api/admin/items Create an item
PUT /zen/api/admin/items?id={id} Update an item
DELETE /zen/api/admin/items?id={id} Delete an item

Categories

Method Route Description
GET /zen/api/admin/categories Category list
GET /zen/api/admin/categories?id={id} Category by ID
POST /zen/api/admin/categories Create a category
PUT /zen/api/admin/categories?id={id} Update a category
DELETE /zen/api/admin/categories?id={id} Delete a category

Transactions

Method Route Description
GET /zen/api/admin/transactions Transaction list
GET /zen/api/admin/transactions?id={id} Transaction by ID
GET /zen/api/admin/transactions?invoice_id={id} Transactions for an invoice
GET /zen/api/admin/transactions?client_id={id} Transactions for a client
POST /zen/api/admin/transactions Record a payment
PUT /zen/api/admin/transactions?id={id} Update a transaction

When creating a transaction, pass send_confirmation_email: true in the body to send a confirmation email to the client.

Recurrences

Method Route Description
GET /zen/api/admin/recurrences Recurrence list
GET /zen/api/admin/recurrences?id={id} Recurrence by ID
POST /zen/api/admin/recurrences Create a recurrence
PUT /zen/api/admin/recurrences?id={id} Update a recurrence
DELETE /zen/api/admin/recurrences?id={id} Delete a recurrence

Client API (user authentication required)

GET /zen/api/invoices/me

Returns invoices linked to the current user's client account. Invoices with draft status are never exposed.

Parameters: page, limit, status, sortBy, sortOrder

Response:

{
  "success": true,
  "linkedClient": {
    "id": 1,
    "client_number": "01",
    "company_name": "Acme Inc.",
    "first_name": "Jean",
    "last_name": "Tremblay",
    "email": "jean@exemple.com"
  },
  "invoices": [...],
  "total": 5,
  "totalPages": 1,
  "page": 1,
  "limit": 20
}

If the user account is not linked to a client, linkedClient is null and invoices is [].


Interest on overdue invoices

Interest is calculated automatically every 5 minutes (cron) on invoices with statuses sent, partial, and overdue whose due date has passed.

Formula (simple interest):

daily_rate = monthly_rate / 30.4375
daily_interest = principal × daily_rate
  • principal = total_amount - paid_amount
  • Calculation starts after the grace period (ZEN_MODULE_INVOICE_INTEREST_GRACE_DAYS)
  • Interest is cumulative (added to the invoice's interest_amount field)
  • One update per day per invoice (internal deduplication)

Automatic reminders

The invoice-reminders cron runs every 5 minutes and sends emails:

  • Pre-due reminder: X days before the due date (configured per invoice via first_reminder_days)
  • Overdue reminder: after the due date
  • Admin notification: email sent to ZEN_MODULE_INVOICE_OVERDUE_EMAIL when an invoice becomes overdue

One reminder of each type is sent per day per invoice.


Recurrences

The invoice-recurrences cron runs every 5 minutes (between 8am and 5pm) and automatically creates new invoices based on the configured frequency. Generated invoices are created with draft status and can be sent manually.


Invoice numbering

Format: CLIENT_NUMBER + YEAR + SEQUENCE

Example: client 01, year 2025, 3rd invoice → 01202503

The sequence resets each year per client.