# Features — kb-online (Kohler Box)

Evidence date: 2026-10-11. Source: `git@bitbucket.org:overdrive/kb-online.git`, `main` at `5aa7141` (2026-09-17).

There is no features document in the source repository. Status labels:

- **Current** — present on `main` and referenced by a page or a class that a page includes.
- **Completed** — called out by a commit and still in the tree.
- **In development** — no unmerged branch was present on fetch.
- **Planned** — described as future work. None was found as a written backlog.
- **Deprecated / removed** — comments, commented-out calls, or duplicate files that the live pages do not include.
- **Uncertain** — the file exists; production use was not established.

## Current — sign-in and shell

| Feature | Where | Notes |
|---|---|---|
| Login form | `login.php` | Email plus MD5 password. Inactive user and inactive security group are rejected |
| Session gate | `_nemo.cls.php` `Nemo` | Missing session redirects to setting `SessionExRedirect` |
| Menu from the database | `_nemo.menu.cls.php` | Level 1 and level 2. Level 2 requires `blnMenuItem` and `blnView` |
| Page rights | `Nemo::iniSecurity` | `blnView`, `blnDelete`, `blnSave`, `blnNew`, `blnSpecial` |
| Home message | `index.php` | Setting `Home Screen Message`. Daily diary on the home page is commented out |
| Access denied | `message.php` | `MID=r09` and `MID=e10` |
| Logout link | `Nemo::Header` | Setting `LogoutRedirect` |
| Own profile | `own.profile.php` | Name and email read-only. Password change asks for the old password |
| Host canonicalisation | `system.php`, `login.php` | Bare `kb-online.co.za` becomes `www.kb-online.co.za`. `www.overdrive.co.za` is sent to `http://www.kb-online.co.za` |
| Login audit | `tblLoginInsert` | Writes `sysLogin` with IP, result, username. Password column is no longer filled |

## Current — sales pipeline

All of these screens include `includes/order.cls.php` and `_nemo.details.order.cls.php`.

| Feature | Where | Notes |
|---|---|---|
| Enquiry list and form | `enquiry.php` | View `vieEnquiry` |
| Send enquiry to estimator | `Order::SendEnquiryToEstimator` | Template "New Enquiry". Status becomes `Estimation: New` |
| Estimation list and form | `estimation.php` | View `vieEstimation` |
| Send estimation to salesperson | `Order::SendEstimationToSalesPerson` | Template "Estimation completed". Status becomes `Quote: New` |
| Pricing estimate screen | `pricing.estimate.php` | Same enquiry view. Default status `Enquiry: Estimate for Pricing` |
| Kohler Box estimate PDF | `Order::GenerateKohlerBoxEstimatePDF` | mPDF |
| Email estimate | `Order::EmailEstimate` | Template "KB Estimate". Modes Estimator and User |
| Convert estimate to quote | `Order::ConvertEstimateToQuote` | Status `Quote: New`, redirect to `quote.php` |
| Quote list and form | `quote.php` | View `vieQuote` |
| Create quote PDF | `Order::GenerateQuote` | File under setting `dir_quotes` |
| Send quote | `Order::SendQuote` | Template "Quote". Status `Quote: Sent to Customer` |
| Convert quote to order | Button `Convert to Order` | Rendered on the quote status field |
| Order list and form | `order.php` | View `vieOrder`. Filters for status, order date, due date, to-be-invoiced |
| My orders list | `my.order.php` | Edit jumps to the stage screen. New opens an enquiry |
| Archive list | `archive.php` | Archived rows. Delete on live lists sets `blnArchived = 1` |
| Production spreadsheet | `Order::GenerateOrder` | Sheets "Inspection Tracking Form" and "Kohlerbox Production Order" |
| Confirm order email | `Order::ConfirmOrder` | Template "Order Confirmation". Does not reset status |
| Delivery schedule | `Order::SaveOrderDelivery` | Complete toggles invoice flag in the browser |
| Signed estimates | `impSignedEstimates` | Upload on save |
| Supporting documents | `impSupportingDocuments` | Upload on save |
| Product price matrix | `Order::renderProductPriceMatrix` | Hidden unit prices unless `blnSpecial` on the estimation page |
| On-screen stage instructions | `OrderDetails::$Instructions` | Enquiry, Estimation, Quote, Order |

## Current — master data

| Feature | Where |
|---|---|
| Customers | `customer.php`, `includes/customer.cls.php` |
| New customer from the enquiry UI | `ajaxfunctions.php` `jsSaveNewCustomer` |
| Contacts | `contact.php`, `includes/contact.cls.php` |
| Contact log | `contact.log.php`, `includes/contact.log.cls.php` |
| Products | `product.php`, `includes/product.cls.php` |
| New product and dimension calculation | `ajaxfunctions.php` `jsSaveNewProduct`, `jsGetCalculatedProductInfo` |
| Boards | `board.php`, `includes/board.cls.php` |
| Styles | `style.php`, `includes/style.cls.php` |
| Descriptors | `descriptor.php`, `includes/descriptor.cls.php` |
| Industries | `industry.php`, `includes/industry.cls.php` |
| Sub-categories | `sub.category.php`, `includes/sub.category.cls.php` |
| Sales reps | `sales.rep.php`, `includes/sales.rep.cls.php` |
| Mailchimp CSV | `Customer::MailChimp_csv_download` from `customer.php` |
| Pastel account code | Customer field `strPastelAccountCode`. Stored only |

