Payroll / Timesheet — End-user view
Four surfaces: Finance Settings (admin picks the hours basis), Staff Attendance (staff/admin clock in/out), Timesheet Approved tab (admin approves & exports) and leave-only rows.
A. Finance Settings → Payroll tab
Admin Portal → Settings → Finance → Payroll. The tab only shows when the BU has Staff Roster enabled.
- The
Payrolltab appears right after Subsidy Settings; hidden when the user/session lacksSTAFF_ROSTERpermission for the current BU. - Route
/settings/finance/payrollis protected by the same rule: direct access withoutSTAFF_ROSTER→ cannot open. - The form has 2 choices mapped straight to backend values:
Rostered Hours=0,Actual Hours=1; missing setting → defaults toRostered Hours(0). - Saving requires
SettingFinancepermission; payloadBusinessUnitPayrollSettingModelviaGET/POST /api/BusinessUnitSetting/Payroll(the route is the permission boundary, not a table).
Real-world example: Admin cannot see the Payroll tab in Settings → Finance. → BU lacks STAFF_ROSTER or Staff Roster is off. → The tab does not render per the rule; it is not a UI bug.
B. Staff Attendance — clock-in / clock-out
Attendance screen; creates a new shift for an employee in the current BU.
- Clock-in a new shift: missing active
OrgEmployeelink forEmployeeId+OrgId→ auto-create and assignShift.OrgEmployeeId; exists → reuse, no duplicate. - Clock-out creating the next shift: copied shift missing/inactive
OrgEmployeeId→ resolve/create an active link before saving the new shift. - Employee or org not active in the BU → the new shift is rejected, no
OrgEmployeecreated, no shift created.
Real-world example: Staff has no OrgEmployee at the new site and clicks clock-in. → Do not let the shift save fail from a missing link. → The backend auto-creates the active OrgEmployee and attaches it to Shift.OrgEmployeeId.
C. Timesheet Approved tab — export CSV
Timesheet → Approved tab → select rows → Export. The whole file is built server-side; the browser does not assemble it.
- After selecting rows and clicking Export → the system asks for the mode before generating the file, default
separated.separated: each selected timesheet row = 1 CSV record.grouped: each staff = 1 CSV record, aggregating the total hours of the selected rows.
- Cancel the prompt: no file generated, no rows marked exported, selection kept.
- The downloaded file is a single CSV (not xlsx/PDF), filename derived from the requested date range.
- Successfully exported rows are marked
exported; the un-export action clears the flag so rows can be selected again. - Exported rows are locked from selection; only the un-export action remains.
Real-world example: Admin selects 3 rows and exports in separated mode. → The file does not depend on what the browser displays. → The server re-queries those 3 ids, jsReport renders CSV, and the 3 rows are marked exported in one round-trip.
D. Leave-only row
- An
EmployeeAbsenceapproved on a day with no shift → shows as a separate row withDate,Name,Leave Hours,Tracking Code;Organd shift-hour columns are empty. - It has its own approval cycle: moves between the draft / approved tabs per the absence's own timesheet status, without touching leave approval.
- Approve/un-approve/export/un-export work like shift rows, but do not write paid time / duration (it does not exist on leave).
- Leave overlapping a shift does not create a leave-only row — it still shows inside the shift row's leave column.
- Unapproved leave (pending/rejected) never appears as a timesheet row in any tab.
Real-world example: Approved leave 09:00–13:00 (code AL) on a day with no shift. → The leave row still reaches payroll. → The Timesheet shows 1 leave-only row: Leave Hours = 4.00, Tracking Code = AL, shift-hour columns empty.
Summary
| Role | What they do |
|---|---|
| Admin (Finance) | Enables/changes the Rostered Hours / Actual Hours basis per BU in Settings → Finance → Payroll. |
| Staff / Admin (Attendance) | Clock in/out; new shifts auto-ensure the OrgEmployee link. |
| Admin (Timesheet) | Approve/un-approve rows, pick export mode, un-export; handles both shift rows and leave-only rows. |