# Features — dthf-hr

Evidence date: 2026-10-16.

Source: `master` at `93552d8` (2026-06-19). Screen files are the root `*.php` scripts. Behaviour classes are under `includes/` unless noted.

Dated copies (`*.20190726.php`, `*20200407.php`, `*20200519.php`, and similar) are listed as retained copies, not as the file the current screen includes.

## Current features

| Feature | What it does | Where |
|---|---|---|
| Login | Email and password against `sysUser` and an active security group. Group 2 opens `staff.php`; other groups open `my.projects.php` | `login.php`, `index.php` |
| Password policy | Salted hash in `sysPassword`, length, history, restricted words, expiry, reset-link interval. Defaults can be inserted by `_nemo.password.cls.php` | `_nemo.password.cls.php`, `resetPassword.php` |
| Forgot password | Ajax `SendResetEmail` sends template "Reset Password" | `login.php`, `ajaxfunctions.php` |
| Failed-login warning | After five recent password failures, emails a suspension warning. Does not persist `blnLogin` | `CheckSecurityLock` in `system.functions.inc.php` |
| Menu and rights | Two-level menu and view/new/save/delete/special flags per security group | `_nemo.menu.cls.php`, `_nemo.cls.php`, `security.group.php` |
| Users | User maintenance | `user.php`, `includes/user.cls.php` |
| Settings | Loads every `sysSettings` row into `$SystemSettings` | `system.php`, `settings.php`, `includes/settings.cls.php` |
| Companies | List with staff count and active project count. Link and unlink staff with a staff code | `company.php`, `includes/company.cls.php` |
| Projects | Project maintenance, including admin project codes reloaded by ajax | `project.php`, `includes/project.cls.php`, `ajaxfunctions.php` |
| Sites | Site maintenance | `sites.php`, `includes/sites.cls.php` |
| Staff | Name, email, active flag, line manager, employee number, company codes, job titles, Excel import | `staff.php`, `includes/staff.cls.php` |
| My projects | Period allocations by project or by staff. Percentage and status. Role-based button rules | `my.projects.php`, `my.projects.staff.php`, `includes/project.staff.allocation2.cls.php` |
| Allocation log | Writes `logProjectStaffAllocation` during month end | `includes/month.end.cls.php`, `psa.logs.php` |
| Month end | Finalise current period, open next period for active staff, generate staff control checks | `month.end.php`, `includes/month.end.cls.php` |
| Month-end checks | Pre-close checks and journal descriptions for salary, HR support, salaries levy, IT support, finance support | `month.end.checks.php`, `includes/month.end.checks.cls.php` |
| Staff cost import | Excel workbook into salary / cost figures. PhpSpreadsheet | `import.staff.costs.php`, `includes/import.staff.costs.cls.php` |
| Finance levy import | Excel finance transactions, with project exclusions recorded in comments | `import.fin.levies.php`, `includes/import.fin.levies.cls.php` |
| Journals | Period journal list and company journals | `journal.php`, `company.journals.php` |
| Timesheet control | One control row per company, staff, and period, with a version. PDF builder | `timesheet.control.php`, `includes/timesheet.control.cls.php` |
| Timesheet email queue | `sysCronJob` job `generateTimesheet`, consumed by the hourly script, PDF attached | `cron.hourly.php` |
| Blind capture | Record the signed timesheet version against the control version | `blind.capture.php`, `includes/blind.capture.cls.php` |
| Bulk blind capture | Grid capture with the validation messages in `system.php`. Groups 1 and 3 can accept an out-of-range signed date | `blind.bulk.capture.php`, `includes/blind.bulk.capture.cls.php` |
| Timesheet rejection | Rejection list and cron notes. The hourly "Timesheet Rejection" case is commented out | `timesheet.rejection.php`, `includes/timesheet.rejection.cls.php` |
| Outstanding reminders | Daily script at 8, 11, 15, and 20 days after month end, copying line managers as coded | `cron.daily.php`, `cron.daily.outstanding.timesheets.php` |
| Outstanding report | Second task in the same daily scripts | `includes/outstanding.timesheet.rpt.php`, `report.php` |
| Public holidays | Date-filtered list. Timesheet PDF greys those dates and Sundays | `public.holiday.php`, `includes/public.holiday.cls.php` |
| Email templates and log | Template editor. Online open marks `tblEmail` read by `UID` | `email.template.php`, `email.php`, `email.read.online.php`, `email.read.receipt.php` |
| Leave storage | `tblLeave` schema, PaySpace insert, staff renderer | `database/tblLeave.sql`, `leave.api.php`, `Staff::renderStaffCompanyLeave` |
| Company control | Company control check and staff control check screens | `company.control.php`, `company.staff.control.check.php` |
| HTTPS redirect | Rewrite to HTTPS | `.htaccess` |
| Header branding | Logo `images/dthf_hr.logo.png` plus `sysSettings` brand. On server name `lamp`, the header also shows the database name | `_nemo.cls.php` |

## Completed features

These are in the tree and are what the current screens call. "Completed" here means present on `master`, not that a product owner signed them off.

