# Features — pernod-ricard-prod

Evidence date: 2026-10-07.

Source: `master` at `19e9775` (2026-06-11).

Menu labels are stored in MySQL (`sysMenuLevel1`, `sysMenuLevel2`). This list is the page scripts and the actions those scripts implement. A page can exist in the tree and still be absent from a user's menu.

## Current features

### Site entry

| Feature | Status | Where |
|---|---|---|
| Force HTTPS | Implemented | Root `.htaccess` |
| Root URL redirects to `/supplier/` | Implemented | `index.php`. Production hosts go to `https://www.prsa-supplierportal.co.za/supplier/` |

### Supplier portal (`supplier/`)

| Feature | Status | Where |
|---|---|---|
| Email and password login | Implemented | `supplier/login.php` |
| Email one-time code after a correct password | Implemented | `supplier/login2fa.php`, `supplier/includes/security.cls.php`. Template "One-Time Password". Resend action on the same page |
| Forgot password | Implemented | Login page posts `SendResetEmail` to `webadmin/ajaxfunctions.php` |
| Terms and conditions on first login | Implemented | `supplier/index.php`. Checkbox and link to `documents/TC/General Terms and Conditions Services.docx` |
| Forced password change when the password is aged | Implemented | `supplier/index.php` with `NemoPassword`. When terms are accepted and the password is not aged, this page does not load an invoice dashboard |
| Invoice list limited to the signed-in supplier's company | Implemented | `supplier/includes/my.invoice.cls.php` appends `whereCompanyID()` when `blnSpecial` is `0` |
| Create and edit own invoices | Implemented | `supplier/my.invoice.php`, `supplier/includes/my.invoice.cls.php` |
| Upload invoice, purchase order, GR, statement, credit note, other file | Implemented | Same invoice page |
| Submit invoice to JDE | Implemented | Supplier page calls `Invoice::SubmitInvoice` in `webadmin/includes/invoice.cls.php` |
| Lock the form after submit, successful match, or paid | Implemented | Status switch in `supplier/my.invoice.php` |
| Payment list on the invoice | Implemented | `supplier/includes/my.payment.cls.php` |
| Remittance list on the invoice | Implemented | Includes `webadmin/includes/remittance.cls.php` |
| Download a stored document | Implemented | `supplier/download_document.php` |
| My profile | Implemented | `supplier/my.userprofile.php` |
| FAQ | Implemented | `supplier/layouts/layout.faq.incl.php`, `supplier/includes/faq.cls.php` |
| Messages page | Implemented | `supplier/message.php` |
| Reports page | Implemented | `supplier/report.php` |

### Webadmin (`webadmin/`)

| Feature | Status | Where |
|---|---|---|
| Microsoft sign-in | Implemented | `webadmin/login.php`, `webadmin/auth.php`, `webadmin/oauthfunctions.php` |
| Dev SSO bypass `?bypass=email` when `SSO_OVERRIDE` is true | Implemented | `webadmin/sso_bypass.php`. Documented in `.env.example` as dev/staging only |
| Refuse security group 10 | Implemented | `login.php`, `auth.php`, `sso_bypass.php`, `download_document.php` |
| Dashboard | Implemented | `webadmin/index.php` calls `getDashboard` |
| Invoice list, edit, export to Excel | Implemented | `webadmin/invoice.php` |
| Pay one invoice or a selected set, with confirmation | Implemented | `Invoice::PayInvoices`. Button shown when security group id is `<= 3` |
| Undo payment back to status `New` | Implemented | Button shown when group id is `<= 2` and status is `Paid` |
| Query an invoice by email | Implemented | `Invoice::sendQuery`, template "Invoice Query" |
| Submit / resubmit to JDE | Implemented | Hidden when status is `Successful 100% match in JDE` |
| Invoice error list | Implemented | `webadmin/invoice.errors.php` |
| Soft-delete an unpaid invoice | Implemented | `blnDeleted = 1` |
| Suppliers, including a linked login user on create | Implemented | `webadmin/supplier.php`, `webadmin/includes/supplier.cls.php` |
| Welcome email | Implemented | Template "Send Welcome Email" |
| Users, profile, password reset | Implemented | `webadmin/user.php`, `webadmin/my.userprofile.php`, `webadmin/resetPassword.php` |
| Security groups and menu permissions | Implemented | `webadmin/security.group.php` |
| Settings | Implemented | `webadmin/settings.php` reads and writes `sysSettings` |
| AP teams | Implemented | `webadmin/includes/APTeam.cls.php` |
| Remittances and file upload | Implemented | `webadmin/remittance.php` |
| Payments list | Implemented | `webadmin/includes/payment.cls.php` |
| Reports: Supplier Invoice Report, Payments Exception Report | Implemented | `webadmin/report.php` |
| Email log and templates | Implemented | `webadmin/email.php`, `webadmin/email.template.php` |
| FAQ maintenance | Implemented | `webadmin/faq.php` |
| Authenticated document download | Implemented | `webadmin/download_document.php` (`type` invoice, remittance, or payment) |
| Direct access to stored invoice files denied | Implemented | Commit `afbd1e7` "Add file download gateway and deny direct access to files". `.gitignore` ignores `webadmin/invoices/*` |

