Files
events-hub/backend/scripts/sample-billing-pdfs.js
T
joshuaandClaude Opus 5.5 6fce0fe90e Billing: invoices, approval, receipts, statements, licence changes (1.7.0)
- Invoices drafted 14 days before each licence's invoice date and emailed
  to the alert email for approval; approved ones go out on their date from
  08:00 SA time. Drafts can be edited, recalculated, sent early, put back
  to draft or voided; one-off invoices too.
- Annual tier review from the 12-month event-income band; approving a tier
  change emails a notice of licence change, applied when the invoice goes out.
  Notices can also be sent by hand.
- Founding churches (35% off as its own line), payments with receipts,
  statements for any dates.
- Every billing email is styled HTML with a PDF (invoice / tax invoice,
  receipt, statement, licence change) and logged per customer.
- Settings -> Billing: business and bank details, VAT (off: plain invoices;
  on: VAT-inclusive tax invoices), timing and numbering.
- Migration 20261103111645_invoicing; pdfkit 0.17.2; tests/billing.test.js;
  scripts/sample-billing-pdfs.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 13:42:45 +02:00

34 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Writes sample billing PDFs (invoice, receipt, statement, licence change) with made-up data, to
* check the layout after changing utils/billing/pdf.js: `node scripts/sample-billing-pdfs.js [dir]`.
* Needs no database.
*/
const fs = require('fs');
const path = require('path');
const { DEFAULTS } = require('../src/utils/settings');
const pdf = require('../src/utils/billing/pdf');
const { draftInvoice, invoiceState, statement } = require('../src/utils/billing/compute');
const out = path.resolve(process.argv[2] || 'billing-samples');
fs.mkdirSync(out, { recursive: true });
const settings = { ...DEFAULTS, bank_name: 'Sample Bank', bank_account_name: 'Cross Code', bank_account_number: '1234 567 890', bank_branch_code: '250655', bank_account_type: 'Cheque' };
const customer = { id: 'c1', name: 'Cedarwood Community Church', contactName: 'Thandi Nkosi', billingAddress: '12 Oak Street, Meyerton, 1961', email: 'office@cedarwood.example', founding: true };
const install = { adminContact: { email: 'admin@cedarwood.example' }, stats: { income: { eventIncome12m: 'R250 001–R400 000' } } };
const licence = { id: 'l1', plan: 'Sprout', billingCycle: 'monthly', billingStart: new Date('2026-01-01'), nextInvoiceDate: new Date('2027-01-01'), reviewDate: new Date('2027-01-01'), customMonthlyCents: null };
(async () => {
const { invoice: draft } = draftInvoice({ licence, customer, install, settings });
const invoice = { ...draft, id: 'i1', number: 'INV-2027-0001', status: 'sent', notes: null };
const payment = { id: 'p1', receiptNumber: 'REC-2027-0001', amountCents: 30000, paidOn: new Date('2027-01-05'), method: 'eft', reference: 'INV-2027-0001' };
const state = invoiceState({ ...invoice, payments: [payment] }, '2027-01-06');
fs.writeFileSync(path.join(out, 'invoice.pdf'), await pdf.invoicePdf({ invoice, customer, settings, state }));
fs.writeFileSync(path.join(out, 'invoice-draft.pdf'), await pdf.invoicePdf({ invoice: { ...invoice, status: 'draft' }, customer, settings, state: invoiceState({ ...invoice, payments: [] }, '2027-01-06') }));
fs.writeFileSync(path.join(out, 'receipt.pdf'), await pdf.receiptPdf({ payment, customer, invoice, state, settings, recipientEmail: invoice.recipientEmail }));
const older = { ...invoice, number: 'INV-2026-0012', issueDate: new Date('2026-12-01'), dueDate: new Date('2026-12-08'), periodStart: new Date('2026-12-01'), periodEnd: new Date('2026-12-31'), totalCents: 36000, payments: [] };
const st = statement({ invoices: [older, { ...invoice, payments: [payment] }], payments: [{ ...payment, invoice }], from: '2026-12-15', to: '2027-01-31' });
fs.writeFileSync(path.join(out, 'statement.pdf'), await pdf.statementPdf({ statement: st, customer, settings, recipientEmail: invoice.recipientEmail }));
const change = { number: 'LC-2026-0001', fromPlan: 'Sprout', toPlan: 'Grow', fromMonthlyCents: 55000, toMonthlyCents: 85000, effectiveDate: new Date('2027-01-01'), incomeBand: 'R250 001–R400 000', createdAt: new Date('2026-12-18') };
fs.writeFileSync(path.join(out, 'licence-change.pdf'), await pdf.licenceChangePdf({ change, customer, settings, founding: true, recipientEmail: invoice.recipientEmail, cycle: 'monthly' }));
console.log(`samples in ${out}`);
})();