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.

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); // 1

Best 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`);
}