## Current — pricing

| Feature | Where |
|---|---|
| Price check from board cost times weight | `project.functions.inc.php` `updateProductPriceCheck` |
| Annual price increase upload, confirm, process | `product.price.increase.php`, `Product::uploadProductPrice`, `ProcessNewCustomerPercIncrease`, `ProcessNewProductPrice` |
| General price-increase email and test | Template "General Price Increase" |
| Personalised price-list upload and email | `product.price.increase.php`, `customer.price.list.php`. Template "Personalised Price Increase" |
| Customer flags for overs, unders, agent, personalised list | Insert in `jsSaveNewCustomer` |

## Current — reports, mail admin, import

| Feature | Where |
|---|---|
| Daily Diary | `includes/daily.diary.rpt.php` |
| Outstanding Production Orders | `includes/outstanding.production.orders.rpt.php` |
| Dormant Customers | `includes/customer.order.rpt.php` |
| Report PDF export | `report.php` action `Export` |
| Email templates | `email.template.php` |
| Compose, send, resend | `email.php`, `_nemo.email.cls.php` |
| Spreadsheet import queue | `data.import.php`, `includes/data.import.cls.php` |
| Users, security groups, settings | `user.php`, `security.group.php`, `settings.php` |
| Barcode image | `barcode.php` (Code 128 default, also 39, 25, Codabar) |

## Completed — changes on `main` since the snapshot landed

| Date | Commit | What changed |
|---|---|---|
| 2026-06-03 | `fecf0b1` | Message: php upgrade. Comments in `system.php` and `_nemo.cls.php` date PHP 8 property fixes to 2022-08-29 |
| 2026-06-03 | `5f3b4a6` | Export date and time |
| 2026-06-05 | `6a901e3` | Confirm Order no longer writes `Order: New` |
| 2026-06-30 | `58d96bf`, `5979a27`, `971007f` | Security changes. `database/passwordCleanup.sql` nulls `strPassword` on `sysUser` and `sysLogin` |
| 2026-08-07 | `75ca321` | Reply-To on enquiry, estimation, quote, estimate, and order-confirmation mail |
| 2026-09-17 | `5aa7141` | `kayla@kohlerbox.com` added beside the other reprint mailboxes |

## In development

None. Fetch of `main` showed no other remote branch.

## Planned

No backlog, issue tracker, or TODO file was found. Inline comments marked `TODO` exist (for example "expand Search WHERE" on the product list). Those are notes in code, not a committed plan.

## Deprecated / removed / not on the request path

| Item | Evidence | Status |
|---|---|---|
| OTP login path | Commit `2bcf33f` "Reverted OTP changes". `login.php` does not redirect to `login2fa.php` | **Removed** from the login path. Files remain: `login2fa.php`, `includes/security.cls.php`, `database/tblMailAuthCodes.sql`, `database/emailtemplate.sql` |
| Home-page daily diary | Commented block in `index.php` | **Removed** from the home page. The report still exists on `report.php` |
| Outstanding Orders report | Commented `addReport` in `report.php`. File `includes/orders.outstaning.rpt.php` remains (filename spelling "outstaning") | **Deprecated** in the report menu |
| Orders Due Today | Commented `addReport`. File was not found under `includes/` | **Removed** from the menu. Report file **Unknown** |
| IIF / timesheet export | Commented block in `report.php` | **Removed** from the report page |
| Second `class Order` | `includes/pricing.estimate.cls.php` is not included | **Uncertain** duplicate |
| Second `class Customer` | `includes/QAcustomer.cls.php` is not included | **Uncertain** duplicate |
| `includes/product.php` | Not included by `product.php` | **Uncertain** duplicate of the page |
| Course-coordinator methods | `includes/user.cls.php` | **Deprecated** leftover. Not called |
| Commented email templates "Course Start", "New Module", "Assignment Reminder", "Course End" | Bottom of `_nemo.email.cls.php` | **Deprecated** leftover from another product |
| `SendSMS` | Defined in `system.functions.inc.php`. No caller | **Uncertain**. The function is current code with no use |
| Old `mpdf/` and `PHPExcel/` trees | Still in the repository. Live order code uses `vendor/autoload.php` | **Deprecated** copies. **Requires Confirmation** before deletion, because a path may still include them |
| Login lockout persistence | `CheckSecurityLock` comments out `Save()` after setting `blnLogin = 0` | **Removed** as a saved state. The email and the on-screen sentence remain |
| `zSandBox.php`, `test.php` | Present at the root | **Uncertain** developer pages |
| `info.php` | `phpinfo()` | **Current** file. Not a product feature |

## Uncertain

- Whether security group names in the database match the comments (SalesPerson for group 4, Admin Sys for groups 1 and 2).
- Whether customers ever sign in. No customer session was found.
- Whether production still runs the SMS gateway, Mailchimp export, or Pastel codes as a business process.
- The exact `ORDER_STATUS` list, because it is a setting.
