Set hourly rates per staff member, let them clock in from their phone with optional location verification, and export the timesheet to CSV or XLSX in one click. Every wage change is versioned; every clock event is append-only; every adjustment leaves an audit trail.
Wage tracking turns the Staff module into the source of truth for what each team member earns and what they actually worked. Set an hourly rate for each staff member; new rates supersede old ones with effective-from dates so the history stays clean. Staff clock in from the mobile waiter shell — optionally verified by Haversine distance against the venue's GPS coordinates. Timesheet aggregation joins clocked minutes × the wage in effect at that time and produces a CSV or XLSX you can hand to your accountant.
The whole pipeline is append-only. Wages are versioned (effectiveFrom / effectiveUntil) — you never UPDATE a row, you supersede it. Clock events are immutable — manager edits write a new MANUAL_ADJUST row referencing the original, the original is preserved verbatim. This makes labour-dispute defence trivial: every number on a payslip can be re-derived from the underlying audit trail months later.
Every wage row stores cents in the venue's currency — no per-row currency column, no exchange-rate drift, no confusion when a staff member transfers between venues. A multi-venue worker has multiple wage rows, one per venue, in each venue's own currency.
When the venue has lat/lng + a non-zero clockInRadiusMeters, the clock event records the device coordinates, computes Haversine distance to the venue, and flags geofenceOk. We never refuse a clock-in over GPS drift — we record the truth and surface flagged events for manager review.
Type 1500 instead of 15.00? You have 5 minutes to undo — the row hard-deletes only if no ClockEvent has been costed against it yet. Past 5 minutes or once a wage is referenced in a payroll run, the only way forward is a corrective supersede with notes.
The timesheet grid exports to CSV or XLSX with userId, username, hourlyRate, hoursWorked, grossPay columns. Pipe it to your accountant's software (Microinvest TRZ, Plus Minus, Ажур L) without manual retyping.
Open Staff → Wages and click an empty Rate cell for each team member. Save. The save creates a new StaffWage row, marks the previous active row's effectiveUntil to now, and writes a StaffAuditLog entry. Currency follows venue.currency.
The mobile waiter shell shows a Clock In/Out button at the top. One tap captures device coordinates (if granted), computes Haversine distance to the venue, records the event, and auto-links to today's scheduled shift if startTime is within 30 minutes.
If a waiter forgot to clock out, open Staff → Audit, find the event, click Adjust. The system creates a new MANUAL_ADJUST row referencing the original (which is preserved). Reason code is required so the next reviewer understands what happened.
Open Staff → Timesheets, pick a date range (default: last month), preview the grid, hit CSV or XLSX. The file downloads with the period in the filename and is ready to import into your payroll software.
Every wage change is a new row. The previous active row gets its effectiveUntil set in the same $transaction. Reading the effective wage at a point in time is a simple WHERE effectiveFrom <= at AND (effectiveUntil IS NULL OR effectiveUntil > at).
Configurable per venue: clockInRadiusMeters = 0 disables the check. Otherwise, every clock event captures device coords, computes the great-circle distance to venue.lat/lng, and stores geofenceOk = (distance <= radius). The check never blocks — it flags.
Every clock event is immutable once written. Manager edits create a new MANUAL_ADJUST row pointing at the original via notes + adjustReason. The original is preserved verbatim — labour-dispute defence is built in.
The aggregator joins clocked minutes per staff × the wage in effect at the period end. Exports include userId, username, hourly rate, hours worked, and gross pay. CSV is universal; XLSX uses the same xlsx library that powers other Ordering.Tools exports.
End of the month: open Staff → Timesheets, select last calendar month, hit XLSX, hand the file to your accountant. The previous Excel-sheet-from-the-paper-clock workflow took 4 hours; this takes 30 seconds.
Anna left at 23:00 but forgot to clock out and the system auto-rolled her shift to midnight. Open the audit log, find the CLOCK_OUT-missing pattern, click Adjust on her last event, set the correct time, add reason 'forgot to clock out — confirmed via security camera'. New MANUAL_ADJUST row lands; original is preserved.
Petar moves from London Pub to Camden venue. He gets a new StaffWage row in Camden's currency (GBP for both, but the data shape supports cross-currency moves). His London Pub history stays intact — every gross-pay calculation against London hours uses London's wage.
A waiter contests a payslip from 6 months ago. Open Staff → Audit, filter by user + date range. Every wage change, every clock event, every manager adjustment is there with the actor's name, the timestamp, and the reason code. Re-derive the gross from raw events in 30 seconds.
A staff member clocks in from home 'because they were waiting for a delivery'. The geofenceOk = false flag surfaces in the audit log. You ask, they confirm, you accept it once and move on — or you tell them to clock in only at the venue, with the audit log as the receipt.
A staff member who covers both server and kitchen shifts has two StaffWage rows (one with role = SERVER, one with role = KITCHEN). The wage resolver picks the right rate based on the shift role at the time the clock event was costed.
Most restaurant POS systems track tips and sales but treat wages as 'someone else's problem'. Ordering.Tools' Staff module closes that gap end-to-end: hourly rates with effective dates, geofenced clock-in, append-only event history, CSV/XLSX exports for any payroll software. The pipeline is designed for the moment a wage gets contested — months later, with the original manager unavailable — and the answer needs to be reproducible from raw rows. That's why we never UPDATE wages or events; only supersede or adjust with audit.
A staff member contests a payslip. The manager who set their rate has left the company. Without append-only history, you have one row showing the current rate and no way to prove what the rate was on the day of the disputed shift. With append-only, you have effectiveFrom / effectiveUntil pairs that re-derive any past day in one query. Same logic for clock events: a forgotten manual edit overwrites history; a MANUAL_ADJUST row preserves it. The cost of append-only is more rows; the benefit is a defensible audit trail.
Indoor GPS drift inside concrete buildings means a staff member can be standing at the bar and show 200 metres off. Blocking on geofence guarantees false negatives that end up paged to the manager mid-rush. Flagging instead of blocking captures the truth (geofenceOk = false) without slowing operations: the clock-in goes through, the manager gets a web-push, and the audit log carries the discrepancy for review. Over weeks, the pattern of flagged events surfaces real abuse (clocking in from home) without punishing legitimate workers for indoor GPS noise.
A multi-venue chain that pays its London team in GBP and its Camden team in GBP doesn't see the difference. A chain with a Sofia venue (BGN) and a London venue (GBP) does — and the cleanest model is one wage row per (staff, venue) pair, in the venue's currency. That's how Ordering.Tools models it. No exchange rate fields, no FX drift, no 'is this 15 GBP or 15 BGN?' confusion. The wage you see for a venue is what the staff member earns at that venue, period.
Set rates, let staff clock in, export to CSV or XLSX. Every row append-only. Premium feature, included in Staff Management.