Documents the shift planning and closure/payroll modules (new tables, routes, stores), the dark redesign, and the docker-compose-broken-host workaround. Adds CLAUDE.md pointing agents at docs/. Translates README to English and keeps host-specific infrastructure details out of the repo.
65 lines
2.5 KiB
Markdown
65 lines
2.5 KiB
Markdown
---
|
||
type: SQLite Table
|
||
title: payroll
|
||
description: Computed + admin-adjusted pay per employee per month — base hours pay, tips, bonus, other, and payment status.
|
||
resource: backend/src/db/index.ts
|
||
tags: [data-model, sqlite, payroll]
|
||
timestamp: 2026-08-16T00:00:00Z
|
||
---
|
||
|
||
# payroll
|
||
|
||
One row per employee per period, created the first time the admin either
|
||
saves a draft adjustment or locks the month.
|
||
|
||
# Schema
|
||
|
||
| Column | Type | Description |
|
||
|---|---|---|
|
||
| `id` | INTEGER PK | autoincrement |
|
||
| `employee_id` | INTEGER | references [employees](./employees.md) |
|
||
| `period` | TEXT | `YYYY-MM` |
|
||
| `worked_minutes` | INTEGER | snapshotted at last save/lock, not live |
|
||
| `base_amount` | REAL | worked hours × the rate active on each shift's own date — see [pay_rates](./pay-rates.md) |
|
||
| `tips_amount` / `bonus_amount` / `other_amount` | REAL | admin-entered, default 0 |
|
||
| `final_amount` | REAL | sum of the four amounts above |
|
||
| `status` | TEXT | `draft` \| `ready` \| `paid` |
|
||
| `payment_date` | TEXT \| NULL | set when marked `paid` |
|
||
| `updated_at` | TEXT | ISO 8601 UTC |
|
||
|
||
`UNIQUE (employee_id, period)`.
|
||
|
||
# Status lifecycle
|
||
|
||
```
|
||
draft --admin locks the month closure--> ready --admin marks paid--> paid
|
||
ready --admin reopens--> draft
|
||
```
|
||
|
||
- **`draft`**: editable. `saveDraftAdjustments`
|
||
(`backend/src/services/payroll.ts`) recomputes `base_amount` /
|
||
`worked_minutes` fresh from
|
||
[attendance_events](./attendance-events.md) on every save, and requires
|
||
the linked [month_closures](./month-closures.md) row to be at least
|
||
`confirmed` (not still `waiting_employee`).
|
||
- **`ready`**: frozen. Set by `lockAndFinalizePayroll`, which locks the
|
||
closure in the same call. `saveDraftAdjustments` refuses to touch a
|
||
non-`draft` row — this is what turns "already locked" into the right
|
||
error message instead of the generic "not confirmed yet" one (a real bug
|
||
caught by `payroll.test.ts`: the two checks used to overlap).
|
||
- **`paid`**: terminal. Set by `markPaid`, stamps today's date. Not
|
||
reopenable — a mistake past this point needs a manual correction, not a
|
||
silent rewrite.
|
||
|
||
This collapses the source system's four-stage accountant pipeline
|
||
(`READY_FOR_ACCOUNTANT` / `PROCESSING` / `PROCESSED` / `PAID` in
|
||
`gscript/PayrollService.js`) down to two — `ready` and `paid` — since
|
||
there's no separate accountant role here for the intermediate stages to
|
||
mean anything.
|
||
|
||
# Related
|
||
|
||
- [month_closures](./month-closures.md)
|
||
- [pay_rates](./pay-rates.md)
|
||
- [Closure API](/docs/api/closure-routes.md), [Admin API](/docs/api/admin-routes.md)
|