# Features — snell-freestock (Freestock Requisition)

Evidence date: 2026-10-02. Source: `master` at `477f559` (2026-09-18).

Status words: **Current** means present on `master` and reachable from a page or include that a page loads. **Dormant** means present but unused, commented out, or hidden. **Superseded copy** means an older file kept beside the live one.

There is no feature register in the repository. Planned work is **Unknown**. Nothing in Git history is a feature flag or a "coming soon" note.

## Current

### Login shell

`index.php` redirects to `login.php`. The login layout shows the Snell logo, the title Freestock Requisition, a message area, and a Login button. No credential fields.

Evidence: `index.php`, `login.php`, `include/layout.login.inc.php`, `include/layout.header.inc.php`.

### Internet Explorer block

On the login page only, IE 6–11 clears the login action and shows a message to install Firefox or Chrome.

Evidence: `login.php`.

### Active-directory wording with a database lookup

The failure message says login is controlled through Active Directory. The working check is `LogginUser` against `mstUser.strDomainLogin` and `blnActive = 1`, joined to `mstUserGroupFreeStock`.

Evidence: `login.php`, `include/system.functions.inc.php`. The `blnActive` predicate was added in `552bae2` (2025-06-03).

### Usage log on success

A successful login inserts `mstUsageLog` with `strSystem = 'FreeStock'` after `sleep(1)`.

Evidence: `LogginUser`.

### Dev identity override on host `sql-server`

That host sets `LOGON_USER` to `silicon\pj` and opens DSN `snell_fsr` without the later `setDatabase("snell_2015")` call used on every other host.

Evidence: `include/system.inc.php`.

### Authorisation list

Menu label "Authorisation List". Filters and a sortable table of requisitions with a rounded total footer. Default filter on first visit: Pending, all managers, month-to-date.

Evidence: `requisition.php`, `Requisition::getFilters`, `Requisition::getList`.

### New and edit requisition

Menu "New Requisition". Form for request type, Marketing or Sales expense, region, bill-to, ship-to, ship-to search, detail, contact name, contact number, delivery or collect, and product lines.

Evidence: `requisitionForm.php`.

### Pink-slip number `ES` + 7 digits

Assigned when the stored number is blank. Not overwritten once set.

Evidence: `Requisition::AssignPinkSlipNumber`. Comment 2026-09-18: safe to retry after a partial first save.

### Posted requisition id kept across save

`PostedRequisitionID` prefers a numeric `POST` id so a save does not insert a second empty header.

Evidence: `include/requisition.cls.php`. Commit `3e1f167` (2026-09-18): "Stop requisitions losing their items and block empty submissions".

### Fail-closed status changes

Submit, approve, decline, and cancel run `Save` first. If `$blnSaveOK` is false they do not change status.

Evidence: `requisitionForm.php` action switch. Commit `520b1c4`.

### Empty submit and empty approve blocked

`ItemCount` must be at least 1. The messages tell the user to add a product.

Evidence: `Requisition::Submit`, `Requisition::Approve`.

### Product lines priced from `dwdProduct`

Add Item clones a hidden row with a negative id. Save inserts negative ids and updates positive ids that belong to the requisition. Costs are re-read from `dwdProduct`. Unknown products and missing brand fields fail that line and mark the save unsuccessful.

Evidence: `jsAddItem`, `Requisition::Save`.

### Remove line

Per-row link `Action=RemoveItem`. Deletes `fsrItem` by item id.

Evidence: `requisitionForm.php`, `Requisition::RemoveItem`.

### Region-driven account lists and ship-to search

AJAX XML types: `ajaxLoadRegionBillToAccountsXML`, `ajaxLoadRegionShipToAccountsXML`, `ajaxSearchShipToAccountXML`, `ajaxReloadProductsXML`. Failed or non-XML replies alert and do not clear a list that was already rendered. Bill-to and ship-to are not re-fetched on initial page load.

Evidence: `ajax.functions.php`, `jsSearch`, `jsReloadBillToAccounts`, `jsReloadShipToAccounts`, `jsReloadProducts`. Commit `43c1254` (2026-09-17) and comments dated 2026-09-18.

### Custom URL decode for product and account text

`custom_urldecode` in the requisition form replaces a set of percent-sequences (including `%92`, `%91`, and accented characters) before `decodeURIComponent`.

Evidence: `requisitionForm.php`. Commits `7c66258` and `0c07935` (2025-06-04).

### Approval band at R10 000

Pending requisitions under the constant are editable by the requisition's manager or alternate. At or above it, by the executive on the requisition. Approve is disabled on Draft for users who are not `blnSpecial`. Special users skip that band and the Draft Approve lock, and are stopped by the Approved lock (and, for group 6, by Completed, Declined, and Cancelled).

Evidence: `$SALESMANAGERMAXVALUE`, permission switch in `requisitionForm.php`. Comments cite fixes on 2016-05-05 and 2020-10-29.

### Submit queues `FSR_NewRequisition`

Deletes any existing cron row of that type and param, inserts status `New`, sets the requisition to Pending.

Evidence: `Requisition::Submit`.

### Approve queues `FSR_RequisitionApproved`

