Invoices
Create and manage invoices with full lifecycle tracking. Generate invoices from orders or create standalone invoices, track payment status, and record partial or full payments.
Important
Invoices can be linked to orders or created as standalone documents. When linked to an order, the invoice inherits the order's customer and items. All monetary amounts are stored in cents.
Invoice Model
class Invoice {
id: string; // Unique UUID identifier
invoiceNumber: string; // Sequential invoice number (e.g. "INV-0001")
orderId: string | null; // Optional reference to an order
customerId: string; // Reference to customer
items: InvoiceItem[]; // Line items
status: InvoiceStatus; // Current status
dueDate: Date; // Payment due date
paidAmount: number; // Amount paid so far (in cents)
}
type InvoiceStatus =
| "DRAFT"
| "SENT"
| "PAID"
| "PARTIALLY_PAID"
| "OVERDUE"
| "CANCELLED";InvoiceItem Model
interface InvoiceItem {
description: string; // Line item description
productId: string | null; // Optional reference to a product
quantity: number; // Quantity
unitPrice: number; // Price per unit in cents
taxRate: number; // Tax rate as percentage (e.g. 19)
taxRateId: string | null; // Optional reference to a tax rate
}Invoice Status Workflow
Invoice Lifecycle
100%
Loading diagram...
Invoice Operations
Create Invoice
Create an invoice with items:
import { createInvoiceService } from "commercio";
const invoiceService = createInvoiceService();
// Create an invoice
const invoice = await invoiceService.createInvoice({
customerId: "customer-123",
dueDate: new Date("2025-02-28"),
items: [
{
description: "Laptop Dell XPS 15",
productId: "product-laptop",
quantity: 1,
unitPrice: 99900, // $999.00
taxRate: 19,
taxRateId: "tax-rate-id",
},
{
description: "Wireless Mouse",
productId: "product-mouse",
quantity: 2,
unitPrice: 2999, // $29.99
taxRate: 19,
taxRateId: "tax-rate-id",
},
],
});
console.log(invoice.id); // UUID
console.log(invoice.invoiceNumber); // "INV-0001"
console.log(invoice.status); // "DRAFT"Create an invoice from an order:
// Create invoice linked to an existing order
const invoice = await invoiceService.createInvoice({
customerId: "customer-123",
orderId: "order-456",
dueDate: new Date("2025-02-28"),
items: [
{
description: "Laptop Dell XPS 15",
productId: "product-laptop",
quantity: 1,
unitPrice: 99900,
taxRate: 19,
},
],
});
console.log(invoice.orderId); // "order-456"Complete Example
import { createServices } from "commercio";
const { invoiceService } = createServices();
// 1. Create an invoice from an order
const invoice = await invoiceService.createInvoice({
customerId: "customer-123",
orderId: "order-456",
dueDate: new Date("2025-03-15"),
items: [
{
description: "Laptop Dell XPS 15",
productId: "product-laptop",
quantity: 1,
unitPrice: 99900, // $999.00
taxRate: 19,
},
{
description: "USB-C Adapter",
productId: "product-adapter",
quantity: 3,
unitPrice: 1499, // $14.99
taxRate: 19,
},
],
});
console.log(invoice.invoiceNumber); // "INV-0001"
console.log(invoice.status); // "DRAFT"
// 2. Send the invoice to the customer
const sent = await invoiceService.sendInvoice(invoice.id);
console.log(sent.status); // "SENT"
// 3. Record a partial payment ($500)
const partial = await invoiceService.recordPayment(invoice.id, {
amount: 50000,
});
console.log(partial.status); // "PARTIALLY_PAID"
console.log(partial.paidAmount); // 50000
// 4. Record the remaining payment
// Total: 99900 + (3 * 1499) = 99900 + 4497 = 104397
// Tax at 19%: 104397 * 0.19 = 19835
// Grand total: 104397 + 19835 = 124232
const remaining = 124232 - 50000; // 74232
const fullyPaid = await invoiceService.recordPayment(invoice.id, {
amount: remaining,
});
console.log(fullyPaid.status); // "PAID"
console.log(fullyPaid.paidAmount); // 124232
// 5. Retrieve the invoice
const retrieved = await invoiceService.getInvoiceById(invoice.id);
console.log(retrieved.invoiceNumber); // "INV-0001"
console.log(retrieved.status); // "PAID"
// 6. List all invoices for the customer
const customerInvoices = await invoiceService.getInvoicesByCustomer("customer-123");
console.log(customerInvoices.length); // 1Best Practices
1. Link Invoices to Orders
When creating invoices for orders, always set the orderId to maintain traceability:
// Good: Link invoice to order
const invoice = await invoiceService.createInvoice({
customerId: order.customerId,
orderId: order.id, // Links to the source order
dueDate: new Date("2025-03-15"),
items: orderItems,
});2. Set Reasonable Due Dates
Always set a due date and check for overdue invoices regularly:
// Set due date 30 days from now
const dueDate = new Date();
dueDate.setDate(dueDate.getDate() + 30);
const invoice = await invoiceService.createInvoice({
customerId: customerId,
dueDate: dueDate,
items: items,
});3. Track Partial Payments
Use the paidAmount field to track payment progress and calculate remaining balances:
const invoice = await invoiceService.getInvoiceById(invoiceId);
// Calculate totals
const subtotal = invoice.items.reduce(
(sum, item) => sum + item.unitPrice * item.quantity, 0
);
const tax = invoice.items.reduce(
(sum, item) => sum + Math.round(item.unitPrice * item.quantity * item.taxRate / 100), 0
);
const total = subtotal + tax;
const remaining = total - invoice.paidAmount;
console.log(`Remaining: $${(remaining / 100).toFixed(2)}`);4. Handle Status Transitions Carefully
Always check the current status before attempting a transition:
const invoice = await invoiceService.getInvoiceById(invoiceId);
if (invoice.status === "DRAFT") {
await invoiceService.sendInvoice(invoiceId);
} else if (invoice.status === "SENT" || invoice.status === "PARTIALLY_PAID") {
await invoiceService.recordPayment(invoiceId, { amount: paymentAmount });
} else {
console.log(`Invoice is ${invoice.status}, no action taken`);
}