Actions and results
What each Human Resources button and automatic behaviour does, with worked numbers and what the system refuses.
On this page (72)
HR HomeEmployee directoryEmployee recordDocumentsIDs & visasAssignment editorAssignmentsJob & pay > ContractsContract detailActivate employee dialogTransfer dialogSuspend / ResumeProbation decisionMy HRApprovalsDelegate my approvalsRenewal campaignsHeadcount & FTEDocument expiryHR mastersDepartmentsApproval escalationEmployees app configurationCandidatesCandidate recordOffer recordNew hireOnboarding tasksOnboarding checklistPay changesPay change recordBenefit plansStart offboardingTermination recordTerminationsDispute holdsOnboarding checklistsOffboarding checklistsTime offTime off > Request leaveApprovals > Leave requestApprovals > Leave cancellationLeave balancesLeave ledgerLeave typesAccrual plansAccrual runs > AccrualAccrual runs > ExpiryAccrual runs > Year endAccrual runs > FTE change recomputeAccrual runs > Run historyAllocations & adjustmentsHolidaysCalendar previewApplications > Employees > FeaturesAttendance daysAttendance day recordCorrectionsOvertime approvalsTimesheetsTimesheet recordShiftsRostersWorking calendarsAttendance exceptionsExpense categoriesTravel policiesTravelExpense claim recordCompany cardsExpense claimsTalent (API)
HR Home
| Action | When | What you do | What happens |
|---|---|---|---|
| Tiles match the drill-down | HR manager; 3 Active, 1 Probation, 1 Notice employee with assignments | Open Home; note Headcount; click it | Headcount counts Active + Probation + Notice (5) with summed FTE; the list shows exactly those 5 |
| Line manager scope | User without hr.employee.view who manages 2 employees | Open Home | 'Showing your team'; tiles count only the 2 reports; no Documents or Probation tile |
| Documents tile buckets | Today 02 Oct 2026; documents expiring 20 Oct, 15 Nov, 20 Dec and one expired 01 Oct | Open Home; read the documents tile; click it | Tile shows 30d 1 · 60d 1 · 90d 1; attention item 'expired documents 1'; click opens Document expiry on 'Next 30 days' |
| Quick actions | Click New employee, Review approvals, Request leave | New employee opens New hire; Review approvals opens Approvals; buttons not allowed for your role are absent |
Employee directory
| Action | When | What you do | What happens |
|---|---|---|---|
| Search and filter | Employees EMP-T001 'Test Employee One' and Arabic name 'موظف تجريبي' | Search 'T001', then the Arabic name, then part of the work email; filter Status = Draft | Each search finds the row; filter shows only drafts; '%' or '_' typed are searched literally |
| Cards / List remembered | Switch to List; reload the page | List is still chosen (per browser); cards show photo or initials and an expiring badge | |
| Create a draft employee | hr.employee.manage | New employee; number EMP-T001, legal name, join date today; Save | Saved as Draft, revision 1; tabs Job & pay, Documents, Time, Access, History appear; audit 'hr.employee.created' |
Employee record
| Action | When | What you do | What happens |
|---|---|---|---|
| Duplicate employee number | EMP-T001 exists | Create another with 'emp-t001' | Refused 'This HR record conflicts with another saved record. Reload and use a unique code or request ID.' (lower case is upper-cased first) |
| Edit general details | Active employee | Edit; change work phone and Arabic name; Save; then try to change join date via the API | Phone/name saved, revision +1; Employee number and Join date boxes are locked; API change refused 'Employee number and joining date cannot change after activation.' |
| Edit conflict | Same employee open in two tabs | Save a change in tab 1; then save another change in tab 2 | Tab 2 refused 'This record changed. Reload before saving.'; no overwrite |
| Private information | HR manager (hr.private.manage) | Edit; nationality, date of birth 15 Mar 1990, personal email, emergency contact; Save | Saved through the private command in the same save; revision +1; the general and private parts share one revision |
| Photo | Upload a 1 MB JPEG; reload; remove it | Photo shown (re-encoded PNG, max 512 px); directory card shows it; removed -> initials; each change moves the revision |
Documents
| Action | When | What you do | What happens |
|---|---|---|---|
| Add a document | Active document type 'Residence visa' (alert 30 days) | Add a document: type, number TEST-VISA-0001, issued 01 Oct 2024, expires 20 Oct 2026; Add | Row shows number, authority and 'Expires in 18 days' in warning colour (today 02 Oct); header Expiring tile counts it |
| Upload evidence | The document above | Upload a 400 KB PDF; click the file link | File listed and downloadable to private HR; a renamed .docx is refused |
| Required and missing banner | Document type 'Labour card' marked required | Open an employee without one | 'Required and missing: Labour card'; Activate readiness shows Required documents as blocked |
IDs & visas
| Action | When | What you do | What happens |
|---|---|---|---|
| Add an Emirates ID | hr.private.manage | Add an identifier: Emirates ID, 784-1990-1234567-1, issued 01 Jan 2025, expires 25 Oct 2026; Add | Listed; band chip '30 days' (23 days left falls in the 30 band, narrowest wins); IDs & visas tile +1 |
| Expiry bands | Identifiers expiring today+5, +14, +45, +100, -1 and +200 days | Open IDs & visas | Bands 7, 15, 60, 120, Expired and none (beyond 120) respectively |
| Remove an identifier | Click the bin icon on a row | Row deleted at once (no confirmation, no history row except audit 'hr.identifier.remove') |
Assignment editor
| Action | When | What you do | What happens |
|---|---|---|---|
| Create and activate an assignment | Draft employee; position SALES-EXEC (capacity 2.0, grade G5), calendar, contract type | Job & pay > New assignment; dept = position's, grade G5, manager, FTE 1; Save; Activate assignment | Saved Draft then Active; snapshot of names kept; Assignments tile 1; activated assignment can no longer be edited ('Active assignments are immutable. End this assignment and create its successor.') |
| Employee FTE ceiling | Employee with an active 0.6 FTE assignment | Add a second overlapping assignment 0.5 to another position; Activate | Refused 'Concurrent assignments cannot exceed 1.0 employee FTE.' (0.6 + 0.5 = 1.1); with 0.4 it activates (total 1.0) |
| Position capacity | Position capacity 1.0; employee A holds 0.6 | Activate employee B at 0.5 on the same dates; then at 0.4 | 0.5 refused 'The position's FTE capacity is exceeded during this interval.' (1.1 > 1.0); 0.4 accepted |
| Reporting cycle | A reports to B | Give B an assignment with manager A overlapping in time | Refused 'This manager creates a reporting cycle during the assignment interval.' |
| End an assignment | Active open-ended assignment | End assignment: last date today + 30, reason; then try to end it again at today + 60 | Valid to set; history entry kept in the snapshot; second end refused 'Use a date earlier than the existing end date; create a successor to extend.' |
Assignments
| Action | When | What you do | What happens |
|---|---|---|---|
| Retry is not doubled | Activate an assignment; replay the same request (same request_id) with the network tab | Same answer returned, nothing done twice; same request_id with different data -> 'This request ID was already used with different command data.' |
Job & pay > Contracts
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a contract from a structure | Structure with Basic 10,000 (EOS, overtime, WPS) + Housing 4,000 (WPS) + Transport 1,000 | New contract: starts 15 Jan 2026, Full time, Expatriate, the structure, probation 6; Create | Draft contract with a generated number; probation ends 14 Jul 2026 (6 calendar months minus one day); lines copied: Gross 15,000, WPS 14,000 (Transport not WPS), EOS base 10,000, currency AED |
Contract detail
| Action | When | What you do | What happens |
|---|---|---|---|
| Hourly rate and Why? | Contract above, 8 h x 5 days, hr.pay.view | Open the contract; read 'One hour is worth'; click Why? on End-of-service base | Hourly = 10,000 / (40 x 52 / 12 = 173.33 h) = AED 57.69; Why? lists Basic included, Housing and Transport excluded 'not marked eos included' |
| Put in force and overlap | Draft contract; another active contract for the same dates | Put in force | Refused 'Contract <no> is already in force for this period. End it first.'; without the clash: state In force, Status chip 'In force' |
| Salary hidden without pay right | User with hr.contract.view but not hr.pay.view | Open Job & pay > Contract & pay; open a contract | Number, dates, type and status shown; Gross, bases, components, hourly and Why? not returned |
Activate employee dialog
| Action | When | What you do | What happens |
|---|---|---|---|
| Readiness blocks activation | Draft employee with no assignment and no contract | Actions > Activate employee | Checks list Assignment in force today, Work calendar, Reporting manager, Signed contract as blocked with 'Go fix' links; Confirm disabled |
| Activate into probation | Active assignment with manager, active contract with probation end in the future, required documents held | Tick each warning (e.g. no bank account, contract unsigned); Confirm | State becomes Probation (not Active); history 'activated'; payroll event raised; an Access request 'Pending' appears on the Access tab when there is no login |
| Waive the manager | Top-of-organisation employee, assignment without manager | Tick waive manager; leave reason empty; then type a reason | Empty reason refused 'Say why this employee has no manager.'; with reason activates and history records the waiver |
Transfer dialog
| Action | When | What you do | What happens |
|---|---|---|---|
| Transfer from a date | Active employee in position A | Transfer from today + 7 to position B with reason | Old assignment ends today + 6, new one starts today + 7 (both checked for FTE/capacity/cycles); History shows the transfer; nothing in the past rewritten |
Suspend / Resume
| Action | When | What you do | What happens |
|---|---|---|---|
| Scheduled suspension | Active employee | Suspend from today + 3 with reason; check the Actions menu; then Cancel scheduled suspension | Notice shows the scheduled suspension; menu offers 'Cancel scheduled suspension'; a second schedule refused 'A suspension is already scheduled. Cancel it first.' |
Probation decision
| Action | When | What you do | What happens |
|---|---|---|---|
| Extend probation | Probation employee, probation start 15 Jan 2026, end 14 Jul 2026 | Extend to 14 Dec 2026; then try 20 Jan 2027 | First saved (contract probation end moves); second refused 'Probation cannot run past 12 months (14 Jan 2027).' |
| Confirm probation | Probation employee | Outcome Confirm; Confirm | State Active; history 'probation confirmed' |
My HR
| Action | When | What you do | What happens |
|---|---|---|---|
| Submit a profile change | Employee with a linked login | My HR > Request a profile change: personal phone +971500000201, reason; Submit | Form replaced by 'A profile change is awaiting HR review.' with Withdraw; a second request refused 'Finish or cancel the pending profile change first.' |
| Request a document renewal | Employee's visa expiring 20 Oct 2026 | My documents > Request renewal; new expiry 19 Oct 2028; reason; attach a PDF; Submit | 'Renewal pending HR review' with Withdraw renewal; the current document stays unchanged until approval |
Approvals
| Action | When | What you do | What happens |
|---|---|---|---|
| Approve a profile change | The request above; HR manager B (not the requester) | Approvals > type Profile change > Approve | Private record updated (personal phone), employee revision +1; requester notified 'Profile change approved'; item leaves the inbox |
| Stale profile change | Pending request; HR then edits the employee's record | Approve the request | Refused 'The employee profile changed after this request was sent. Reject it and ask the employee to submit the current values again.' |
| Reject needs a reason | Pending item | Reject; leave reason empty; then type 'Number not reachable' | Reject disabled while empty (API: 'Say why you are rejecting this.'); rejection saved and shown to the requester |
| Bulk approve | 3 leave requests + 1 profile change selected | Approve selected | '3 approved, 1 not approved' - profile changes are decided one by one; max 100 per bulk |
| Overdue flag | Response time 48 h; an item submitted 50 h ago | Tick Overdue only | Item shown with 'Overdue'; items under 48 h hidden |
Delegate my approvals
| Action | When | What you do | What happens |
|---|---|---|---|
| Delegate leave approvals | Manager with direct reports; EMP-T002 active with a login | Delegate my approvals: EMP-T002, today to today + 7; Delegate; sign in as EMP-T002 | Delegation listed with Revoke; EMP-T002 sees the team leave under 'Delegated to me' (leave only, not profile changes) |
Renewal campaigns
| Action | When | What you do | What happens |
|---|---|---|---|
| Approve a renewal | Pending renewal; HR manager other than the requester | Approve with a note | Document number/dates/authority replaced by the renewal's; old files kept inactive, new files active; expiry reminders resolved; employee notified 'Document renewal approved' |
| Preview and launch a campaign | Company today 02 Oct; 5 documents expire 01 Nov-31 Dec: 1 has a pending renewal, 1 has an unresolved reminder, 1 belongs to an employee without a login | Name 'Q4 visa renewals', 01 Nov 2026 - 31 Dec 2026; Preview recipients; Launch campaign | Preview: Eligible 2, Already pending 1, Already notified 1 (employee without login not counted); launch creates 2 notifications; history row 'launched', Recipients 2 |
| Campaign completes | Campaign with 2 recipients | Both employees submit renewals; HR approves one, rejects one | Recipient states approved 1 / rejected 1; campaign state 'completed' |
| Nothing to launch | Preview a window with no documents; force Launch via the API | Launch button disabled at 0; API refused 'No eligible employee documents match this campaign.' |
Headcount & FTE
| Action | When | What you do | What happens |
|---|---|---|---|
| Report arithmetic | On 30 Sep 2026: A active 1.0 (Sales), B active 0.5 Sales + 0.5 Ops, C active 1.0 (Ops), D draft with an assignment | As of 30 Sep 2026; Run report | Distinct employees 3, Active assignments 4, FTE 3.0000; Sales: 2 employees / 1.5 FTE; Ops: 2 employees / 1.5 FTE (department headcounts overlap); D excluded |
Document expiry
| Action | When | What you do | What happens |
|---|---|---|---|
| Windows | Documents expiring -1, +10, +40, +80 days | Click each window chip | Expired 1, Next 30 days 1, 31-60 1, 61-90 1, All within 90 days 3; no numbers shown |
HR masters
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a position and archive guard | Job, department, grade | Positions > New record: SALES-EXEC, capacity 2; Save; assign someone; then set Status Archived | Saved; archiving refused 'This master is used by an active position or current/future assignment.'; changing its code refused 'Create a new master for structural changes once this master has active assignments or positions.' |
Departments
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a department | reference.manage | Departments > New record: HR-OPS, Human resources operations; Save; use it on a position | Saved upper-case; offered on positions and assignments |
Approval escalation
| Action | When | What you do | What happens |
|---|---|---|---|
| Change the response time | hr.configure | Edit; Response time 24; Save; wait for the scheduler (or HR runs escalation) | Saved (revision +1); open approval notices re-timed; an item older than 24 h is escalated and admins get 'HR approval is overdue' when the box is ticked |
Employees app configuration
| Action | When | What you do | What happens |
|---|---|---|---|
| Hide Personal email | Two company admins | A: Fields > Personal email = Hidden; Propose; B approves; open an employee and My HR | Personal email box gone on the record and on My HR's profile change; a profile change sending personal_email is refused |
| Turn off Document renewal campaigns | Two admins | A: Features > Document renewal campaigns Off; B approves; open Reporting > Renewal campaigns; try Launch via the API | Menu entry gone; POST refused 'capability_disabled'; existing campaigns still readable |
Candidates
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a candidate | User with hr.recruit.manage | Hiring > Candidates > New candidate; Full name 'Layla Hassan', Source Referral; Save | Reference CAN-nnnn, status New; not listed in Employees, Headcount or Home counts |
| Status tabs and search | 5 candidates in mixed statuses | Click each status tab; search by part of a name and by CAN reference | Tab counts add up; list narrows; search matches reference, name and email |
Candidate record
| Action | When | What you do | What happens |
|---|---|---|---|
| Duplicate identifier is refused | Candidate CAN-0001 (live) has passport P1234567 | Create a second candidate with ID type Passport and number 'p-123 4567' | Refused: 'CAN-0001 is already this person (same identifier).' (spaces, dashes, case ignored). After CAN-0001 is rejected the same number is accepted |
| Consent and retention date | Candidate open for edit | Type a Keep details until date with consent unticked; then tick consent and save; then untick and save | First: 'Record the candidate's consent before setting a retention date.' With consent: date saved and consent time stamped once; untick clears both |
| Screen a candidate | Candidate in New | Screen | Status Screening. Screen on a candidate already Screening is refused: 'A screening candidate cannot be moved to screening.' |
| Reject / withdraw needs a reason and no live offer | Candidate with a Submitted offer | Reject with a reason; then withdraw the offer and reject again; try a blank reason | First refused: 'Withdraw offer OFR-0001 first.'; blank reason: 'Say why.'; after the offer is withdrawn the candidate is Rejected and can no longer be edited ('A rejected candidate can no longer be edited.') |
| Edit conflict | Same candidate open in two browsers | Save a change in browser A; save a different change in browser B | B refused with 'This record changed. Reload before saving.' and nothing of B is saved |
Offer record
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a draft offer with pay | Candidate Screening; position 'Sales executive' with free capacity; user with hr.recruit.manage + hr.pay.manage | New offer: position, calendar, contract type Limited (probation 6), start 2026-11-01, FTE 1; pay BASIC 9000.00, HOUSING 4000.00, TRANSPORT 800.00; Save | Offer OFR-nnnn Draft; Total per month 13,800.00 AED; probation ends 2027-04-30 (calendar months); no seat is reserved yet |
| Probation default and end date | Contract type Limited has probation 6 | Leave Probation blank; then enter 3; start 2026-08-31 with 6 months | Blank takes 6; 3 gives end one day before 3 calendar months later; start 31 Aug + 6 months ends 27 Feb 2027 (short month handled, not +180 days) |
| Offer without pay permission | User with hr.recruit.manage but not hr.pay.view / manage | Open the offer; try to save pay lines (API) | No pay block, 'Pay is restricted'; list shows only whether pay exists; saving pay refused: 'Setting pay needs the pay permission.' (403); saving the offer without pay lines keeps the existing proposal |
| Submit reserves the seat (capacity worked) | Position capacity 2.0000; one employee in post at FTE 1.0; one other Approved offer for FTE 0.5 | Submit a new offer FTE 0.5 from 2026-11-01; then submit another FTE 0.5 | First: peak 1.0+0.5+0.5 = 2.0, accepted. Second: peak 2.5 > 2.0, refused: 'The position has no free capacity from that date (people in post and other offers already fill it).' |
| Submit for approval | Draft offer; creator has hr.recruit.manage | Submit for approval | Status Submitted; creator and submitter recorded; Approve/Reject buttons are not offered to the creator |
| Approver is a different person | Submitted offer; user B has hr.recruit.approve and is neither author nor submitter | B: Approve; try the same as the author (API) | B: Approved and the candidate moves to Offered. Author/submitter: 'You cannot decide an offer you prepared.' (403) |
| Reject an offer | Submitted offer | Approver: Reject with blank reason; then with reason | Blank: 'Say why the offer is rejected.'; with reason: Rejected, seat released |
| Record acceptance and expiry | Approved offer expiring 2026-10-20; today 2026-10-02 / 2026-10-25 | Record acceptance on each date | On 2 Oct: Accepted. On 25 Oct: 'This offer has expired.' Only an Approved offer can be answered ('Only an approved offer can be answered.') |
| Candidate declines | Approved offer | Candidate declined (note) | Offer Declined; candidate returns to Screening if no other live offer |
| Withdraw an offer | Offers in Draft, Submitted, Approved, Accepted | Withdraw each with a reason; try with blank reason; try on a Hired offer | Allowed in those four states; blank: 'Say why the offer is withdrawn.'; Hired: 'A hired offer cannot be withdrawn.'; candidate back to Screening when no live offer remains |
| Only a draft can be edited | Submitted offer | Try to edit (API PATCH) | 'Only a draft offer can be edited. Withdraw it and make another.' |
| Start date in the past | Draft offer | Set start date yesterday; Save | 'The start date cannot be in the past.' |
New hire
| Action | When | What you do | What happens |
|---|---|---|---|
| Full guided hire (happy path) | Accepted offer for candidate CAN-0001 with passport number recorded; user holds recruit.manage, employee.manage, private.manage, contract.manage | Open the offer (re-enters at step 3); enter Employee number blank and a work email; step 4 keep the default checklist; step 5 Create employee | Success panel: Employee (Draft state), Contract (draft) with the offered pay lines, N onboarding tasks; offer and candidate Hired; assignment Active from the start date; history 'hired' event |
| What the hire creates, in one step | Same as above | After the hire open the employee record | Private info holds nationality, personal email/phone from the candidate; passport identifier is Primary and not verified; contract draft with probation start = start date and end by calendar months; worker category national only when nationality matches the company country |
| Hire needs the ID number | Accepted offer, candidate with no ID number | Create employee | 'Record the candidate's passport or national ID number before hiring.' - nothing created |
| Nobody is hired twice | An existing employee already holds the passport P1234567 | Hire a candidate with 'P-1234567' | Refused: 'This identifier already belongs to employee EMP-T001. Nobody is hired twice.' Nothing is created |
| Hire is atomic and idempotent | Accepted offer | Click Create employee twice quickly / retry after a lost answer | One employee only; the second call returns the first answer; a different employee number on the same request is refused ('This request ID was already used with different command data.'); a used offer: 'This offer has already been used to hire someone.' |
| Hire revalidates seat and date | Accepted offer; meanwhile another person filled the last seat / the start date passed | Create employee | 'The position has no free capacity ...' / 'The offer's start date has passed. Withdraw it and make a new offer.' - nothing created |
| Missing rights are explained | User with recruit.manage but not private.manage | Reach step 5 | A notice names the missing permissions; the server refuses the hire with 403 and creates nothing |
| One-person team stops at approval | User both writes and is the only approver | Submit; try to Approve | Wizard shows 'Waiting for approval' with a link to Offers; the offer is saved; approving as the same person is refused |
| Onboarding tasks dated from the join date | Checklist ONB-STD: 'Collect documents' due -3, 'Issue laptop' due 0, 'Orientation' due +5; join date 2026-11-01 | Hire; open employee Overview > Onboarding | Due dates 2026-10-29, 2026-11-01, 2026-11-06; progress 0/3 (0%); editing the template afterwards does not change these tasks |
Onboarding tasks
| Action | When | What you do | What happens |
|---|---|---|---|
| Tick, waive, reopen a task | Employee with 3 open tasks; one assigned to the line manager | Manager ticks their task Done; manager tries Waive; HR waives another with a note; HR reopens a done task | Done by assignee ok; manager waive refused 'Only HR can waive a task or reopen it.'; HR waive without note 'Say why this task is being waived.'; reopening clears who/when; progress counts done+waived |
Onboarding checklist
| Action | When | What you do | What happens |
|---|---|---|---|
| Which checklist a hire gets | Checklists: one for contract type Limited, one company default | Hire a Limited offer; hire an Unlimited offer; pick a checklist explicitly on step 4 | Limited uses its own; Unlimited uses the default; explicit choice wins; no checklist at all still hires (0 tasks) |
Pay changes
| Action | When | What you do | What happens |
|---|---|---|---|
| Raise a salary (worked) | Employee EMP-T010 Active, contract in force with BASIC 9000.00; user with hr.pay.manage | New change: Salary, BASIC, effective 2026-11-01, new 9900.00, reason; Save | Draft PCH-nnnn; In force before 9,000.00, New 9,900.00, Difference +900.00 |
Pay change record
| Action | When | What you do | What happens |
|---|---|---|---|
| Nothing to change is refused | Same employee | Enter new amount 9000.00 | 'That is what is already in force from that date; there is nothing to change.' |
| Reason needed to submit | Draft without reason | Submit for approval | 'A reason is required before a pay change is submitted.' |
| Approval by a different person | Submitted change; approver has hr.pay.approve | Approver (not requester, not submitter): Approve. Requester tries Approve (API) | Approved. Requester refused: 'A pay change is approved by somebody other than whoever wrote or submitted it.' (403) |
| Apply writes a version, never edits history | Approved change, no frozen period involved | Apply | Status Applied; one new pay version (BASIC 9,900.00 from 2026-11-01, previous 9,000.00) is written; the contract line, earlier versions and old payslips are untouched; Pay history shows both |
| Stale change is refused | Approved change drafted at 9000.00; another change took BASIC to 9500.00 first | Apply | 'The pay in force from that date has changed since this request was written. Withdraw it and raise a new one.' |
| Retroactive change (worked) | BASIC 9000 -> 9900; July, August and September payroll periods frozen; effective 2026-08-01 | Submit (Retroactive banner appears); approve; Apply without ticking acknowledge; then with it and a reason | Without: refused with the acknowledge message naming the periods. With: Applied; one queued adjustment per affected frozen period of +900.00 (the periods from the effective date on: Aug and Sep = Adjustments queued 2); frozen runs and payslips unchanged; adjustments appear in the next open run |
| Retro apply needs a reason | Retro approved change with blank reason | Apply with acknowledge ticked | 'Say why a retroactive change is being applied.' |
| Only one open change per item | Submitted change for EMP-T010 BASIC | Create another BASIC change for the same employee | Refused: 'PCH-0001 is already submitted for this employee and item. Finish or withdraw it first.' |
| Benefit enrolment (worked) | Plan MED-GOLD employee 150.00 / employer 300.00, both mapped; employee joined 2025-01-10; plan needs 12 months | New change: Benefit, plan MED-GOLD, effective 2026-11-01 | Shown from plan: employee 150.00, employer share 300.00; eligibility passes (21 months served); applying writes one version per share |
| Benefit eligibility refusals | Plan for expatriate staff, 12 months; employee national / joined 2026-03-15 | Try each | 'Plan MED-GOLD is for expatriate staff; this employee's contract is national.' / '... needs 12 months of service by the effective date; this employee will have 6.' |
| End a benefit | Employee enrolled in MED-GOLD | Tick End this benefit; effective 2026-12-01; apply | New shares 0.00 / 0.00; applying writes versions to zero. Not enrolled employee: 'This employee is not enrolled in the plan on that date.' |
| Loan instalment cap (worked) | Active loan principal 6000.00, repaid 1500.00 | Change instalment to 5000.00; then 500.00 | 5000: 'The instalment cannot be more than the 4500.00 still owed.'; 500.00 accepted |
| Withdraw and reject | Changes in Draft, Submitted, Approved, Applied | Withdraw each; reject a submitted one with blank reason | Withdraw allowed for the first three; Applied: 'A applied request cannot be withdrawn.'; reject blank 'Say why the change is rejected.' |
| Only working employees | Terminated and Draft employees | Raise a change for each | 'Pay changes are for people who are working (on probation, active, on notice or suspended).' |
Benefit plans
| Action | When | What you do | What happens |
|---|---|---|---|
| Create and edit a plan | User with hr.pay.manage | New plan: code MED-GOLD, shares, dates, worker class, mapping; Save; reopen and change the name | Saved; list shows shares and dates; Archive hides it from new enrolments |
| Share needs a payroll component | New plan | Employee share 150 and no component | 'A share needs the pay component that carries it into payroll.' |
| Code is frozen once used | Plan used by an applied pay change | Change the code | 'A plan with history keeps its code; archive it and create a new one.' |
Start offboarding
| Action | When | What you do | What happens |
|---|---|---|---|
| Give notice (notice worked) | Employee Active; checklist notice 30 days; today 2026-10-02 | Start offboarding: last day 2026-10-20; Next; read the preview | Notice required 30, served 18 (20 Oct minus 2 Oct), shortfall 12; Give notice creates TRM-nnnn Draft; the employee state becomes Notice |
| Notice waiver request | Preview shows shortfall 12; checklist allows waiver | Request a waiver with a reason; Give notice | Waiver 'requested', a second person must decide; blank reason refused; a checklist that forbids waiver refuses it; full notice shows 'The notice is served in full.' |
| One separation per person | Employee already has a draft termination | Start offboarding again | 'This employee already has a separation in progress.' |
Termination record
| Action | When | What you do | What happens |
|---|---|---|---|
| Approve by a different person | Draft termination requested by user A | A: Approve (refused). B with hr.offboard.approve: Approve | A: 'A different person must approve a separation you recorded.' B: state Notice; clearances seeded per checklist; recoveries listed; leave frozen at the last day; access cutoff defaulted |
| Guard checklist blocks clearing | Notice state, nothing done | Read Guard checklist; Move to cleared | Blocked items (notice, each department clearance, assets, recoveries, access, leave, inputs) listed; refused with the list in the Blockers box |
| Clearances | Notice state, 9 departments required | Decide Finance Cleared; IT Blocked with note; Store Not applicable; Fleet request waiver | Counters Clearance done/total update; Blocked needs a note; waiver stays 'waits for a second person' until an approver other than the requester decides it |
| Waiver decided by a different person | Clearance / notice / recovery waiver requested by user A | A tries to decide; B (approver) approves; B refuses another | A: 'A different person must decide a waiver you requested.' B approve: item Waived and counts as satisfied; refuse: back to Pending |
| Assets and recoveries | Employee holds a laptop, owes a 1,200.00 advance | Refresh what is owed; mark laptop returned; set advance to Recover from final pay | Both listed; asset 'returned' accepted (loans cannot be marked returned by HR); decided items no longer block; 'Owed back' tile falls |
| Leave freeze | Employee has approved leave starting after the last day and one request spanning it; balances 12 days | Freeze leave; choose Keep on purpose or Cancel them too | Leave starting after the last day cancelled; spanning leave blocks clearing until one choice; balances snapshotted before/after |
| Freeze settlement inputs | All recoveries decided | Freeze inputs; then change a recovery; then freeze again | First locks leave snapshot and recoveries for payroll; later edit refused 'The settlement inputs are frozen; this item is locked.'; freezing twice 'The settlement inputs are already frozen.'; undecided recoveries refuse the freeze |
| Access cutoff | Approved termination; employee has a login | Schedule cutoff 2026-11-01 17:00; try a past time; use checklist default; Revoke now (approver) | Future time saved; past refused; default follows the rule (end of last day / hour / immediate); Revoke now by an approver ends sign-in at once, logged |
| Move to cleared | All guard items satisfied except the two terminate-only ones | Move to cleared | State Cleared; a later new blocker (e.g. an asset reissued) drops it back to Notice |
| Terminate on the last day | Cleared; last day today; no open hold | Terminate | State Terminated; employee Terminated; sign-in revoked; payroll is told through a termination event (identifiers and dates only, no money); settlement requested |
| Terminate before the last day | Cleared; last day in 10 days | Terminate as hr.offboard only; then 'Terminate before the last day' as approver with a reason | Plain: 'Their last day has not come yet.' Early by non-approver: 'Terminating before the last day needs an approver.'; blank reason refused; approver succeeds (last-day check skipped, all others kept) |
| Open hold stops termination | Cleared record with an open hold | Terminate | Refused: 'This separation cannot be terminated yet.' with 'No dispute hold: 1 open hold(s): HLD-0001.' |
| Close after settlement is paid | Terminated record; payroll settlement Posted / Paid | Close when Posted; close when Paid | Posted: 'Payroll has not reported the final settlement paid or closed.' Paid: Closed |
| Cancel a separation | Draft / notice / cleared record | Cancel with reason; try on terminated; try with blank reason | Employee returns to the state before notice; terminated: 'Only a separation that has not ended can be cancelled; use ...'; blank 'Say why the separation is cancelled.' |
| Reinstate (approver) | Terminated record | Reinstate as approver with a reason; as hr.offboard only | Approver: separation Cancelled and employee returns to work with reason logged; non-approver refused (403); blank 'Say why the employee is reinstated.' |
| Settlement handoff states the facts only | Terminated record | Read the Settlement card and the handoff data | Shows join date, last day, reason, service days and 'calculated by payroll'; no AED amount. Payroll (not HR) works the gratuity: e.g. 7 years 6 months of service = 5 x 21 + 2.5 x 30 = about 180.04 days of basic |
| Probation not confirmed leads here | Employee in Probation | Probation decision > Terminate with a last day | A Draft termination (reason 'Probation not confirmed') appears in Terminations; a different person must approve; it never terminates by itself |
Terminations
| Action | When | What you do | What happens |
|---|---|---|---|
| Overdue and status tabs | An open record whose last day was last week | Switch 'Overdue only'; open each status tab | Overdue badge shown; list narrows to open records past their last day; tabs count by status |
Dispute holds
| Action | When | What you do | What happens |
|---|---|---|---|
| Place a hold | User with hr.hold.manage | Place hold: employee, Legal, reason | HLD-nnnn Open; attached to the employee's open termination if any; Holds counter on the termination rises |
| Release by a different person | Open hold placed by user A | A: Release; B: Release with blank note; B with note | A: 'A different person must release a hold you placed.'; blank: 'Say why the hold is released.'; B: Released, stays in history; releasing twice 'This hold has already been released.' |
| Hold placed before the termination exists | Open hold on an Active employee | Give that employee notice | The hold is adopted by the new termination and blocks terminating |
Onboarding checklists
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a checklist | User with hr.configure | New record ONB-STD; add 3 tasks (key, title, owner, due, required); Save | Saved; tasks table keeps order; keys must be unique; archived checklists are not offered at hire |
Offboarding checklists
| Action | When | What you do | What happens |
|---|---|---|---|
| One active checklist per contract type | Active checklist for Limited exists | Create another active one for Limited; create two company defaults | 'Another active checklist already covers this contract type.' / 'Another active checklist is already the company default.' |
| Checklist drives a new termination | Checklist for Limited: 30 days, departments HR+Finance+IT, assets laptop+mobile, cutoff hour 17 | Start offboarding for a Limited employee; approve | Notice required 30 (locked, source checklist); only HR, Finance, IT clearances; only laptop and mobile listed; default cutoff 17:00 on the last day |
Time off
| Action | When | What you do | What happens |
|---|---|---|---|
| Status chips and counts | Requests exist in several states | 1. Open Employees > Time off. 2. Note the counts on All, Pending, Approved, Rejected, Cancelled. 3. Click Pending. | The list shows only pending requests; the chip counts add up to All; counts follow the people the signed-in person may see (a manager sees only their team). |
Time off > Request leave
| Action | When | What you do | What happens |
|---|---|---|---|
| Price a request on a Mon-Fri calendar | Aisha has 10 days of ANNUAL; no holidays in the range | 1. Time off > Request leave. 2. Employee Aisha Test, type Annual leave. 3. From Thu 15 Oct 2026 to Tue 20 Oct 2026, whole days. 4. Read the live summary and 'Day by day'. | Thu 1, Fri 1, Sat 0 (weekend), Sun 0 (weekend), Mon 1, Tue 1: 'Charges 4' against 'asked for 6'; Balance 10, available 10, after approval 6; the plan ANNUAL30 shown; Send request is enabled. |
| Whole-day holiday inside the range | Holiday 'Test holiday' on Mon 19 Oct 2026 on STD40 (whole day) | 1. Quote the same 15-20 Oct request. 2. Read Day by day. | Monday shows the holiday name and costs 0; total charge 3. |
| Half-day holiday inside the range | Half-day holiday on Fri 16 Oct 2026 (no other holiday) | 1. Quote 15-20 Oct 2026. | Friday costs 0.5; total 1 + 0.5 + 1 + 1 = 3.5. |
| Leave type that counts calendar days | A type with 'Count calendar days' on | 1. Quote 15-20 Oct 2026 with that type. | Weekends and holidays are charged: Thu 1, Fri 1, Sat 1, Sun 1, Mon 1, Tue 1 = 6 days. |
| Morning, afternoon and hours | ANNUAL allows half days and hours; STD40 is 8 h a day | 1. Quote Mon 19 Oct 2026, 'Morning'. 2. Quote the same day with hours 09:00-11:00. 3. Switch to a type counted in hours and quote 09:00-11:00 again. | Morning = 0.5 day; 2 hours = 2 / 8 = 0.25 day on a day type; on an hours type the charge is 2 (hours). A morning and an afternoon of the same day do not clash with each other. |
| Half days at the start and end of a range | ANNUAL allows half days | 1. Tick 'Half day at the end' for Thu 15 Oct to Fri 16 Oct 2026. | Charge is 1.5 days (Thursday 1 + Friday morning 0.5). |
| Send a request | Quote shows no blockers | 1. Send request with reason 'Family event'. 2. Open Time off. 3. Open Approvals as Omar. | Message 'Leave request sent. It now waits in Approvals for the reporting manager.'; list shows Pending, Days 4; nothing is deducted yet (Balance still 10, Pending 4); Omar sees it in his Approvals inbox; the request keeps its balance before (10), pending and after (6). |
| Not enough balance | Aisha balance 6, another pending request holds 2 | 1. Request 5 chargeable days. | Refused with 'Only 4 days are left (2 more are held by requests awaiting a decision).' (numbers may print with decimals); the dialog shows 'Not enough balance for this request.' |
| Overlapping request | Aisha has a pending request for 19-20 Oct 2026 | 1. Request 20-21 Oct 2026. | Dialog warns 'This time overlaps ... leave already requested' and Send is disabled; the API says 'This time overlaps Annual leave leave already requested (<dates>, pending, request <8 chars>).' |
| Weekend-only request | STD40 works Mon-Fri | 1. Request Sat 17 Oct to Sun 18 Oct 2026. | Refused: 'Those days are not worked, so there is no leave to take.' |
| Minimum service | Leave type with minimum service 6 months; employee joined 1 Jul 2026 | 1. Request 15 Oct 2026 on that type. | Refused with '<type name> needs 6 months of service.' (3 months have passed). |
| Plan eligibility | Plan ANNUAL30 with waiting period 3 months; employee joined 1 Sep 2026 | 1. Request ANNUAL leave for 15 Oct 2026. | Quote shows 'Not eligible for this leave' with the reason; submit is refused with '<employee> is not eligible for Annual leave: still in the waiting period.' |
| Leaving employee freeze | A termination in progress with last day 31 Oct 2026 | 1. Request 30 Oct to 4 Nov 2026. | Refused: "This employee's last day is 2026-10-31. Leave cannot run past it." |
| Archived leave type and unknown employee (API) | API access | 1. POST /leave/requests with an archived type. 2. Again with an employee id of another company. | 'That leave type is archived.' and 'Choose an employee of this company.' |
| Retry with the same request ID (API) | API access | 1. POST /leave/requests twice with the same request_id (8-80 characters) and identical body. 2. A third time with a different body. | The second call returns the first answer and creates no second request; the third is refused with a conflict ('This request ID was already used with different ...'); a 5-character request_id -> 'A request ID is 8 to 80 characters.' |
Approvals > Leave request
| Action | When | What you do | What happens |
|---|---|---|---|
| Approve leave and spend the balance | Pending 4-day request; balance 10; Hana (not Aisha) decides | 1. Employees > Approvals > Approve on Aisha's request. 2. Open Reporting > Leave balances and Leave ledger. | Request Approved; ONE ledger row 'used' of -4 dated the first leave day; Balance 6, balance after 6; payroll period '2026-10' recorded; 'Leave request approved' notification; Used column +4 in this year's equation. |
| Balance re-checked at approval | Two pending requests of 6 days each against a balance of 10 (the second was quoted when 10 were free) | 1. Approve the first. 2. Approve the second. | Second refused with 'Only 4 days are left now.'; stays pending (unless the plan allows a negative balance, then it approves and the balance goes to -2). |
| Reject needs a reason | Pending request | 1. Reject with an empty reason. 2. Reject with 'No cover that week'. | 'Say why it was refused.' first; then the request is Rejected, the reason is stored, and no ledger row is written. |
| Decision on a changed request | Open the same request in two browsers | 1. Approve in browser A. 2. Reject in browser B without reloading. | B gets 'This request changed. Reload before deciding.' (or 'Only a pending request can be decided.'); one ledger row only. |
| Nobody decides their own leave | Hana is also an employee and has a pending request | 1. Hana opens her own request (or calls approve). | Refused: 'A different HR user must decide this leave request.' (403). |
Approvals > Leave cancellation
| Action | When | What you do | What happens |
|---|---|---|---|
| Cancel approved leave and refund | Approved 4-day request, balance 6 | 1. Cancel it with note 'Plans changed'. 2. Open the ledger. | State Cancelled; a 'cancellation' row +4 dated today refers to the 'used' row; balance back to 10; answer says refunded 4; if the pay period was already frozen the days come back as a payroll adjustment in the next run (payroll_adjustment true). |
| Cancel a pending request | Pending request | 1. Cancel it. | State Cancelled; no refund row (nothing was spent); refunded 0. |
| Cannot cancel what is finished | Rejected or cancelled request | 1. Try to cancel it (API). | 'Only leave that stands can be cancelled.' |
Leave balances
| Action | When | What you do | What happens |
|---|---|---|---|
| Balance equation for the year | Aisha: opening 10 on 1 Jan, accrued 25, used 12, expired 3, adjustments +2 | 1. Open Reporting > Leave balances. 2. Find Aisha / Annual leave. | Opening 10, Accrual 25, Used 12, Expired 3, Adjustments +2, Closing 22 (10 + 25 - 12 - 3 + 2); Balance matches the whole ledger sum; Pending shows requests awaiting a decision as a memo. |
| Manager sees the team only | Omar is a manager with no hr.employee.view | 1. Omar opens Leave balances and Time off. | Only his direct reports appear; a person with no HR access and no team gets 'You do not have access to time off.' |
Leave ledger
| Action | When | What you do | What happens |
|---|---|---|---|
| Report equation, totals and drill-down | hr.report.view; ledger movements in several types | 1. Open Reporting > Leave ledger with Cutoff 31 Dec 2026. 2. Filter Leave type = Annual leave. 3. Open 'Movements' on a row. | Each row reconciles (Yes); the totals by unit use the same filters and keep days and hours apart; the drawer lists every movement (accrual, used, expired, carryover, adjustment...) with plan version and note. |
| Period validation | hr.report.view | 1. Set From 1 Dec 2026 and Cutoff 1 Nov 2026. | 'The period cannot start after its cutoff.' |
Leave types
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a leave type | hr.configure | 1. New leave type. 2. Code SICK, Name Sick leave, counted in Days, Deducts from a balance off, Paid on. 3. Save. | Type saved Active; appears in Request leave; a request on it needs no balance check and writes no ledger row when approved. |
| Duplicate code and length limits | Type ANNUAL exists | 1. Create another with code ANNUAL. 2. Use a 31-character code. | 'A leave type with that code exists.' and 'That is too long: 30 characters for the code and 120 for the names.' |
| Unit locked after use | ANNUAL has ledger rows | 1. Change 'Balance is counted in' to Hours and save. | 'Balances or requests already use this type, so its unit cannot change.' |
| Archive a type | Open requests on the type exist | 1. Untick Active and save. 2. Open Request leave. | The type is no longer offered in new requests (API: 'That leave type is archived.'); existing requests and balances remain. |
| Edit conflict | Two users open the same type | 1. Both change the name. 2. Save one, then the other. | Second save: 'This leave type changed. Reload before continuing.' |
Accrual plans
| Action | When | What you do | What happens |
|---|---|---|---|
| Author a plan | hr.configure; hr.leave.policy.approve held by someone else | 1. New plan. 2. Code ANNUAL30, leave type Annual, each month, Rate 2.5, Maximum 30, Prorate by FTE on, waiting 0, carryover capped 5, carried leave lapses after 3 months, legal source filled. 3. Save. | Plan v1 with status Configured, author you; it cannot post accruals yet; 'Before this plan can go into force' shows source done, cases not yet. |
| Only the author edits while configured | Configured plan authored by Hana | 1. Hamdan opens it and tries to change the rate. | 403 'Only the plan's author changes it while it is being configured.'; the figures are read-only for him. |
| Independent expected cases | Plan configured by Hana; Hamdan holds hr.leave.policy.approve | 1. Hana tries to add a case (needs the approve permission). 2. Hamdan adds: 'Full-time, 12 months' FTE 1 service 12 expected 2.5; 'Half-time' FTE 0.5 expected 1.25; 'Third' FTE 0.3333 expected 0.8333. | Each case shows Plan computes 2.5, 1.25, 0.8333 (2.5 x 0.3333 = 0.83325, half-up to 4 places) and 'Matches'; cases by the author would show 'Author's own - does not count'; a case is removed only by the person who entered it ('A case is removed by the person who entered it.'). |
| Approve with a wrong case | Same plan, a case with expected 2 | 1. Hamdan clicks Approve plan. | Refused with 'The plan cannot be approved yet.' listing 'Case "Full-time, 12 months" expects 2 but the plan computes 2.5.' (figures may print as 2.0000 / 2.5000); status stays Configured. |
| Approve with no cases, or without a source | Plan with no cases / blank legal source (not DEMO) | 1. Approve. | Problems listed: 'Enter at least one expected case, worked out without the plan's figures.' / 'Cite the legal source the figures come from.' |
| Author cannot approve | Plan authored by Hana with passing cases | 1. Hana (also holding the approve permission) clicks Approve. | 403 'A plan is approved by somebody other than its author.'; button explains 'You wrote this plan. A different person approves it.' |
| Approve then put in force | Passing independent cases | 1. Hamdan approves. 2. Hana (hr.configure) clicks Put the plan in force, In force from 1 Nov 2026. | Status Approved ('Approved. The plan can now be put in force.', content hash saved) then In force from 1 Nov 2026; all five checks ticked; only now can it post accruals and govern requests. |
| Cannot activate before approval | Configured plan | 1. Try Activate (API). | 'A plan goes into force only after an independent review approves it.' |
| New version supersedes the old | ANNUAL30 v1 in force from 1 Nov 2026 | 1. New version (v2, Configured, no cases, same figures). 2. Change Rate to 3. 3. New cases, approve, activate from 1 Jan 2027. | v1 gets 'In force to' 31 Dec 2026 and status Superseded; v2 in force from 1 Jan 2027; activating v2 on or before v1's start date is refused ('Version 1 starts on <date>; start this one after it.'); a second new version while one is still Configured is refused. |
| Retire a plan | Plan in force | 1. Retire plan, confirm. | Status Retired, plan inactive; what it posted stays in the ledger; it can no longer be approved or run ('That plan is archived.'). |
| Create DEMO plan | hr.configure | 1. Click Create DEMO plan twice. | A DEMO leave type and DEMO-LEAVE plan (2 a month, cap 30, carryover capped 5) with DEMO badge and a 'NOT A LEGAL SOURCE' text; the second click creates nothing new; it still needs the same independent review. |
Accrual runs > Accrual
| Action | When | What you do | What happens |
|---|---|---|---|
| Preview (dry run) | ANNUAL30 in force; 3 employees covered | 1. Pick the plan, As of 31 Oct 2026. 2. Click Preview. | Rows show Decision, Units, FTE, Period 2026-10, Why skipped; 'nothing was posted'; the ledger is unchanged afterwards. |
| Monthly accrual at FTE 1 and 0.5 | Aisha FTE 1, Basma FTE 0.5, both eligible | 1. Run accrual As of 31 Oct 2026. | Aisha +2.5, Basma +1.25 (2.5 x 0.5), one ledger row each with plan version, period 2026-10 and FTE used; run appears in history with People 2, Postings 2, Units 3.75. |
| Cap on the balance | Maximum 30; Aisha balance 28.5 | 1. Run accrual for October. | Aisha lands 1.5 (room left), the gross 2.5 is recorded; with balance 30 the row is skipped with 'at the cap'. |
| Running twice adds nothing | October already run | 1. Run accrual As of 31 Oct again. | Everyone is skipped with 'already run'; no new ledger rows; two people pressing together also post once. |
| Waiting period | Waiting 3 months; Dina joined 1 Aug 2026 | 1. Run As of 30 Sep. 2. Run As of 30 Nov. | Sep: Dina skipped 'still in the waiting period' (1 whole month); Nov: 3 whole months, she earns 2.5 for November only - September and October are not back-paid. |
| Probation, joiners and leavers | Plan 'Earn during probation' off; one probation employee; one who joins 15 Nov 2026; one with a termination last day 15 Oct 2026 | 1. Run As of 31 Oct 2026 (preview). | Probation employee 'on probation'; future joiner 'not yet joined' when As of is before the join date; the leaver 'leaving: accrual stops after the last day'. |
| Mid-month joiner is not pro-rated by days | Joined 20 Oct 2026, eligible, FTE 1 | 1. Run As of 31 Oct 2026. | A full 2.5 is earned for October (the plan prorates by FTE only, not by days of service). Record as expected behaviour; raise with HR if a day-based proration is required. |
| Upfront plan in monthly slices | Plan frequency 'a year released in monthly slices', Rate 20, FTE 1 | 1. Run As of 1 Jan 2026. 2. Read the ledger. | Twelve monthly rows: 1.6667, 1.6666, 1.6667, 1.6667, 1.6666, 1.6667 ... adding up to exactly 20.0000 (each slice = running total rounded less the previous rounded total); a second run posts only missing months. |
| Upfront slices follow the FTE month by month | Rate 30 upfront; FTE 1 January-June, 0.5 from July | 1. Run for the year. | January-June 2.5 each (15), July-December 1.25 each (7.5): total 22.5; changing the FTE from July leaves January-June untouched. |
| Real run needs a plan in force and hr.configure | Configured plan; a user without hr.configure | 1. As Hana run accrual on the configured plan. 2. As a user without hr.configure open the screen. | Run refused 'This plan is not in force yet (configured). ...'; preview is allowed; the second user sees 'Running accruals, expiry, year end and recomputation needs the HR configure permission. You can read the history below.' and disabled buttons. |
Accrual runs > Expiry
| Action | When | What you do | What happens |
|---|---|---|---|
| Lapse expired grants | Allocation of 4 days effective 1 Jan 2026 lapsing 30 Jun 2026; 1 day taken in March | 1. Expiry As of 1 Jul 2026, Preview then Run expiry. | 3 days lapse (4 less the 1 used, which draws on the earliest-expiring grant first): ledger row 'expired' -3 dated 30 Jun 2026; running again lapses nothing; the Leave balances Expired column shows 3. |
Accrual runs > Year end
| Action | When | What you do | What happens |
|---|---|---|---|
| Close the year, capped carryover | Plan carryover capped 5, lapse after 3 months; Aisha balance 12 on 31 Dec 2026 | 1. Year end 2026, Preview, then Close the year. | Carries over 5, lapses 7: rows 'expired' -7 ('Above the carryover limit at 2026 year end'), 'carryover' -5 and 'carryover' +5 expiring 31 Mar 2027; balance becomes 5; the preview showed 'carried leave lapses on 2027-03-31'. |
| Carryover none, unlimited and repeat | Plans with carryover none / unlimited (no expiry months) | 1. Close 2026 for each. 2. Close 2026 again for the first. | none: the whole balance lapses; unlimited with no expiry: 'nothing to lapse or re-date' and no rows; second close: 'already closed for this year'; a person governed by another plan is left alone with 'governed by another plan'. |
Accrual runs > FTE change recompute
| Action | When | What you do | What happens |
|---|---|---|---|
| Future FTE change re-prices posted periods | Aisha FTE 1 -> 0.5 from 1 Nov 2026; Nov and Dec 2026 already accrued 2.5 each | 1. Pick Aisha, effective 1 Nov 2026, Preview. 2. Apply. | Preview lists Nov and Dec: Posted 2.5, Should be 1.25, Difference -1.25 each; Apply reverses and re-posts each period (net -2.5); running the preview again says 'Nothing to change: the postings already match the FTE.' |
| Past-dated change becomes a review | Same, effective 1 Aug 2026 (before today) with Aug and Sep posted at 2.5 | 1. Hana runs the recompute for 1 Aug 2026. 2. Hamdan opens Reviews awaiting HR and clicks Apply with a reason. | Nothing is changed immediately; a review appears; after Hamdan applies, Aug and Sep become 1.25 each (-2.5 in total); Hana cannot decide her own review ('A different HR user decides a change that was raised by you.'); Dismiss leaves the ledger untouched; empty reason -> 'Say why you are applying or dismissing it.' |
Accrual runs > Run history
| Action | When | What you do | What happens |
|---|---|---|---|
| History of real runs | Several runs done | 1. Read Run history. | Each real run lists time, kind, plan and version, People, Skipped, Postings, By; previews never appear. |
Allocations & adjustments
| Action | When | What you do | What happens |
|---|---|---|---|
| Allocation approved by a second person | Hana holds hr.leave.allocate, Hamdan holds hr.leave.policy.approve; Aisha balance 10 | 1. Hana: New request, Allocation, +2, effective 5 Oct 2026, lapses 31 Dec 2026, reason 'Worked 2 Dec'. 2. Hamdan approves. | Pending until approval, balance still 10; on approval ONE ledger row 'allocation' +2 expiring 31 Dec 2026, balance 12; the dialog showed Current balance 10 -> 12 'if approved'. |
| Negative adjustment | Balance 12 | 1. Adjustment -1.5 with reason. 2. Approve by another HR user. | Ledger row 'adjustment' -1.5; balance 10.5; an adjustment cannot have 'Lapses on'. |
| Maker-checker and self-service refusals | Hana raised the request; Aisha's own HR login (if any) | 1. Hana tries to approve her own request. 2. Aisha, if she holds the approve permission, tries to approve a change to her own balance. | 403 'A different HR user must decide this request.' and 403 'Nobody decides a change to their own leave balance.' |
| Reject and withdraw | Two pending requests | 1. Reject one with an empty note, then with a note. 2. The requester withdraws the other; someone else tries to withdraw it. | 'Say why it was refused.' then Rejected; ledger untouched for both; withdraw by the asker -> Cancelled ('Withdrawn'), by someone else 403 'Only the person who asked can withdraw it.'; a decided request cannot be decided again ('Only a pending request can be decided.'). |
| Opening balance is a one-time direct load | hr.configure (API POST /leave/adjustments); employee with no movements | 1. Post an opening balance of 10 with a note. 2. Post another for the same person and type. | First: one 'adjustment' row (source 'opening'), balance 10. Second: refused 'This person already has movements for this leave type. Ask for an allocation or an adjustment, which a second person approves.'; no note -> 'Say why the balance is being corrected.' |
Holidays
| Action | When | What you do | What happens |
|---|---|---|---|
| Add and remove a holiday | hr.configure; calendar STD40 | 1. Pick STD40, 2026. 2. Add holiday 2 Dec 2026 'UAE National Day'. 3. Add the same date again. 4. Remove it and confirm. | Listed with Day (Wednesday) and Whole day; duplicate -> 'That date is already a holiday on this calendar.'; removal asks 'Keep it / Remove'; later requests price the day at 0 only while the holiday exists (existing approved requests are not re-priced). |
| Half-day holiday | STD40 | 1. Add 1 Dec 2026 'Eve of National Day' with Half day on. 2. Quote leave over that day. | Charges 0.5 for the day. |
| View-only user | User with hr.employee.view but not hr.configure | 1. Open Holidays. | Holidays visible; Add and Remove are not offered (server would refuse with a permission error). |
Calendar preview
| Action | When | What you do | What happens |
|---|---|---|---|
| Price a range without saving | Any calendar | 1. Choose STD40, Annual leave, 15-20 Oct 2026. 2. Choose a bad range (end before start). | Day-by-day table with 'Charge' and 'Chargeable'; bad range shows 'Choose a valid range.'; nothing is stored. |
Applications > Employees > Features
| Action | When | What you do | What happens |
|---|---|---|---|
| Turn off Time off | Two company admins | 1. Admin A sets Time off Off and proposes; B approves. 2. Open Employees menu. 3. Try POST /leave/requests. | Menus Time off, Leave balances, Leave ledger disappear; new requests, runs and allocations are refused with 'capability_disabled'; old requests and balances still read. |
| Turn off Time and attendance | Two company admins | 1. Admin A sets Time and attendance Off; B approves. 2. Look at the menu. 3. Try to import punches or approve a day. | The Time & attendance group, Attendance exceptions and ESS attendance menus go; changes are refused with 'capability_disabled'; recorded days and punches stay readable. |
Attendance days
| Action | When | What you do | What happens |
|---|---|---|---|
| Generate absent days | Aisha was due at work Mon-Fri 5-9 Oct 2026, no punches, no leave; hr.attendance.manage | 1. Attendance days > Generate absent days. 2. From 5 Oct, To 9 Oct 2026. 3. Generate. | Dialog says 'days created', 'of them absences', 'people considered'; five rows with Exception 'Absent', Net 0.00, Scheduled 8.00; running again creates nothing new; an approved leave day shows 'On leave' instead of Absent. |
| Generate limits | Same screen | 1. Range of 90 days. 2. From after To. 3. A range ending today or in the future. | 'Generate at most 62 days at a time.' (API) ; the screen blocks From after To ('The period cannot start after it ends.'); today and the future are never generated (the end is cut to yesterday); people without a known schedule or not yet joined are skipped. |
| Scope: company, team, nobody | A: hr.employee.view; B: Omar, manager with reports; C: no HR and no reports | 1. Each opens Attendance days. | A sees the company; B only his direct reports; C gets 'You do not have access to attendance.' (menu entries for the listing screens need a scope). |
| Net hours with an automatic lunch | DAY shift; punches in 09:00, out 18:00 | 1. Import the two punches. 2. Open the day. | Clocked 9.00, unpaid break 1.00, Net 8.00, Regular 8.00, Overtime 0.00, Payable 8.00 (once approved), no exceptions. |
| Lunch taken by punching out is not deducted twice | DAY shift; punches 09:00-13:00 and 14:00-18:00 | 1. Import. 2. Open the day. | Clocked 8.00, break deduction 0.00, Net 8.00. With 13:15-13:45 out (30 minutes): clocked 8.50, deduction 0.50, Net 8.00. With only 09:00-12:00 worked: nothing deducted, Net 3.00 (nobody was there for the lunch). |
| Paid break taken punched out | Shift with a paid break window 11:00-11:30 (allowance 15); lunch as above; punches 09:00-11:00 and 11:15-18:00 | 1. Open the day. | Clocked 8.75, unpaid break 1.00, paid break added back 0.25, Net 8.00: a paid break never costs the employee anything. |
| Night shift across midnight (T006) | Shift NIGHT 22:00-06:00; the same two punches (Mon 22:00 in, Tue 06:00 out) imported twice | 1. Import both rows twice (second as a repeat file). 2. Open the days of Mon and Tue. | One session of 8.00 hours belongs to Monday (the evening it started), not 16.00 and nothing on Tuesday; the repeat rows are skipped as duplicates (dedupe by source, device, person, moment). |
| Daily overtime bucket | DAY shift, policy OT-TEST; punches 09:00-19:30 | 1. Open the day. | Clocked 10.50 - 1.00 lunch = Net 9.50; threshold = shift's 8.00 scheduled; Overtime found 1.50 in the Daily bucket, Regular 8.00; exception 'Unapproved overtime' until decided. Payroll later prices it (test multiplier 1.25x -> 1.875 equivalent hours); attendance shows hours only. |
| Weekly bucket | Policy weekly threshold 48 h; Aisha already worked 44 regular hours this week; use Shifts > Sample day with 'Regular hours already worked this week' 44 | 1. Calculate 09:00-19:30 on a working day. | Daily 1.50; of the 8.00 regular hours, 44 + 8 - 48 = 4 fall over the weekly limit: Weekly 4.00; overtime total 5.50, regular 4.00. |
| Rest day and holiday buckets | Policy has the rest-day and holiday buckets on; Sat 17 Oct is a rest day; 2 Dec 2026 a holiday | 1. Sample day, Kind of day = Rest day, 09:00-15:00. 2. Holiday, 09:00-17:00 with no lunch. 3. Turn the rest-day bucket off and repeat 1. | Rest day: all 6.00 hours in the Rest-day bucket; holiday: all 8.00 in the Holiday bucket; with the bucket off the 6.00 hours are plain regular hours with no overtime. |
| Minimum minutes and rounding | Policy minimum overtime 30 min; round 15 min; use Sample day | 1. Net 8.33 (20 minutes over). 2. Punch to 19:24 (1.40 over): nearest, down, up. | 20 minutes is below the minimum so overtime is 0.00; 1.40 h = 84 min: nearest -> 90 min = 1.50, down -> 75 min = 1.25, up -> 1.50. |
| Late, early leave and grace | DAY shift grace in 10, grace out 5; punches 09:25-17:30 | 1. Open the day. | Late 15 (25 - 10), Early 25 (30 - 5); exceptions 'Late' and 'Left early' (and 'Short' only for the minutes not explained by those); column Short shows the remainder. |
| Missing punch and repeat swipe | Punches: one 'in' at 09:00 and no out; another person with ins at 09:00 and 09:05 | 1. Open both days. | First: day Incomplete, exception 'Missed punch out', cannot be approved; second: the two swipes within 10 minutes count once, exception 'Device duplicate'; an exit with no entrance gives 'Missed punch in'. |
Attendance day record
| Action | When | What you do | What happens |
|---|---|---|---|
| Approve a day | Complete day with no overtime; Hamdan (hr.attendance.approve) or Omar (mss.approve_attendance) | 1. Open the day. 2. Approve day (note optional). | 'Day approved.'; status Approved; Payable hours = Regular; approved by and at recorded. |
| Approve is refused on a missing punch | Incomplete day | 1. Approve day. | 'This day has a missing punch. Correct it before approving.' |
| Approve the day and the overtime together | Day with 1.50 daily overtime, overtime needs approval; Hamdan | 1. Approve day without the tick. 2. Reopen. 3. Approve day with 'Also approve the overtime found'. | Without the tick the overtime stays found and unpaid (Payable 8.00); with it Overtime approved 1.50, Payable 9.50 (regular 8.00 + approved 1.50), overtime item Approved. |
| Reopen withdraws overtime approval | Approved day with approved overtime | 1. Reopen day. | 'Day reopened. Any overtime approval made with it was withdrawn.'; status Open; overtime back to Waiting; payable hours drop to regular. |
| Day locked by payroll | Period locked with this day (state Locked); payroll period still frozen | 1. Try Approve / Reopen / Correct the times. | 'Payroll has this day already.' / 'Payroll has this day. Correct it in the next period.'; a change allowed after unlock is queued as a payroll adjustment instead of rewriting frozen pay. |
| HR direct correction of the times | hr.attendance.manage; day with in 09:30 out 18:00; HR is not the employee | 1. Correct the times. 2. First in 09:00, reason 'Device offline'. 3. Save correction. | A correction request is created and approved in one act (source HR, note 'Corrected directly by HR'); a correction punch is added and the original swipe stays visible as 'Replaced'; day redrawn (late disappears); Change log shows Before/After and the reason. |
| Corrections never overwrite punches | Day after a correction | 1. Read the Punches section. | Original punches remain (marked Replaced); correction punches marked 'Correction'; sessions and net hours use the corrected ones. |
| Nobody corrects their own day | HR user who is also an employee with a day | 1. Open own day and click Correct the times. | 403 'You cannot correct your own day.' |
Corrections
| Action | When | What you do | What happens |
|---|---|---|---|
| Raise a correction (HR, manager, employee) | Aisha forgot to swipe out on Mon 5 Oct 2026 | 1. Omar (manager with mss.approve_attendance): New correction for Aisha, work date 5 Oct, kind Missing punch out, time out 18:00, reason 'Forgot to swipe'. | Request Pending with 'Raised through Manager'; the day is unchanged until decided; a second request for the same day is refused ('There is already a correction waiting for that day.'). |
| Approve a correction | Pending request raised by Omar; Hamdan decides | 1. Hamdan opens the request and clicks Approve. | Status Approved; 'Applied to the day'; a correction punch out at 18:00 makes the day complete (Missed out exception gone); decided by and on recorded. |
| Reject needs a note | Pending request | 1. Reject with an empty note. 2. Reject with 'Door log shows exit at 16:00'. | 'Say why the correction is rejected.' then 'Rejected. The day was not changed.' |
| Maker-checker and self decision | Omar raised the request; Aisha is the employee | 1. Omar tries to approve it. 2. Aisha tries to approve it. | 403 'A correction is decided by somebody other than the person who raised it.' and 403 'You cannot decide your own correction.' |
| Withdraw | Pending request raised by Omar | 1. Omar withdraws (confirm 'Yes, withdraw'). 2. Another manager tries to withdraw one. | State Withdrawn, day unchanged; others get 403 'Only the person who raised it, the employee or HR withdraws a correction.'; a decided request: 'Only a correction that is waiting can be withdrawn.' |
| Validation of a new correction | Corrections screen | 1. Work date tomorrow. 2. Date before the join date. 3. Missing session with only a time in. 4. Time out earlier than time in. 5. A locked day. | 'A correction is for a day that has happened.'; 'That is before the employee joined.'; 'A missing session needs both times.'; 'The exit must be after the entrance.'; 'Payroll has this day. Correct it in the next period.' |
Overtime approvals
| Action | When | What you do | What happens |
|---|---|---|---|
| Approve all found overtime | Candidate item with Daily 1.50; Omar (mss.approve_overtime) or Hamdan | 1. Overtime approvals > Approve. 2. Leave the hours as found. 3. Confirm. | 'Approved N hours'; status Approved; Approved (h) 1.50, Approved buckets Daily 1.50; immutable payable units created with units version 1; day payable hours now include 1.50. |
| Approve part of the hours per bucket | Item with Daily 1.50 and Weekly 4.00 | 1. Approve with Daily 1.50 and Weekly 2.00 (Total to approve 3.50). 2. Try Weekly 5. | First approved: Approved 3.50; second refused 'Only 4.00 hours of weekly overtime were found.'; all zeros refused 'Approve some hours, or reject the overtime.' |
| Reject overtime | Waiting item | 1. Reject without a note. 2. Reject with 'Not pre-approved'. | 'Say why the overtime is rejected.' then 'Rejected. No units are payable for this day.'; a rejected item can still be approved later. |
| Withdraw an approval | Approved item | 1. Withdraw without a reason. 2. Withdraw with a reason. 3. Approve again. | 'Say why the approval is withdrawn.'; then the old units are superseded (nothing is deleted) and the item is Waiting; re-approval creates units with the next version number. |
| Segregation and scope | Omar's own overtime; an employee of another team | 1. Omar decides his own item. 2. Omar decides another team's item. | 403 'You cannot decide your own overtime.'; 403 'This overtime is not yours to decide.' (or not found when out of scope). |
| Overtime after payroll froze | Day locked by payroll, approved item changes | 1. Withdraw or approve on that day. | Refused 'Payroll has this day already. Unlock the period, or change it in the next period.' unless the period was unlocked, in which case the difference is queued as a payroll adjustment. |
Timesheets
| Action | When | What you do | What happens |
|---|---|---|---|
| Create the week's sheet | Aisha (employee) or HR | 1. New timesheet. 2. A date in the week: Wed 7 Oct 2026. 3. Create. 4. Create again for 9 Oct. | Sheet for Mon 5 Oct to Sun 11 Oct 2026 in Draft with attendance hours pre-filled for reconciliation; second attempt 'That week already has a timesheet.'; a user without rights for that employee: 'You cannot start a timesheet for this employee.' |
Timesheet record
| Action | When | What you do | What happens |
|---|---|---|---|
| Lines and limits | Draft sheet | 1. Add lines Mon-Thu 8 h on PRJ-ERP and Fri 12 h (total 44). 2. Add a line with no project and no task. 3. Two lines on one day of 14 and 12 hours. 4. A line dated 12 Oct. | Total (not saved yet) updates; refusals: 'Every line names a project or a task.', 'More than 24 hours on <date>.', '<date> is outside the week of 2026-10-05.'; a project not in the Projects module is flagged 'Not known to Projects' but accepted. |
| Variance flag against attendance | Attendance net 40.00 for the week; tolerance 2.00 hours (company setting) | 1. Save the 44-hour sheet. 2. Read Reconciliation. 3. Set the tolerance to 4.00 and save again. | Reported 44, Attendance 40.00, Variance +4.00, Flag 'Flagged'; the Day table marks 'Reported time, no attendance' / 'Attendance, nothing reported' where they differ; with tolerance 4.00 the variance is not flagged (only greater than tolerance flags); a flag never blocks submit or approval. |
| Submit and approve | Saved sheet with hours; Aisha submits, Omar (mss.approve_timesheet) decides | 1. Aisha: Submit. 2. Omar: Approve with a note. | 'Submitted for approval.' then 'Approved.'; lines locked (editing: 'Only a draft or returned timesheet can be edited.'); submitted by and decided by recorded. |
| Submit an empty sheet | Draft with no lines | 1. Submit. | 'Add some hours before submitting.' |
| Return needs a note | Submitted sheet | 1. Return with an empty note. 2. Return with 'Thursday looks high'. | 'Say why the timesheet is returned.' then 'Returned to the employee for correction.'; status Returned; Aisha edits and re-submits (decision cleared). |
| Segregation of duties | Aisha submitted; HR submitted on behalf of Aisha | 1. Aisha tries to approve her own sheet. 2. HR who submitted it tries to approve. | 403 'You cannot decide your own timesheet.' and 403 'A timesheet is decided by somebody other than the person who submitted it.' |
Shifts
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a day shift and read its scheduled hours | hr.configure | 1. New shift: code DAY, 09:00-18:00. 2. Add break Fixed 13:00-14:00, unpaid, deducted automatically. 3. Save. | Scheduled (paid length) 8.00 = 9.00 span - 1.00 unpaid; Overnight 'Same day'; appears in the list and can be assigned. |
| Night shift and break window | hr.configure | 1. New shift NIGHT 22:00-06:00. 2. Add a Window break 02:00-03:00 with allowance 30, unpaid, automatic. | Overnight set automatically; Scheduled 7.50 = 8.00 - 0.50; the break belongs to the morning after the shift starts; allowance 90 on a 60-minute window is refused 'A break allowance cannot be longer than its window.' |
| Validation | Shift form | 1. Code of 31 characters. 2. Duplicate code. 3. Grace in 800. 4. Unknown overtime policy (API). 5. 22:00-06:00 forced to 'same day' (API). | 'A shift needs a code of up to 30 characters.'; 'A shift with that code exists.'; 'Must be between 0 and 720.'; 'There is no overtime policy with that code.'; 'The shift ends before it starts, so it crosses midnight.' |
| Assign an employee to a fixed shift | hr.attendance.manage; self-service installed; shift DAY active | 1. Open DAY > Assign employee. 2. Aisha from 1 Nov 2026, leave Until empty. 3. Assign. 4. Assign NIGHT from 15 Nov 2026. | She is listed 'Open'; the DAY assignment ends 14 Nov when NIGHT starts; Until before From -> 'The assignment cannot end before it starts.'; an archived shift cannot take assignments. |
| Sample day calculator | Shift DAY open | 1. Sample day: clock in 09:00, out 19:30, Working day, regular hours so far 44. 2. Calculate. 3. Change an input. | Shows 'clocked - unpaid breaks + paid breaks = net', overtime by bucket and the policy used; nothing is saved; after an input change it says 'The inputs changed. Calculate again.' |
Rosters
| Action | When | What you do | What happens |
|---|---|---|---|
| Weekly roster | hr.configure | 1. New roster WEEK5, Weekly, Mon-Fri DAY, Sat-Sun blank. 2. Save. | Seven days saved (blank = rest day); an array that is not exactly 7 days is refused 'Give exactly 7 days: a shift for each, or blank for a rest day.' |
| Rotating roster with a phase offset | Shifts DAY and NIGHT exist; Aisha has no roster | 1. New roster ROT3: Rotating, 3 days, Day 1 = 1 Oct 2026; days DAY, NIGHT, rest. 2. Assign Aisha from 1 Oct 2026 with offset 1. 3. Show schedule 1-6 Oct. | Day index = (date - anchor + offset) mod 3, so 1 Oct NIGHT, 2 Oct rest, 3 Oct DAY, 4 Oct NIGHT, 5 Oct rest, 6 Oct DAY, with 'Read from: roster'; a weekly roster ignores the offset and follows the weekday. |
| Overlapping assignment and precedence | Aisha already on ROT3 from 1 Oct 2026; she also has a fixed DAY shift and a calendar | 1. Assign ROT3 again from 10 Oct. 2. Show schedule across a week. | 'That person already has a roster over those dates.'; the schedule reads the roster first, then the fixed shift, then the working calendar; leave and holidays show in 'Holiday or leave' ('On leave', 'Part-day leave'). |
Working calendars
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a calendar | hr.configure | 1. Configuration > Working calendars > New. 2. Code STD40, Name 'Standard 40-hour week', Timezone Asia/Dubai, Hours per week 40, tick Monday-Friday. 3. Save. | Saved Active; leave on it is priced at 40 / 5 = 8 hours a day; timezone and hours validate (Dubai alone, 0 or 169 hours, no weekday ticked are all refused with 'Use the supported fields and valid values for this master.'). |
| Calendar already in use | STD40 used by a current assignment | 1. Change hours to 45 and save. 2. Untick Active and save. | 'Create a new master for structural changes once this master has active assignments or positions.' and 'This master is used by an active position or current/future assignment.'; name and Arabic name can still be changed. |
| Weekend choice drives leave and absence | Calendar with Sunday-Thursday ticked | 1. Quote leave Fri 16 - Sun 18 Oct 2026 for a person on it. 2. Generate absent days for that week. | Friday and Saturday cost 0; Sunday 1; absent days are generated only for ticked weekdays. |
Attendance exceptions
| Action | When | What you do | What happens |
|---|---|---|---|
| Filter the exceptions | Days with late, absent and unapproved overtime exist | 1. Open Reporting > Attendance exceptions. 2. Set From/To to October 2026. 3. Choose Exception kind = Absent. 4. Tick 'Also list days with no exceptions'. | Only absent days list; with the tick, clean days appear too; filters on shift, department and status narrow both rows and footer. |
| Reconciliation footer | A month with imports and overtime decisions | 1. Read the footer. 2. Filter to one employee and compare. | Punches: unique = 2 x sessions + unpaired + repeats ('Matches the stored punches'); Hours: clocked - unpaid + paid = net, regular + overtime found = net; Overtime: found = approved + waiting + declined; Payable = regular on approved days + approved overtime; Imports counts batches, rows, duplicates skipped, rows rejected, batches voided. |
| Export to CSV | A filtered period | 1. Click Export. | attendance-exceptions.csv contains the same filtered rows (never more than the scope allows, capped at the export limit); an audit entry 'attendance.report.exported' is written. |
Expense categories
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a category | hr.expense.configure | New category TAXI, receipt above 50, line limit 200 | Listed; used by new lines at once |
Travel policies
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a policy | New policy GCC-STD: per diem 300, meal deduction 50, mileage 0.50, trip cap 2,000 | Listed |
Travel
| Action | When | What you do | What happens |
|---|---|---|---|
| Trip and per diem | Policy GCC-STD | New trip 5-8 Oct (4 days), 2 meals provided (API meals_provided=2) | Days 4; per diem = 4 x 300 - 2 x 50 = 1,100.00 in the answer |
| Approve a trip and pay the advance | Trip with advance 1,000 for employee B | Approver: Approve; settler: Pay the advance | Approved, then 'Advance paid' with date; paying twice -> 'That advance has already been paid.'; paying before approval -> 'Only an approved trip can draw an advance.' |
Expense claim record
| Action | When | What you do | What happens |
|---|---|---|---|
| Create a claim and add lines | Employee B, category TAXI | New claim; title; Create; Add an expense 85.50 paid by employee with purpose and receipt | Claim Draft; line listed; Total 85.50; Payable 85.50 |
| Mileage line | Claim linked to a trip with mileage 0.50 | Add an expense: amount empty, distance 120 km | Amount = 120 x 0.50 = 60.00 |
| Submit refuses policy faults (all at once) | Line 250 in TAXI (limit 200) with no receipt and no purpose | Submit | Refused 'Check the highlighted lines.' listing all three: receipt required, 'Above the Taxi limit of 200.00.', 'Say what this was for.'; claim stays Draft |
| Duplicate inside a claim holds it | Two lines same date, merchant, amount, currency | Submit | State Held with 'Lines <a> and <b> look like the same expense (detail).'; not refused |
| Same receipt on another claim holds it | Receipt RCPT-1 used on an earlier claim | Submit a new claim with RCPT-1 | Held 'Receipt RCPT-1 has already been claimed.' |
| Let a held claim through | Held claim; approver | Let through with a note | Submitted; hold reason kept on the record; note recorded |
| Approve / Refuse | Submitted claim of employee B; approver A (not B) | Approve (another: Refuse with reason) | Approved / Refused with note and who decided |
| Settle with no advance | Approved claim: employee paid 400, card 600 | Settle | Settled: Total 1,000; On the card 600; Payable to employee 400.00; Returnable 0.00; figures frozen |
| Settle against an advance (employee owed) | Trip advance 1,000 paid; claim: 700 spent from advance, 500 employee paid | Settle | Advance applied 1,000 (700 + 300 offset); Payable 200.00; Returnable 0.00; trip becomes Settled |
| Settle against an advance (employee returns) | Advance 1,000; claim: 400 from advance, 100 employee paid | Settle | Advance applied 500; Returnable by employee 500.00; Payable 0.00 (never both non-zero) |
| Card line | Statement line CC-TEST-1 450.00 | Add an expense paid on the company card, pick CC-TEST-1 | Line linked; Company cards shows Claimed Yes; not payable to the employee |
| Remove a card line frees the transaction | Card line in a draft claim | Remove line | Line gone; CC-TEST-1 Claimed No and offered again |
| Closed claim cannot change | Submitted / approved / settled claim | Add or remove a line (API) | Refused 'A submitted claim cannot be changed.' |
| Settlement does not post or pay | Settled claim | Look for a journal or payment | None: settlement only records who owes whom (finance posting not wired) - mark N/A |
Company cards
| Action | When | What you do | What happens |
|---|---|---|---|
| Load a statement twice | Load 3 transactions; load the same 3 again | First: added 3; second: added 0, skipped 3 |
Expense claims
| Action | When | What you do | What happens |
|---|---|---|---|
| Feature switch | Admin turns off 'Expenses, travel and company cards' | Open the menus; try New claim (and ESS expenses) | Menus gone; changes refused 'capability_disabled'; lists readable |
| Field settings | Expense merchant = Hidden; Receipt reference = Required | Add a line with a merchant; add a line without a reference | Merchant refused when sent; line without reference refused (HR form) |
Talent (API)
| Action | When | What you do | What happens |
|---|---|---|---|
| Vacancy lifecycle | Position with capacity 1; users R (raises) and V (approves) | R: create, submit; V: approve; R: name a recruiter, open; fill when hired | draft -> submitted -> approved -> open -> filled; R cannot approve; opening without a team -> 'Name a recruiter or a hiring manager ...'; fill early -> 'Not every seat has been filled yet (0 of 1 hired).' |
| Applicant privacy | Vacancy team member T; other HR user O | List applications as T and as O | T sees the vacancy's applicants; O sees none (no count either) unless hr.applicant.all; salary expectation only with hr.pay.view |
| Review cycle | Template in force; 3 active employees | Create cycle (draft), preview, launch; close with reviews open | Reviews created pending_self; close refused '<n> review(s) are not published yet...' |
| Self and manager assessment | Launched review for E with reviewer M | E: self; M: manager with every competency rated and overall rating | Only E writes the self part ('Only the person being reviewed writes their own ...'); only M the manager part |
| Calibrate, sign off, publish, acknowledge, appeal | Review in calibration; HR user H with hr.review.publish | H calibrates, signs off, publishes; E acknowledges or appeals; another H resolves | Reviewer cannot sign off own ('The reviewer cannot sign off their own assessment.'); nobody acts on their own review; appeal resolved by neither E nor M |
| Goals | Draft goal written by M for E | M agrees it (refused); E agrees; report progress; close | 'Whoever wrote a goal cannot agree it: the other party does.'; SMART fields required; weights capped at 100 |
| Training session | Course and approved provider | Create session, register 3, complete with results after it ends | Registered; complete before the end refused 'A session cannot be completed before it has ended.' |
| Learning plan approval | Plan version with 2 items submitted by M | M decides own (refused); approver approves | 'You cannot decide a plan you submitted ...'; approved version in force |