Same queue pattern. Stores the approver's user name on `strAuthorizedBy`.

Evidence: `Requisition::Approve`.

### Decline

Sets Declined and marks matching `sysCronJob` rows Removed. No item-count check.

Evidence: `Requisition::Decline`.

### Manager chain and mailto links

Save copies manager, alternate, and the manager's executive onto the requisition. The form shows Man / Alt / Exc with `mailto:` links from `vieRequsitionManager` when names are present, otherwise red "n/a".

Evidence: `UpdateManagers`, `requisitionForm.php`.

### Email-link login hook

Any `Link` query parameter on the form page runs `LogginUser` again. The value of `Link` is ignored.

Evidence: `requisitionForm.php`.

### Logout

Menu shows "Logout: {user name}" and opens `logout.php?Action=Logout`.

Evidence: `include/layout.menu.inc.php`, `logout.php`.

### User administration

Menu Users when `blnSpecial = 1`. List, active/inactive filter, new, edit, and Make Inactive (`blnActive = 0`). Duplicate domain login blocked on create. Manager and executive checkboxes rewrite the manager foreign keys.

Evidence: `user.php`, `include/user.cls.php`. User filter commits `721ed68` and `5f46bb5` (2025-06-04). Active/inactive commits `54a047a` and `552bae2` (2025-06-03). The version comment dates the feature to 2016-05-31.

### Footer version

Prints `Version 2.0.1s` and `31 May 2016`. Adds `[Dev]` when the host is `sql-server`.

Evidence: `include/layout.footer.inc.php`, constants in `include/system.inc.php`.

### IIS default document

`web.config` clears the default-document list and puts `index.php` first.

Evidence: `web.config`.

## Recently changed

On this evidence date, "recent" means the commits after `f6a9391` (2025-06-04), which was the revision the onboarding scan recorded.

| Change | Commits | Date |
|---|---|---|
| AJAX error alerts, XML treated as unusable unless it contains `<rows>`, custom decode retained | `43c1254`, merge `307d804` | 2026-09-17 |
| Live files restored from a production backup | `45460cd`, `a52a245`, merge `477f559` | 2026-09-18 |
| Save uses the posted requisition id; empty submit and approve refused; status changes skipped when save fails; pink-slip assignment is retryable; item keys and product lookups validated | `3e1f167`, `520b1c4` | 2026-09-18 |

Earlier in 2025, still on `master` and still in the running code: user active flag, login restricted to active users, user-list status filter, URL-decoding of account and product text.

## Dormant

### Cancel requisition button

The control is rendered with `display: none`. `Requisition::Cancel` still sets status Cancelled if something posts `Action=Cancel Requisition`.

Evidence: `requisitionForm.php` line comment "20150208 - hiding the cancel button".

### `checkLogin`

IP-to-session comparison. No caller.

Evidence: `include/system.functions.inc.php`.

### `$OVERRIDE_USERNAME`

The Azure AD sample assignment is commented (`notforprod`). The `if ($OVERRIDE_USERNAME != null)` branch remains.

Evidence: `LogginUser`.

### adLDAP construction

`login.php` and the email-link branch `require` `ldap/adLDAP.php`. `new adLDAP()` is commented out. No other page constructs it.

Evidence: `login.php`.

### Cookie `ckyFSR`

`system.inc.php` reads a cookie variable named `ckyFSR`. The cookie write inside `checkLogin` is commented out.

Evidence: `include/system.inc.php`, `checkLogin`.

### Commented requisition-page actions

`requisition.php` contains a commented switch for Close, Save, and Delete aimed at `user.php`. It does not run.

### `User::getList_old`

Previous user grid with a Delete button. `user.php` calls `getList`.

Evidence: `include/user.cls.php`.

### `test.php`

Manual page: counts `sysQuery`, prints URL-encoding samples, and posts one ship-to AJAX call with region hardcoded to `KZN`. Uses the login layout, so it does not require `$_SESSION[USER]`.

Evidence: `test.php`. Not linked from the menu.

## Superseded copy

`include/requisition.cls.20210503.php` is an older requisition class (about 494 lines). No page includes it. The live class is `include/requisition.cls.php`.

## Shared script file with unused screens

`include/javascript/scripts.js` defines popups and AJAX helpers for courses, clients, contacts, and candidates. The freestock pages call `d()`, `formatNumber`, and `urldecode` from that file. No freestock page was found that calls the course or client popups. Provenance: **Inferred** leftover from a shared script. The file is still loaded by the header.

## Removed

Git history does not show a feature removed by a dedicated commit message, other than "removed debugging code" (`f6a9391`), which did not delete a user-facing screen. `getList_old` remains in the class.

The onboarding scan listed `sonar-project.properties` and `sonarqube_scan.bat`. They are not in Git history, so they were not removed by a commit visible here. **Unknown** whether they existed only as untracked scan-host files.

## Planned

No planned feature is written in the repository. **Unknown**.

## Not built here

- A UI to edit request types, brands, products, or customers.
- A screen that sets requisition status to Completed.
- Server-side email. Manager contact is `mailto:`.
- The cron worker for `FSR_NewRequisition` and `FSR_RequisitionApproved`.
- Automated tests.
