# Features — personal_laundry

Evidence date: 2026-10-07. Source: `main` at `0b3d107`.

Status words mean:

- **Current** — present in source on `main` and wired to a screen, script, or route.
- **Completed** — a change that landed in history and is still the behaviour on `main`.
- **Planned** — described as future and not implemented in the current contract.
- **Changed** — an older behaviour that `main` replaced.
- **Removed** — present in history or in a design note, and explicitly dropped from the current install script.
- **Unverified in production** — the source contains it; nobody has confirmed the live database or tills in this investigation.

## Current features

### Floor POS

| Feature | What it does | Where |
|---|---|---|
| Company and operator login | Loads companies and usernames independently. Failed load shows the database error instead of a blank pair of dropdowns | `PersonalLaundry/PersonalLaundry/LoginForm.cs` |
| Console | Buttons for count, pack, bag, dispatch, and holdback. Status grid refreshes every 5 seconds. Shows the signed-in username and role | `ConsoleForm.cs` |
| Branding switch | Company id 2 shows Texcare. Other ids show Personal Laundry | `ConsoleForm.SetCompanyHeaders` |
| Idle restart | Restarts the app after 10 minutes without input | `ConsoleForm.UpdateTimer_Tick` |
| ClickOnce update check | Logo click | `ConsoleForm.InstallUpdateSyncWithInfo` |
| On-screen version | Designer label `v1.5.0.132` | `ConsoleForm.Designer.cs` |
| Counting station | Lists workloads in statuses 1–4, counts items, finishes the count, optional trolley notes | `Station_01_Counting/` |
| Packing station | Creates packages from invoice lines, including defective items and quality events | `Station_02_Packing/CreatePackage.cs` |
| Open Prelist Finder | Search open prelists and open pack without creating a bag | `Station_02_Packing/OpenPrelistFinder.cs` |
| Bagging | Lists invoices at status 3 and seals a bag through `CreateDispatch` | `Station_03_Bagging/BagForm.cs` |
| Double bag label | Second print when `Customers.DoublePrintBagLabel` is set | `BagForm.cs`, `BagInvoiceForm.cs` |
| Dispatch | Prints and sends bags out for delivery (`DispatchStatusId` 3) | `Station_04_Dispatch/DispatchForm.cs` |
| Holdback on hand | Build a pool of clean, stain, or defective quantity by type and size | `Station_05_Holdback/HoldbackOnHandForm.cs` |
| Holdback allocate | LIFO plan across open prelists, then `CreatePackage` | `HoldbackAllocateForm.cs`, `HoldbackService.cs` |
| Count emails | Count-recon email and condemned-items email on finish | `CountCustomersLaundry.sendEmail` |
| Local logging | Appends to `C:\LogFiles` | `ConsoleForm.Log`, counting `Log` |

### Holdback Phase 1 (current)

Shipped on the console as the orange Holdback button. The changelog calls the feature set `v1.5.0.127`. The visible label is now `v1.5.0.132`.

Included:

- On-hand pool with wider type and size fields, quantity and add on their own row, Browse Prelists beside the customer, Continue as the primary action.
- Allocate help text, empty LIFO message, muted Apply when disabled, missing-reason column with tooltip.
- Finder loading overlay and refresh on activate.
- `PackageInvoice` can close when opened with no bag.

Evidence: `CHANGELOG.md` and the station files above.

### Personal Admin (current)

| Feature | Where |
|---|---|
| Active customers and inactive customers, each with a scrollable list, inventory, and logins | `PersonalAdmin/ConsoleForm.cs`, `CustomersMenuPanel` |
| Add customer | `CustomerForm` |
| Operators list, add operator, toggle a role that can or cannot log in | `OperatorLoginsForm`, `OperatorsMenuPanel` |
| Price increase | `PriceIncreaseForm` |
| Reports: Outstanding Order, Bag Recon, Order Reference, plus reference substring search | `ReportConsoleForm.cs` and the RDLC files |
| Settings, including the post-count manager code | `SettingsForm`, `Common/Settings.cs` |
| Companies list and add company | `CompanyForm` |
| Version label from ClickOnce when network deployed, otherwise the assembly version | `ConsoleForm.GetDisplayedApplicationVersion` |

### Website (current)