- Nemo list/detail shell used by every authenticated screen.
- PHP 8.2 compatibility pass recorded at `a647fe3` (2023-11-06), covering salary and finance-levy fixes, after the October 2023 dynamic-property and null fixes.
- Replacement of PHPExcel by PhpSpreadsheet at `af32517` (2023-10-23). The import classes use the new library. The `PHPExcel/` directory is still in the repository.
- Employee number column on `tblStaff` (`database/tblstaff0260107.sql`) so leave rows can be matched.

## In development

Nothing in Git is on a branch ahead of `master` except `Leave-integration`, which was merged at `93552d8`.

The leave work is merged and then partly disabled in the same history:

- `fe527e3` (2026-06-19) message: "Disabled Leave Integration changes".
- `includes/timesheet.control.cls.php` and `staff.php` comment dated 20260619: "Temporarily remove leave from Timesheet".
- `cron.employee.leave.php` is still an executable script.

Provenance: **Implemented** as merged code with the display calls commented out. It is not an open pull request.

## Planned

No roadmap, ticket, or TODO file describes future work.

The word "Temporarily" on the 2026-06-19 comment is the only statement that leave display might return. That is a comment, not a scheduled change. **Unknown / Requires Confirmation.**

`cron.hourly.php` comments dated 20200407 say timesheet generation and "Timesheet Email All" were paused at a person's request. The `generateTimesheet` case is active in the file that was read. The "Timesheets Email All" case remains commented. Provenance: **Implemented** as commented-out. Whether the pause is still the business intention is **Unknown / Requires Confirmation**.

## Recently changed

Relative to the onboarding scan tip `a647fe3` (2023-11-06):

| Date | Commit | Change |
|---|---|---|
| 2026-02-06 | `92b8332`, `ea1d04e`, `cd7fdab` | Cron and PDF changes. Debug code removed in the third commit |
| 2026-06-19 | `fe527e3`, `93552d8` | Leave integration merged from pull request #1, with timesheet calendar painting and the staff leave panel commented out |

Inside the merged leave code:

- OAuth client-credentials call to `https://identity.yourhcm.com/connect/token`.
- Leave applications read from PaySpace OData for one company id taken from the token response.
- `tblLeave` insert.
- Leave type short codes prepared for the PDF and then not printed.
- `renderStaffCompanyLeave` prepared and then not called from `staff.php`.

## Deprecated or retained copies

| Item | Evidence | Status |
|---|---|---|
| `PHPExcel/` | Superseded by PhpSpreadsheet in 2023-10. Directory still committed | **Inferred** unused by current import classes |
| `includes/mpdf/` and `includes/mpdf_20190305/` | Composer package is `mpdf/mpdf` ^8.1 under `vendor/` | **Inferred** legacy. A comment in `cron.hourly.php` records a fatal `_fgets` redeclaration between old mPDF and FPDI |
| `includes/project.staff.allocation.cls.php` and `project.staff.allocation2.cls.20191028.php` | `my.projects.php` includes `project.staff.allocation2.cls.php` | Retained copy |
| `includes/staff.cls.20190726.php`, `staff.cls20200519.php`, `staff.cls20200520.php`, `staff.cls20200520_1.php`, `staff.cls.latest.php` | `staff.php` includes `includes/staff.cls.php` | Retained copies |
| `includes/import.fin.levies20200403.cls.php`, `20200406`, `20200407` | Current screen uses `includes/import.fin.levies.cls.php` | Retained copies |
| `includes/month.end.checks20200403.cls.php`, `20200406`, `20200504` | Current class is `includes/month.end.checks.cls.php` | Retained copies |
| `cron.hourly.20190726.php`, `cron.hourly.20190919.php`, `cron.hourly20200407.php` | Current hourly file is `cron.hourly.php` | Retained copies |
| `cron.daily.outstanding.timesheets.20190726.php`, `cron.daily.send.outstanding.timesheets.20190919.php` | Current names drop the date | Retained copies |
| `xcron.daily.outstanding.timesheets.*.80.php`, `Xcron.daily.php` | Prefixed so they are not the main cron names | **Inferred** side copies |
| `blind.capture.20190726.php` and matching class | Current file is `blind.capture.php` | Retained copy |
| `_nemo.database2.20190909.cls.php`, `_nemo.details.20190909.cls.php`, `_nemo.report.cls20200519.php`, `_nemo.report.cls20200520.php` | Current scripts include the undated class names | Retained copies |
| Home-page usage log in `index.php` | The whole dashboard is commented. The script only redirects | Removed from the running page |
| MD5 password compare in `login.php` | Replaced by `NemoPassword::checkPassword`. The MD5 line is a comment | Removed from the running check |
| Hourly cases "Timesheets Email All" and "Timesheet Rejection" | Inside a block comment in `cron.hourly.php` | Not executed by that file |
| PDF encryption via FPDI | Calls to `pdfEncrypt` are commented, with a note that FPDI and mPDF both declare `_fgets` | Not executed |
| Date-signed range check in ajax | Commented under "Disable Date Validation - 20200921" | Not executed on that ajax path. The bulk screen can still surface the message |

## Not a product feature

- `info.php` prints `phpinfo()`.
- `test.php` and `zSandBox.php` are scratch scripts.
- `SQL1` is a one-off `UPDATE` that sets allocations to `Final` for company 3, period `2019-01`.
- `includes/upload-krugerrand-sell.php` is in the includes tree. Nothing in the HR screens that were read includes it. Provenance: **Unknown** whether it belongs to this product.
