Skip to content
Nikesh Khatri
All work

ERP

Jul – Aug 2026

Independent product

Garment Manufacturing ERP

Order to ledger for a factory floor — merchandising, production, tax and double-entry accounting in one self-hostable system.

Trial balance report in the Garment ERP with an “Accounts match” badge: account codes 1300–5400 with debit and credit columns, both totalling Rs 2,291,700.00.
Every invoice, purchase, payroll run and stock movement posts a balanced journal, so the trial balance matches to the paisa.

Role

Sole engineer — architecture, backend, frontend, deployment

Stack

  • Django
  • DRF
  • PostgreSQL
  • React
  • Vite
  • TypeScript
  • Celery
  • Redis
  • Docker
  • Tailwind CSS
  • Playwright
  • Vitest
  • Tauri
  • ReportLab

Evidence

Merged pull requests
159
Commits
516

The problem

What this had to solve.

A garment factory runs on quotes, cut tickets, piece-rate payslips and tax invoices that mostly live in spreadsheets and on paper. Nothing reconciles: the costing sheet does not agree with the purchase ledger, and the VAT return is assembled by hand at the end of the month. The system had to cover the whole chain — from a buyer enquiry to a posted journal entry — and run on the factory’s own hardware.

Architecture

How it actually works.

Invoice to statementsArchitecture
Confirming a document emits a balanced journal entry inside the same database transaction, so the trial balance is derived rather than reconciled. Voids and credit notes post compensating entries instead of mutating history, which is what lets an auditor reconstruct the books as they stood on any given day.DOCUMENTBALANCED POSTINGSTATEMENTSInvoiceconfirmedJournal entrysame transactionDEBITaccounts receivableCREDITsales + VATTrial balanceP & LBalance sheetΣ DR = Σ CRenforced at write time

Confirming a document emits a balanced journal entry inside the same database transaction, so the trial balance is derived rather than reconciled. Voids and credit notes post compensating entries instead of mutating history, which is what lets an auditor reconstruct the books as they stood on any given day.

What I built

My contribution.

  • 01

    Built an end-to-end ERP spanning merchandising, orders, costing, procurement, inventory, production, quality, shipping, HR/payroll, tax billing and accounting.

  • 02

    Implemented double-entry accounting with invoice-to-ledger posting, supplier and client statements, AR aging, P&L, balance sheet, VAT, credit/debit notes and IRD/CBMS billing workflows.

  • 03

    Developed production features including WIP tracking, piece-rate and SAM workflows, barcode-first logging, QC inspections, rework loops and DHU reporting.

  • 04

    Delivered a responsive bilingual interface with Bikram Sambat dates, PWA support, optional Tauri desktop packaging and guided task workspaces.

  • 05

    Added hardened deployment, backups, health checks, production security controls and release/handover documentation for self-hosted operation.

The hard part

Making every money movement post itself

The temptation in an ERP is to let accounting be a reporting layer bolted on at the end — read the invoices table, sum it, call it revenue. That falls apart the moment someone voids an invoice or issues a credit note. I moved the ledger to the centre instead: every document that moves money emits a balanced journal entry at the moment it is confirmed, inside the same database transaction. Reports then read only from the ledger, so the trial balance is the source of truth rather than a coincidence. The hard part was reversals — credit notes, voids and edits had to post compensating entries rather than mutate history, so an auditor can always reconstruct what the books said on any given day.

Read the full note, with the code →

Interface

What it looks like in use.

VAT sales register for September 2026 listing seven tax invoices, INV-2026-27-000001 to 000007, with Bikram Sambat dates beside AD dates and net, 13% VAT and gross amounts.

Gapless per-fiscal-year invoice numbers, the VAT rate frozen at issue, and an IRD-ready register in AD and BS dates.

“Where are the pieces” production table by style: 1,320 pieces cut equals 320 with workers plus 992 in finished stock plus 8 spoiled.

Event-sourced work in progress: every cut piece is accounted for from the cutting table to finished stock, and the columns reconcile.