| Feature | Route or page |
|---|---|
| Forms login for customer email or operator username | `Login.aspx` |
| Private-network bypass cookie when `ReturnUrl` is present | `Login.aspx.cs` |
| Pickups list, create, update, view | `pickups`, `pickup.aspx` |
| Bag labels and bag label print | `BagLabels.aspx`, `BagLabelsPrint.aspx` |
| Invoice list and invoice, category groups, multi-prelist sections | `Invoice.aspx`, `Invoices.aspx` |
| Dispatch view and Pastel-aware barcode | `Dispatch.aspx` |
| Customer maintenance and Pastel reference | `Admin/Customers.aspx`, `Admin/EditCustomer.aspx` |
| Operator maintenance | `Admin/Operators.aspx` |
| Pastel export and export log | `Admin/Export.aspx`, `App_Code/PastelExport.cs` |
| Settings | `Admin/Settings.aspx` |
| Pickup report | `Reports/Pickup.aspx` |
| Mobile customer page | `Mobile/Customer.aspx`, `Mobile/Default.aspx` |
| Driver action log | `Mobile/MobileHandler.ashx` |
| Barcode image handler | `Handlers/BarcodeHandler.ashx` |

### Database behaviour shipped as scripts (current in source)

| Script | Behaviour |
|---|---|
| `GenerateInvoiceFromWorkloadCounts.sql` | One insert if the workload has no invoice; return invoices for the workload |
| `FinishCounting.sql` | Invoice status 2, workload status 4 |
| `CreateDispatch.sql` | Multi-prelist, one customer, representative minimum invoice id, workload status 5 |
| `GetDispatchesReadyToPrint.sql` | One print-list row per `DeliveryId` |
| `Phase2_MultiPrelistBag.sql` | Install target for the procedures above plus `vwBagPrelistContents` and `vwDeliveryNoteByPrelistBagSeal` |
| `UpdateWorkloadItem.sql` | Allow item edits in workload status 1 or 4 |
| `SyncInvoiceItemsFromWorkload.sql` | Insert invoice items missing after a reopened count |
| `CreatePostCountEditAudit.sql` | Audit table and insert procedure |
| `UpdateInvoiceItemCount.sql`, `UpdateInvoiceItemBadCount.sql` | Count and bad-count updates |
| `GetItemCostForReceiving.sql` | Cost lookup for Inteltag at count |
| `GetWorkloadInventoryForDispatch.sql`, `GetWorkloadInventoryForDispatches.sql` | Inventory lines used by dispatch and invoice print |
| `SwapSeal.sql` | Seal swap. Detailed rules were not expanded in this pass |
| `CreatePackageWithDefectiveItems.sql` | Defective package path |
| `rptBagReconDeliveries.sql` | Bag recon deliveries report query |
| `Database/Scripts/2025-09-22-defective.sql`, `2025-09-30-backup-defective.sql` | Defective-item schema notes from September 2025 |

Applying these scripts to production is **Unverified**.

### Development and test features (current in source)

| Feature | Where |
|---|---|
| Pseudo POS printer service object | `PersonalLaundry/PseudoPosPrinter` |
| Smoke harness that opens and prints without registration | `PseudoPosPrinter/Smoke` |
| FlaUI console harness | `PersonalLaundry/PosUiTests` |
| `TestApp` | Small .NET Framework 4.8 project. Purpose beyond the project file was not read |
| SQL UAT notes | `PersonalLaundry/documents/phase2-multi-prelist-verification.md` |
| Manual holdback test list | `scope/Holdback Module/Task_Holdback_Phase1_Manual_Test.md` |

`PosUiTests` references FlaUI but the verification note says the 2026-09-08 run did not launch `PersonalLaundry.exe`.

## Completed features

These are on `main` and called out as finished in history.

