Time entries (CSV import + approve)
Time entries are the declarative billable rows: one row = one (placement, work date, pay code item, qty). FlecBase doesn't derive shifts from clock-in/out — the operator (or the source system) declares the split.
A typical shift might decompose into 5 rows for one day: 7.6h NORMAL + 3h T15 + 2h T20 + 1× TOOL + 1× TRAVEL. Pay codes can supersede mid-week without breaking history; time entries snap pay/charge/super-applies/taxable at the moment they're entered, and those snapshots are the historical truth.
Time lands via CSV. The importer is idempotent on external_ref — re-running the same file updates the existing rows instead of creating duplicates. Every import gets a batch UUID; a bad import can be dropped with one click.
After import, rows sit in status Imported until an approver flips them to Approved. Only approved + unbilled rows are eligible to be billed. The placement → invoice spawn locks them with SELECT … FOR UPDATE so two concurrent spawn clicks can't bill the same hour twice.
time-entries_1.png