### Scheduled work

| Feature | Status | Where |
|---|---|---|
| Assign invoice due dates from supplier terms | Implemented | `cron.daily.php` task 1 |
| Move invoices to Due and Overdue | Implemented | Task 2. Skips `Paid` and `Partial Payment` |
| Email due and overdue lists | Implemented, and skipped while `$isDebug` is true | Task 3. Committed file sets `$isDebug = true` |
| Deactivate supplier users after an inactive interval | Implemented | Task 4. Interval is `sysSettings` `INACTIVE_ACCOUNT_Suspension_Interval`. Comment in the script says 30 days |
| Import JDE payments and mark invoices paid or partial | Implemented | Task 5. Not wrapped in the debug check |
| Email suppliers their paid invoices | Implemented, skipped while `$isDebug` is true | Task 6, template "Paid Invoices to Supplier" |
| Email the payments exception report | Implemented, skipped while `$isDebug` is true | Task 7, template "Payments Exception Report" |
| Email AP about old invoices in status `New` or `Submitted` | Implemented, skipped while `$isDebug` is true | Task 8. Age is `sysSettings` `DATE_OLDER_THAN_Interval` (comment says 3 days). Template "Unsuccessful Invoice Orders". Recipient in code is `groupcreditors@pernod-ricard.com`, with CC `maanie@overdrive.co.za`. The status value `Submitted` is not one of the enum values in `invoice.cls.php` (`Submitted to JDE`) |
| Deactivate supplier users with no login for 6 months, including never-logged-in accounts older than 6 months | Implemented | `webadmin/cron.inactive-users.php` (comment 2026-03-23). Runs the update even when `$isDebug` is true |

What schedules these scripts is **Unknown / Requires Confirmation**.

## Completed features

These are present and called out by comments as delivered work, not as a separate release list.

- Password policy class (2016-09): strength, history, expiry, reset token. `webadmin/_framework/_nemo.password.cls.php`. The supplier app includes that same file.
- Phase 2 payment sub-list on the invoice (2018-07).
- JDE voucher match with OAuth (comments 2020-11 and 2022-08).
- VAT excluding and including amounts (2020-11).
- Profile picture path on the session (comment 2025-02-11).
- Environment variables instead of credentials in `system.php` (comment 2025-11-11).

## Planned or unfinished in the tree

| Item | Evidence | Status |
|---|---|---|
| Webadmin email-and-password form | Markup and the `Login` branch remain. The form is inside an HTML comment. On-screen text says all users must use Azure AD | Not shown. The password branch still runs if `Action` is `Login` |
| CSV/FTP payment import | `import.payments.CSV.cls.php`. The call in `cron.daily.php` is commented out | Replaced by the JSON importer for the daily script |
| Remember-me for Azure | `rememberUser` and `getRememberedUserId` in `oauthfunctions.php` are commented out | Not active |
| Supplier "Query Invoice" | The case in `supplier/my.invoice.php` is commented out | Not active on the supplier page |
| Purchase-order and GR as their own upload buttons | Button constants exist and the cases are commented. Those file types are options on the "other" upload list | Partial |
| Course-email samples inside `NemoEmail` | Calls to templates "Course Start", "New Module", and similar, inside the email class | Framework sample. No course pages were found in this application |

No issue tracker or roadmap file in the repository states further planned work.

## Recently changed

From the last 40 commits on `master`, ending at `19e9775` (2026-06-11):

- Invoice file download error fix (`04afd47`).
- SSO bypass (`79e1e8f`).
- File download gateway and denial of direct file access (`afbd1e7`).
- Session path and root redirect behaviour on non-production hosts (`9b9c1b8`).
- Security-changes series: auth variable names, SonarQube-oriented query changes, inactive-user cron, login adjustments that were later reverted (`9f7bd66` "reverted login changes").

The 2025-02-11 profile-picture commit named in the onboarding scan is older than this window. The session fields are still in the login scripts.

## Deprecated or leftover

| Item | Evidence |
|---|---|
| `invoice20210215.php`, `invoice20210216.php`, `my.invoice20210215.php`, `my.invoice20210216.php`, `my.invoice20210302.php`, `cron.daily20210215.php`, `project.functions.inc20210215.php`, `system.functions.inc20210326.php`, `invoice.cls20210215.php` | Dated copies. Later edits are on the undated files. Whether a database menu still links to a dated page is **Unknown** |
| `webadmin/test_jde_token_request.php` and `webadmin/test_data.json` | A token-request test script and sample JSON. Not referenced by the daily cron |
| `webadmin/cron.test.php` | Test cron entry. Not referenced by `cron.daily.php` |
| Sonar project files named in the 2026-09-28 scan | `sonar-project.properties` and `sonarqube_scan.bat` are not in `19e9775` |

## Removed behaviour

- Supplier login no longer sets the session before the one-time code. `supplier/login.php` only redirects to `login2fa.php` after the password check.
- Auto-creation of an extra user step was removed in commit `f5cb587` ("removed extra user creation step") on the security branch, later merged. The supplier save in `supplier.cls.php` still inserts one `sysUser` row.
- A default report on `webadmin/report.php` was removed (comment 2022-09-22). The user chooses Supplier Invoice Report or Payments Exception Report.
