Worker Payment Lifecycle & Ledger Architecture
This document describes how worker earnings, payments, and adjustments are tracked and audited in Floorix using a double-entry ledger model.
Overview
Floorix uses the worker ledger as the single source of truth for all financial transactions between a factory and its workers. Rather than attempting per-job settlement matching (which breaks down when advances, deductions, corrections, or lump-sum payments occur), payments are made to workers as a whole.
The architecture is built on three core transaction types recorded in the LedgerEntry collection:
job_earning(Credit): Added automatically when a worker completes a job step. Increases the worker's balance.payment(Debit): Added when management makes a payment (Cash, Bank Transfer, etc.) to the worker. Decreases the worker's balance.adjustment(Credit or Debit): Added manually by management for bonuses, advance repayments, deductions, or accounting corrections.
Worker Balance Field
The balance field on a Worker document represents the current net amount owed:
| Value | Meaning |
|---|---|
balance > 0 |
Factory owes the worker. Worker has accumulated net earnings. |
balance = 0 |
Account is fully settled. Nothing is owed in either direction. |
balance < 0 |
Worker was paid in advance (negative balance). Future completed jobs will bring the balance back toward zero or positive. |
Transaction Flows
1. Job Step Completion (job_earning)
When a job step transitions to Completed in jobController.ts:
- Earned amount is calculated from the job item size quantities and step rate snapshot (
jobDetails.rate × jobDetails.pairs). - An entry is created in
LedgerEntry:await addEntry({ workerId, type: "job_earning", credit: amount, debit: 0, description: `${stepName} completed - ${jobName}`, referenceId: job.jobId, referenceModel: "Job", jobDetails: { articleName, stepName, rate, pairs }, tenantId, }); worker.balanceincreases byamount.- An immutable audit record is stored with
runningBalance.
2. Worker Payment (payment)
When management records a payment in the Ledger or Transactions page:
- A
Transactionrecord is created (with amount and payment method like Cash/Transfer). - A corresponding debit entry is added to
LedgerEntry:await addEntry({ workerId, type: "payment", credit: 0, debit: paymentAmount, description: `Payment - ${transactionType}`, referenceId: transaction.transactionId, referenceModel: "Transaction", tenantId, }); worker.balancedecreases bypaymentAmount.- If payment exceeds the current balance,
worker.balancesmoothly transitions to a negative value (advance credit).
3. Manual Adjustment (adjustment)
When an admin records a manual adjustment directly in the Ledger:
- Admin specifies a credit (bonus/incentive) or debit (advance/deduction/penalty) and description.
addEntryrecords the adjustment:await addEntry({ workerId, type: "adjustment", credit: credit || 0, debit: debit || 0, description: description || "Manual adjustment", tenantId, });worker.balanceis updated accordingly (balance + credit - debit).
Reporting & UI Responsibilities
With the ledger as the single source of truth:
| Business Need | Where to View | Underlying Data |
|---|---|---|
| Current balance owed to worker | Worker Ledger → Closing Balance | worker.balance |
| Opening balance for date range | Worker Ledger → Opening Balance | closingBalance - totalCredits + totalDebits |
| Detailed financial history | Worker Ledger table & printout | LedgerEntry collection |
| Record a worker payment | Worker Ledger → "Make Payment" button | /api/v1/transaction/create |
| Work completed by worker | Worker Jobs Report | Ledger entries of type job_earning |