Skip to main content
A punch is a raw event: someone clocked in or out, at a time, from a source, maybe with a location and a photo. A day record is the reconciled answer for one employee on one date: what status the day has, how many hours were worked, how late they were, how much overtime accrued. Punches are facts. The day record is a derivation over those facts and the shift policy that applies. Understanding that split explains most of what follows.

Where punches come from

Every punch carries a direction (in or out) and a status:
  • Approved — counted. The ordinary case.
  • Pending — recorded but waiting on a decision. This is what an out-of-geofence punch becomes.
  • Rejected — decided against; not counted.
A mobile punch also carries a geofence result: Inside, Outside, or Pending when the device could not establish a position. The server does this check, not the phone.

Becoming a day record

Each punch immediately updates the day record for its date. Through the working day that record is in progress: hours accumulate, the status reflects what has happened so far. A day record ends up with exactly one status: The shift template supplies the judgement: what time work should have started, how much grace before a punch counts as late, when the unpaid break is deducted, what the half-day cutoff is, and when hours start counting as overtime.

The nightly close

Once a day is over, OnTime closes it — a sweep that finalizes every employee’s record for that date. Two properties matter:

It closes yesterday, never today

A day still in progress has a live clock. Someone who has not punched yet is not a no-show, so Absent is never written to a day that is still running.

It re-derives rather than asserts

The close runs the same engine every other writer uses. Running it twice, or after a punch has already been reconciled, produces the same row it produced the first time.
This is why a missing absence appears the next morning. If someone did not turn up today, today’s record will not say Absent until the close runs. That is a day’s delay, not a bug — and it is the reason the live board and the closed day report can differ.

What changes a closed day

A closed day is not frozen. Three approvals rewrite it:
  • Approved leave sets the covered dates to Leave (or Half for a half-day).
  • An approved regularization applies the correction that was requested — a missing punch filled in, an off-zone punch accepted, a whole day manually entered.
  • Approved overtime writes the approved minutes onto the day.
Each of these happens inside the same transaction as the approval itself. There is no window where a request is approved but the day has not caught up.
Payroll freezes attendance. Once a payroll cycle has frozen a month, a regularization that would rewrite a day in that month is refused rather than silently ignored. Clear the queue before you freeze.

Approvals are inputs, not a parallel ledger

There is one day record per employee per date, and it is the only place the answer lives. Approvals feed into it; payroll, reports, exports and the API all read out of it. Nothing keeps a second, competing version of the truth. That is why an approved leave request shows up on the calendar, in the month report, in the payroll cycle’s paid-days count, and in the statutory register — without any of those being told about it separately.