# Features — por (Purchase Order Requisition)

Evidence date: 2026-10-06. Source: `git@bitbucket.org:overdrive/por.git`, `master` at `6fabdc090d2a3693f369f9fe50dea47990109349` (2026-06-23).

Status words used here:

- **Current** — present on `master` and reached from a live entry point or include.
- **Leftover** — file is in git and is not linked from the menu or from `system.inc.php`.
- **External** — a status or job the UI expects, with no writer in this repository.

History before the tip was not walked (shallow clone). Feature dates below come from source comments and `CHANGELOG.md`, not from a full `git log`.

## Current

### Sign-in and shell

| Feature | Location | Notes |
|---|---|---|
| Redirect to login | `index.php` | `Location: login.php` |
| Windows login | `login.php`, `loginUser` in `include/system.functions.inc.php` | Matches `LOGON_USER` to `mstUser.strDomainLogin` plus `mstUserGroupPOR` |
| IE 6–11 block | `login.php` | Message asks for Firefox or Chrome |
| Dev impersonation | `RGBC_POR_DEV_LOGIN_OVERRIDE` | Optional. README: not for production |
| Login debug page | `RGBC_POR_LOGIN_DEBUG` | Dumps DSN, catalog, and sample counts |
| Usage log | `loginUser` | Inserts `mstUsageLog` for system `POR` |
| Logout | `logout.php` | Destroys session when `Action=Logout` |
| Menu | `include/layout.menu.inc.php` | Purchase Order List, Receipts List, Vendors List, Logout. Imports, Reports, and Settings are conditional |
| Version line | `include/system.inc.php`, `include/layout.header.inc.php` | `1.3.0`, `1 Sep 2018`, `[Dev]` when host is `sqlsrv02` |
| Session gate | `include/layout.full.inc.php` | Missing `$_SESSION['USER']` redirects to `login.php` |

### Purchase orders

| Feature | Location | Notes |
|---|---|---|
| Filterable paged list | `requisition.php`, `include/requisition.cls.php` | Page size 100. Slow-search guard when ignore-dates has no other filter |
| New draft | `requisitionForm.php`, `Requisition::save` | Status Draft. Number `PORGB` + 10-digit `intPONumber` |
| Line items | `porItem` via `Requisition::save` | Qty, cost, GL, region, brand, key account, PE, TME |
| GL dropdown cascade | `ajax.functions.php` | Region, brand, key account, PE, TME, and description |
| Quote upload and delete | `Requisition::uploadDocument`, `deleteDocument` | Files under `include/documents/` |
| Submit | `Requisition::submit` | Pending + cron `POR_1NewRequisition`. GL combination must exist on `mstGLCode` |
| Approve / decline | `Requisition::approve`, `decline` | Approved or Declined, with cron types `POR_2ApprovedRequisition` and `POR_2DeclinedRequisition` |
| User-group limits | `challengeUgAccess` | `viePOR_UGAccess` levels, SELF / MAN / ALT / email |
| Cancel one or many | `requisition.php`, `Requisition::cancel` | PO and its receipts become Cancelled. Cron `POR_2CancelledRequisition` |
| Copy | `Requisition::copyRequisition` | New Draft, lines copied, quote number cleared |
| Close PO | `Requisition::closePo` | Status `Completed`. No cron insert. Special user, and only some statuses show the button |
| Complete balance | `Requisition::completePo` | Status `Complete balance no longer applicable`. Cron `POR_CompletedRequisition` |
| CSV export | `Requisition::getExportPORList` | `POR_Approved_PO_List_YYYYMMDD.csv`. Excludes Draft, Cancelled, Pending |
| AP export | `include/requisition.exports.inc.php` | HTML table for Excel. Includes items, GL segments, receipt numbers |
| ESN vendor exclusion | `requisitionForm.php`, `ajaxSearchVendorXML` | `strVendor NOT LIKE 'ESN%'` |
| Payment terms and request types | `requisitionForm.php` | `mstPaymentTerms`, `fsrRequestType`. New PO defaults payment term id 1 |
| Customer ship-to / bill-to lookups | `ajax.functions.php` | `dwdCustomer`. Bill-to also requires `blnPromotionalAccounts = 1` |
| Email link entry | `requisitionForm.php` when `Link` is set | Re-runs `loginUser`. Includes `ldap/adLDAP.php` without binding |

### Receipts

| Feature | Location | Notes |
|---|---|---|
| Receipt list | `receipts.php`, `include/receipts.cls.php` | PO statuses Approved, Partially Receipted, Completed |
| Draft receipt | `Receipts::Save` | Status `New`. Number `RCPRGB` + 10-digit `ReceiptID`. Blocked if another `New` receipt exists |
| Invoice number and lines | `receiptsForm.php` | Qty times cost, rounded to 2 decimals |
| Qty ceiling | `jsCheckReceiptItemQty` | Cannot exceed PO line quantity across other receipts |
| Submit | `Receipts::Submit` | Requires invoice number. Status `Submitted`. Cron `POR_3Receipted` |
| Fiscal period lock | `Receipts::checkFiscalPeriod` | `sysQuery.strName = POR_FISCAL_PERIOD` |
| PO-date check | `checkFiscalPeriodPoRcpDates` | Receipt date before PO date forces form status text `FISCAL PERIOD LOCKED` |
| Invoice upload | `receiptsForm.php` | Type `Invoice`, filename prefix is the receipt number |
| Re-receipt | `Receipts::reReceipt` | Special users. Requeues `POR_3Receipted`. Does not change receipt status |
| Invoiced CSV | `getExportInvoiceList` | `POR_Invoiced_PO_List_YYYYMMDD.csv` for status `Completed` |
| Accounts can receipt others' POs | `receiptsForm.php` | `refUserGroupPORID == 23` |

