Full-stack textile manufacturing ERP. This document summarizes the existing project and specifies the Client Invoice & Payment Ledger feature for the
/ordersmodule (http://localhost:8080/orders).
- Project Overview
- Current Implementation Status
- Tech Stack
- Existing Modules Summary
- New Feature: Client Invoice & Payment Ledger
- Business Rules & Calculations
- Data Model (Proposed)
- UI / UX Specification
- PDF Outputs
- API Endpoints (Proposed)
- File Structure (Planned Additions)
- Implementation Task List
- Open Questions
- Getting Started
TextileERP digitizes the full textile production lifecycle — from receiving a client order through material sourcing, production expenses, quality control, inventory, and reporting.
| Area | Description |
|---|---|
| Orders | Client PO capture, size/color breakdown, production status, delivery timeline |
| Materials | 4-step pipeline: Order → Evaluate → Material Utilized → Inventory Left Over |
| Inventory | Stock levels with in/out history |
| Expenses | Local buyer, cutting, stitching, finishing/QC, fixed, and admin costs per order |
| Reports | P&L, monthly summaries, PDF/CSV export |
| Auth | JWT login/signup with role-based access |
Client Order → Material Evaluation → Cutting → Stitching → Finishing/QC → Dispatch
↓
Expense tracking at each stage
↓
Reports & P&L per order
For full architectural detail, database schemas, and API design for all modules, see guide.md.
| Layer | Status | Notes |
|---|---|---|
| Frontend | ✅ Running | React 18 + Vite on port 8080 |
| UI | ✅ Built | shadcn/ui, dark theme, responsive layout |
| Orders list | ✅ Mock data | OrdersPage.tsx — filter, sort, search |
| Order detail | ✅ Mock data | OrderDetailPage.tsx — breakdown, timeline, workflow |
| PDF export | ✅ Partial | orderPdf.ts, expensePdf.ts, inventoryPdf.ts, reportsPdf.ts via jsPDF |
| Backend | ❌ Not wired | No Express/MongoDB connected yet — all data in src/data/*.ts |
| Auth | ✅ UI only | Login/signup pages exist; no real API |
| Invoice / payments | ❌ Not built | "Invoice" button on order detail is a placeholder |
Currency today: PKR (Rs) via src/lib/currency.ts.
Manual process reference (screenshots): GBP (£) CNF pricing per piece for export clients.
| Layer | Technology |
|---|---|
| Frontend | React 18, Vite, TypeScript, TailwindCSS, shadcn/ui |
| Routing | React Router v7 |
| State | React Query (installed), local state + mock data files |
| jsPDF + jspdf-autotable | |
| Backend (planned) | Node.js, Express, Mongoose, MongoDB Atlas |
| Auth (planned) | JWT + bcrypt |
- List (
/orders): searchable table with status pills, date filters, sortable columns - Detail (
/orders/:id): client info, size/color breakdown, production progress, delivery overview, workflow stepper - Actions: Print order summary PDF, placeholder Invoice button, New Order dialog
- Statuses:
draft,active,in-production,qc-hold,completed,dispatched,overdue
4-step stepper: Order overview → Evaluate → Material utilized → Inventory leftover
Material stock levels, reorder alerts, PDF export
Tabs: Local Buyer, Cutting, Stitching, Finishing, Fixed, Admin — each with line items and totals
KPIs, charts, PDF export
Factory name, address (used in PDF headers)
Your company currently tracks export/client billing in spreadsheets:
-
Sheet 1 — Order line items per client
All products and charges for one client in a running list: description, qty, CNF price/pc, invoice value, color-coded fulfillment status. Includes a previous outstanding amount row and a total amount of goods footer. -
Sheet 2 — Payment ledger per client
Running account: total goods value, individual payments received (dated), total received, and balance outstanding.
This must be replicated professionally inside the app — only on the Orders side — with PDF download, credit/debit handling, and batch invoicing.
| Goal | Description |
|---|---|
| Client-centric ledger | One client can have many order line items; view and manage them together |
| Fulfillment tracking | Status per line (delivered, in process, partial, waiting design, etc.) with color coding |
| Debit / credit accounting | Proper ledger entries: invoices (debit client), payments (credit), credit notes (cancel/adjust) |
| Payment recording | Add payments as client sends money; auto-update balance |
| Batch invoicing | Select delivered/uninvoiced lines → bundle into one invoice → download PDF |
| Opening balance | Carry forward prior outstanding (e.g. £4,110.00) when onboarding a client |
| Audit trail | Every invoice, payment, and adjustment is dated, numbered, and immutable once issued |
| In scope | Out of scope (for now) |
|---|---|
/orders list — client filter / client account entry point |
Materials, inventory, expenses modules |
| Client account view (ledger + line items) | Multi-currency FX conversion |
| Invoice PDF generation | Bank reconciliation / payment gateway |
| Credit notes for cancellations | Tax/VAT engine (unless specified later) |
| Payment input form | Email invoice to client (future) |
Image 1 — Order tracking sheet
| Column | App field |
|---|---|
| Sr. # | Auto serial / line number |
| Product Description | description (hoodies, patches, courier charges, etc.) |
| Quantity (Pcs) | quantity |
| CNF Price/Pc (GBP) | unitPrice + currency |
| Invoice Value (GBP) | quantity × unitPrice (computed) |
| Row color | fulfillmentStatus |
Status legend (from screenshot)
| Color | Status |
|---|---|
| Green | Goods Delivered |
| Blue | Waiting Sticker Design |
| Orange | In Process |
| Yellow | Partial Delivered |
Special rows
| Row type | Treatment |
|---|---|
| Previous outstanding amount | openingBalance on client account (one-time or imported) |
| Courier / service charges | Regular line item with type: "service" |
| Total Amount of Goods | Computed: openingBalance + sum(active line items) |
Image 2 — Payment ledger
| Row | App field |
|---|---|
| Total Amount of Goods | totalDebits (ledger summary) |
| Received Payment [date] | Payment entry with type: "payment_received" |
| Total Amount received | sum(payments) |
| Total Balance Payment | totalDebits - totalReceived (negative = client owes) |
Client Account Balance = Total Debits − Total Credits
Where:
Debits = Invoices issued + opening balance + debit adjustments
Credits = Payments received + credit notes (cancellations, returns, discounts)
| Transaction type | Effect on balance | Example |
|---|---|---|
| Opening balance | Increases what client owes (debit) | £4,110 prior outstanding |
| Invoice issued | Increases balance (debit) | Batch invoice for 5 delivered lines = £12,400 |
| Payment received | Decreases balance (credit) | £2,000 on 09-Oct-2025 |
| Credit note | Decreases balance (credit) | Order cancelled — reverse £3,500 |
| Debit note | Increases balance (debit) | Extra courier charge added after dispatch |
Created → In Process → Partial Delivered → Delivered
↘ Waiting Design ↗
↘ Cancelled (triggers credit note option)
Invoicing rule (default): Only lines with status delivered or partial-delivered (configurable qty) can be added to an invoice batch. Lines already on a finalized invoice cannot be re-invoiced.
1. User opens Client Account from /orders
2. Filters line items (e.g. status = Delivered, not yet invoiced)
3. Selects lines → "Create Invoice"
4. System generates:
- Invoice number (INV-2026-001)
- Line items with qty, unit price, subtotals
- Invoice total
- Ledger debit entry linked to invoice
5. User downloads PDF
6. Invoice status = Issued (locked)
1. User clicks "Record Payment"
2. Enters: date, amount, reference/note, payment method (optional)
3. System creates credit ledger entry
4. Balance updates immediately
5. Optional: allocate payment to specific invoice(s) — see Open Questions
1. User marks line item as Cancelled (or reduces qty on partial cancel)
2. System prompts: "Issue credit note?"
3. Credit note created:
- CN-2026-001
- References original line / invoice if applicable
- Reduces client balance
4. Credit note PDF available for download
type Client = {
id: string;
name: string; // e.g. "Scotland Print Client"
contact?: { name; email; phone };
billingAddress?: string;
currency: "GBP" | "PKR" | "USD"; // per-client currency
openingBalance: number; // debit carried forward
openingBalanceDate?: string;
openingBalanceNote?: string; // e.g. "Imported from spreadsheet"
createdAt: string;
};type FulfillmentStatus =
| "in-process"
| "waiting-design"
| "partial-delivered"
| "delivered"
| "cancelled";
type LineItemType = "product" | "service" | "adjustment";
type ClientLineItem = {
id: string;
clientId: string;
orderId?: string; // link to production order if exists
serialNumber: number; // Sr. # in sheet
description: string;
quantity: number;
unitPrice: number;
invoiceValue: number; // computed: qty × unitPrice
currency: string;
type: LineItemType;
fulfillmentStatus: FulfillmentStatus;
invoiced: boolean;
invoiceId?: string; // set when included in issued invoice
creditNoteId?: string; // if cancelled / credited
orderDate?: string;
notes?: string;
createdAt: string;
updatedAt: string;
};type InvoiceStatus = "draft" | "issued" | "void";
type Invoice = {
id: string;
invoiceNumber: string; // INV-2026-001
clientId: string;
lineItemIds: string[];
subtotal: number;
openingBalanceIncluded: number; // if first invoice includes opening balance
total: number;
currency: string;
status: InvoiceStatus;
issuedAt?: string;
dueDate?: string;
notes?: string;
pdfUrl?: string; // if stored in cloud later
createdBy?: string;
};type CreditNote = {
id: string;
creditNoteNumber: string; // CN-2026-001
clientId: string;
lineItemId?: string;
invoiceId?: string; // original invoice if partial cancel
amount: number;
reason: string; // "Order cancelled", "Qty reduction", etc.
currency: string;
issuedAt: string;
};type LedgerEntryType =
| "opening_balance"
| "invoice"
| "payment"
| "credit_note"
| "debit_note";
type LedgerEntry = {
id: string;
clientId: string;
type: LedgerEntryType;
date: string;
description: string; // "Received Payment 09-Oct-2025"
debit: number; // increases client owes
credit: number; // decreases client owes
balance: number; // running balance after entry
referenceId?: string; // invoiceId, paymentId, creditNoteId
createdAt: string;
};type Payment = {
id: string;
clientId: string;
date: string;
amount: number;
currency: string;
description: string; // "Payment received 11-Jun-2026"
method?: "bank_transfer" | "cash" | "other";
reference?: string; // bank ref / cheque no.
allocatedInvoiceIds?: string[]; // optional payment allocation
};type ClientAccountSummary = {
clientId: string;
totalAmountOfGoods: number; // opening + all active line items (or ledger debits)
totalAmountReceived: number; // sum of payments + credit notes
balanceOutstanding: number; // totalDebits - totalCredits (negative = client owes)
lineItemCount: number;
uninvoicedDeliveredCount: number;
};| Route | Page | Purpose |
|---|---|---|
/orders |
Orders list (existing) | Add "Client Accounts" tab or toggle; group/filter by client |
/orders/clients/:clientId |
Client Account (new) | Main ledger + line items view |
/orders/clients/:clientId/invoices/:invoiceId |
Invoice detail (new) | View issued invoice, re-download PDF |
┌─────────────────────────────────────────────────────────────┐
│ ← Orders CLIENT NAME [Record Payment] │
│ Balance: -£15,021.02 (outstanding) [New Invoice]│
├─────────────────────────────────────────────────────────────┤
│ Summary cards: │
│ Total Goods £94,021 │ Received £79,000 │ Outstanding £15,021│
├──────────────────────────┬──────────────────────────────────┤
│ LINE ITEMS (tab) │ PAYMENT LEDGER (tab) │
│ ┌──┬──────────┬───┬────┐│ ┌────────────────┬──────────┐ │
│ │☐ │ Product │Qty│ £ ││ │ Description │ Amount │ │
│ │☐ │ Hoodies │800│3.4k││ │ Total Goods │ 94,021 │ │
│ │☐ │ Courier │ 1 │450 ││ │ Payment 09-Oct │ 2,000 │ │
│ └──┴──────────┴───┴────┘│ │ ... │ │ │
│ Status filter pills │ │ Total Received │ 79,000 │ │
│ Color-coded rows │ │ Balance │-15,021 │ │
│ [+ Add line item] │ │ [+ Add payment]│ │ │
└──────────────────────────┴──────────────────────────────────┘
| Column | Notes |
|---|---|
| Checkbox | For batch invoice selection |
| Sr. # | Serial |
| Description | Full product/service text |
| Qty (Pcs) | Editable until invoiced |
| CNF Price/Pc | Unit price in client currency |
| Invoice Value | Computed, read-only |
| Status | Badge with color (green/blue/orange/yellow) |
| Invoiced | Yes/No + invoice link |
| Status | Tailwind / CSS token |
|---|---|
| Delivered | bg-success/15 text-success (green) |
| Waiting Sticker Design | bg-info/15 text-info (blue) |
| In Process | bg-warning/15 text-warning (orange) |
| Partial Delivered | bg-yellow-500/15 text-yellow-600 (yellow) |
| Cancelled | bg-muted text-muted-foreground (grey, strikethrough) |
| Action | Who / when |
|---|---|
| Add line item | New product row or service charge |
| Update status | Production/dispatch team as goods move |
| Select + Create Invoice | Finance — bundle delivered lines |
| Record Payment | Finance — when client pays |
| Issue Credit Note | On cancel or dispute |
| Set opening balance | Once per client onboarding |
| Download Statement PDF | Full ledger export |
| Download Invoice PDF | Per issued invoice |
- Add view mode:
All Orders|By Client - In
By Clientmode: show one row per client with order count, total goods, balance, last payment date - Click client row →
/orders/clients/:clientId
Reuse existing jsPDF + autotable pattern (src/lib/orderPdf.ts).
Filename: INV-2026-001-{ClientName}.pdf
Sections:
- Company header (from Settings)
- Client billing details
- Invoice number, date, due date
- Line items table: Sr., Description, Qty, CNF Price/Pc, Amount
- Subtotal
- Optional: opening balance line
- Invoice Total
- Footer: payment terms, bank details
Style: Match professional export invoice — clean table, GBP formatting (£ 4,350.00).
Filename: {ClientName}-statement-{date}.pdf
Sections:
- Client name + period
- Total Amount of Goods (blue header row)
- All payment rows (yellow-style alternating rows)
- Total Amount Received
- Balance Outstanding
Filename: CN-2026-001-{ClientName}.pdf
- References original invoice/line
- Credit amount and reason
Add formatGBP() alongside formatPKR() in src/lib/currency.ts, or a generic formatMoney(amount, currency) helper.
When backend is connected:
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/clients |
List clients with account summaries |
| POST | /api/clients |
Create client |
| GET | /api/clients/:id |
Client detail + summary |
| PUT | /api/clients/:id |
Update client / opening balance |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/clients/:id/line-items |
All line items for client |
| POST | /api/clients/:id/line-items |
Add line item |
| PUT | /api/clients/:id/line-items/:lineId |
Update qty, price, status |
| DELETE | /api/clients/:id/line-items/:lineId |
Soft delete (only if not invoiced) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/clients/:id/invoices |
List invoices |
| POST | /api/clients/:id/invoices |
Create invoice from selected line IDs |
| GET | /api/invoices/:invoiceId |
Invoice detail |
| POST | /api/invoices/:invoiceId/void |
Void draft / issued (with rules) |
| GET | /api/invoices/:invoiceId/pdf |
Generate / return PDF |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/clients/:id/ledger |
Full ledger with running balance |
| POST | /api/clients/:id/payments |
Record payment |
| POST | /api/clients/:id/credit-notes |
Issue credit note |
| GET | /api/clients/:id/statement/pdf |
Statement PDF |
erp/src/
├── data/
│ ├── clients.ts # Mock clients + line items + ledger
│ └── clientAccounts.ts # Summary helpers, balance calculations
├── lib/
│ ├── currency.ts # + formatGBP / formatMoney
│ ├── clientInvoicePdf.ts # Invoice PDF generator
│ ├── clientStatementPdf.ts # Statement / ledger PDF
│ └── creditNotePdf.ts # Credit note PDF
├── components/orders/
│ ├── ClientAccountSummary.tsx
│ ├── ClientLineItemsTable.tsx
│ ├── ClientLedgerTable.tsx
│ ├── RecordPaymentDialog.tsx
│ ├── CreateInvoiceDialog.tsx
│ ├── CreditNoteDialog.tsx
│ ├── AddLineItemDialog.tsx
│ └── FulfillmentStatusBadge.tsx
└── pages/orders/
├── OrdersPage.tsx # + client view mode
└── ClientAccountPage.tsx # NEW — main feature page
- A1. Create
src/data/clients.tswith sample client matching screenshot data (GBP, ~46 line items, opening balance £4,110, payments ledger) - A2. Add
formatGBP()/formatMoney(currency)tosrc/lib/currency.ts - A3. Implement
computeClientSummary()— total goods, received, balance - A4. Implement
buildLedger()— running balance from opening balance, lines, invoices, payments, credit notes - A5. Add
FulfillmentStatusBadgecomponent with color coding from manual sheet
- B1. Create
ClientAccountPage.tsxat route/orders/clients/:clientId - B2. Build summary KPI cards (Total Goods, Received, Outstanding)
- B3. Build line items table with status filters, checkbox selection, color-coded rows
- B4. Build payment ledger tab/table (mirror screenshot 2 layout)
- B5.
RecordPaymentDialog— date, amount, description, optional reference - B6.
AddLineItemDialog— description, qty, unit price, type, initial status - B7.
CreateInvoiceDialog— preview selected lines, confirm, assign invoice number - B8.
CreditNoteDialog— trigger from cancelled line or manual adjustment - B9. Wire routes in
App.tsx
- C1. Add "By Client" view toggle on
OrdersPage.tsx - C2. Client grouped rows: name, # orders, total goods, balance, last payment
- C3. Link each client row to
ClientAccountPage - C4. Keep existing per-order table as "All Orders" view
- D1.
generateClientInvoicePdf()— professional invoice layout - D2.
generateClientStatementPdf()— ledger statement (image 2 style) - D3.
generateCreditNotePdf()— credit note document - D4. Hook PDF buttons on Client Account and Invoice detail views
- D5. Use Settings workspace details in PDF header
- E1. Prevent invoicing already-invoiced lines
- E2. On invoice issue: mark lines invoiced, create ledger debit entry
- E3. On payment: create ledger credit entry, update balance
- E4. On credit note: reduce balance, link to line/invoice
- E5. Cancellation flow: status → cancelled, prompt credit note
- E6. Opening balance: editable once on client setup
- E7. Partial delivery: allow invoicing delivered qty only (if confirmed — see Open Questions)
- F1. On
OrderDetailPage, link "Invoice" button to client account (not standalone) - F2. Show invoice status on order if line item is linked
- F3. Optionally auto-create client line item when production order reaches
dispatched
- G1. Mongoose models: Client, ClientLineItem, Invoice, Payment, CreditNote, LedgerEntry
- G2. REST endpoints per API table above
- G3. Replace mock data with React Query hooks
- G4. Persist PDFs to Cloudinary/S3 (optional)
- G5. Auth guards — finance role for payments/invoices
- H1. Empty states (no clients, no payments, no delivered lines)
- H2. Confirm dialogs for void invoice / large credit note
- H3. Toast notifications on payment / invoice / credit note
- H4. Export ledger CSV
- H5. Manual test against spreadsheet numbers (totals must match £94,021.02 / £79,000 / £15,021.02)
- H6. Responsive layout for tablet/desktop
Please confirm these before implementation starts:
-
Currency — Screenshots use GBP. Rest of app uses PKR. Should export clients use GBP per client while local orders stay PKR? Or convert everything to one currency?
-
Line items vs production orders — Should each spreadsheet row map 1:1 to an existing
Orderin the app, or can finance add standalone rows (courier, patches) without a production order? -
Opening balance — Is it a one-time import per client, or can it be adjusted later with a debit/credit note?
-
Payment allocation — Are payments applied to the general client account (as in the screenshot), or must each payment be linked to a specific invoice?
-
Partial delivery invoicing — Invoice full line qty or only the delivered portion?
-
Invoice numbering — Preferred format? e.g.
INV-2026-001, or client-specific prefix? -
Company details for PDF — Business name, address, bank details for GBP receipts — should these live in Settings?
-
First client to seed — Should we use the exact Scotland/export client from the screenshot as demo data?
cd erp
npm install
npm run dev
# → http://localhost:8080| Route | Description |
|---|---|
/orders |
Orders list (feature will extend this) |
/orders/:id |
Single order detail |
/orders/clients/:clientId |
(planned) Client account & invoicing |
| File | Contents |
|---|---|
guide.md |
Full system spec, DB schemas, all modules, dev phases |
frontend.md |
Frontend module notes |
DESIGN.md |
UI design tokens and patterns |
Last updated: June 2026 — Client Invoice & Payment Ledger feature spec added.