- Holdback Phase 1 station, allocate flow, and finder. Merged through pull request #3 and later UX commits.
- Order Reference Report and global reference search (2026-03, recorded in `PROJECT_MEMORY.md`).
- Post-count edit with manager code (changelog, unreleased section).
- Multi-prelist invoice print sections (`bdfae9e`, pull request #8, 2026-10-02).
- Tax invoice category grouping restored after a prelist-breakdown experiment (`5ab28ee`).
- Login dropdowns no longer both go blank when one query fails (changelog).
- Personal Admin operator menu scrolls (`9157226`).
- Pastel export built from deliveries rather than from an older invoice-shaped call. The old call remains commented in `Export.aspx.cs`.

## Changed features

| Used to | Does now | Evidence |
|---|---|---|
| `CreateDispatch` required exactly one distinct invoice on the package list. A second prelist produced no dispatch | One or more invoices are accepted when the customer count is 1 | `scope/Why_The_Delivery_Invoice_Exists.md` section 4 versus `Scripts/CreateDispatch.sql` |
| `Dispatches.InvoiceId` was the only prelist on the bag | It is `MIN(invoice id)` and contents come from `DispatchPackages` | `scope/IntelTag_MultiPrelist_What_Changed.md` |
| A short-lived design created a delivery invoice at seal | The install script does not create that invoice | `Phase2_MultiPrelistBag.sql` header |
| Tax invoice briefly broke lines down by prelist | Category breakdown (Laundry / Linen / Food and Bev) is restored. Bag slips keep prelist sections | commit `5ab28ee`, verification note check 8 |
| `UpdateWorkloadItem` allowed edits only in status 1 | Status 1 or 4 | `CHANGELOG.md` |
| Personal Admin referenced a built `Common.dll` | It references the `Common` project so new settings APIs compile | `CHANGELOG.md` |
| SMTP comments name an internal relay and `smtp.vanilla.co.za` | The live call uses `smtp.office365.com` port 587 | `CountCustomersLaundry.sendEmail` |
| Dispatch barcode and invoice barcode were treated alike | Only dispatch barcodes include the Pastel code | `Dispatch.aspx.cs` comment, 2025-03-18 |

## Removed or rejected

| Item | State on `main` |
|---|---|
| `IsDeliveryInvoice` column as a required part of the design | Must not be recreated. Cleanup script deletes retained delivery invoices from a mapped backup |
| `BagPrelistLink`, `DispatchInvoiceLink` | Not created by the current install script. Dropped by `Phase2_MultiPrelistBag_Revert.sql` if present |
| `GenerateDeliveryInvoicesForBagSeal` | Same. Absent after revert, per `phase2-recovery-map.md` |
| Delivery-invoice rows created in the August 2026 experiment | Cleanup script plus recovery map. 50 delivery invoices were in the backup. Whether production still has them is **Unknown / Requires Confirmation** |
| Printing a tax invoice with `Pre List #` section headers | Verification note says those headers are not on the tax invoice or the copy |

`zzDispatchForm` and `zzPrintNotesForm` remain in the POS project. The `zz` prefix indicates retired forms that are still compiled. They are not the buttons on `ConsoleForm`. Provenance: **Inferred** from the file names and from `ConsoleForm` opening `DispatchForm` and `PrintNotesForm` without the `zz` prefix.

A conflicted copy of the POS project file and of `CountCustomersLaundry` from 2012-08-23 / 2012-08-24 is still in the tree. It is not the project the solution builds.

## Planned or only described

| Item | Evidence | Status |
|---|---|---|
| Holdback pseudocode "Phase 2" with `BagPrelistLink` and a delivery invoice per seal | `holdback-module-pseudocode.md` | Not the current install. Superseded by the no-delivery-invoice bag. Do not build this schema unless a person reopens the decision |
| `NewKnowledgeBase.md` statement that multi-prelist bags are not in the build | `NewKnowledgeBase.md` | Stale. The SQL and IntelTag note describe the feature as current |
| Inteltag client changes | `scope/IntelTag_MultiPrelist_What_Changed.md` | Instructions for another system. Not implemented inside this repository |
| `scope/Task_RFID_PostCount_TestPlan.md` | Cited from `.cursor/plans/holdback_module_breakdown_a504c7b6.plan.md` | File is not in the checkout |
| Acme HTML template site | `PersonalLaundry.sln` | Folder `AcmeTemplates` is not in the checkout |

## Recently changed (last commits on `main`)

| Commit | Date | Change |
|---|---|---|
| `0b3d107` | 2026-10-02 | Merge of pull request #8 |
| `bdfae9e` | 2026-10-02 | Invoice print groups multi-prelist items by prelist section |
| `d66b16b` | earlier | Merge of `josh_work` pull request #6 |
| `8c4de2d` | — | Pseudo printer accuracy |
| `5ab28ee` | — | Tax invoice category breakdown restored |
| `1d89956` | — | Pseudo printer rendering |
| `708749f` | — | Web and admin invoice and bag recon fix |

## Deprecated files to avoid using as the product

- `PersonalLaundry/documents/holdback-module-pseudocode.md` Phase 2 schema, when it conflicts with `Scripts/Phase2_MultiPrelistBag.sql`.
- The middle sections of `scope/Why_The_Delivery_Invoice_Exists.md`. Read the closing section.
- `.cursor/PROJECT_MEMORY.md` sentence that Phase 2 bagging is not in the build.
- Commented connection strings and the commented email block inside `FinishCounting.sql`.