### Vendors

| Feature | Location | Notes |
|---|---|---|
| Vendor list and filters | `vendors.php`, `include/vendors.cls.php` | `porVendor` |
| New vendor draft | `Vendors::Save` | `VEN` + 5-digit id. Departments, BBBEE, CIPC, VAT, RGBC-customer flag |
| Document types | `uploadDoc` | CIPC, Tax, Bank, BBBEE |
| Status path | `vendorForm.php` | Draft, Pending, Approved, Declined, Finance Approved, Complete, InComplete, Active, Done |
| Cron per transition | `vendors.cls.php` | `POR_NewVendor`, `POR_ApprovedVendor`, `POR_VendorDeclined`, `POR_FinanceApproved`, `POR_VendorCompleted`, `POR_VendorInCompleted`, `POR_Activate`, `POR_VendorDone` |
| Vendor code on Done | `updateVendorCode` | Posted `strVendorCode`. Button rules differ for special users and fixed user ids |

The PO form's vendor list is `mstVendor`, not `porVendor`.

### Administration

| Feature | Location | Notes |
|---|---|---|
| Import user-group access | `import.UGAccess.php` | Excel to `stgUGAccess`, then truncate-and-load `porUGAccess`. Admin or Dev menu |
| Import user-group GL codes | `import.UGGLCodes.php` | Same pattern for `porUGGL` |
| GL allocation report | `include/report.cls.php` | xlsx, landscape A4. PhpSpreadsheet |
| Vendor allocation report | same | Reads `mstVendor` |
| Settings grid | `settingsForm.php` | `sysQuery` names like `POR%`. `blnSpecial == 1` |

### Configuration and security changes called out in docs

| Feature | Location | Notes |
|---|---|---|
| Env-based ODBC | `include/SecureConfig.php`, `.env.example`, `CHANGELOG.md` | Split `RGBC_POR_ODBC_*` or `RGBC_POR_CONNECTION_STRING`. Changelog section is **Unreleased** |
| `.env` ignored | `.gitignore` | `.env.example` is not ignored |

## External (expected by the UI, not written here)

| Item | Evidence |
|---|---|
| PO status `Partially Receipted` | Listed and used for buttons. No `UPDATE` in this repo sets it |
| Receipt status `Processed` | Disables the receipt form together with Submitted and Cancelled. No `UPDATE` in this repo sets it |
| All `POR_*` cron types | Inserted with status `New`. No worker in this repo |
| Mail after `Mail Pending` | Column updated on vendor transitions. No mailer in this repo |
| Accpac posting | Named in the GL warning only |

## Leftover files

| File | Notes |
|---|---|
| `requisitionForm.maanie.php` | Older form. Not the target of `requisition.php` |
| `requisition20210330.php` | Older list page |
| `include/requisition20210330.cls.php`, `include/requisition20230327.cls.php` | Dated class copies |
| `receiptsForm.pj.php`, `include/receipts.cls.pj.php` | Parallel receipt copies. Live page is `receiptsForm.php` |
| `database/odbc.cls.php`, `database/sql_object.cls.php` | Not the copies included by `system.inc.php` (`include/database/`) |
| `PHPExcel/` | Legacy library tree. Reports use Composer PhpSpreadsheet |
| `ldap/` | adLDAP library. Included on email-link login and not instantiated there |
| `Excel/` | Present as a directory at the root. Not referenced by the live import classes' includes (`include/import.XLS.cls.php`) |
| `test_folder_share_read.php` | Echoes one hardcoded link to a PDF under `//superbowl_pdf/` |
| `cursor_security_updates_implementation.md` | Cursor transcript about RGBC Promotions (VB), not this application |
| `rgbc por.sublime-project`, `rgbc por.sublime-workspace` | Editor files |
| Root `layout.*.inc.php` | Parallel to `include/layout.*`. Pages include the `include/` copies |

## Planned

No planned-feature list exists in the repository.

`CHANGELOG.md` **Unreleased** describes security work that is already present in `SecureConfig.php` and `loginUser` (env connection string, no hardcoded dev login, LDAP admin password comment removed). Treat that section as a description of the current tree, not as a future release, until someone publishes a version.

## Removed

Not established. The shallow clone has only the tip commit. Dated class files suggest older forms were copied rather than deleted.

## Recently changed

The tip commit message is `#88_po system Key account Fix #xx_Contact information save Fix` (2026-06-23). The diff of that commit against its parent was not available in the shallow clone.

**Requires confirmation:** which lines that commit changed, and whether production has it.
