ThreadCount Community edition
Uniform stock management for healthcare linen rooms: the coordinator app, the phone counter and the staff app, for your own server. Built from a113353 on 2026-09-15. Licensed under the Functional Source License (FSL-1.1-ALv2).
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="320" viewBox="0 0 1280 320" role="img" aria-labelledby="t d">
|
||||
<title id="t">ThreadCount</title>
|
||||
<desc id="d">Uniform stock management for healthcare linen rooms. Community edition.</desc>
|
||||
<rect width="1280" height="320" fill="#201e1d"/>
|
||||
<!-- the mark: four rules stepping down, a stock count falling to its reorder point -->
|
||||
<rect x="72" y="88" width="120" height="16" fill="#ec3013"/>
|
||||
<rect x="72" y="128" width="96" height="16" fill="#f3f2f2"/>
|
||||
<rect x="72" y="168" width="68" height="16" fill="#f3f2f2"/>
|
||||
<rect x="72" y="208" width="44" height="16" fill="#f3f2f2"/>
|
||||
<g font-family="Archivo, 'Helvetica Neue', Arial, sans-serif" fill="#f3f2f2">
|
||||
<text x="240" y="150" font-size="84" font-weight="800" letter-spacing="-3">ThreadCount</text>
|
||||
<text x="244" y="200" font-size="24" font-weight="500" fill="#b5b1af">Uniform stock management for healthcare linen rooms</text>
|
||||
<text x="244" y="242" font-size="15" font-weight="800" letter-spacing="3" fill="#ec3013">COMMUNITY EDITION · RUN IT ON YOUR OWN SERVER</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,119 @@
|
||||
# Writing the ThreadCount manual
|
||||
|
||||
The manual is the set of Markdown files under `docs/manual/<section>/<slug>.md`. The website
|
||||
renders them at `/docs/<section>/<slug>` and the app renders the same files at
|
||||
`/app/help/<section>/<slug>`, so one file serves both. The Community edition ships the folder.
|
||||
|
||||
## The one rule
|
||||
|
||||
**Every sentence must be true of the code as it is today.** Read the screen, the API route and
|
||||
the library before you describe them. If you cannot verify a behaviour by reading the code, leave
|
||||
it out. Never describe a feature that is planned, and never soften a limitation. Where a figure
|
||||
comes from a constant (`lib/plan.ts`, `lib/sets.ts`), quote the constant's value.
|
||||
|
||||
## Front matter
|
||||
|
||||
```
|
||||
---
|
||||
title: Issue a garment
|
||||
section: counter
|
||||
order: 1
|
||||
summary: Scan the garment, pick the person, record it. What is written, and what the counter refuses.
|
||||
screen: Counter
|
||||
role: Admin or Issuer
|
||||
keywords: issue, scan, barcode, six sets, refusal, slip
|
||||
---
|
||||
```
|
||||
|
||||
- `section`: one of `start`, `counter`, `stock`, `people`, `reports`, `apps`, `account`,
|
||||
`selfhost`, `reference`. Fixed list; the tree is built from it.
|
||||
- `order`: position within the section, from 1.
|
||||
- `summary`: one sentence, shown in the tree's search results and on the section index.
|
||||
- `screen`: the app menu label or path the page is about, e.g. `Settings › Data`. Omit if none.
|
||||
- `role`: who can do it. One of `Admin`, `Admin or Issuer`, `Staff`, `Anyone`, `Self-hosting admin`.
|
||||
- `keywords`: comma-separated words a coordinator would type into search. Include the words the
|
||||
screens use AND the words a newcomer would use ("stocktake, count, audit").
|
||||
|
||||
## Body
|
||||
|
||||
Plain Markdown, this subset only:
|
||||
|
||||
- `## Heading` for sections. They are numbered automatically and listed in the rail. Four to
|
||||
seven per page. No `#` or `###`.
|
||||
- Paragraphs. Short. One idea each.
|
||||
- `- item` bullet lists and `1. step` numbered lists (steps: bold the action first,
|
||||
`1. **Scan the garment.** Then…`).
|
||||
- Tables with `|`, a header row, then `|---|` then rows. Keep to four columns.
|
||||
- Fenced code blocks with three backticks for commands and file contents.
|
||||
- Callouts: a blockquote whose first line is a bold label.
|
||||
`> **In plain terms** One sentence.` (navy: commentary)
|
||||
`> **Careful** One sentence.` (red: a way to lose data or lock yourself out)
|
||||
`> **In ThreadCount** …` is only for the guides; do not use it here.
|
||||
- Inline `code` for settings, file names and values. Screen paths in code too: `Settings › Data`.
|
||||
- Links: `[text](/docs/stock/barcodes)` to other manual pages, `[text](/pricing)` to the site.
|
||||
- **Bold** sparingly, never for whole sentences. No italics, no emoji, no headers inside callouts.
|
||||
|
||||
## Voice
|
||||
|
||||
- Australian English. Second person for the reader ("you issue"), the product by name or "it".
|
||||
- Say what the screen does, then what it writes, then what it refuses and why. The
|
||||
"What is written" table (Record · Change · Undo) belongs on every page about an action.
|
||||
- Numbers as digits. Times as `07:40`. Dates as `13 Sep 2026`.
|
||||
- No marketing, no adjectives about the product, no "simply", no "just". The manual explains.
|
||||
- Sample data: the fictional **Riverside General** hospital, cost centres `RGH-4010` style,
|
||||
suppliers **Northline Workwear** and **Harbour Embroidery** only, people like A. Hassan and
|
||||
P. Nair, addresses at `example.com`. Never a real hospital, health service, supplier or person.
|
||||
|
||||
## Where to look
|
||||
|
||||
| Area | Read |
|
||||
|---|---|
|
||||
| Screens | `app/app/<screen>/page.tsx` and the components they import |
|
||||
| Mutations | `app/api/mutate/route.ts` and `lib/ops.ts` (the `op` names and their checks) |
|
||||
| Rules | `lib/sets.ts` (entitlement), `lib/plan.ts` (plans, limits), `lib/switches.ts` |
|
||||
| Data | `prisma/schema.prisma` |
|
||||
| Imports | `lib/csv.ts`, `app/api/import*`, `Settings › Data` in `app/app/settings/page.tsx` |
|
||||
| Phone apps | `app/m/**` (counter app), `app/my/**` (staff app), `lib/nativescan.ts` |
|
||||
| Self-hosting | `README.md`, `docker-compose.yml`, `.env.example`, `Dockerfile`, `lib/edition.ts` |
|
||||
| Billing, SSO, users | `lib/billing.ts`, `components/PlanTab.tsx`, `lib/sso.ts`, `components/SsoSettings.tsx`, `components/TwoFactor.tsx` |
|
||||
| What each email says | `lib/accountmail.ts`, `lib/approvallink.ts`, `lib/billing-mail.cjs` |
|
||||
|
||||
## Hard constraints
|
||||
|
||||
- Never name a real hospital, health service, government health department or uniform supplier,
|
||||
not even as an example. Use Riverside General, Northline Workwear, Harbour Embroidery.
|
||||
`scripts/check-identity.sh` and the manual linter both fail a page that does.
|
||||
- No personal email addresses. Product addresses only: hello@, support@, privacy@,
|
||||
security@threadcount.tech.
|
||||
- Never copy a secret, key or token into a page.
|
||||
- Read-only for these files, never edit them: `app/m/**`, `app/my/**`, `components/screens/**`,
|
||||
`components/m.tsx`, `components/my.tsx`, `components/staffui.tsx`, `components/staffnav.tsx`,
|
||||
`components/MAuth.tsx`, `components/MPerson.tsx`, `components/MScan.tsx`, `androidshell/**`,
|
||||
`staffshell/**`.
|
||||
- Write only inside your own section folder. Do not run git, the dev server or a build.
|
||||
- Length: 400 to 900 words a page, 4 to 7 `##` sections. The CSV reference may run to 1400.
|
||||
|
||||
## Every page in the manual
|
||||
|
||||
Link only to these. A link to anything else is a broken link.
|
||||
|
||||
| Section | Slugs, in order |
|
||||
|---|---|
|
||||
| `start` | threadcount-in-one-page, set-up-in-an-afternoon, the-two-roles, your-first-order |
|
||||
| `counter` | issue-a-garment, exchanges-and-returns, requests-from-staff, manager-approvals, pickup-call-list, delivery-rounds, slips-and-signatures |
|
||||
| `stock` | catalogue-sizes-and-cuts, barcodes, reorder-levels, stocktakes, order-list, receiving-and-back-orders, suppliers |
|
||||
| `people` | staff-register, groups-and-routes, entitlement-rule, managers, deactivating-and-deleting |
|
||||
| `reports` | the-nine-reports, cost-centres, journal-export, month-end-pack |
|
||||
| `apps` | counter-app, staff-app, scanning-and-browsers |
|
||||
| `account` | users, two-factor, single-sign-on, plan-and-billing, export-and-backup, delete-an-account |
|
||||
| `selfhost` | install, first-run, updating, backups, email, configuration-reference |
|
||||
| `reference` | csv-templates, glossary, keyboard-and-scanner |
|
||||
|
||||
A manual link is `/docs/<section>/<slug>`. Site pages you may also link: `/pricing`, `/compare`,
|
||||
`/security`, `/security/questionnaire`, `/sla`, `/privacy`, `/terms`, `/delete-account`,
|
||||
`/changelog`, `/demo`, `/about#contact`, and the guides under `/guides/`.
|
||||
|
||||
## When you finish
|
||||
|
||||
Reply with the files written, then a short list of anything you could not verify in the code and
|
||||
therefore left out. That list is how the manual's gaps get found, so be specific.
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: Delete an account
|
||||
section: account
|
||||
order: 6
|
||||
summary: Delete your login or the whole facility, clear data without deleting anything else, remove a wearer's staff sign-in, and what stays behind.
|
||||
screen: Settings › People & sign-in
|
||||
role: Admin or Issuer
|
||||
keywords: delete account, close account, delete facility, remove login, wipe, wipe activity, start fresh, reset, empty facility, staff app access, privacy, erase data
|
||||
---
|
||||
|
||||
## The two cases
|
||||
|
||||
`Delete my account` is at the bottom of `Settings › People & sign-in`. What it deletes depends on whether anyone else can still sign in.
|
||||
|
||||
- **Other active users remain.** Only your login goes. The facility and its records stay.
|
||||
- **You are the last active user.** Your account and the whole facility go together.
|
||||
|
||||
The note above the button says which case you are in. The public page at [/delete-account](/delete-account) explains the same thing without signing in.
|
||||
|
||||
## Delete your login
|
||||
|
||||
1. **Press `Delete my account`.**
|
||||
2. **Type your password.**
|
||||
3. **Press `Delete my login`.** You are signed out and taken to the home page.
|
||||
|
||||
Your user row is deleted, not deactivated. Issues, stocktakes and slips you recorded keep the name they were stamped with.
|
||||
|
||||
If you are an admin and other users remain but no other active admin, it is refused: `You're the only admin left. Make someone else an admin first, or delete the whole facility.`
|
||||
|
||||
## Delete the facility
|
||||
|
||||
1. **Take a backup.** The note offers `Download a backup first`. See [Export and backup](/docs/account/export-and-backup).
|
||||
2. **Press `Delete my account and this facility`.**
|
||||
3. **Type your password, and type the facility name exactly.**
|
||||
4. **Press `Delete everything`.**
|
||||
|
||||
Every user, the catalogue and barcodes, the staff register, and every issue, return, order, delivery, stocktake, request, photo and signature are deleted at once. It cannot be undone. This needs an admin account.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Your user | Deleted | None |
|
||||
| Facility | Deleted with everything in it | None; a backup file can be restored into a new facility |
|
||||
|
||||
Deleting works in a read-only facility, but not in the demo.
|
||||
|
||||
> **Careful** Deleting the facility does not stop a card plan. Press `Stop at period end` on `Settings › Plan` first.
|
||||
|
||||
## Clear data, keep the account
|
||||
|
||||
Two boxes at the bottom of `Settings › Data`, for admins, remove data and leave everyone signed in.
|
||||
|
||||
| | Wipe recorded activity | Start fresh |
|
||||
|---|---|---|
|
||||
| Confirm | Type `WIPE` | Type `RESET`, then confirm |
|
||||
| Deletes | Issues, orders, pickups, stocktakes, stock moves, approvals, alterations, hand-ins, staff-app requests and messages, waitlist, kit checks, damage reports, record queries, the ward notice, photos | Everything in Wipe, plus the catalogue, barcodes, stock levels, departments, suppliers, locations, the staff register and its staff sign-ins |
|
||||
| Keeps | Catalogue, staff register, departments, suppliers, barcodes, locations, opening balances, users | Users, facility name and settings |
|
||||
| Also | Stock adjustments and pre-loved counts set to 0; order and request numbers restart | Order, catalogue and request numbers restart |
|
||||
|
||||
Both happen at once and cannot be undone.
|
||||
|
||||
## Staff sign-ins
|
||||
|
||||
A wearer cannot delete their staff sign-in from the staff app. An admin opens their record on the staff register and presses `Remove access`, then confirms. The sign-in is deleted and every session it had ends. A new code lets them back in later.
|
||||
|
||||
Their register entry and issue history stay, because they are the facility's stock records. Removing those is covered in [Deactivating and deleting](/docs/people/deactivating-and-deleting). A wearer who would rather not ask their coordinator can write to privacy@threadcount.tech.
|
||||
|
||||
## What is kept
|
||||
|
||||
- **Your name on records,** when only your login was deleted.
|
||||
- **Backup files you downloaded.** They are on your own device. Delete them yourself.
|
||||
- **Nothing in the facility,** once the facility is deleted. Its rows and its photo files go together.
|
||||
|
||||
The [privacy policy](/privacy) describes the hosted service's own encrypted backups.
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Export and backup
|
||||
section: account
|
||||
order: 5
|
||||
summary: The one-file backup, CSV exports, the last-backup date, what a restore replaces and refuses, and whose backups are whose.
|
||||
screen: Settings › Data & audit log
|
||||
role: Admin
|
||||
keywords: backup, export, download, restore, import backup, JSON, CSV, last backup, data, recovery, take my data, leave
|
||||
---
|
||||
|
||||
## The backup file
|
||||
|
||||
`Export backup` on `Settings › Data` downloads the whole facility as one JSON file, named for the date where your facility is, such as `threadcount-backup-2026-09-13.json`. `Download backup` on `Settings › Plan` gets the same file. Only admins can take it.
|
||||
|
||||
The file holds the facility's settings and every record. That covers the catalogue, barcodes, stock and its movements, and locations. It also covers departments, suppliers, the staff register, manager approvals, issues, orders and their deliveries, pickups, stocktakes, hand-ins and cost changes. The staff app's side is in it too: requests and their messages, the waitlist, kit checks, damage reports, record queries and the ward notice. Photos and signatures are written into the file.
|
||||
|
||||
Left out on purpose:
|
||||
|
||||
- users and staff sign-ins, because those rows hold passwords;
|
||||
- ThreadCount's own notes about your plan.
|
||||
|
||||
The newest photos travel, up to 2000 photos or 40 MB. Older ones are counted and left out, so the file stays small enough to restore, and the screen says how many. The records they belong to are all in the file, and the images stay on the server.
|
||||
|
||||
The backup still downloads when the facility is read-only.
|
||||
|
||||
## CSV exports
|
||||
|
||||
Reports, People, Stock (On hand, Count and Locations), Orders, Requests and the audit log in Settings download CSV files. So do the department and supplier lists in Settings. The files are for reading and for finance; see [The nine reports](/docs/reports/the-nine-reports).
|
||||
|
||||
Only the backup file restores a facility. A CSV export does not change the last-backup date.
|
||||
|
||||
## The last-backup date
|
||||
|
||||
`Settings › Data` shows `Last backup:` with the date and how many days ago, or `No backup taken yet.` Past 7 days, or with no backup at all, the line is marked in red.
|
||||
|
||||
Each download of the backup file, from either screen, sets the date.
|
||||
|
||||
## Restore a backup
|
||||
|
||||
1. **Open `Settings › Data` and choose `Import backup`.**
|
||||
2. **Pick a ThreadCount backup file.**
|
||||
3. **Confirm.** The warning says the restore replaces all data in this facility.
|
||||
|
||||
Everything in the facility is deleted and rebuilt from the file, facility settings included. The facility name, slips, groups, sets and time zone all come from the file. It keeps the users, single sign-on settings and plan. Staff sign-ins survive, re-attached to register entries by staff number.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Facility | All records replaced by the file's | Restore an earlier file |
|
||||
| Facility | Settings replaced by the file's | Restore an earlier file |
|
||||
| Staff sign-ins | Re-attached by staff number | None needed |
|
||||
|
||||
A restore is refused when:
|
||||
|
||||
- the file is not a ThreadCount backup;
|
||||
- the facility is read-only;
|
||||
- the file holds more staff records than the plan allows, 60 on Hosted Small;
|
||||
- the file exceeds a count limit, such as 20,000 staff or 300,000 issues;
|
||||
- you have made 20 restores or imports in 10 minutes;
|
||||
- the upload is over 60 MB.
|
||||
|
||||
Photos beyond 2000 in a file are dropped rather than refused, and the screen says how many. Keep that file, because those images exist only in it.
|
||||
|
||||
> **Careful** A restore replaces what is there now. Take a fresh backup first if today's records matter.
|
||||
|
||||
## Your backups and the service's
|
||||
|
||||
The Plan screen's `Backups` row shows the hosted service's own nightly backups: 14 days on Hosted Small, 35 days on the other plans. What they commit to is in the [Service Level Agreement](/sla) and on [Security](/security).
|
||||
|
||||
No screen restores one facility from those backups. The only restore in the app is `Import backup` with a file you hold.
|
||||
|
||||
The [Terms](/terms) make exporting and keeping regular backups the facility's own responsibility. Store the file under your records policy; it holds the staff register. Self-hosted servers need a backup of their own, as described in [Backups](/docs/selfhost/backups).
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: Plan and billing
|
||||
section: account
|
||||
order: 4
|
||||
summary: The hosted plans and prices, the trial, paying by card or invoice, grace and read-only, and every billing email.
|
||||
screen: Settings › Plan
|
||||
role: Admin
|
||||
keywords: plan, billing, price, pricing, trial, subscribe, card, invoice, receipt, tax, GST, ABN, monthly, yearly, cancel, stop, read-only, grace, grandfathered, health service, purchase order
|
||||
---
|
||||
|
||||
## Plans and prices
|
||||
|
||||
Prices are in Australian dollars before tax, from `PRICES` and `PLANS` in `lib/plan.ts`.
|
||||
|
||||
| Plan | Price | Staff records | Backups kept |
|
||||
|---|---|---|---|
|
||||
| Hosted Small | Free | 60 | 14 days |
|
||||
| Hosted Facility | $129 a month or $1,290 a year | No ceiling | 35 days |
|
||||
| Health Service | $4,990 a year for 5 facilities, $890 each extra | No ceiling | 35 days |
|
||||
|
||||
On Hosted Small the 60 counts every staff record, deactivated ones included. Past it, adding a person is refused with `The register is full for this plan — 60 staff records.`
|
||||
|
||||
A facility inside a health service takes the health service's plan, and its Plan screen shows a `Health service` row. That plan is invoiced yearly against the health service's purchase order.
|
||||
|
||||
A facility created before plans went live is grandfathered. Its status reads `Free · everything included, for good`, and there is nothing to buy.
|
||||
|
||||
`Settings › Plan` appears for admins only, and not in the demo. The Community edition has no plans.
|
||||
|
||||
## The trial
|
||||
|
||||
When you create a facility, choose Hosted Small, or a 30-day Hosted Facility trial. Neither takes a card. During the trial the status reads `Trial` with the days left.
|
||||
|
||||
## Pay by invoice or card
|
||||
|
||||
`Request an invoice` sends ThreadCount a notice naming your facility and the plan chosen: `Hosted Facility · annual` or `Health Service · annual`. ThreadCount raises the invoice to the `Billing contact` and records the payment. You can ask up to 3 times a day. A renewal is requested the same way.
|
||||
|
||||
`Subscribe by card` appears only when card payments are set up on the server. It opens a four-step page for Hosted Facility:
|
||||
|
||||
1. **Plan.** Monthly $129 or yearly $1,290.
|
||||
2. **Business.** Legal name, street, city and country are required, and so is the postcode, except in Ireland, Hong Kong, the United Arab Emirates and Macao. Tax ID is optional. `Billing email` is your billing contact and cannot be edited here.
|
||||
3. **Agreements.** Tick the Terms of Service, Privacy Policy and Service Level Agreement. The time of the ticks is recorded.
|
||||
4. **Card.** Press `Continue to card`, type the card into Stripe's fields on the page, then `Pay`. The total shown includes tax, which Stripe works out from the country and address. Card numbers never pass through ThreadCount.
|
||||
|
||||
Paying during a trial charges that day, and the paid period starts then. The Plan screen shows the plan as paid once Stripe confirms the payment.
|
||||
|
||||
## The Plan screen
|
||||
|
||||
The table shows `Status`, `Staff records`, `Backups`, the end date (`Trial ends`, `Paid until` or `Writable until`), `Paid by`, `Invoiced to` and `Billing contact`. `Save contact` changes the billing contact.
|
||||
|
||||
A facility that pays by card also sees `Card on file`, `Next charge`, `Cadence` and `Invoices`, each invoice with a PDF link.
|
||||
|
||||
- **`Update card`** takes a new card on the same page. It is used for every later charge, and any unpaid invoice is charged straight away.
|
||||
- **`Stop at period end`**, then **`Yes, stop it`**, stops the renewal at the end of the paid period. Nothing more is charged, and nothing is refunded. `Keep my plan` undoes it before that date.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Facility | Billing contact | `Save contact` again |
|
||||
| Facility | Business details and agreement times | Subscribe again |
|
||||
| Card plan | Card replaced | `Update card` |
|
||||
| Card plan | Set to stop at period end | `Keep my plan` |
|
||||
|
||||
## Grace, then read-only
|
||||
|
||||
When a trial or a paid period ends unpaid, 14 days of grace follow. The status reads `Ended · still writable`, with `Writable until`.
|
||||
|
||||
After grace the facility is read-only. Changes are refused with `Read-only: this facility's plan has lapsed.` Nothing is deleted. A failed card payment changes nothing until 14 days after `Paid until`.
|
||||
|
||||
Still working when read-only:
|
||||
|
||||
- signing in, reports, CSV exports, printing and the backup download;
|
||||
- the billing contact and `Request an invoice`;
|
||||
- your own name and password, and deleting your account.
|
||||
|
||||
Restoring a backup is refused. Writing starts again when a payment is recorded.
|
||||
|
||||
## Billing emails
|
||||
|
||||
These go to the billing contact, or to every active admin if none is set.
|
||||
|
||||
| Email | Sent |
|
||||
|---|---|
|
||||
| Trial started | When the facility is created on a trial |
|
||||
| Five trial notes | On days 1, 3, 7, 21 and 28 of the trial |
|
||||
| Days left on your trial | Once in the last 7 days, then the day before |
|
||||
| Trial ended | The day the trial ends |
|
||||
| Now read-only | The day grace runs out |
|
||||
| Receipt | Each card payment above zero |
|
||||
| Payment did not go through | A card payment fails, once a day at most |
|
||||
| Card updated | A new card is saved |
|
||||
| Plan will end, or has ended | A card plan is set to stop, and when it ends |
|
||||
|
||||
The trial notes, days left, trial ended and now read-only emails are checked once a day and sent once each. Facilities paying by card, grandfathered ones and health-service members do not get them.
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
title: Single sign-on
|
||||
section: account
|
||||
order: 3
|
||||
summary: Connect your facility's identity provider, route people to it by email domain, make it optional or required, and keep a break-glass admin.
|
||||
screen: Settings › People & sign-in
|
||||
role: Admin
|
||||
keywords: single sign-on, SSO, SAML, OpenID Connect, OIDC, Microsoft Entra, Azure AD, Okta, Google Workspace, identity provider, IdP, email domain, required, break-glass, metadata
|
||||
---
|
||||
|
||||
## What it does
|
||||
|
||||
Single sign-on lets the people at your facility sign in with the work account they already have, through your own identity provider: Microsoft Entra, Okta, Google Workspace, or any provider that speaks SAML or OpenID Connect.
|
||||
|
||||
An admin sets it up for one facility on `Settings › People & sign-in`. On a server with no sign-on service the tab says `Single sign-on isn’t available on this server.` It is not offered in the demo. Users who are not admins see one line saying whether the facility uses it.
|
||||
|
||||
Single sign-on never creates an account. The address your identity provider returns must already belong to an active user at your facility, added as described in [Users and passwords](/docs/account/users). Anyone else is told that the address has no account at this facility yet.
|
||||
|
||||
## Connect your identity provider
|
||||
|
||||
1. **In your identity provider, add an application for ThreadCount.** `Settings › People & sign-in` shows the two values it asks for: the ACS or redirect URL, ending in `/api/auth/sso/callback`, and the Entity ID.
|
||||
2. **Give ThreadCount the provider's metadata.** Paste its `Metadata URL`, which must start with `https://`, or paste the XML into `…or metadata XML`.
|
||||
3. **List your email domains,** comma-separated. A domain is the part after the @, such as `example.com`.
|
||||
4. **Press `Connect single sign-on`.**
|
||||
|
||||
The metadata is handed to the sign-on service and not shown again. The panel then reads `Connected`, with the provider's name when it has one.
|
||||
|
||||
Domains are checked each time they are saved:
|
||||
|
||||
- 10 at most, and at least 1.
|
||||
- Public mail services such as `gmail.com` and `outlook.com` are refused.
|
||||
- A domain belongs to one facility. One already registered elsewhere is refused.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Facility | Connected, domains saved | `Disconnect single sign-on…` |
|
||||
| Facility | `Require` or `Staff may use it too` switched | Untick it |
|
||||
| User | Marked break-glass | Untick it |
|
||||
| Facility | Disconnected, every switch off | Connect again |
|
||||
|
||||
## Routing by email domain
|
||||
|
||||
ThreadCount has one Log in screen for every facility, so it routes by address. When someone types an address ending in one of your domains, the screen offers `Continue with` and your facility's name. That button takes them to your identity provider, and they come back signed in.
|
||||
|
||||
A sign-in through your identity provider asks for no ThreadCount two-factor code. A deactivated user is refused.
|
||||
|
||||
## Optional or required
|
||||
|
||||
Once connected, single sign-on is optional. The Log in screen offers the button first, and `Prefer your password?` lets a user sign in with a password instead.
|
||||
|
||||
Tick `Require single sign-on` and:
|
||||
|
||||
- a correct password is refused for every user except break-glass admins, and the Log in screen sends them to single sign-on;
|
||||
- password reset emails stop, except for break-glass admins.
|
||||
|
||||
`Require single sign-on` cannot be ticked until at least one active admin is marked break-glass.
|
||||
|
||||
## The break-glass admin
|
||||
|
||||
Under `Break-glass admins`, tick each admin who keeps a working password for the day the identity provider is down. Only admins can be marked. On the Log in screen they open `Break-glass admin? Sign in with a password instead`.
|
||||
|
||||
> **Careful** A break-glass admin is the only way in while the identity provider is down. Keep that password, and that admin's two-factor, working.
|
||||
|
||||
## Staff sign-ins
|
||||
|
||||
Tick `Staff may use it too` and wearers who already have a staff sign-in can use single sign-on. They type their address on the website's Log in screen and land in their own staff view.
|
||||
|
||||
This is web only. The ThreadCount Staff app keeps their password, and `Require single sign-on` does not turn staff passwords off. See [The staff app](/docs/apps/staff-app).
|
||||
|
||||
## Disconnect
|
||||
|
||||
Press `Disconnect single sign-on…`, then `Disconnect`. The connection is removed from the sign-on service, and `Require` and `Staff may use it too` are switched off. Everyone goes back to signing in with a password.
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: Two-factor sign-in
|
||||
section: account
|
||||
order: 2
|
||||
summary: Turn on codes from an authenticator app, keep the recovery codes, sign in with them, and recover from a lost phone.
|
||||
screen: Settings › People & sign-in
|
||||
role: Admin or Issuer
|
||||
keywords: two-factor, 2FA, MFA, authenticator, TOTP, code, six digits, recovery codes, lost phone, new phone, trust this computer, security
|
||||
---
|
||||
|
||||
## What it does
|
||||
|
||||
With two-factor on, a correct password is not enough to sign in. The Log in screen also asks for the six-digit code from an authenticator app on your phone.
|
||||
|
||||
It is set for your own account, from your own `Settings › People & sign-in`. Nobody else can turn it on or off for you, and it is optional for every role. An admin with two-factor off sees a note on the tab saying it is worth turning on.
|
||||
|
||||
It covers password sign-in. A sign-in through [single sign-on](/docs/account/single-sign-on) asks for no ThreadCount code, because your identity provider handles the second factor.
|
||||
|
||||
## Turn it on
|
||||
|
||||
1. **Open `Settings › People & sign-in` and press `Set up two-factor`.** A QR code appears, with the key written out under `Or type it in`.
|
||||
2. **Scan the QR code with any authenticator app,** or type the key into it.
|
||||
3. **Type the code the app shows and press `Turn it on`.** Nothing changes until this code is accepted. `Cancel` leaves your sign-in as it was.
|
||||
4. **Save the recovery codes.** Ten appear, each in the form `XXXXX-XXXXX`. `Copy all` puts them on the clipboard. Press `I have saved them` when they are safe.
|
||||
|
||||
The tab then shows `On` and how many recovery codes are left.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Your user | Two-factor on, 10 recovery codes made | `Turn off` |
|
||||
| Your user | 10 new recovery codes, the old ones dead | None |
|
||||
| Your user | Two-factor off, recovery codes deleted | Set it up again |
|
||||
|
||||
Each of these is also written to the facility's sign-in record.
|
||||
|
||||
## Recovery codes
|
||||
|
||||
Recovery codes are stored hashed. They are shown once, when they are made, and nobody can read them back afterwards, ThreadCount included. Print them or keep them somewhere you can reach without your phone.
|
||||
|
||||
Each code works once, in place of a code from the app. When 2 or fewer are left, the tab suggests a fresh set.
|
||||
|
||||
`New recovery codes` asks for your password, then shows 10 new codes. Every earlier code stops working at that moment.
|
||||
|
||||
## Signing in
|
||||
|
||||
After a correct password the Log in screen asks for the code. `Use a recovery code instead` switches the box to take a recovery code.
|
||||
|
||||
- Tick `Trust this computer for 30 days` and that browser is not asked for a code for 30 days. Changing your password ends the trust.
|
||||
- The code step accepts 10 attempts per account in 15 minutes, then answers `Too many attempts — try again in a few minutes.`
|
||||
- If the step has expired, the screen says `That sign-in has expired. Start again.` Type your password again.
|
||||
|
||||
A password reset by email also asks for the code before it signs you in, so a reset is not a way around two-factor.
|
||||
|
||||
## A lost or replaced phone
|
||||
|
||||
1. **Sign in with a recovery code.**
|
||||
2. **Open `Settings › People & sign-in`, press `Turn off` and confirm with your password.**
|
||||
3. **Press `Set up two-factor`** and scan the new QR code with the new phone. A new set of recovery codes comes with it.
|
||||
|
||||
If the old phone still works, do the same steps with a code from it instead of a recovery code.
|
||||
|
||||
There is no screen where an admin turns off two-factor for another user.
|
||||
|
||||
> **Careful** A user with no phone and no recovery codes cannot sign in from any screen. For an only admin, that means nobody can. Keep the codes, and keep a second admin.
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: Users and passwords
|
||||
section: account
|
||||
order: 1
|
||||
summary: Add admins and issuers, change your own password, reset a forgotten one by email, and keep a second admin so the facility never locks.
|
||||
screen: Settings › People & sign-in
|
||||
role: Admin or Issuer
|
||||
keywords: users, add user, admin, issuer, coordinator, login, sign in, password, change password, forgot password, reset, deactivate, reactivate, second admin, locked out
|
||||
---
|
||||
|
||||
## Who can sign in
|
||||
|
||||
The people who sign in to the web app and the counter are users. Each has a work email, a password and one of two roles, Admin or Issuer. What each role may do is on [The two roles](/docs/start/the-two-roles).
|
||||
|
||||
Users are not the people on the staff register. A wearer who signs in to the staff app has a staff sign-in attached to their register entry, and it is managed from their staff record, not here.
|
||||
|
||||
`Settings › People & sign-in` lists every user under `Users`, for admins only. Everyone sees their own name, title, password and two-factor settings there.
|
||||
|
||||
## Add a user
|
||||
|
||||
1. **Open `Settings › People & sign-in` and press `Add user`.**
|
||||
2. **Fill in first name, last name, title and work email.**
|
||||
3. **Choose the role.** `Issuer` is chosen until you change it.
|
||||
4. **Set a password of at least 8 characters and press `Save`.**
|
||||
|
||||
ThreadCount does not email the new user. Hand the password over yourself. One email address holds one user account across the whole service, so an address already in use is refused with `That email already has an account`.
|
||||
|
||||
`Edit` on a user changes name, title, role and password. The work email cannot be changed. A new password set here ends every session that user has open.
|
||||
|
||||
`Remove` deactivates the login rather than deleting it. Records keep the name, and the user moves to `Deactivated users`, where `Reactivate` lets them sign in again. You cannot remove yourself. A deactivated user who signs in is told the account has been deactivated.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| User | Added, with a role and a password | `Remove` deactivates it |
|
||||
| User | Name, title, role or password changed | `Edit` again |
|
||||
| User | Deactivated, cannot sign in | `Reactivate` |
|
||||
|
||||
## Change your own password
|
||||
|
||||
Under `Password` on `Settings › People & sign-in`, type your current password and the new one twice, then press `Change password`. The new one must be at least 8 characters.
|
||||
|
||||
You stay signed in on the device you used. Every other session signed in with the old password ends.
|
||||
|
||||
Your first name, last name and title are also yours to change on the same tab. They stamp every issue, stocktake and slip you record.
|
||||
|
||||
## Reset a forgotten password by email
|
||||
|
||||
On the Log in screen, type your work email, then choose `Forgot your password?`. The screen says `Reset link sent` whatever the address, so it cannot be used to find out who has an account.
|
||||
|
||||
- The link works once and expires in an hour.
|
||||
- Asking again cancels any earlier link.
|
||||
- At most 4 reset emails go to one address in an hour.
|
||||
- A deactivated account is sent nothing.
|
||||
- At a facility that requires single sign-on, only break-glass admins are sent a link. See [Single sign-on](/docs/account/single-sign-on).
|
||||
- If two-factor is on, the reset asks for your code before it signs you in.
|
||||
|
||||
A completed reset signs you in and ends every other session on the account.
|
||||
|
||||
## When the email never arrives
|
||||
|
||||
Nothing arrives if the server has no mail set up, or if the address on the account is wrong. The Log in screen says the same thing either way, so it cannot tell you which. Self-hosting admins set mail up as described in [Email](/docs/selfhost/email).
|
||||
|
||||
Another admin at your facility can set you a new password with `Edit` under `Users`. The address itself cannot be changed there.
|
||||
|
||||
If you are the only admin, the reset screen asks you to write to support from an address you control, naming the facility and the address on the account.
|
||||
|
||||
## Why a second admin matters
|
||||
|
||||
ThreadCount refuses to demote or remove the last active admin, with `Keep at least one active admin`. It does not make you add a second one.
|
||||
|
||||
With one admin, that person's inbox is the only way back in when the password is forgotten, and their phone is the only way past [two-factor](/docs/account/two-factor). If the last person who can sign in deletes their account, the facility goes with it. See [Delete an account](/docs/account/delete-an-account).
|
||||
|
||||
> **Careful** Add a second admin with a working address before you need one. It is the one way back in that needs no email and no support.
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: The counter app
|
||||
section: apps
|
||||
order: 1
|
||||
summary: The linen room's phone app, on Android and in a phone browser. Choosing a server, signing in, the screens, and what it keeps on the phone.
|
||||
screen: /m
|
||||
role: Admin or Issuer
|
||||
keywords: counter app, android, phone, mobile, play store, install, sign in, server, self-hosted, community, offline, camera, stocktake, count, issue
|
||||
---
|
||||
|
||||
The counter app is the coordinator's side of ThreadCount on a phone. You sign in with the same Admin or Issuer account as the website and see the same records, served at `/m`.
|
||||
|
||||
## Two ways to open it
|
||||
|
||||
- **In a phone browser.** Go to `https://threadcount.tech/m`, or `https://your-host/m` on your own server. You don't need to install anything.
|
||||
- **The Android app.** It is called **ThreadCount** on Google Play. It shows the same `/m` screens inside the app and adds the phone's own barcode scanner (see [Scanning and browsers](/docs/apps/scanning-and-browsers)).
|
||||
|
||||
There is no iOS app. On an iPhone or iPad, open `/m` in the browser.
|
||||
|
||||
## The first screen and choosing a server
|
||||
|
||||
The first time you open the Android app, the welcome screen shows **Sign in**, **Sign up** and a line reading `Server: threadcount.tech · Change`.
|
||||
|
||||
Most rooms use the hosted service and leave that line alone. A room running the Community edition on its own server changes it, once, on each phone:
|
||||
|
||||
1. **Tap `Server: threadcount.tech · Change`.** The `Which server?` screen opens.
|
||||
2. **Choose `Self-hosted`** and type the server's address, for example `uniforms.example.com`.
|
||||
3. **Tap `Check and use this server`.** The app checks the server's `/api/app-info` to confirm it is a ThreadCount server.
|
||||
|
||||
The app refuses an address that doesn't answer over https within 8 seconds, or that answers but isn't a ThreadCount server. Once the check passes, the app saves the address on that phone and opens that server from then on. Choosing `ThreadCount hosted` puts the phone back on `threadcount.tech`.
|
||||
|
||||
Once you have tapped `Sign in` or `Sign up` on that phone, the app skips the welcome screen and goes straight to `/m`.
|
||||
|
||||
## Signing in and signing up
|
||||
|
||||
`Sign in` asks for your work email and password. If your account has two-factor turned on, it then asks for the six-digit code from your authenticator app. A recovery code also works. `Forgot password` emails a reset link that works once and expires after an hour. See [Two-factor](/docs/account/two-factor).
|
||||
|
||||
`Sign up` creates a new facility. It doesn't add you to an existing one. The person who signs up becomes the new facility's first Admin. To add someone to an existing facility, an Admin sets up their account on the website: see [Users](/docs/account/users).
|
||||
|
||||
## The screens
|
||||
|
||||
The bar at the bottom has four tabs.
|
||||
|
||||
| Tab | What it does |
|
||||
|---|---|
|
||||
| Home | Today's issued and returned counts, lines below par, days since the last count, recent activity |
|
||||
| Count | Pick a shelf and count it by scanning; gaps go to a variance screen before the count is filed |
|
||||
| Stock | On hand against par, worst first, with a reorder draft |
|
||||
| Search | People and stock in one box, or scan a garment to find it |
|
||||
|
||||
Home also has `Issue to someone`, and `Deliveries, pickups, rounds and more` opens `More`:
|
||||
|
||||
- `Receive a delivery`
|
||||
- `Pickup call list`
|
||||
- `Delivery round`, with a signature on the phone
|
||||
- `Reprint a label`
|
||||
- `Variance over time`
|
||||
- `Catalogue`, where an Admin can add and edit garments
|
||||
- `Settings`
|
||||
|
||||
Open a person's record from Search or Issue to issue to them, take a return or swap a size. [Issue a garment](/docs/counter/issue-a-garment) and [Exchanges and returns](/docs/counter/exchanges-and-returns) say what each of those writes.
|
||||
|
||||
`More › Settings` holds only what the phone controls:
|
||||
|
||||
- `Beep and buzz on a scan`, which applies to this device only
|
||||
- `Reason required at`, the count gap that needs a reason. An Admin can change it; an Issuer can only see it.
|
||||
- links to the privacy policy, the terms and account deletion
|
||||
- `Sign out`
|
||||
|
||||
The staff register, reports, ordering and facility settings are on the desktop site.
|
||||
|
||||
## What it keeps on the phone
|
||||
|
||||
The app keeps only these on the phone:
|
||||
|
||||
- your session
|
||||
- any shelf count you have started but not filed. It is kept under your own account, so the next person on a shared phone never sees it. Filing the count deletes it, and signing out deletes all your open counts.
|
||||
- the beep setting, the chosen server, and whether the welcome screen has been seen
|
||||
|
||||
Issues, returns, stock, the staff register and every other record stay on the server.
|
||||
|
||||
## Permissions and connection
|
||||
|
||||
The Android app asks for one permission, the camera, and uses it only to read barcodes. No picture from scanning is stored or sent.
|
||||
|
||||
The app works online only. With no connection it shows `No connection.` and a `Try again` button, and it won't let you issue or count anything. Nothing is queued to send later. A count you hadn't filed stays on the phone until you're back online.
|
||||
|
||||
> **Careful** Signing out deletes any shelf count you haven't filed. File it first, or you'll have to count that shelf again.
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: Scanning and browsers
|
||||
section: apps
|
||||
order: 3
|
||||
summary: USB scanners, the barcode formats ThreadCount reads, which browsers can scan with the camera, the Android scanner, and what happens with a code it doesn't know.
|
||||
role: Admin or Issuer
|
||||
keywords: scan, scanner, barcode, usb, camera, chrome, edge, safari, firefox, iphone, ean, upc, code 128, unknown barcode, bind, label, print
|
||||
---
|
||||
|
||||
ThreadCount reads a barcode in one of three ways: a USB scanner typing into a box, the camera in a supported browser, or the scanner built into the Android counter app. All three give the same result, and wherever you can scan, you can also type the code.
|
||||
|
||||
## USB scanners
|
||||
|
||||
A USB scanner that types the code and then presses Enter works with any browser. These desktop boxes accept one:
|
||||
|
||||
| Screen | Box |
|
||||
|---|---|
|
||||
| `Stock › Count` | `Scan barcode to count +1, then Enter` |
|
||||
| `Counter` | `Scan barcode, then Enter`, under `2 · Scan items` |
|
||||
| `Stock › On hand › Scan to add` | `Scan with a USB scanner, or type the code and press Enter` |
|
||||
| A garment's `Scan sizes` | The prompt names the size to scan next |
|
||||
|
||||
`Scan to add` and `Scan sizes` bind codes to the catalogue; the `Scan to add` button is shown to Admins only. Click into the box first. See [Keyboard and scanner](/docs/reference/keyboard-and-scanner).
|
||||
|
||||
## Formats it reads
|
||||
|
||||
Camera scanning, in the browser and in the Android app, reads these formats only:
|
||||
|
||||
- EAN-13 and EAN-8
|
||||
- UPC-A and UPC-E
|
||||
- Code 128, Code 39 and Code 93
|
||||
|
||||
ITF and Codabar are left out because they carry no check digit, so a partial read can pass as a different valid code. No 2D codes are read.
|
||||
|
||||
A USB scanner or a typed code isn't limited to that list, because the box just receives characters. In `Scan to add`, a 13-, 12-, 8- or 14-digit code has its check digit tested. If it fails, you see `check digit doesn't match — the scan may have mis-read`.
|
||||
|
||||
## Camera scanning in a browser
|
||||
|
||||
In a browser, the camera reads barcodes with the browser's built-in barcode detector.
|
||||
|
||||
| Browser | Camera scanning |
|
||||
|---|---|
|
||||
| Chrome | Yes |
|
||||
| Edge | Yes |
|
||||
| Safari on iPhone or iPad | No |
|
||||
| Firefox | No |
|
||||
|
||||
Where the camera opens but the browser can't read barcodes, the screen says `Live reading isn't supported here — type the code instead.` Where the browser has no camera access at all, it says `This browser has no camera access — type the code instead.`
|
||||
|
||||
On an iPhone, type the code or use a USB scanner.
|
||||
|
||||
## The Android scanner
|
||||
|
||||
Inside the **ThreadCount** Android app, the phone's own scanner reads the code instead of the browser's detector. If the app can't load that scanner, it uses the browser detector instead.
|
||||
|
||||
When counting a shelf, scanning stays on until you press `Stop scanning`. The same code seen again within 0.9 seconds is taken as the same garment still in view, not a second one. `Beep and buzz on a scan` in `More › Settings` turns the sound and vibration on or off for that phone.
|
||||
|
||||
The ThreadCount Staff app has no scanner.
|
||||
|
||||
## Codes ThreadCount doesn't know
|
||||
|
||||
A code is known once it is bound to one size of one garment. What happens with an unknown code depends on the screen:
|
||||
|
||||
- **Counting a shelf:** `isn't a garment ThreadCount knows. Bind it to a size first`. A known code from another shelf names that shelf instead.
|
||||
- **Issuing:** `isn't a garment ThreadCount knows.` Nothing is added.
|
||||
- **Returns:** the code has to match something the person is holding.
|
||||
- **Search:** the code is put in the search box.
|
||||
- **`Scan to add`:** you can start a new product from the code, or attach it to a size you already have.
|
||||
|
||||
With `Settings › Data` product lookup turned on, `Scan to add` first asks a public barcode database for a product name. With it off, nothing leaves the server.
|
||||
|
||||
A code can be on one size only. Binding a code that is already on another garment is refused unless you choose to move it. See [Barcodes](/docs/stock/barcodes).
|
||||
|
||||
## Printing ThreadCount barcodes
|
||||
|
||||
For garments that arrived without a barcode, `Generate barcodes` on the garment's page under `Stock` gives each size without a code one of ThreadCount's own. These are EAN-13 codes starting `29`, a prefix set aside for use inside one business, with a real check digit. A size that already has a supplier's code keeps it.
|
||||
|
||||
`Print labels` prints an A4 sheet of 6 labels at a time, one per garment on hand, for each size that has a code. A 13-digit code with a valid check digit prints as EAN-13, and any other code prints as Code 128.
|
||||
|
||||
`Reprint a label` in the counter app prints 1 to 24 copies of one size's label. It only lists sizes with a barcode bound to them. It prints from a phone browser. Inside the Android app the button reads `Print it on the desktop`, because that app can't print.
|
||||
|
||||
> **Careful** A garment without a readable barcode drops out of every scanned count. Reprint worn labels before the next stocktake.
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: The staff app
|
||||
section: apps
|
||||
order: 2
|
||||
summary: The app for people who wear the uniform. How a staff member gets a sign-in, what they see and can do, what managers get, and how access is removed.
|
||||
screen: /my
|
||||
role: Staff
|
||||
keywords: staff app, wearer, nurse, self-service, code, slip, activation, sign in, kit, request, waitlist, damage, kit check, manager, approve, ward round, remove access
|
||||
---
|
||||
|
||||
The staff app shows one staff member their own uniform record, and lets them ask the linen room for what they need. It is at `/my` in any browser. On Android it is also on Google Play as **ThreadCount Staff**, which opens the same screens. There is no iOS app.
|
||||
|
||||
A staff sign-in is not a coordinator account. It is attached to the person's entry on the staff register, and it cannot open `/app` or `/m`.
|
||||
|
||||
## Getting a sign-in
|
||||
|
||||
An Admin gives each person a one-time code from their staff record on the website:
|
||||
|
||||
1. **Open the person in `People`** and press `Generate a code` in the `Staff app` panel.
|
||||
2. **Print the slip or copy the code.** The code is 12 characters in three groups and is shown once only.
|
||||
3. **Give the slip to the person.** In the app they tap `I have a code` (or `First time? I have a code` on the sign-in screen).
|
||||
4. **They enter the code, an email address and a password** of at least 8 characters, and tick the terms box if it is shown.
|
||||
|
||||
The code works once. It expires 14 days after it was printed (`SLIP_DAYS` in `lib/compute.ts`), and the staff record says how many days it has left. `New code` replaces an unused code, and `Cancel the code` withdraws it. A person who already has a sign-in cannot be given a code until their access is removed.
|
||||
|
||||
The email address is theirs to choose and may be a personal one. Each staff sign-in needs its own email address.
|
||||
|
||||
A staff member who forgets their password cannot reset it by email. The linen room removes their access and gives them a new code.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Staff record | A code and its print date are stored | `Cancel the code` |
|
||||
| Staff account | Created with the email and a hashed password; the code is spent | `Remove access` |
|
||||
|
||||
## What a staff member sees and can do
|
||||
|
||||
The bar at the bottom has `Home`, `Kit`, `Orders` and `Messages`.
|
||||
|
||||
- **Home** shows the request furthest along (with its collection code once it is ready), how many garments they hold, and shortcuts.
|
||||
- **Kit** lists what the linen room has recorded against them. `This isn't right` raises a query about the record.
|
||||
- **Request** asks for one or more garments with a reason. The request goes to the manager recorded on their staff record for approval.
|
||||
- **On the shelf** shows each size as `In stock`, `Low` or `None on shelf`, and says when it was last counted.
|
||||
- **Waitlist** is offered for a size with none on the shelf, showing their place before they join. Accepting a held garment sends it to their manager as a request.
|
||||
- **Report damage** can also request a replacement. The garment leaves their record only when handed in at the counter.
|
||||
- **Kit check** is open only while the linen room is running one, and Home prompts for it if they hold garments and haven't answered yet. They confirm how many of each they still have.
|
||||
- **Orders** lists their open and finished requests, each with a message thread to the linen room.
|
||||
- **Your sign-in** changes their password. A new password signs them out on every other phone or browser.
|
||||
|
||||
## What they never see
|
||||
|
||||
- prices, costs or any payment
|
||||
- stock numbers: the shelf is shown in words only
|
||||
- anyone else's record, unless that person reports to them as a manager
|
||||
|
||||
They cannot delete their own account; only the linen room can remove access.
|
||||
|
||||
## Manager functions
|
||||
|
||||
A staff member becomes a manager when someone on the register names them as their manager. See [Managers](/docs/people/managers). They get:
|
||||
|
||||
- **Approvals.** Home shows how many requests are waiting. They can approve or decline each line, with a reason when they decline.
|
||||
- **Approve by link.** The email about a new request links to `/my/approve`, which needs no sign-in. The link lasts 14 days and stops working once the request is decided or either person leaves the register.
|
||||
- **Ward.** Who on their team holds what, with each person's set count.
|
||||
- **Raise for your team.** A request typed for someone who reports to them. It goes to the manager's own manager for approval.
|
||||
|
||||
A person with `On the ward desk` ticked in the `Staff app` panel of their staff record also gets `Ward round`, where bags delivered to their ward are signed for. Whoever signs is named on the order. See [Delivery rounds](/docs/counter/delivery-rounds).
|
||||
|
||||
## Permissions and connection
|
||||
|
||||
ThreadCount Staff asks for internet access and nothing else: no camera, location, contacts, files, photos or microphone. It has no barcode scanner. It works online only. With no connection it shows `No connection.` and nothing is saved to send later.
|
||||
|
||||
## Having access removed
|
||||
|
||||
On the person's staff record, an Admin presses `Remove access` and confirms. The staff account is deleted and every session it had ends at once. Their register entry and issue history stay.
|
||||
|
||||
Deactivating the person on the register also stops their sign-in straight away, with the message `You're no longer on the register at this facility.` See [Deactivating and deleting](/docs/people/deactivating-and-deleting).
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: Delivery rounds
|
||||
section: counter
|
||||
order: 6
|
||||
summary: Take waiting pickups to the wards and have the receiver sign on screen. How signatures are stored and removed, and the ward round for staff requests.
|
||||
screen: Delivery rounds
|
||||
role: Admin or Issuer
|
||||
keywords: delivery round, round, ward, deliver, trolley, signature, sign, received by, handover photo, proof, ward desk, ward clerk
|
||||
---
|
||||
|
||||
ThreadCount has two rounds. `Delivery rounds` takes pickups, garments ordered in for a person, to the wards. Approved staff requests go on the ward round, signed for by the ward desk in the staff app.
|
||||
|
||||
## What a round is
|
||||
|
||||
`Delivery rounds` lists every pickup not yet picked up or delivered, grouped by the ward on the person's staff record. A person with no ward recorded is listed under `Unknown`. Each ward shows its cost centre and how many pickups it has.
|
||||
|
||||
Three tiles sit above: `To deliver`, `Garments on the trolley` and `Waiting 14+ days`. The last is flagged when any pickup has waited 14 days or more.
|
||||
|
||||
Each row shows the person, their phone number, the garments, the order code and the days waiting.
|
||||
|
||||
## Handing over
|
||||
|
||||
1. **Press `Delivered — sign`** on the row.
|
||||
2. **Type the receiver's name** in `Received by (name)`.
|
||||
3. **Have them sign** in the `Signature` box. `Clear` wipes it.
|
||||
4. **Press `Add handover photo`** if you want one.
|
||||
5. **Press `Mark delivered`.**
|
||||
|
||||
The name, signature and photo are each optional. The counter app's round takes a name and a signature, with no photo ([Counter app](/docs/apps/counter-app)).
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Pickup | Picked up today, the name typed, the signature and photo linked, marked as delivered on a round | No screen reverses it |
|
||||
| Issue | One row per line, as `Picked up` writes, marked signed when a signature was drawn | Record a return |
|
||||
| Photo | The signature, and the handover photo if taken | See below |
|
||||
|
||||
Delivery refuses `Already handed over` when the pickup was picked up or delivered first, and `Size <size> is no longer on <garment> — fix the catalogue before marking this delivered`.
|
||||
|
||||
## How signatures are stored and removed
|
||||
|
||||
The signature is saved as a PNG image before the delivery is recorded. An image may be up to 700 KB. It is kept as a file on the server, and the database holds a pointer to it. A self-hosted server keeps the files in the folder named by `PHOTO_DIR`, or `.photos` in the app's folder when that is unset ([Configuration reference](/docs/selfhost/configuration-reference)).
|
||||
|
||||
A signature is shown only to a signed-in user of the same facility.
|
||||
|
||||
No screen deletes a single signature. Images are removed in two cases:
|
||||
|
||||
- An image nothing refers to, such as a signature saved for a delivery that then failed, is deleted once it is more than 1 day old. The clean-up runs on about 1 image save in 20.
|
||||
- Wiping the facility's activity or resetting the facility removes every image the facility holds. Restoring a backup removes them and puts back the images the backup carries.
|
||||
|
||||
A backup carries up to 2000 images, and up to 40 MB of them.
|
||||
|
||||
> **Careful** A wipe of activity removes every delivery signature at once, with no way to keep some.
|
||||
|
||||
## The ward round for staff requests
|
||||
|
||||
On `Requests`, a request being picked has `Send on the ward round` ([Requests from staff](/docs/counter/requests-from-staff)). It refuses in two cases:
|
||||
|
||||
- `<first name> has no ward recorded, so there is no round to send this on. Hold it at the counter, or record their ward on the staff register first.`
|
||||
- `Nobody on <ward> can sign for a round bag — that needs somebody with the ward-desk flag and their own staff-app account. Hold it at the counter instead, or set the flag on their staff record first.`
|
||||
|
||||
The wearer is emailed `On the ward round` when they have an account and email is set up: `Whoever signs for it at the desk will be named on your order.`
|
||||
|
||||
Somebody on that ward signs for the bag in the staff app. No drawn signature is taken. ThreadCount records the signer's name, their role (`ward clerk` for somebody with the ward-desk flag), the time, and a history line `Delivered to <ward>`. The issues are written at that moment. The shelf is not checked at the ward, so a short shelf does not stop the hand-over; a later count corrects it. The wearer or the ward desk then marks the bag collected from the ward. See [Staff app](/docs/apps/staff-app).
|
||||
|
||||
## Ward delivery notes
|
||||
|
||||
The paper that travels with a bag is the delivery slip, `Uniform ward delivery`. Its footer is `Delivery slip footer` in Settings, which reads `After hours deliveries are left with the manager or team leader on duty.` until changed. See [Slips and signatures](/docs/counter/slips-and-signatures).
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: Exchanges and returns
|
||||
section: counter
|
||||
order: 2
|
||||
summary: Returns with a condition, size exchanges, hand-ins and the pre-loved pool. What each writes and how it moves the sets a person holds.
|
||||
screen: Counter
|
||||
role: Admin or Issuer
|
||||
keywords: return, returned, exchange, swap size, wrong size, hand-in, hand in, pre-loved, preloved, rag, lost, written off, damaged, credit
|
||||
---
|
||||
|
||||
Garments come back three ways. A return closes one issue line with a condition. An exchange swaps a size of the same garment. A hand-in takes back whatever the person brings and sorts it into the pre-loved pool or rags.
|
||||
|
||||
## Returns
|
||||
|
||||
`Return` sits against each line in the issue history on `Counter` and on the person's staff record. The counter app has its own return screen.
|
||||
|
||||
1. **Press `Return`** on the line.
|
||||
2. **Say how many are coming back** when the line is more than 1 garment. The rest stays out with the person.
|
||||
3. **Take a photo if you want one.** `Photo the garment (damage evidence)` is optional.
|
||||
4. **Press a condition:** `Returned – Good`, `Returned – Damaged`, `Lost` or `Written Off`.
|
||||
|
||||
Pressing the condition records the return. A garment issued from stock and returned `Returned – Good` counts back into the shelf figure; the other three conditions do not. A pre-loved garment returned `Returned – Good` goes back into the pre-loved pool instead.
|
||||
|
||||
Returns refuse `This issue has already been returned / written off` and `This garment was handed in on <date> — it's already back in the pool`.
|
||||
|
||||
## Exchanges
|
||||
|
||||
Size exchanges are made in the counter app, from the person's page: choose `Exchange`, pick or scan the garment that does not fit, then pick the size that does. It swaps 1 garment at a time. The `Counter` screen has no exchange. See [Counter app](/docs/apps/counter-app).
|
||||
|
||||
An exchange:
|
||||
|
||||
- marks the garment coming back `Returned - Good`, splitting the line if they hold more than 1
|
||||
- issues the new size today, condition `New` at today's catalogue cost, or `Pre-loved` at cost 0 from the pool when the original was pre-loved
|
||||
- carries across `offGroup` and `offStyle` from the original line
|
||||
- changes the top or trousers size on the staff record when the garment is a top or trousers
|
||||
|
||||
It makes no ceiling check. It refuses `Pick a different size`, `Not enough size <size> on the shelf`, `Not enough pre-loved size <size> in the pool`, `That garment has already been returned` and `That garment was handed in on <date>`.
|
||||
|
||||
## Hand-ins
|
||||
|
||||
`Hand-in` appears on `Counter` once a person is chosen, and on their staff record.
|
||||
|
||||
1. **Add each garment and size.** Tap a size again to add one.
|
||||
2. **Mark each line** `Good` or `Rag`, and `Laundered` or `Unlaundered`.
|
||||
3. **Tick `Credit the good garments back`** if the allowance should be credited.
|
||||
4. **Press `Record hand-in`**, or `Record & print receipt`.
|
||||
|
||||
ThreadCount matches each line to the person's issues of that garment and size that are not returned or handed in: new before pre-loved, newest first. Matched issues are stamped handed in today; part of a line is split off. Good lines join the pre-loved pool and rags are counted for disposal, whether or not they matched an issue.
|
||||
|
||||
Credit applies only to Good lines matched to new, not pre-loved, issues. The larger of the credited tops and credited trousers is given back as sets to the person's manager's approvals, newest first, and the year's report figure is credited.
|
||||
|
||||
A hand-in refuses only `Add at least one garment` and `Invalid hand-in line`.
|
||||
|
||||
A damage report from the staff app is cleared separately on `Requests`. Clearing it does not return the garment ([Requests from staff](/docs/counter/requests-from-staff)).
|
||||
|
||||
## The pre-loved pool
|
||||
|
||||
The pool is a count per garment and size. It grows from Good hand-in lines, from pre-loved garments returned `Returned – Good`, and from pre-loved garments given back in an exchange. It shrinks when a pre-loved line is issued or exchanged out.
|
||||
|
||||
A pre-loved issue costs the ward nothing and never comes off a manager's approval. It does count towards the ceiling. `Today` shows the pool's total under `Pre-loved pool`. A stocktake can count the pool on its own ([Stocktakes](/docs/stock/stocktakes)).
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Return | Return date today and the condition on the issue; photo linked | No screen reverses a return |
|
||||
| Exchange | Old line returned `Returned - Good`; new issue row today; staff record size | No screen reverses an exchange |
|
||||
| Hand-in | A hand-in with its lines; matched issues stamped handed in; pool up by the Good lines | No screen reverses a hand-in |
|
||||
| Approval, on credit | Sets used go down | Issue the sets again |
|
||||
|
||||
## How each moves sets held
|
||||
|
||||
Sets held count every issue that is not returned and not handed in, plus garments still owed.
|
||||
|
||||
| Action | Sets held |
|
||||
|---|---|
|
||||
| Return, any condition | The returned garments stop counting |
|
||||
| Exchange | 1 garment out, 1 in: the count does not change |
|
||||
| Hand-in, credit ticked or not | Matched garments stop counting |
|
||||
| Hand-in line matching no issue | No change |
|
||||
|
||||
> **In plain terms** The credit tick is about approvals and reports; the hand-in itself is what makes room under the ceiling.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Issue a garment
|
||||
section: counter
|
||||
order: 1
|
||||
summary: Pick the person, scan the garments, choose where each comes from, record it. What is written, and what the counter refuses.
|
||||
screen: Counter
|
||||
role: Admin or Issuer
|
||||
keywords: issue, issue stock, scan, barcode, counter, six sets, ceiling, override, pre-loved, order in, refusal, slip, hand out uniform
|
||||
---
|
||||
|
||||
`Counter` hands garments to one person at a time, and the server repeats every check.
|
||||
|
||||
## At the counter
|
||||
|
||||
1. **Find the person.** Search by name or staff number. Inactive staff are not listed. Each result shows the sets they hold against the ceiling.
|
||||
2. **Scan the garments.** Scan into the barcode box and press Enter, use `Camera`, or tap a size under `Quick add`; tap again for one more. An unknown code opens a dialog to bind it ([Barcodes](/docs/stock/barcodes)).
|
||||
3. **Choose a source for each line.** `From stock`, `Pre-loved` (shown when the pool holds that size) or `Order in`. A line with both shelf and pre-loved stock reads `Both available — pick a source` until you choose.
|
||||
4. **Read the box under the bag.** It says `Inside what one person holds`, or names each reason the bag needs an override.
|
||||
5. **Set the approval deduction.** When the person has a manager's approval with sets left, choose how many sets come off it. It starts at the larger of the tops and the trousers in the bag, not counting pre-loved lines.
|
||||
6. **Print a slip if needed.** `Collection slip` and `Delivery slip` list the stock and pre-loved lines.
|
||||
7. **Press `Record issue`.** Once the person signs, tick `signed` against the line in their issue history.
|
||||
|
||||
`Repeat last issue` fills the bag with the unreturned lines from the person's most recent issue date.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Issue, from stock | One row per line: today's date, condition `New`, today's catalogue cost | No screen deletes an issue; record a return |
|
||||
| Issue, pre-loved | Condition `Pre-loved`, cost 0; the pool goes down | Return it as `Returned – Good` |
|
||||
| Replenishment draft | Stock lines added to the supplier's draft on `Orders` | Edit the draft |
|
||||
| Order, for Order in | One order per supplier, status `Ordered`, for this person | Received lines join the [pickup call list](/docs/counter/pickup-call-list) |
|
||||
| Manager's approval | Sets used go up, oldest approval first | A hand-in with credit ticked gives sets back |
|
||||
| Signed tick | Marks the issue signed | Untick it |
|
||||
|
||||
An override is stamped only on the rows it applies to: `override` for the ceiling, `offGroup` for a garment outside the staff group, `offStyle` for the wrong cut. For `Order in` lines it is written into the order's note.
|
||||
|
||||
## What the counter refuses
|
||||
|
||||
| Refusal | Why | What to do |
|
||||
|---|---|---|
|
||||
| `This staff member is inactive — reactivate them on their profile first` | The record is inactive | Reactivate them on `People` |
|
||||
| `Not enough on the shelf for <garment> <size>` | Shelf count below the bag | Switch to `Order in`, or count the shelf |
|
||||
| `Not enough pre-loved <garment> <size> in the pool` | Pool below the bag | Switch to `From stock` or `Order in` |
|
||||
| `<garment> is discontinued` | The garment is archived | Choose a current garment |
|
||||
| `A. Hassan is holding 6 tops and 5 pairs. That would be 7 tops and 5 pairs, and the most anyone holds is 6 sets — 6 tops and 6 pairs. Hand a top in to make room, or a coordinator can record an override.` | Past the ceiling | Record a hand-in first, or tick the override |
|
||||
| `<garment> is for <groups> — <name> is in <group>. Tick the coordinator override to issue it anyway.` | Outside their staff group | Choose their group's garment, or tick the override |
|
||||
| `<garment> is the <cut> cut — <name> is set to <style>. Tick the coordinator override to issue it anyway.` | Not their uniform style | Choose their cut, or tick the override |
|
||||
|
||||
A cart wrong on several counts gets one refusal naming every reason.
|
||||
|
||||
A refusal ending `refresh and try again` means somebody changed the shelf, the pool, the approval or the person's holdings while you were serving. Refresh and record the bag again.
|
||||
|
||||
## The ceiling and the override
|
||||
|
||||
The ceiling is sets held at any time: 6 unless the facility has set its own figure. Tops and trousers are counted separately, so 7 tops and 2 pairs is past it. Garments outside a set, such as a fleece, have a ceiling of the same number, counted in garments. Holdings include garments on order, on the pickup list, and in approved request bags not yet collected. Pre-loved garments count. See [The entitlement rule](/docs/people/entitlement-rule).
|
||||
|
||||
One tick, `Issue anyway`, answers the ceiling, the staff group and the uniform style together. It clears when you change the person or the bag.
|
||||
|
||||
The `garments drawn since July` line is a running total for the reports. Nothing refuses on it.
|
||||
|
||||
> **In plain terms** A hand-in makes room; an override records that somebody chose to go past the rule.
|
||||
|
||||
## On a phone
|
||||
|
||||
The counter app has its own issue screen, recorded through the same server check. See [Counter app](/docs/apps/counter-app).
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
title: Manager approvals
|
||||
section: counter
|
||||
order: 4
|
||||
summary: One manager on each staff record approves that person's requests and signs their order form. Deciding in the app or by email, self-approval, and recording a signed form.
|
||||
screen: People › a person › Requests
|
||||
role: Admin or Issuer
|
||||
keywords: manager, approval, approve, decline, approver, email link, self-approved, signed form, order form, sets, FTE, credit slip, delegate
|
||||
---
|
||||
|
||||
Each staff record names one manager. That person approves the wearer's requests in the staff app and signs their paper order form.
|
||||
|
||||
## One manager per record
|
||||
|
||||
The manager is set in the `Manager` box under `Manager’s approval` on the staff record. Search the register by name or staff number and choose; it saves at once. Only an Admin can set, change or remove it.
|
||||
|
||||
- Anyone may be their own manager. The box then shows `Self-approved`.
|
||||
- An inactive person cannot be chosen: `That manager is no longer active on the register.`
|
||||
- A manager whom others still name cannot be deactivated: `<n> people still name <first name> as their manager, and a request can't be sent to somebody who is off the register. Give them a new manager first.`
|
||||
|
||||
Without a manager, the staff app refuses to raise a request: `Your manager isn't set yet — the linen room has to record who approves your requests.`
|
||||
|
||||
A request is addressed to the manager recorded when it was raised. Changing the manager later does not move it; use re-address on `Requests` ([Requests from staff](/docs/counter/requests-from-staff)).
|
||||
|
||||
## Deciding in the app
|
||||
|
||||
The manager opens the request in the staff app. Every garment starts marked approved. They can decline a single garment, or the whole request, with one of 3 reasons: `Over allowance`, `Not needed right now` or `Wrong item for the role`. Every garment must be decided before sending.
|
||||
|
||||
When at least 1 garment is approved the request goes to the linen room; when none is, it is declined. The wearer is emailed the result with the reason against each declined garment, when they have an account and email is set up.
|
||||
|
||||
## Deciding by email
|
||||
|
||||
When a request is raised, its manager is emailed `Uniform request from <name>`, or `Uniform request for <name>` when somebody raised it on the wearer's behalf. The link opens a page showing the request. Nothing is decided until the manager chooses on that page.
|
||||
|
||||
- The link lasts 14 days.
|
||||
- It decides the whole request: approve every garment, or decline every garment with one of the 3 reasons.
|
||||
- It works once. After either choice, both links in the email stop working.
|
||||
- It stops working when the manager or the wearer is no longer active on the register.
|
||||
|
||||
The decision is filed under the manager's name and marked as made from the email.
|
||||
|
||||
## Self-approval and the raise rule
|
||||
|
||||
Anybody may approve a request for their own uniform. It is never recorded as an ordinary approval: the history line reads `Approved by <name> — their own request`, with `Self-approved` beside it.
|
||||
|
||||
Nobody approves a request they raised for somebody else:
|
||||
|
||||
- A manager's raise for one of their own staff goes to the manager's own manager. If there is none, or it would come back to them, the request waits on `Needs an approver`.
|
||||
- Re-addressing to the raiser is refused: `<first name> raised this request, so it can't be sent back for <first name> to approve. Pick somebody else.`
|
||||
- Sending a request to its wearer is refused unless they are set as their own manager.
|
||||
- A decision by the raiser is refused: `You raised this request, so somebody else has to approve it — ask the linen room to re-address it.`
|
||||
|
||||
## Recording a signed order form
|
||||
|
||||
1. **Press `Print order form`** on the staff record, and have the manager sign it ([Slips and signatures](/docs/counter/slips-and-signatures)).
|
||||
2. **Under `Record a signed order form`, enter** `Sets`, `FTE`, `Date signed` and any `Note on the form`. The date cannot be after today.
|
||||
3. **Press `Photo the signed form`** if you want the sheet on file.
|
||||
4. **Press `Record approval`.** It needs a manager set in the box: `Set their manager first.`
|
||||
|
||||
The approval is recorded under the manager in the box. When the sets are above what the FTE table proposes, ThreadCount writes a sentence saying so after your note, and shows it first under `This will go on the record as written:`.
|
||||
|
||||
Each approval then shows `<n> of <m> sets left` or `Fully collected`, with `Form` to view the photo and `Credit slip` to print the balance. Sets come off at [Counter](/docs/counter/issue-a-garment). An Admin can remove an approval with `×`.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Staff record | The manager | An Admin changes or removes it |
|
||||
| Request and its lines | Each line approved or declined with a reason; status accepted or declined; decided time; a history line | None |
|
||||
| Approval | Date signed, manager's name as signed, link to the manager, sets, FTE, note, photo; sets used starts at 0 | An Admin removes it |
|
||||
|
||||
The name on an approval is a copy. It still reads as signed after the manager is renamed or leaves.
|
||||
|
||||
> **In plain terms** The manager in the box is the only approver, on screen and on paper.
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: Pickup call list
|
||||
section: counter
|
||||
order: 5
|
||||
summary: Garments ordered in for a person wait here until they are collected. Days waiting, contacted, the collection slip and picked up.
|
||||
screen: Today
|
||||
role: Admin or Issuer
|
||||
keywords: pickup, call list, awaiting pickup, collection, collected, picked up, contacted, ring, phone, waiting, fortnight, order in
|
||||
---
|
||||
|
||||
The call list is the `Awaiting pickup — call list` panel on `Today`. It holds every pickup that has arrived and has not been picked up or delivered.
|
||||
|
||||
## How a line joins it
|
||||
|
||||
A pickup starts as an order for a staff member, raised with `Order in` on [Counter](/docs/counter/issue-a-garment) or on `Orders` ([Order list](/docs/stock/order-list)).
|
||||
|
||||
When the delivery is received, each line goes to `Shelf` or `Pickup`. On an order for a staff member every line starts on `Pickup`. Pickup lines become one pickup for that person, dated with the delivery date; shelf lines go into stock. A short delivery is split off as a back order, which becomes its own pickup when it arrives. See [Receiving and back orders](/docs/stock/receiving-and-back-orders).
|
||||
|
||||
The garments count towards the person's ceiling from the day they are ordered.
|
||||
|
||||
## Reading the list
|
||||
|
||||
Rows are sorted by days waiting, longest first. Days waiting runs from the received date to today.
|
||||
|
||||
Each row shows the days waiting, the person's name and phone number (a call link where the device can dial), each garment with size and quantity, and the order code.
|
||||
|
||||
A pickup waiting 14 days or more is flagged and reads `Waiting a fortnight or more`. The `Awaiting pickup` tile counts every pickup and says how many have reached 14 days.
|
||||
|
||||
## Contacted, slip, picked up
|
||||
|
||||
1. **Ring them, then press `Mark contacted`.** The button becomes a `Contacted` tag. No screen unmarks it.
|
||||
2. **Print the `Collection slip`** if the bag needs one. It carries the name, ward, number of garments, the order's reference (or its code), the date received, and a tick against `Phone` under `Staff notified` once contacted. `Date notified` prints blank. It does not list the garments.
|
||||
3. **Press `Picked up`** when they collect. The row leaves the list.
|
||||
|
||||
When two people work the list at once, a refusal is shown above the rows. Pressing `Picked up` on a pickup already collected changes nothing.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Pickup | Contacted | No screen clears it |
|
||||
| Pickup | Picked up today | No screen reverses it |
|
||||
| Issue | One row per line: today's date, condition `New`, today's catalogue cost, the order code, marked as a pickup | Record a return from the person's history |
|
||||
|
||||
Picking up makes no ceiling check and stamps no ceiling override. It stamps `offGroup` or `offStyle` on a garment outside the person's staff group or uniform style.
|
||||
|
||||
It refuses one case: `Size <size> is no longer on <garment> — fix the catalogue before marking this picked up`. Put the size back on the garment, then press `Picked up` again.
|
||||
|
||||
## Hold period
|
||||
|
||||
A pickup has no hold period. There is no hold date and nothing expires: it stays on the list until it is picked up or delivered. The 14-day flag marks it and does nothing else.
|
||||
|
||||
A staff request held at the counter carries a `Held until` note ([Requests from staff](/docs/counter/requests-from-staff)), and a waitlist offer is held for 48 hours. Neither applies to pickups.
|
||||
|
||||
> **In plain terms** The list is a queue of phone calls, and nothing leaves it on its own.
|
||||
|
||||
## Delivering instead
|
||||
|
||||
[Delivery rounds](/docs/counter/delivery-rounds) lists the same pickups by ward. A delivery signed for there writes the same issue rows as `Picked up`, with the receiver's name and signature.
|
||||
|
||||
The counter app's `Pickups` screen has contacted and picked up. See [Counter app](/docs/apps/counter-app).
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
title: Requests from staff
|
||||
section: counter
|
||||
order: 3
|
||||
summary: Staff ask for uniform in the staff app, their manager decides each garment, the linen room picks the bag. The queue, codes, messages and the waitlist.
|
||||
screen: Requests
|
||||
role: Admin or Issuer
|
||||
keywords: request, ward request, staff request, approve, declined, pick, pick list, bag, collection code, hold, messages, waitlist, needs an approver, withdraw
|
||||
---
|
||||
|
||||
A request is one ask for one person, raised in the staff app and approved by that person's manager before the linen room can act. `Requests` is the linen room's side.
|
||||
|
||||
## What staff can ask for
|
||||
|
||||
- Up to 10 lines, and between 1 and 20 of each garment. The same garment and size asked for twice becomes one line.
|
||||
- A reason, from `Worn out`, `Damaged`, `Lost` and `Extra for shifts`, and a note of up to 400 characters. Both are optional.
|
||||
- Only garments for their own staff group, or for every group, and in their uniform style.
|
||||
|
||||
A person with no manager recorded cannot raise one. A manager may raise a request for somebody who reports to them; it then goes to the manager's own manager, never back to the raiser. Each request gets a code such as `R-0042`. See [Staff app](/docs/apps/staff-app) and [Manager approvals](/docs/counter/manager-approvals).
|
||||
|
||||
## The queue
|
||||
|
||||
| Tab | Holds |
|
||||
|---|---|
|
||||
| `To do` | Approved and not yet handed over |
|
||||
| `Needs an approver` | Waiting, with nobody asked to approve |
|
||||
| `Open` | Everything not yet finished, waiting ones greyed |
|
||||
| `All` | Every loaded request |
|
||||
| `Record queries`, `Damage`, `Kit check & waitlist` | The staff app's other reports |
|
||||
|
||||
The queue loads the most recent 400 requests; older ones are on the person's staff record. `Export CSV` writes the tab on screen, one row per garment.
|
||||
|
||||
Opening a request lists every line with its decision. A declined line is struck through with its reason and is never picked.
|
||||
|
||||
## The bag
|
||||
|
||||
1. **Press `Start picking`.**
|
||||
2. **Hold it at the counter or send it on the ward round.** `Hold at the counter` takes an optional `Held until` note, such as `Fri 6pm`. `Send on the ward round` is covered in [Delivery rounds](/docs/counter/delivery-rounds).
|
||||
3. **Match the code at the counter.** Holding gives the bag a 4-digit collection code, different from every other bag waiting at the counter.
|
||||
4. **Press `Collected`** when the person takes it.
|
||||
|
||||
Holding at the counter emails the person `Ready to collect` with the code and the held-until note, when they have a staff-app account and email is set up. The `Held until` note is text; nothing expires on it.
|
||||
|
||||
`Collected` checks the shelf and refuses `Not enough <garment> <size> on the shelf to hand over — count the shelf or order it in first.` It writes an issue for each approved line at today's catalogue cost and adds the garments to the supplier's replenishment draft. It does not refuse on the ceiling; a line past it is stamped as an override.
|
||||
|
||||
A request moves only forward. A stale screen gets `A request that is "<status>" can't move to "<status>".` or `Somebody else moved that request just now — reopen it.`
|
||||
|
||||
`Collection slip`, `Delivery slip` and `Print order form` print the approved lines ([Slips and signatures](/docs/counter/slips-and-signatures)).
|
||||
|
||||
## Messages
|
||||
|
||||
Each request has its own messages. Staff write from their order in the staff app; you reply in `Reply to this order` and press `Send`. Replies are named `(linen room)`. ThreadCount sends no email when a message is written. The request's `History` lists every step, who took it and when.
|
||||
|
||||
## Stuck requests
|
||||
|
||||
A request on `Needs an approver`, or one waiting on a manager who will never answer, has two ways out:
|
||||
|
||||
- **Re-address it.** Choose a name and press `Ask them` or `Re-address`. People without a staff-app account are listed under `Can’t be asked — no staff-app account`. The person who raised it is left out. The wearer is listed only when set as their own manager, and choosing them is a self-approval.
|
||||
- **Withdraw it.** `Withdraw it` declines the request with the reason `Withdrawn — no approver available` and emails the person.
|
||||
|
||||
Deactivating a person closes their waiting requests.
|
||||
|
||||
## The waitlist
|
||||
|
||||
Staff join a waitlist for a garment and size in the staff app. No approval is needed to join. The `Kit check & waitlist` tab lists who is waiting.
|
||||
|
||||
When the size arrives, press `It’s in — offer it`. The garment is held for 48 hours, and the person is emailed when they have an account. Accepting in the staff app raises a request, reason `Extra for shifts`, which still needs their manager. After 48 hours the row reads `Hold lapsed — offer to the next person` and the staff app refuses the acceptance.
|
||||
|
||||
An offer is refused when the garment is now outside the person's staff group or uniform style, with a message ending `Take them off this waitlist instead.`
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Request | Status, route, collection code, held-until note, a history line per step | None; it only moves forward |
|
||||
| Issue | One row per approved line on `Collected` | Record a return |
|
||||
| Message | Your reply, with your name | None |
|
||||
| Waitlist entry | Offered time | None |
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: Slips and signatures
|
||||
section: counter
|
||||
order: 7
|
||||
summary: Every document the counter prints, where each prints from, what it carries, and which signatures ThreadCount records.
|
||||
screen: Counter
|
||||
role: Admin or Issuer
|
||||
keywords: slip, print, printing, collection slip, delivery slip, order form, credit slip, hand-in receipt, access slip, signature, signed, receipt, paper
|
||||
---
|
||||
|
||||
Each document opens in a new window and starts the browser's print dialog. If nothing opens, allow pop-ups for ThreadCount.
|
||||
|
||||
## The documents
|
||||
|
||||
| Document | Printed from | Paper |
|
||||
|---|---|---|
|
||||
| Collection slip | `Counter`, the `Today` call list, `Requests` | A4 |
|
||||
| Delivery slip | `Counter`, `Requests` | A4 |
|
||||
| Order form | A staff record, `Requests`, a recorded approval | A4, one page |
|
||||
| Credit slip | The approval block on `Counter`, a staff record's approvals | A5 landscape |
|
||||
| Hand-in receipt | The hand-in dialog, a staff record's hand-ins | A5 landscape |
|
||||
| Access slip | A staff record | A5 landscape |
|
||||
|
||||
Garment labels and the supplier purchase order print from the stock screens: see [Barcodes](/docs/stock/barcodes) and [Order list](/docs/stock/order-list).
|
||||
|
||||
## Collection and delivery slips
|
||||
|
||||
Both carry the facility logo, or `Organisation name on slips` from Settings, or the facility name. Both carry `Staff name`, and `Collection code` beside it for a request held at the counter.
|
||||
|
||||
When printed from a bag, `Garments — tick each one as it goes in the bag` lists each line. Up to 10 lines print; the rest show as `+<n> more lines — see the request in ThreadCount.`
|
||||
|
||||
| Slip | Fields | Signature |
|
||||
|---|---|---|
|
||||
| `Uniform ready for collection` | Ward / Department, Date received, PO / Order no., Garments, Staff notified, Date notified | `Collected by (signature)`, `Date collected` |
|
||||
| `Uniform ward delivery` | Ward / Department, Deliver to, Garments, PO / Order no., Date received, Requested by, Delivered by, Date / time | `Received on ward by (name + sign)` |
|
||||
|
||||
The footer is `Collection slip footer` or `Delivery slip footer` from Settings.
|
||||
|
||||
What each screen fills in:
|
||||
|
||||
- **Counter.** The stock and pre-loved lines, marked `(pre-loved)` where they are; ordered-in lines are left off. `Requested by` is the staff number and `Delivered by` is the coordinator named in Settings. The buttons work only when the bag could be recorded.
|
||||
- **Requests.** The approved lines, with the cut named unless unisex. `PO / Order no.` is the request code. A request on the ward round prints a delivery slip, any other a collection slip. A declined request has no slip.
|
||||
- **Today.** Name, ward, garment count, the order reference, date received, and a `Phone` tick once contacted. No garment list.
|
||||
|
||||
## Order form
|
||||
|
||||
The form the manager signs. It prints three ways:
|
||||
|
||||
- From a staff record, with the person's details filled in and blank garment rows.
|
||||
- From a request on `Requests`, with the garments written on and declined lines left off. A request still waiting prints with the manager's block blank.
|
||||
- From a recorded approval, as a copy. It prints the date, sets, FTE and manager's name as signed. Every other field prints blank, and `Signature (on the signed sheet)` stays empty.
|
||||
|
||||
It has a `Staff member signature` line, a `Manager / financial delegate approval` block with signature, position and date, and a block for the linen room: date ordered, PO number, value, invoice number, stock received, date collected and staff signature. See [Manager approvals](/docs/counter/manager-approvals).
|
||||
|
||||
## Credit slip, hand-in receipt and access slip
|
||||
|
||||
- **Credit slip.** `Uniform Credit`, the sets left on one approval (`2 of 5 sets remaining`), the person, who approved it and when, the FTE and notes. It tells the person to bring the slip or their payroll number to collect the rest.
|
||||
- **Hand-in receipt.** Each garment, size, quantity and condition, `unlaundered` where marked, how many went to the pre-loved pool and to rag disposal, and whether the allowance was credited ([Exchanges and returns](/docs/counter/exchanges-and-returns)).
|
||||
- **Access slip.** The one-time code a person uses to claim their staff-app account, with the steps ([Staff app](/docs/apps/staff-app)).
|
||||
|
||||
## Signatures
|
||||
|
||||
ThreadCount does not read ink. What it records:
|
||||
|
||||
| Where | What is recorded | By |
|
||||
|---|---|---|
|
||||
| An issue | The `signed` tick | You, in the issue history, after the slip is signed |
|
||||
| A delivery on `Delivery rounds` | The drawn signature as an image, the receiver's name, and the `signed` tick on the issues | The receiver, on screen |
|
||||
| A request bag on the ward round | The signer's name, role and time; no image | The ward desk, in the staff app |
|
||||
| A manager's approval | A photo of the signed order form, if taken | You, when recording it |
|
||||
|
||||
`Today`'s `Receipts not yet signed` counts issues without the tick that have not been returned or handed in.
|
||||
|
||||
How drawn signatures and photos are stored and removed is on [Delivery rounds](/docs/counter/delivery-rounds).
|
||||
|
||||
> **In plain terms** Paper carries the signature; ThreadCount carries a tick, a name, or a picture of the paper.
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
title: Deactivating and deleting
|
||||
section: people
|
||||
order: 5
|
||||
summary: Deactivate someone who has left and keep their history, delete only a record entered by mistake, remove staff-app access, and handle a privacy request.
|
||||
screen: People › a person
|
||||
role: Admin
|
||||
keywords: deactivate, inactive, leaver, left, delete staff, remove, reactivate, history, finance, remove access, staff app account, privacy, personal information
|
||||
---
|
||||
|
||||
## Deactivate or delete
|
||||
|
||||
Someone who has left is deactivated. Their record stays, and so does everything recorded against it.
|
||||
|
||||
Delete removes the record itself. It is for a record entered by mistake, and it is refused for anyone with history.
|
||||
|
||||
## Deactivate
|
||||
|
||||
`Deactivate` is on the person's page.
|
||||
|
||||
It is refused while anyone else still active names them as manager, and the refusal says how many. Give those people a new manager first. Somebody who is only their own manager is not held up by this.
|
||||
|
||||
When it goes through:
|
||||
|
||||
- Every request for them still waiting on approval is closed as declined, with the reason that they are no longer on the register and a timeline entry. The page says how many were closed. Nobody is emailed about it.
|
||||
- The counter refuses to issue to them, and they drop out of the Counter search.
|
||||
- A request cannot be raised for them at the counter or in the staff app.
|
||||
- Their staff-app sign-in is refused with `You're no longer on the register at this facility. Ask the linen room.` Sessions already open stop working.
|
||||
- An emailed approval link about them, or sent to them as a manager, shows no details and decides nothing.
|
||||
- They leave the register's tiles and missing lists, and are hidden unless `Show inactive` is ticked.
|
||||
|
||||
`Reactivate` puts them back. Requests closed at deactivation stay closed and have to be raised again.
|
||||
|
||||
## What stays for finance
|
||||
|
||||
A deactivated record keeps its issues, orders, approvals, hand-ins, alterations, requests and notes. Each issue keeps the cost it was issued at, so reports and the [journal export](/docs/reports/journal-export) go on including it. The People export writes `Inactive` under `Register status` for them.
|
||||
|
||||
## Delete
|
||||
|
||||
`Delete` appears on the person's page only when they have no issues and no orders. The server then checks everything else, and refuses if the record has any of:
|
||||
|
||||
- issues, orders, manager approvals, alterations or hand-ins;
|
||||
- requests for them or raised by them;
|
||||
- waitlist places, kit-check answers, damage reports or queries;
|
||||
- a staff-app account.
|
||||
|
||||
The refusal lists what was found and says to deactivate instead.
|
||||
|
||||
> **Careful** A delete cannot be undone.
|
||||
|
||||
## Remove staff-app access
|
||||
|
||||
The `Staff app` panel on the person's page manages their account.
|
||||
|
||||
- **Remove access** deletes the account after a confirmation. Every session it had ends at once and any code is cleared. The register entry and history stay. To sign in again they need a new code.
|
||||
- **Cancel the code** withdraws a code that has not been used. A code also stops working 14 days after it was generated.
|
||||
|
||||
Removing access does not deactivate the person. See [the staff app](/docs/apps/staff-app).
|
||||
|
||||
## Privacy requests
|
||||
|
||||
ThreadCount has no screen that exports or erases one person's information in a single step. What it has:
|
||||
|
||||
- The staff app shows a person their own record, and a query they raise there about it reaches the linen room.
|
||||
- The People export, searched to one name, gives that person's register row without notes or start date.
|
||||
- The backup holds the whole facility. See [export and backup](/docs/account/export-and-backup).
|
||||
- Notes can be edited or cleared on the person's page.
|
||||
- A record with history cannot be deleted; it can be deactivated and its access removed.
|
||||
|
||||
The [privacy policy](/privacy) tells staff to ask their coordinator to remove their access, and says their register entry and history stay because the facility needs them for its own records. Anyone who would rather not ask their coordinator can write to privacy@threadcount.tech, and the request is routed through the facility's own privacy process.
|
||||
|
||||
Deleting a whole facility is on [delete an account](/docs/account/delete-an-account).
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Deactivate | The record marked inactive; waiting requests declined. | `Reactivate`. Closed requests stay closed. |
|
||||
| Delete | The record removed. | None. |
|
||||
| Remove access | The staff-app account deleted, any code cleared. | Generate a new code. |
|
||||
| Cancel the code | The code cleared. | Generate a new code. |
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: The entitlement rule
|
||||
section: people
|
||||
order: 3
|
||||
summary: Six sets held at any time, for every group, with no financial year. How sets held are counted, how hand-ins make room, and where overrides are recorded.
|
||||
screen: Settings › Issuing rules
|
||||
role: Admin or Issuer
|
||||
keywords: entitlement, six sets, ceiling, cap, allowance, sets held, over the ceiling, override, hand-in, credit, yearly figure, financial year
|
||||
---
|
||||
|
||||
## The rule
|
||||
|
||||
Nobody holds more than the ceiling: 6 sets unless the facility sets its own. It limits what a person holds at any one time, and it is the same for every staff group and every route. There is no financial year in it and nothing resets in July.
|
||||
|
||||
A set is one top and one pair of trousers. The ceiling applies to each half, so 6 sets means at most 6 tops and at most 6 pairs. Somebody holding 6 tops and 2 pairs can take another pair, not another top.
|
||||
|
||||
Garments that are part of no set, such as fleeces, jackets and maternity wear, have their own ceiling of the same number, counted in garments.
|
||||
|
||||
Past the ceiling, the next garment comes only after a hand-in or on a coordinator's override.
|
||||
|
||||
## How sets held are counted
|
||||
|
||||
A garment's type decides which half it is.
|
||||
|
||||
| Half | Types |
|
||||
|---|---|
|
||||
| Top | `Shirt`, `Polo`, `Tunic`, `Scrub top`, `Blouse` |
|
||||
| Trousers | `Pants`, `Trousers`, `Cargo pants`, `Shorts`, `Skort`, `Skirt` |
|
||||
|
||||
A garment with no type is judged by its name. A type typed in by hand that is not on the list counts toward no set, so pick from the list.
|
||||
|
||||
What a person holds is the total of:
|
||||
|
||||
- everything issued to them and not handed in or returned, pre-loved garments included;
|
||||
- orders placed for them, drafts included, less what has already arrived;
|
||||
- pickups waiting for them at the counter;
|
||||
- request lines a manager has approved that nobody has collected.
|
||||
|
||||
People, the person's page and the counter all use this count.
|
||||
|
||||
## At the counter
|
||||
|
||||
A bag that would take someone past either ceiling is refused, with a sentence giving what they hold, how much of it is still to come, and the ceiling. The check runs again as the issue is saved, so two counters serving one person at once cannot both pass.
|
||||
|
||||
Ticking the override lets the issue through. See [issue a garment](/docs/counter/issue-a-garment).
|
||||
|
||||
## Where overrides are recorded
|
||||
|
||||
- Each issue row that went past the ceiling is stamped as an override, pre-loved rows included. It shows as an `Override` tag in the person's `Issue history`.
|
||||
- For garments ordered in, the order's notes say the person is past the ceiling and name the coordinator who recorded the override.
|
||||
- The People screen's `Over the ceiling` tile counts everyone above it, and their row's status is `OVER`.
|
||||
- The monthly exceptions report lists `Past 6 sets on an override`.
|
||||
|
||||
The stamp is written only when the ceiling was actually passed. Garments outside a person's staff group or uniform style carry their own separate stamps.
|
||||
|
||||
## Hand-ins
|
||||
|
||||
`Record hand-in` on the person's page makes room straight away. Matched issues are marked handed in and stop counting toward what the person holds, whether or not the credit box is ticked. Where only part of an issue line comes back, the line is split.
|
||||
|
||||
- `Good` garments join the pre-loved pool. `Rag` garments are counted for disposal.
|
||||
- The credit tick gives sets back to the manager's approvals, newest first, and credits the yearly figure. Only good garments matched to new issues earn credit; pre-loved garments do not.
|
||||
|
||||
Returns and exchanges are on [exchanges and returns](/docs/counter/exchanges-and-returns).
|
||||
|
||||
## The facility's own figures
|
||||
|
||||
`Settings › Issuing rules` holds three figures:
|
||||
|
||||
| Field | What it does |
|
||||
|---|---|
|
||||
| `Ceiling, every group (sets)` | The rule on this page. A blank, nought or unreadable entry saves as 6. Fractions are rounded down. |
|
||||
| `Starting kit (sets)` | The first-day kit for groups on the starting kit. |
|
||||
| `Yearly figure for reports (garments)` | What a year's drawing is measured against on Reports. It never limits the counter. A person's own figure can be set on their record; groups on the FTE table are not measured. |
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Issue with override | Issue rows stamped as an override, or a note on the order. | Return or hand in the garment. The stamp stays. |
|
||||
| Hand-in | A hand-in record, matched issues marked handed in, the pool updated. | None on screen. |
|
||||
| Credit tick | Approval balances and the yearly figure credited. | None on screen. |
|
||||
| Change the ceiling | The facility's ceiling. | Set it back. |
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
title: Staff groups and routes
|
||||
section: people
|
||||
order: 2
|
||||
summary: Name your staff groups, put each on the FTE table, the starting kit or manager approval, and restrict garments by group.
|
||||
screen: Settings › Issuing rules
|
||||
role: Admin
|
||||
keywords: staff groups, groups, routes, fte table, starting kit, manager approval, initial kit, nursing, rename group, garment groups, outside group
|
||||
---
|
||||
|
||||
## Name your groups
|
||||
|
||||
Staff groups are the facility's own names, listed under `Settings › Issuing rules` in `Staff groups`. A new facility has none, and ThreadCount reads nothing into the letters of a name.
|
||||
|
||||
- **Add** a name in `New staff group`. It starts on manager approval.
|
||||
- **Rename** changes the name on the list, on its route, on every staff record filed under it and on every garment tagged for it, in one step. Renaming onto a name already in use is refused. Changing only the case or spacing is allowed.
|
||||
- **Remove** (`×`) is refused while any active staff member is filed under the group. Move them, or rename the group instead.
|
||||
|
||||
A staff import files people under whatever group the file names and adds nothing to this list. Groups on the register but not on the list are shown below it, each with an `Add` button and a head count. Their staff are on manager approval until the group is added and given another route. With no groups at all, everybody is on manager approval.
|
||||
|
||||
An Issuer can read the routes but not change them.
|
||||
|
||||
## The three routes
|
||||
|
||||
Each group takes one route, picked with the `FTE table`, `Starting kit` or `Manager approval` buttons on its row. A group cannot be on two; the server refuses the save. If a restored backup carries a group on both, it is read as being on the FTE table.
|
||||
|
||||
Every route stops at the same ceiling of sets held (see [the entitlement rule](/docs/people/entitlement-rule)). The routes differ only in how somebody gets there.
|
||||
|
||||
## The FTE table
|
||||
|
||||
The person's `Combined FTE` proposes their initial kit:
|
||||
|
||||
| FTE | Sets proposed |
|
||||
|---|---|
|
||||
| `1.0`, `0.9` | 5 |
|
||||
| `0.8`, `0.7` | 4 |
|
||||
| `0.6`, `0.5` | 3 |
|
||||
| `0.4`, `0.3` | 2 |
|
||||
| `0.2`, `0.1` | 1 |
|
||||
| `Casual` | None. The form names 1, 2 or 3 and leaves the number to the manager. |
|
||||
|
||||
A fraction not on the table, such as `0.75`, is read by the band it falls in. With no FTE recorded, no kit is proposed and the register lists the person under `No FTE`.
|
||||
|
||||
The proposal is not a limit. A manager may sign for more, and the signed form is recorded as written with a sentence added, such as `Above the FTE table: 5 sets at 0.6 FTE, where the table proposes 3.` A signature does not lift the ceiling.
|
||||
|
||||
## The starting kit
|
||||
|
||||
`Starting kit (sets)` under `Settings › Issuing rules` is what the group is handed on the first day: 3 sets unless the facility sets its own. A blank or nought saves as 3, fractions are rounded down, and a figure above the ceiling is read as the ceiling. After that, more is issued as needed up to the ceiling. Nothing has to be handed back first.
|
||||
|
||||
## Manager approval
|
||||
|
||||
There is no starting kit. The person's manager approves sets, on a signed order form recorded on the person's page or on a request in the staff app.
|
||||
|
||||
> **In plain terms** The counter refuses on the ceiling, the staff group and the uniform style. It does not refuse an issue because no approval is on file.
|
||||
|
||||
On the person's page, `Initial kit` counts every garment ever issued to them that was not pre-loved, against the kit their route gives. It is a lifetime count, and a hand-in does not give it back.
|
||||
|
||||
## Garments restricted by group
|
||||
|
||||
Each catalogue garment is tagged for one or more staff groups, or for all groups when it has no tag. See [catalogue, sizes and cuts](/docs/stock/catalogue-sizes-and-cuts).
|
||||
|
||||
- The staff app refuses a request for a garment outside the person's group. The one exception is a damage replacement for a garment they already hold.
|
||||
- A request raised at the counter is refused the same way.
|
||||
- Issuing one at the counter needs a coordinator override. Each issue row is stamped as outside the group; for a garment ordered in, the order's notes say so instead.
|
||||
- The monthly exceptions report lists these as `Outside their staff group on an override`.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Add group | The facility's group list. | Remove it while nobody active is filed under it. |
|
||||
| Pick a route | The facility's FTE-table and starting-kit lists. | Pick the old route. |
|
||||
| Rename | The list, the route, staff records and garment tags. | Rename it back. |
|
||||
| Remove | The group comes off the list and off its route. | Add it back and pick its route again. |
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: Managers
|
||||
section: people
|
||||
order: 4
|
||||
summary: The one manager on each record approves that person's requests and signs their order forms. Self-approval, raising for others, email links and changing a manager.
|
||||
screen: People › a person › Details & access
|
||||
role: Admin
|
||||
keywords: manager, approver, approval, sign, order form, self-approved, own manager, reports to, email link, needs an approver, re-address, reassign
|
||||
---
|
||||
|
||||
## One manager, both jobs
|
||||
|
||||
Each record names at most one manager, in the `Manager` box under `Manager's approval` on the person's page. That person approves their requests in the staff app, and a signed paper order form for them is recorded as signed by that manager.
|
||||
|
||||
1. **Type a name or staff number.** Only active people on the register are offered.
|
||||
2. **Pick the name.** It saves straight away.
|
||||
|
||||
`Change` picks someone else. `Remove` clears it after a confirmation. Setting a manager who is inactive is refused. The import's `manager` column sets the same field, by staff number.
|
||||
|
||||
Nobody can raise a request, in the staff app or at the counter, without a manager set. A manager who has left the register counts as none: the request is refused with `The recorded manager is no longer on the register.`
|
||||
|
||||
`Whose requests they approve`, lower on the manager's own page, lists everyone who names them. `Add somebody who reports to them` changes that other person's record, after a card that names who they are being moved from.
|
||||
|
||||
## What a manager sees and signs
|
||||
|
||||
In the staff app, a manager has an approvals queue, oldest first. They approve or decline each garment, or the whole request. A decline needs a reason from a fixed list, and the wearer is emailed the decision if they have an account. A manager with people reporting to them also has a ward view listing those people, what they hold, and their sets against the ceiling. See [manager approvals](/docs/counter/manager-approvals) and [the staff app](/docs/apps/staff-app).
|
||||
|
||||
The linen room cannot approve on a manager's behalf.
|
||||
|
||||
On paper, `Record a signed order form` takes the sets, FTE, the date signed (not after today), an optional note and a photo of the form. It needs an active manager set, and records their name linked to their record. An Admin or Issuer can record one; only an Admin can remove one.
|
||||
|
||||
## Self-approval
|
||||
|
||||
Anyone may be recorded as their own manager. The box then shows `(themselves)` and a `Self-approved` tag.
|
||||
|
||||
- A request they decide for themselves is written into its timeline as their own request, marked `Self-approved`, naming them as both the manager and the person it is for.
|
||||
- A signed form they approved for themselves is tagged `Self-approved` on their record.
|
||||
- In the approvals queue, their own requests are set apart under `Your own request`.
|
||||
|
||||
## Raising for somebody else
|
||||
|
||||
A manager can raise a request for the people who report to them. Nobody approves a request they raised for somebody else, so it goes to the raiser's own manager instead. If there is nobody above, or the raiser is their own manager, it is created with no approver and waits under `Requests › Needs an approver`.
|
||||
|
||||
The linen room re-addresses a waiting request from there. Re-addressing it to the person who raised it is refused. Sending it to the person it is for is allowed only if they are recorded as their own manager.
|
||||
|
||||
## Email links
|
||||
|
||||
When a request is addressed to a manager who has a staff-app account, and the server is set up to send mail, the manager is emailed a link to approve or decline it.
|
||||
|
||||
- The link lasts 14 days, and works only while the request is still waiting. Once a decision is made, both links in the email stop working.
|
||||
- Opening the link shows the request. The decision is made by pressing a button on that page, not by opening the link.
|
||||
- If the manager or the wearer is no longer on the register, the page shows no details and decides nothing.
|
||||
- A request for the manager's own uniform says `Your own uniform`.
|
||||
|
||||
A manager with no staff-app account is not emailed. The request still waits for them.
|
||||
|
||||
## Changing a manager
|
||||
|
||||
New requests go to the new manager. Requests already waiting stay addressed to the old manager until the linen room re-addresses them. A manager cannot be deactivated while anyone else active still names them; give those people a new manager first. See [deactivating and deleting](/docs/people/deactivating-and-deleting).
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Set or change a manager | The person's manager. | `Change` or `Remove`. |
|
||||
| Record a signed form | An approval with sets, FTE, date, signer, note and photo. | `×` on the approval (Admin). |
|
||||
| Re-address a request | The request's manager, and a timeline entry. | Re-address again while it waits. |
|
||||
| Approve or decline | Request and garment statuses, and a timeline entry. | None. |
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: The staff register
|
||||
section: people
|
||||
order: 1
|
||||
summary: Who is on the register, what each record holds, how to add, import, edit and search it, and what a person's page shows.
|
||||
screen: People
|
||||
role: Admin
|
||||
keywords: staff register, staff, people, add staff, import, roster, csv, payroll number, sizes, fte, uniform style, search, export, missing, approver
|
||||
---
|
||||
|
||||
## What a record holds
|
||||
|
||||
Each person on the register is one record. `Add staff member` opens the form.
|
||||
|
||||
| Field | Notes |
|
||||
|---|---|
|
||||
| Staff number | Required and unique in the facility. It cannot be changed after the record is saved, because issue history and reports are keyed to it. |
|
||||
| First and last name | Both required. |
|
||||
| Phone, group, department or ward | The group decides the person's route (see [groups and routes](/docs/people/groups-and-routes)). The ward decides the cost centre unless an override is set. |
|
||||
| Top size, pants size | One of each. |
|
||||
| Uniform style | `Men's`, `Women's`, `Either`, or blank. Blank offers every style, as `Either` does. |
|
||||
| Combined FTE | `1.0` down to `0.1`, or `Casual`. Only read for groups on the FTE table. |
|
||||
| Yearly report figure | Garments. Used by reports only; the counter never refuses on it. |
|
||||
| Cost centre override, start date, notes | Optional. |
|
||||
|
||||
The manager and the `On the ward desk` tick are set on the person's page, not on this form. When the plan's staff limit is reached, a new record is refused with `The register is full for this plan`.
|
||||
|
||||
## Import from a spreadsheet
|
||||
|
||||
`Settings › Data` imports the `Staff register` template. Its columns are `num,first,last,phone,group,dept,cc,manager,fte,style,top,pants,ccoverride,ent,start,notes`.
|
||||
|
||||
- A row with no `num` or no `first` is skipped.
|
||||
- A row whose staff number is already on the register updates that record. Only cells with something in them are written; a blank cell keeps what is there.
|
||||
- `dept` with `cc` creates the department if it does not exist.
|
||||
- `manager` is the manager's staff number, not their name. Managers are linked after every row is in, so a manager can appear anywhere in the file. A number that matches nobody is reported.
|
||||
- An `fte`, `start` or `style` cell that cannot be read is reported and left blank. Dates are written `YYYY-MM-DD`.
|
||||
- At most 20,000 rows at a time. Rows past the plan's staff limit are skipped and the refusal is reported once.
|
||||
|
||||
An import does not add group names to `Settings › Issuing rules`. See [groups and routes](/docs/people/groups-and-routes) for what that means. The template itself is on [CSV templates](/docs/reference/csv-templates).
|
||||
|
||||
## Search, filter and export
|
||||
|
||||
The search box matches name, staff number or ward. Beside it are a group filter, a filter for what records are missing, and `Show inactive`.
|
||||
|
||||
The missing filter has two parts. `Has to be set` lists `No approver` (no manager, or a manager no longer on the register), `No FTE` (FTE-table groups only) and `No sizes`. `Optional` lists `No staff app` and `No uniform style`. Inactive records are never in these lists.
|
||||
|
||||
The tiles count the whole active register, whatever the search: `On the register`, `On a ward desk`, `Over the ceiling` and `Records to finish`. Each row's `Status` is `OK`, `AT LIMIT` (a full half of a set), `OVER` or `Inactive`.
|
||||
|
||||
`Export CSV` downloads the rows on screen. It uses the import's headers, so a ward's list can go to its manager, come back with `Manager number` filled in, and be imported again. `Approver name (reference only)` is ignored on import. Notes and start dates are left out of the file.
|
||||
|
||||
## Last sizes
|
||||
|
||||
The register holds one top size and one pants size. In the staff app, a request starts from the register's size for a top or trousers. For any other garment, or where the register has no size, it starts from the size of the last one that person was issued. The ward desk's raise screen does the same for garments the register has no size for.
|
||||
|
||||
## A person's page
|
||||
|
||||
Click a name to open it. It shows:
|
||||
|
||||
- `Details`, with `Edit details`, `Deactivate` and, for a record with no issues and no orders, `Delete`.
|
||||
- `Uniform held and owed`: sets held against the ceiling, room left, anything still on order, sets signed for and not collected, the `Combined FTE` picker (saved as soon as it changes) and the initial kit.
|
||||
- `Manager's approval`: the manager, `Print order form`, and the signed forms recorded. See [managers](/docs/people/managers).
|
||||
- `Previous order forms`, `Notes`, `Waiting for pickup`, `Staff app` and `Whose requests they approve`.
|
||||
- `Alterations`, `Uniform hand-ins`, `Issue history` (with an `Override` tag where one was recorded) and `Orders for this staff member`.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Add staff member | A new staff record. | Delete it while it has no history. |
|
||||
| Edit details, FTE picker | The fields on the record. | Edit again. The staff number cannot change. |
|
||||
| Import | Records created or updated, managers linked, departments created. | None. Import a corrected file, or edit by hand. |
|
||||
|
||||
Every change is listed under `Activity`.
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: CSV templates
|
||||
section: reference
|
||||
order: 1
|
||||
summary: The six import files, the columns each one reads, how a row is matched to a record, and what every importer message means.
|
||||
screen: Settings › Data & audit log
|
||||
role: Admin
|
||||
keywords: csv, import, template, spreadsheet, columns, headers, upload, catalogue, staff register, departments, barcodes, reorder levels, opening balances, bulk load
|
||||
---
|
||||
|
||||
## Load order and the basics
|
||||
|
||||
Under `Settings › Data › Import from CSV`, an Admin picks a file kind, presses `Download template` for `threadcount-<kind>-template.csv` (header row plus one example row), fills it in, saves it as CSV and presses `Import CSV`.
|
||||
|
||||
Load in this order, because later files look up what earlier ones created:
|
||||
|
||||
1. **Departments & cost centres** (`depts`)
|
||||
2. **Catalogue** (`catalog`)
|
||||
3. **Staff register** (`staff`)
|
||||
4. **Supplier barcodes** (`barcodes`)
|
||||
5. **Opening balances** (`opening`)
|
||||
6. **Reorder levels** (`reorder`)
|
||||
|
||||
For every file:
|
||||
|
||||
- Headers are matched ignoring case, spaces and punctuation, so `Staff no.` reads as `staffno`. Unknown columns are ignored.
|
||||
- Cells are trimmed and cut at 400 characters. Blank lines are skipped.
|
||||
- The apostrophe ThreadCount's exports put before `=`, `+`, `-`, `@` or a space is removed, so an exported file imports back unchanged.
|
||||
- On a re-import a blank cell keeps what the record holds. An import cannot clear a field.
|
||||
|
||||
## Departments and catalogue
|
||||
|
||||
**Departments & cost centres.** Matched by exact name. The row order becomes the list's order.
|
||||
|
||||
| Column | Required | Rule | Example |
|
||||
|---|---|---|---|
|
||||
| `dept` | Yes | Also `department`, `name`, `ward`. | `Harbour Ward` |
|
||||
| `cc` | No | Also `costcentre`, `costcenter`, `code`. Blank keeps the existing one. | `RGH-4010` |
|
||||
|
||||
**Catalogue.** Updates the garment with the same `item` and gender, and the same `sku` when given; otherwise creates one.
|
||||
|
||||
| Column | Required | Rule | Example |
|
||||
|---|---|---|---|
|
||||
| `item` | Yes | Also `name`, `itemname`, `garment`. | `Scrub Top` |
|
||||
| `gender` | No | Starts `m`: men's. Starts `f` or `w`: women's. Anything else or blank: Unisex. | `Women's` |
|
||||
| `sku` | No | Also `code`, `productcode`. | `NW-ST-220` |
|
||||
| `supplier` | No | Also `vendor`. A new name is added to the supplier directory; a known one, in any case, takes the directory's spelling. | `Northline Workwear` |
|
||||
| `cost` | No | Also `unitcost`, `price`. Non-digits dropped. Blank or 0 keeps the existing cost. | `31.50` |
|
||||
| `group` | No | Also `staffgroup`. Several separated by a pipe; `All` is every group. Blank: All when new, unchanged on update. | `Midwife` |
|
||||
| `sizes` | New garments | Also `size`. Separated by a pipe, `,`, `;` or `/`. An update adds new sizes and removes none. | `S/M/L/XL` |
|
||||
| `notes` | No | Also `note`. | `Navy` |
|
||||
| `type` | No | Not in the template. Also `producttype`, `garmenttype`. Decides top, trousers or neither. | `Scrub top` |
|
||||
|
||||
## Staff register
|
||||
|
||||
Updates the person with the same staff number, or creates one. Managers are linked after every row is written, so a manager can sit anywhere in the file. A row without a staff number or first name is skipped.
|
||||
|
||||
| Column | Required | Rule | Example |
|
||||
|---|---|---|---|
|
||||
| `num` | Yes | Also `staffnumber`, `staffno`, `number`, `payroll`, `payrollnumber`, `id`. | `00400127` |
|
||||
| `first` | Yes | Also `firstname`, `given`. A `name` or `fullname` column is split at the first space if first and last are blank. | `Amira` |
|
||||
| `last` | No | Also `lastname`, `surname`, `family`. | `Hassan` |
|
||||
| `phone` | No | Also `mobile`, `contact`. | `0400 000 000` |
|
||||
| `group` | No | Also `staffgroup`, `classification`. Not checked against `Settings › Issuing rules`. | `Registered Nurse` |
|
||||
| `dept` | No | Also `department`, `ward`, `wardunit`. | `Harbour Ward` |
|
||||
| `cc` | No | Also `costcentre`, `costcenter`, `departmentcostcentre`. With `dept`, creates a missing department. Never changes an existing one. | `RGH-4010` |
|
||||
| `manager` | No | Also `managernum`, `managernumber`, `approver`, `reportsto`. A staff number, not a name. | `00400019` |
|
||||
| `fte` | No | Also `combinedfte`, `totalcombinedfte`, `totalfte`, `employmentfraction`, `fraction`. Above 0, or `Casual`. | `0.8` |
|
||||
| `style` | No | Also `uniformstyle`, `uniform`, `cut`, `gender`. `m`, `male`, `men's`: Men's. `f`, `w`, `female`, `women's`, `ladies`: Women's. `either`, `both`, `any`, `all`, `unisex`: Either. | `Women's` |
|
||||
| `top` | No | Also `topsize`, `shirt`, `shirtsize`. | `M` |
|
||||
| `pants` | No | Also `pantsize`, `pant`, `trouser`. | `12` |
|
||||
| `ccoverride` | No | Also `costcentreoverride`. | `RGH-4090` |
|
||||
| `ent` | No | Also `entitlement`, `annualentitlement`. Whole number for the yearly report; limits nothing. | `10` |
|
||||
| `start` | No | Also `startdate`, `commenced`. `YYYY-MM-DD`, or day first as `11/03/2024`. | `2026-02-02` |
|
||||
| `notes` | No | Also `note`. | `Night shift` |
|
||||
|
||||
The `People` export uses headers that read back onto these columns. See [the staff register](/docs/people/staff-register) and [managers](/docs/people/managers).
|
||||
|
||||
## Barcodes, opening balances, reorder levels
|
||||
|
||||
Each row must match exactly one garment on whichever of `sku` (also `code`, `productcode`), `item` (also `name`, `itemname`, `garment`) and `gender` it fills in, then a `size` spelt as on the garment. Blank `gender` matches any. A header named `code` is read as the SKU.
|
||||
|
||||
| File | Column | Rule | Example |
|
||||
|---|---|---|---|
|
||||
| Supplier barcodes | `barcode` | Also `ean`, `code128`, `scan`. Blank skips the row. | `9300000000017` |
|
||||
| Opening balances | `opening` | Also `qty`, `quantity`, `onhand`, `count`. Overwrites; blank leaves the size alone. | `14` |
|
||||
| Opening balances | `reorder` | Optional. Also `reorderat`, `reorderlevel`. Not a number: sets 0. | `4` |
|
||||
| Reorder levels | `reorder` | Also `reorderat`, `reorderlevel`, `level`. Overwrites; not a whole number skips the row. | `4` |
|
||||
|
||||
Negative figures are stored as 0. Every row these files write counts as created. See [barcodes](/docs/stock/barcodes) and [reorder levels](/docs/stock/reorder-levels).
|
||||
|
||||
## Messages and what to do
|
||||
|
||||
The result reads like `Catalogue: 12 created, 3 updated, 1 skipped.`, then up to 40 row messages. `Row 1` is the first row under the header, blank lines not counted; the two whole-file refusals give the file's line number.
|
||||
|
||||
| Message | Meaning | Fix |
|
||||
|---|---|---|
|
||||
| `Line N: a quote is opened and never closed…` | Nothing imported. | Fix the quote. |
|
||||
| `Lines N: the wrong number of columns…` | Nothing imported; usually a stray `"`. | Fix those lines. |
|
||||
| `No rows found — check the header row.` | Nothing under the header. | Save the right sheet. |
|
||||
| `Row N: X has no sizes` | New garment skipped. | Add `sizes`. |
|
||||
| `Row N: start date “X” isn't a date…` | Stored blank. | Write `YYYY-MM-DD`. |
|
||||
| `Row N: FTE “X” isn't a fraction…` | Stored blank. | Write `0.75` or `Casual`. |
|
||||
| `Row N: uniform style “X” isn't…` | Stored blank. | Use Men's, Women's or Either. |
|
||||
| `Row N: no staff member with number X to be the manager` | Not linked. | Add or fix the manager's row. |
|
||||
| `The register is full for this plan — 60 staff records…` | Said once; further new people skipped, updates applied. | See [plan and billing](/docs/account/plan-and-billing). |
|
||||
| `Row N: no catalogue items match…` or `several…` | Skipped. | Fill in `item` or `gender`. |
|
||||
| `Row N: size X not on Y` | Skipped. | Match the size's spelling. |
|
||||
| `Row N: opening “X” isn't a number…` | Size left alone. | Write a whole number. |
|
||||
| `X is already on Y · size Z…` | Code bound to another size, as a one-code-per-style list does. | One code per size. |
|
||||
| `X is the generated code for Y…` | Refused. | Use the printed label's code. |
|
||||
|
||||
## Limits
|
||||
|
||||
- 20,000 rows a file: `Import at most 20,000 rows at a time`.
|
||||
- 20 imports and backup restores together per person in 10 minutes: `Too many imports — wait a few minutes.`
|
||||
- Over 60 MB: `Request too large`.
|
||||
- An Issuer gets `Admin only`. A read-only facility gets the read-only message pointing to `Settings › Plan`.
|
||||
- Hosted Small holds 60 staff records (`PRICES.freeStaff`). Other plans and the Community edition have no ceiling.
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: Glossary
|
||||
section: reference
|
||||
order: 2
|
||||
summary: The words ThreadCount's screens use, in alphabetical order, each with a line of meaning and the page that explains it.
|
||||
role: Anyone
|
||||
keywords: glossary, terms, definitions, words, meaning, vocabulary, what does it mean
|
||||
---
|
||||
|
||||
## A–C
|
||||
|
||||
**Activity** — The screen listing every change in the facility, newest first, with who made it. Managed by [admins](/docs/account/users).
|
||||
|
||||
**Admin** — The [coordinator role](/docs/start/the-two-roles) that manages settings, the staff register, the catalogue, pricing, suppliers and departments.
|
||||
|
||||
**Back Order** — An order status for stock the supplier has not yet sent. See [receiving](/docs/stock/receiving-and-back-orders).
|
||||
|
||||
**Barcode** — The code bound to one size of one garment, so a scan finds that size. See [barcodes](/docs/stock/barcodes).
|
||||
|
||||
**Casual** — The FTE for someone with no fixed fraction; the [FTE table](/docs/people/groups-and-routes) leaves their kit to the manager.
|
||||
|
||||
**Catalogue** — The garments stocked, each with [sizes, SKU, supplier, cost, type and groups](/docs/stock/catalogue-sizes-and-cuts).
|
||||
|
||||
**Ceiling** — The most sets anyone may hold at once, 6 unless changed under `Settings › Issuing rules`, the same for every group. See [the entitlement rule](/docs/people/entitlement-rule).
|
||||
|
||||
**Collection code** — The 4-digit code on a bag waiting at the counter, read out at [hand-over](/docs/counter/pickup-call-list).
|
||||
|
||||
**Cost centre** — The finance code a department's issues are [charged to](/docs/reports/cost-centres).
|
||||
|
||||
**Cost centre override** — A [cost centre](/docs/reports/cost-centres) on one person's record, used instead of their department's.
|
||||
|
||||
## D–G
|
||||
|
||||
**Damage report** — A garment reported damaged; the replacement starts when it is [handed in](/docs/counter/exchanges-and-returns).
|
||||
|
||||
**Delivery round** — Requests going out to wards, grouped by ward and [signed for on screen](/docs/counter/delivery-rounds).
|
||||
|
||||
**Department** — A ward or unit, with its [cost centre](/docs/reports/cost-centres).
|
||||
|
||||
**Draft** — An order not yet placed with the supplier. See [the order list](/docs/stock/order-list).
|
||||
|
||||
**Either** — The uniform style offered [both cuts](/docs/stock/catalogue-sizes-and-cuts).
|
||||
|
||||
**FTE** — A person's combined employment fraction, such as 0.8, or Casual. See [groups and routes](/docs/people/groups-and-routes).
|
||||
|
||||
**FTE table** — The [route](/docs/people/groups-and-routes) where FTE proposes the starting kit: 5 sets at 1.0 and 0.9, 4 at 0.8 and 0.7, 3 at 0.6 and 0.5, 2 at 0.4 and 0.3, 1 at 0.2 and 0.1.
|
||||
|
||||
**Grace** — The 14 days after a trial or paid period ends, when changes are still accepted. See [plan and billing](/docs/account/plan-and-billing).
|
||||
|
||||
**Grandfathered** — A facility created before plans existed, [hosted free](/docs/account/plan-and-billing) with everything for as long as it exists.
|
||||
|
||||
**Group** — A staff group, such as Registered Nurse. Each is on one [route](/docs/people/groups-and-routes), and garments are tagged for the groups that wear them.
|
||||
|
||||
## H–M
|
||||
|
||||
**Hand-in** — Garments returned: good ones join the pre-loved pool, rags are counted for disposal. See [exchanges and returns](/docs/counter/exchanges-and-returns).
|
||||
|
||||
**Issue anyway** — The override for an issue past the ceiling, outside the person's group or not their uniform style, noted on the record. See [issue a garment](/docs/counter/issue-a-garment).
|
||||
|
||||
**Issuer** — The [coordinator role](/docs/start/the-two-roles) that issues stock, runs stocktakes and receives deliveries, and cannot edit a price or a past issue.
|
||||
|
||||
**Items (FY)** — What someone has drawn since 1 July. It feeds the [reports](/docs/reports/the-nine-reports) and never limits the counter.
|
||||
|
||||
**Kit check** — A facility-wide round asking people whether their locker matches the record; a shortfall is written off, never charged. See [the staff app](/docs/apps/staff-app).
|
||||
|
||||
**Manager** — The person, recorded by staff number, who [approves someone's requests](/docs/people/managers) and signs their order form.
|
||||
|
||||
**Manager approval** — The route with no starting kit, where the manager [approves each set](/docs/counter/manager-approvals).
|
||||
|
||||
## N–R
|
||||
|
||||
**Needs an approver** — Where a request waits under `Requests` when nobody is above the manager who [raised it](/docs/counter/requests-from-staff).
|
||||
|
||||
**Opening balance** — The count a size starts from before any movement. See [stocktakes](/docs/stock/stocktakes).
|
||||
|
||||
**Order list** — Under `Orders`, every size at or below its reorder level, topped up to twice the level less what is on order, grouped by supplier. See [the order list](/docs/stock/order-list).
|
||||
|
||||
**Pre-loved** — Good handed-in garments, reissued free, which count toward the ceiling like new ones. See [exchanges and returns](/docs/counter/exchanges-and-returns).
|
||||
|
||||
**Rag** — A handed-in garment counted for [disposal](/docs/counter/exchanges-and-returns).
|
||||
|
||||
**Read-only** — After grace: reports, exports, printing and the backup work and nothing is deleted, but changes are refused except for the plan, your own password and profile, and deleting your account. See [plan and billing](/docs/account/plan-and-billing).
|
||||
|
||||
**Reorder level** — The count at or below which a size joins the order list. See [reorder levels](/docs/stock/reorder-levels).
|
||||
|
||||
**Request** — Garments asked for in the staff app, numbered like `R-0001`, moving from Awaiting approval to Collected or Delivered. See [requests from staff](/docs/counter/requests-from-staff).
|
||||
|
||||
**Route** — How a group's garments are decided: FTE table, Starting kit or Manager approval. See [groups and routes](/docs/people/groups-and-routes).
|
||||
|
||||
## S
|
||||
|
||||
**Self-approved** — A request approved by someone who is [their own manager](/docs/people/managers).
|
||||
|
||||
**Set** — One top and one pair of trousers; the garment's type decides which half it is. See [the entitlement rule](/docs/people/entitlement-rule).
|
||||
|
||||
**Slip** — A printed collection or delivery slip, or the slip with a staff app code, which works once and expires after 14 days. See [slips and signatures](/docs/counter/slips-and-signatures).
|
||||
|
||||
**Starting kit** — The [route](/docs/people/groups-and-routes) giving sets on the first day, 3 by default, then more as needed.
|
||||
|
||||
**Stock on hand** — The live count of each size on the shelf. See [stocktakes](/docs/stock/stocktakes).
|
||||
|
||||
**Stock take** — A count of the shelf against the system figure, normal or blind. See [stocktakes](/docs/stock/stocktakes).
|
||||
|
||||
## T–Z
|
||||
|
||||
**Trial** — 30 days for a new hosted facility, no card taken. See [plan and billing](/docs/account/plan-and-billing).
|
||||
|
||||
**Uniform style** — The cut a person is offered, Men's, Women's or Either, plus everything unisex; blank offers every style. See [the staff register](/docs/people/staff-register).
|
||||
|
||||
**Variance** — The difference between a stock take's count and the system figure. See [stocktakes](/docs/stock/stocktakes).
|
||||
|
||||
**Waitlist** — A queue for a size not on the shelf; joining needs no approval. See [the staff app](/docs/apps/staff-app).
|
||||
|
||||
**Ward desk** — A flag on a staff record letting that person sign for bags a round leaves at their ward. See [delivery rounds](/docs/counter/delivery-rounds).
|
||||
|
||||
**Ward Requests** — The old name of `Requests`, the screen where the linen room works through [staff requests](/docs/counter/requests-from-staff).
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
title: Keyboard and scanner
|
||||
section: reference
|
||||
order: 3
|
||||
summary: Setting up a USB barcode scanner, the symbologies ThreadCount reads and prints, the keys the screens answer to, and how printing works.
|
||||
screen: Counter, Stock › Count, Stock › On hand
|
||||
role: Admin or Issuer
|
||||
keywords: usb scanner, keyboard wedge, enter, suffix, barcode, ean-13, code 128, keyboard, shortcut, escape, tab, print, labels, slip, pop-up
|
||||
---
|
||||
|
||||
## Setting up a USB scanner
|
||||
|
||||
ThreadCount has no scanner driver. A USB scanner in keyboard mode (keyboard wedge) types the code into whichever field has focus, and the field acts when it receives Enter.
|
||||
|
||||
1. **Set the scanner to keyboard mode.** Most are out of the box; the scanner's own manual has the setup barcode.
|
||||
2. **Set the suffix to Enter (carriage return).** A Tab suffix moves focus instead, and nothing is recorded.
|
||||
3. **Click into the scan field first.** Keystrokes that land anywhere else do nothing. No screen listens for a scan outside its field.
|
||||
4. **Scan a known garment to test.** On `Stock › Count` its count goes up by 1.
|
||||
|
||||
Spaces before and after the code are trimmed.
|
||||
|
||||
## Where a scan goes
|
||||
|
||||
| Screen | Field | What Enter does |
|
||||
|---|---|---|
|
||||
| `Counter` | `Scan barcode, then Enter`, under `2 · Scan items` | Adds 1 of that size to the pickup; a repeat scan adds another |
|
||||
| `Stock › Count` | `Scan barcode to count +1, then Enter`, focused on arrival | Adds 1 to that size's count |
|
||||
| `Stock › On hand › Scan to add` | `Scan with a USB scanner, or type the code and press Enter`, focused on open | Finds the garment, or offers to add it |
|
||||
| A garment's page, `Scan sizes` | The size prompt, focused on open | Binds the code to the chosen size |
|
||||
| A garment's page, a size's barcode field | The code | Saves it |
|
||||
|
||||
A code nobody has bound, or one bound to an archived garment, opens `Unknown barcode` on `Counter` and `Stock › Count`. An Admin picks the garment and size to bind it; an Issuer is told only an Admin can. See [barcodes](/docs/stock/barcodes).
|
||||
|
||||
## Formats
|
||||
|
||||
| Where | Formats |
|
||||
|---|---|
|
||||
| USB scanner | Whatever the scanner types. A binding keeps up to 64 characters. |
|
||||
| Camera, in the browser and the counter app | EAN-13, EAN-8, UPC-A, UPC-E, Code 128, Code 39, Code 93 |
|
||||
| Printed labels | EAN-13 for a valid 13-digit code, Code 128 for anything else |
|
||||
|
||||
`Generate barcodes` on a garment's page gives each size with no code a 13-digit EAN-13 starting `29`, the GS1 range reserved for use inside one organisation, so any scanner reads it.
|
||||
|
||||
At a window 780 pixels wide or narrower, a `SCAN` button sits at the bottom right. On `Counter` and `Stock › Count` it opens the camera for that screen; anywhere else it opens search with the camera running, to find a person, a garment or an order. It hides while a dialog is open. Which browsers can use the camera is on [scanning and browsers](/docs/apps/scanning-and-browsers).
|
||||
|
||||
## Keys the screens answer to
|
||||
|
||||
ThreadCount has no single-key shortcuts. These are the keys the screens handle.
|
||||
|
||||
| Key | Where | Does |
|
||||
|---|---|---|
|
||||
| Enter | The scan fields above | Records the scan |
|
||||
| Enter | `Settings › Issuing rules`, `New staff group` | Adds the group |
|
||||
| Enter | A `Rename` dialog, `New name` | Saves |
|
||||
| Enter | A garment's page, `Add a size` | Adds the size |
|
||||
| Escape | Any dialog | Closes it |
|
||||
| Tab, Shift+Tab | Any dialog | Moves round the dialog's controls without leaving it |
|
||||
| Down arrow | Staff record, `Manager` search | Moves from the search box to the first match |
|
||||
| Up and Down arrows | The manager matches | Move between names |
|
||||
| Escape | `Manager` search while changing | Cancels the change |
|
||||
|
||||
## Keys in this manual
|
||||
|
||||
The manual has its own keys, on the website at `/docs` and inside the app under `Help`.
|
||||
|
||||
| Key | Where | Does |
|
||||
|---|---|---|
|
||||
| / | Any manual page, when you are not typing in a field | Puts the cursor in the search box |
|
||||
| Up and Down arrows | The search results | Move between results |
|
||||
| Enter | The search results | Opens the highlighted page, at the matching section when the match was a heading |
|
||||
| Escape | The search box | Closes the results |
|
||||
|
||||
Every manual page also has `Print` and `Copy link` in the rail beside the page, on a wide enough screen. A printed manual page leaves off the section tree and the rail.
|
||||
|
||||
## Printing
|
||||
|
||||
Printing uses the browser's own print dialog. Two routes lead there.
|
||||
|
||||
- **A print page in a new tab** opens the dialog after half a second and keeps a `Print` button for another try. These are the collection or delivery slip (1 to 3 copies), the order form (`Print the form` on a staff record or a request), the supplier order sheet (`Print` in the order list, `Order sheet` on an order) and labels (`Print labels` on a garment's page).
|
||||
- **A print window** carries the document itself: `Print` on `Reports`, which prints the selected tab, `Print count sheet` on `Stock › Count`, `Print credit slip` on `Counter`, and the hand-in receipt. If the browser blocks it, ThreadCount says `Pop-up blocked — allow pop-ups for ThreadCount to print.`
|
||||
|
||||
The label sheet holds 6 labels to an A4 page. From a garment's page it prints one label per garment on hand for each size with a code, after you confirm the number. A single code prints 1 to 24 copies, 6 unless set.
|
||||
|
||||
The menu, the mobile bar and the `SCAN` button are left off a printed screen.
|
||||
|
||||
> **Careful** The counter app cannot print. A print page opened there says `This app can't print. Open this page in a browser — on the computer at the counter — to print it.`
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Cost centres
|
||||
section: reports
|
||||
order: 2
|
||||
summary: How an issue reaches a cost centre, why each issue keeps the price of the day it went out, and what moving a person between departments does to the reports.
|
||||
screen: Settings › Places & cost centres
|
||||
role: Admin
|
||||
keywords: cost centre, cost center, department, ward, override, price, unit cost, re-price, valuation, move staff, transfer, unallocated
|
||||
---
|
||||
|
||||
## Where the cost centre comes from
|
||||
|
||||
A cost centre belongs to a department, and a person belongs to a department. When the reports group an issue, they look up the person it was issued to and use, in this order:
|
||||
|
||||
1. **Their cost centre override**, if one is set on their staff record.
|
||||
2. **Their department's cost centre**, from `Settings › Places & cost centres`.
|
||||
|
||||
If neither gives a code, the issue falls under an em dash on Overview and under `UNALLOCATED` on the journal. Finance cannot post that line, so the Journal tab marks it; see [Journal export](/docs/reports/journal-export).
|
||||
|
||||
## Setting departments and codes
|
||||
|
||||
`Settings › Places & cost centres` lists each department or ward with its cost centre and the number of staff on it. An Admin can edit both boxes in place, and each change saves as you type. To add one, enter a name such as `Ward 4A` and a code such as `RGH-4010`, then press `Add`; both are required.
|
||||
|
||||
- A name already on the list is refused, including when you rename a department to it.
|
||||
- Renaming a department moves its staff and any orders filed under the old name to the new name.
|
||||
- A department with staff on it cannot be removed.
|
||||
- Two departments may share a code. The journal then gives them one line.
|
||||
|
||||
On a staff record, `Cost centre override` offers the codes already on your departments, or `None — derived from department`. The profile shows the result followed by `— override` or `— from department`. See [Staff register](/docs/people/staff-register).
|
||||
|
||||
## The price on the day
|
||||
|
||||
When a garment is issued, the issue stores the catalogue cost of that garment at that moment as its unit cost. This is true at the counter, on a pickup, and when a delivery goes straight to the person who ordered it. An issue from the pre-loved pool stores $0.
|
||||
|
||||
In an exchange, the garment that came back keeps its original unit cost, and the replacement stores the catalogue cost on the day of the exchange. A partial return splits the row, and both halves keep the unit cost. See [Exchanges and returns](/docs/counter/exchanges-and-returns).
|
||||
|
||||
Every issued figure on Reports is quantity times that stored unit cost. An issue with no stored cost (a row from before costs were stored) falls back to today's catalogue cost.
|
||||
|
||||
## Why nothing is re-priced
|
||||
|
||||
Changing a garment's cost in the catalogue updates the catalogue and records the old and new cost with your name. It does not touch any issue. A journal for a month finance has already posted totals the same after a supplier raises its prices.
|
||||
|
||||
Three figures are not price-on-the-day. Valuation and Shrinkage use the current catalogue cost, and so does the value saved on Pre-loved. Those figures move when a catalogue cost changes.
|
||||
|
||||
## Moving a person between departments
|
||||
|
||||
The cost centre is not stored on the issue. The reports work it out from the staff record each time the screen opens. When you change a person's department or cost centre override, every issue they have ever had moves to the new cost centre, including issues in months already closed. Changing a department's code moves the issues of everyone on that department in the same way.
|
||||
|
||||
> **Careful** Changing a department, an override or a department's code re-files that history in every month, so a reprinted journal for a posted month will no longer match what finance posted.
|
||||
|
||||
If a person transfers at month end, print the month-end pack and export the journal first, then change the record. The unit costs stay as they were.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Department | Name and cost centre; a rename also renames it on staff and orders | Edit the boxes back |
|
||||
| Staff record | Department and cost centre override | Edit the record back |
|
||||
| Catalogue cost | New catalogue cost and a cost change entry; issues untouched | Enter the old cost |
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: Journal export
|
||||
section: reports
|
||||
order: 3
|
||||
summary: One debit line per cost centre for the month, its exact CSV layout, where the GL account is set, and how to trace a line back to the issues.
|
||||
screen: Reports › Journal
|
||||
role: Admin or Issuer
|
||||
keywords: journal, GL, general ledger, account code, finance, debit, CSV, export, posting, month end, reconcile, cost centre, unallocated
|
||||
---
|
||||
|
||||
## What the journal is
|
||||
|
||||
`Reports › Journal` turns the month's issues into one debit line per cost-centre code. It starts from the cost centre table on Overview, drops cost centres with no items this month, and adds together departments that share a code. Lines are sorted by debit, largest first, and a `TOTAL` row closes the table.
|
||||
|
||||
The journal counts exactly what Overview counts: issues dated in the month, less garments returned as `Returned - Good`, less issues from the pre-loved pool, each at the unit cost stored when it was issued. Its total equals Overview's issued value for the month. See [The nine reports](/docs/reports/the-nine-reports).
|
||||
|
||||
The export has debit lines only. There is no credit line and no date column.
|
||||
|
||||
## The columns
|
||||
|
||||
Press `Export journal CSV` on the tab, or `Export CSV` in the header. The file is `threadcount-journal-YYYY-MM.csv`, for example `threadcount-journal-2026-08.csv`.
|
||||
|
||||
| Column | Holds |
|
||||
|---|---|
|
||||
| Cost Centre | The code, or `UNALLOCATED` |
|
||||
| Department | The department name; several are joined with ` / ` |
|
||||
| GL Account | The GL account from Settings, the same on every line |
|
||||
| Description | The description prefix, a space, then the month |
|
||||
| Items | Items issued, a whole number |
|
||||
| Debit | The value to 2 decimal places, with no dollar sign or commas |
|
||||
|
||||
The first row is the header and the last row is `TOTAL`, with the item count and the debit total and the middle columns blank:
|
||||
|
||||
```
|
||||
"Cost Centre","Department","GL Account","Description","Items","Debit"
|
||||
"RGH-4010","Ward 4A","631020","Uniform issues August 2026",42,"1386.00"
|
||||
"RGH-5090","Ward 5C / Theatres","631020","Uniform issues August 2026",17,"602.50"
|
||||
"TOTAL","","","",59,"1988.50"
|
||||
```
|
||||
|
||||
Text is wrapped in double quotes, and so is the debit. Text that begins with a space, `=`, `+`, `-` or `@` gets a leading apostrophe, so a spreadsheet does not read it as a formula. The file is UTF-8 with a byte-order mark.
|
||||
|
||||
## The GL account and description
|
||||
|
||||
An Admin sets both under `Settings › Facility`, in `Finance & reports`:
|
||||
|
||||
- `GL account`, up to 40 characters. While it is blank, the journal shows `—` in its place.
|
||||
- `Journal description prefix`, up to 120 characters. While it is blank, the journal uses `Uniform issues`.
|
||||
|
||||
The month is added after the prefix as a full month name and year, so `Uniform issues` becomes `Uniform issues August 2026`. There is one GL account per facility.
|
||||
|
||||
## Choosing the period
|
||||
|
||||
The journal covers one calendar month, the one in the month picker at the top of `Reports`. There is no custom date range. An issue belongs to the month of its date, and that date is the day in the facility's `Time zone` under `Settings › Facility` when it was recorded.
|
||||
|
||||
`Print` on the Journal tab prints the same table on A4, headed `End-of-month journal` and the month.
|
||||
|
||||
## UNALLOCATED lines
|
||||
|
||||
An issue to someone with no cost centre override, whose department has no code, lands on `UNALLOCATED`. The Journal panel is then marked, and its footer tells you to set the person's department or override on People before posting. Fix the record, and the line moves to the right code the next time the screen draws. See [Cost centres](/docs/reports/cost-centres).
|
||||
|
||||
## Reconciling a line
|
||||
|
||||
1. **Pick the month and open Journal.**
|
||||
2. **Press the cost centre code.** A window opens listing the issues behind that line: date, staff, item, size, quantity, unit cost and value, with a total that equals the line's debit.
|
||||
3. **Press `Export CSV` in that window** to give finance the detail. The file is `threadcount-cost-centre-rgh-4010-2026-08.csv`, with a first line naming the cost centre and the month, then the columns `Date, Staff, Item, Size, Qty, Unit cost, Value` and a `TOTAL` row.
|
||||
|
||||
The detail is counted from the same issues as the line each time it opens, so the two agree. Both follow each person's cost centre as it is now, not as it was in that month.
|
||||
|
||||
> **Careful** Moving a person to another department re-files their past issues, so export the journal before you change anyone's department at month end.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Month-end pack
|
||||
section: reports
|
||||
order: 4
|
||||
summary: One printed document for finance with the month's summary figures, cost centres, journal and top stock, plus shrinkage, exceptions and approvals when there are any.
|
||||
screen: Reports
|
||||
role: Admin or Issuer
|
||||
keywords: month-end pack, month end, EOM, finance pack, print, summary, journal, shrinkage, exceptions, approvals, monthly routine, close
|
||||
---
|
||||
|
||||
## What the pack is
|
||||
|
||||
`Month-end pack` is a button in the header of `Reports`. It prints one A4 document for the month in the month picker, titled `Month-end pack` and the month, for example `Month-end pack — August 2026`. The line under the title gives the facility name, the location, today's date and the coordinator.
|
||||
|
||||
The pack is print only. It has no CSV of its own; the journal CSV comes from the Journal tab, see [Journal export](/docs/reports/journal-export). Printing it writes nothing.
|
||||
|
||||
## What it contains
|
||||
|
||||
Four sections are always there:
|
||||
|
||||
1. **Summary.** The six figures below.
|
||||
2. **Cost centre summary.** One row per journal line: code, department, items and value, with a `TOTAL` row.
|
||||
3. **Journal.** One debit per cost centre, headed with the GL account: code, description and debit.
|
||||
4. **Top stock.** The 10 garments with the most items issued in the month, with quantity and value.
|
||||
|
||||
Three sections appear only when they have rows:
|
||||
|
||||
- **Shrinkage.** Each stocktake filed from 1 July to the end of the month: date, counted by, variances, net units and net value.
|
||||
- **Staff exceptions.** Staff, cost centre and the flag, as on the Exceptions tab.
|
||||
- **Uncollected manager's approvals.** Staff, approved by, and sets remaining.
|
||||
|
||||
The pack does not include the supplier table, the pre-loved tables, the totals by staff group or staff member, the financial year table, or the valuation line by line. Print those from their tabs; see [The nine reports](/docs/reports/the-nine-reports).
|
||||
|
||||
## The summary figures
|
||||
|
||||
| Figure | Counted as |
|
||||
|---|---|
|
||||
| Issued value | Month's issues at the unit cost stored on each |
|
||||
| Items issued | Items in those issues |
|
||||
| Supplier orders placed | Orders dated in the month that were placed, less back orders |
|
||||
| Stock on hand value | Units on hand today at current catalogue cost |
|
||||
| Shrinkage (FY to end of month) | Net stocktake variance at current catalogue cost |
|
||||
| Stocktakes counted (FY) | Stocktakes filed from 1 July to the end of the month |
|
||||
|
||||
Issues exclude garments returned as `Returned - Good` and issues from the pre-loved pool. Stock on hand value is always as at today, and so are the approvals, even when you print a past month.
|
||||
|
||||
## Running and printing it
|
||||
|
||||
1. **Open `Reports` and pick the month.**
|
||||
2. **Press `Month-end pack`.** A new window opens with the document and the print dialog.
|
||||
3. **Print from the dialog.** If nothing opens, allow pop-ups for ThreadCount and press the button again.
|
||||
|
||||
A pack for a closed month can be printed again at any time. Issued figures use the unit cost each issue was stored with, and year-to-date figures stop at the end of that month. The cost centre on each line follows each person's staff record as it is today; see [Cost centres](/docs/reports/cost-centres).
|
||||
|
||||
## A monthly routine
|
||||
|
||||
In the first days of the new month:
|
||||
|
||||
1. **Pick last month and open Journal.** If a line reads `UNALLOCATED`, set the person's department or cost centre override on the [Staff register](/docs/people/staff-register), then check the line has gone.
|
||||
2. **Open Exceptions.** Read each override and anyone at the monthly threshold before finance asks.
|
||||
3. **Open Approvals.** Follow up sets approved but not collected; see [Manager approvals](/docs/counter/manager-approvals).
|
||||
4. **Print the month-end pack.**
|
||||
5. **Export the journal CSV** and send it to finance with the pack.
|
||||
6. **Only then move anyone between departments.** A move re-files that person's past issues.
|
||||
|
||||
Stocktakes are counted in the pack by the date they were filed. File the month's count before the month ends if you want it in that month's shrinkage. Because the stock on hand value is as at today, print the pack early in the month for a figure close to month end. See [Stocktakes](/docs/stock/stocktakes).
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title: The nine reports
|
||||
section: reports
|
||||
order: 1
|
||||
summary: The nine reports on the three Reports tabs, what each one counts and leaves out, the period it covers, and how to print or export it.
|
||||
screen: Reports
|
||||
role: Admin or Issuer
|
||||
keywords: reports, finance, overview, journal, top stock, valuation, shrinkage, exceptions, suppliers, approvals, pre-loved, month, print, CSV, export
|
||||
---
|
||||
|
||||
## How the screen works
|
||||
|
||||
`Reports` has three tabs, `Spend`, `Stock` and `People`, and one month picker. The nine reports sit on them as panels: Spend holds the Overview figures and tables, the Journal and the financial year; Stock holds Valuation, Shrinkage, Top stock and Supplier spend; People holds Exceptions, Approvals outstanding and Pre-loved. The picker lists the current month, every month with an issue or an order in it, and the 5 months before the month you have chosen. Every report reads the month you pick, except Valuation and Approvals, which describe today.
|
||||
|
||||
`Export CSV` in the header downloads the main report of the tab you are on: cost centres on Spend, Valuation on Stock and Exceptions on People. Most panels also carry their own `CSV` and `Print`; `Print` opens an A4 page in a new window, headed with the facility, location, today's date and the coordinator. `Month-end pack` in the header prints a separate document; see [Month-end pack](/docs/reports/month-end-pack).
|
||||
|
||||
On Spend, each cost-centre code is a button that opens the issues behind its figure, with their own `Export CSV`.
|
||||
|
||||
## The reports at a glance
|
||||
|
||||
| Report (tab) | Answers | A row is | Period |
|
||||
|---|---|---|---|
|
||||
| Overview (Spend) | What did we issue, and to whom? | A cost centre and department | Month, previous month, financial year |
|
||||
| Journal (Spend) | What does finance post? | One cost centre | Month |
|
||||
| Top stock (Stock) | What goes out most? | A garment, top 15 | Month, financial year to date |
|
||||
| Valuation (Stock) | What is on the shelf worth? | A garment with stock on hand | Today |
|
||||
| Shrinkage (Stock) | Is stock going missing? | A filed stocktake | Financial year to the end of the month |
|
||||
| Exceptions (People) | Whose issues need a look? | A staff member with a flag | Month |
|
||||
| Suppliers (Stock) | What did we order, from whom? | A supplier | Month |
|
||||
| Approvals (People) | Which approvals are uncollected? | An approval with sets remaining | Today |
|
||||
| Pre-loved (People) | What did the pool save? | A pool issue, a hand-in, a garment in the pool | Month, and the pool today |
|
||||
|
||||
## What counts as issued
|
||||
|
||||
An issue counts when its date falls in the month and the garment has not come back as `Returned - Good`. A garment returned in any other condition still counts. Issues from the pre-loved pool are left out of every issued figure and reported only on Pre-loved.
|
||||
|
||||
The financial year starts on 1 July. Every year-to-date figure stops at the end of the chosen month, so a pack reprinted for a closed month does not pick up later months. Each issue is valued at the unit cost stored on it when it was issued; see [Cost centres](/docs/reports/cost-centres).
|
||||
|
||||
## Overview and Journal
|
||||
|
||||
The Spend tab opens with three figures: issued value against the month before, garments issued with how many of them were pre-loved, and the value ordered from suppliers with the number of orders. Below them are issued value by cost centre, totals by staff group and by staff member, a 6-month bar chart, the Journal and a financial year table by month. Each bar is a button that changes the month.
|
||||
|
||||
Journal folds the cost centre table into one debit per cost-centre code. It is covered in [Journal export](/docs/reports/journal-export).
|
||||
|
||||
## Top stock, Valuation and Shrinkage
|
||||
|
||||
Top stock ranks the 15 garments with the most items issued in the month, with their value, their share of the month's items, and their quantity for the financial year.
|
||||
|
||||
Valuation counts units on hand for every garment and size today, whatever month is picked, and prices them at the current catalogue cost. Garments with no units are left out. A size below zero counts as 0, and the panel says how many sizes are negative. The pre-loved pool is not in this figure.
|
||||
|
||||
Shrinkage lists every stocktake filed from 1 July to the end of the month: lines counted, variances, net units (counted less expected) and net value at the current catalogue cost. Counts of the pre-loved pool are left out. See [Stocktakes](/docs/stock/stocktakes).
|
||||
|
||||
## Exceptions and Approvals
|
||||
|
||||
Exceptions names a staff member when, in that month, they were issued garments on an override past the sets ceiling, outside their staff group, or not in their uniform style. It also names anyone whose items for the month reach `Exception threshold (items/month)` in `Settings › Facility`. The ceiling is `Ceiling, every group (sets)`, and 6 when it is blank; the threshold is 10 when it is blank. Rows with an override come first. `Items (FY)` is a running tally, and nobody is flagged on it; see [The entitlement rule](/docs/people/entitlement-rule).
|
||||
|
||||
Approvals lists every manager's approval with sets not yet collected, whenever it was given. It does not follow the month picker.
|
||||
|
||||
## Suppliers and Pre-loved
|
||||
|
||||
Suppliers totals orders dated in the month that were placed with the supplier. Drafts, cancelled orders and back orders are left out, so a short line is not counted twice. A delivered line is valued at the cost recorded on its receipt, and an undelivered line at catalogue cost. The invoice column collects the invoice numbers on the order and on its receipts.
|
||||
|
||||
Pre-loved lists issues from the pool in the month with the value saved at catalogue cost, hand-ins in the month split into good and rag with whether they were credited, and what is in the pool today at $0 book value.
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: Backups and restore
|
||||
section: selfhost
|
||||
order: 4
|
||||
summary: Nightly database dumps and photo copies from the compose file's own services and volumes, the in-app export as a second copy, and how to restore and test a restore.
|
||||
role: Self-hosting admin
|
||||
keywords: backup, restore, pg_dump, pg_restore, database, photos, signatures, volume, cron, export, import, disaster recovery, test restore
|
||||
---
|
||||
|
||||
## What has to be kept
|
||||
|
||||
A Community instance keeps its data in two Docker volumes. Back up both, together.
|
||||
|
||||
| Volume | Mounted at | Holds |
|
||||
|---|---|---|
|
||||
| `threadcount_db` | `/var/lib/postgresql/data` in `db` | Every record: catalogue, stock, staff, issues, orders, requests, users |
|
||||
| `threadcount_photos` | `/data/photos` in `app` | Signatures and damage photographs |
|
||||
|
||||
The names come from `docker-compose.yml`: the project is named `threadcount`, and its volumes are `db` and `photos`.
|
||||
|
||||
Photos are not in the database. Each one is a file at `<facility id>/<photo id>.jpg` (or `.png`) under `/data/photos`, and the database holds only that path. A database dump without the photos restores every record but none of the signatures or photographs.
|
||||
|
||||
## Nightly dumps
|
||||
|
||||
The checkout includes `docker/backup.sh`. Run it from the checkout and give it a destination directory:
|
||||
|
||||
```sh
|
||||
cd /srv/threadcount
|
||||
docker/backup.sh /srv/backups/threadcount
|
||||
```
|
||||
|
||||
Each run writes a dated directory, for example `2026-09-15-033001`, containing:
|
||||
|
||||
- `threadcount.dump`: the database as a custom-format `pg_dump`, taken inside `db` as the `threadcount` user
|
||||
- `photos.tgz`: the photos directory copied out of `app`
|
||||
|
||||
It keeps the newest 14 directories and deletes older ones. Run it nightly from cron:
|
||||
|
||||
```
|
||||
30 3 * * * cd /srv/threadcount && docker/backup.sh /srv/backups/threadcount >> /var/log/threadcount-backup.log 2>&1
|
||||
```
|
||||
|
||||
> **Careful** A backup on the same disk as the volumes is lost with them. Copy the backup directory to another machine.
|
||||
|
||||
## The export as a second copy
|
||||
|
||||
An admin can download the whole facility as one JSON file from `Settings › Data` with Export backup. It needs no access to the server's command line, and it can be imported on another server.
|
||||
|
||||
| Part | In the export |
|
||||
|---|---|
|
||||
| All facility records | Yes |
|
||||
| Photos | The newest ones only: at most 2000 photos and 40 MB of image data. The screen says how many were left out. |
|
||||
| Users (admins and issuers) | No |
|
||||
| Staff app logins | No. A restore keeps the existing logins and re-attaches them by staff number. |
|
||||
|
||||
Import backup on the same screen replaces all of that facility's data with the file's. Users are kept. See [export and backup](/docs/account/export-and-backup).
|
||||
|
||||
Because it leaves out older photos and users, the export is a second copy, not a replacement for the dump.
|
||||
|
||||
## Restore from a dump
|
||||
|
||||
This replaces everything on the server with the backup. Choose the backup directory first; these steps use `2026-09-15-033001`.
|
||||
|
||||
1. **Extract the photos.**
|
||||
|
||||
```sh
|
||||
cd /srv/backups/threadcount/2026-09-15-033001
|
||||
tar -xzf photos.tgz
|
||||
```
|
||||
|
||||
2. **Stop the stack and remove both volumes.**
|
||||
|
||||
```sh
|
||||
cd /srv/threadcount
|
||||
docker compose down
|
||||
docker volume rm threadcount_db threadcount_photos
|
||||
```
|
||||
|
||||
3. **Start only the database, then load the dump.**
|
||||
|
||||
```sh
|
||||
docker compose up -d db
|
||||
docker compose exec -T db pg_restore -U threadcount -d threadcount --clean --if-exists < /srv/backups/threadcount/2026-09-15-033001/threadcount.dump
|
||||
```
|
||||
|
||||
4. **Start everything.** `migrate` runs first and finds nothing to apply that the dump does not already have.
|
||||
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
5. **Put the photos back and give them to the app's user.**
|
||||
|
||||
```sh
|
||||
docker compose cp /srv/backups/threadcount/2026-09-15-033001/photos app:/data/
|
||||
docker compose exec -u root app chown -R threadcount:threadcount /data/photos
|
||||
```
|
||||
|
||||
Restore onto the release the dump was taken from, or a later one. Migrations only go forwards.
|
||||
|
||||
> **Careful** `docker volume rm` deletes the live data. Take a fresh backup first if the current data might still be needed.
|
||||
|
||||
## Test a restore
|
||||
|
||||
A backup that has never been restored is not proven. Restore into a second, separate stack on the same server, under another project name and port, so the live instance is untouched:
|
||||
|
||||
```sh
|
||||
cd /srv/threadcount
|
||||
APP_PORT=3100 docker compose -p tcrestore up -d db
|
||||
docker compose -p tcrestore exec -T db pg_restore -U threadcount -d threadcount --clean --if-exists < /srv/backups/threadcount/2026-09-15-033001/threadcount.dump
|
||||
APP_PORT=3100 docker compose -p tcrestore up -d --build
|
||||
curl -fsS http://127.0.0.1:3100/api/health
|
||||
```
|
||||
|
||||
Then check what came back:
|
||||
|
||||
- **Sign in.** Forward the port with `ssh -L 3100:127.0.0.1:3100` and open `http://localhost:3100` on your own machine.
|
||||
- **Compare the counts.** Check the tiles on `Settings › Data` against the live instance.
|
||||
|
||||
When you are done, remove the test stack and its volumes:
|
||||
|
||||
```sh
|
||||
docker compose -p tcrestore down -v
|
||||
```
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: Configuration reference
|
||||
section: selfhost
|
||||
order: 6
|
||||
summary: Every environment variable, whether it is required, its default and what it does, with the hosted-only ones marked.
|
||||
role: Self-hosting admin
|
||||
keywords: configuration, environment, variables, env, .env, settings, reference, session secret, smtp, turnstile, signups disabled, app port, edition, hosted only
|
||||
---
|
||||
|
||||
## How settings are read
|
||||
|
||||
Settings go in `.env` in the checkout. `docker-compose.yml` passes the whole file to the `app` container, then sets five values itself, and those win over `.env`:
|
||||
|
||||
| Variable | Set by compose to |
|
||||
|---|---|
|
||||
| `DATABASE_URL` | The bundled `db` service, using `POSTGRES_PASSWORD` |
|
||||
| `EDITION` | `community` |
|
||||
| `PHOTO_DIR` | `/data/photos` |
|
||||
| `PORT` | `3000` |
|
||||
| `HOSTNAME` | `0.0.0.0` |
|
||||
|
||||
Variables starting `NEXT_PUBLIC_` are compiled into the app when the image is built. The build does not read `.env`: compose passes only `NEXT_PUBLIC_SITE_URL` and `NEXT_PUBLIC_TURNSTILE_SITEKEY` into it. Any other `NEXT_PUBLIC_` variable in `.env` has no effect on a Docker install. A change to either of those two needs `docker compose up -d --build`; any other change needs `docker compose up -d`.
|
||||
|
||||
The repository's `.env.example` lists the variables the Community edition reads. The tables below also list the ones only threadcount.tech uses, marked hosted only, so you know they can stay blank.
|
||||
|
||||
## Required
|
||||
|
||||
| Variable | Default | What it does |
|
||||
|---|---|---|
|
||||
| `SESSION_SECRET` | `change-me` | Signs every session cookie. The server refuses to start with the placeholder or with none. Make one with `openssl rand -base64 48`. |
|
||||
| `POSTGRES_PASSWORD` | none | The bundled database's password. Compose refuses to start without it. |
|
||||
| `NEXT_PUBLIC_SITE_URL` | `http://localhost:3000` | The address people open. Every link in an email is built from it. Build-time. |
|
||||
| `EDITION` | none | `community`. Turns off plans, the staff ceiling, the demo and reporting to ThreadCount, and makes Turnstile optional. |
|
||||
| `DATABASE_URL` | set by compose | The Postgres connection. Required outside compose. |
|
||||
|
||||
## Mail
|
||||
|
||||
See [email](/docs/selfhost/email).
|
||||
|
||||
| Variable | Default | What it does |
|
||||
|---|---|---|
|
||||
| `SMTP_HOST` | none | Mail server. Mail is on only when this, `SMTP_USER` and `SMTP_PASS` are all set. |
|
||||
| `SMTP_PORT` | `587` | `465` connects with TLS from the start. |
|
||||
| `SMTP_USER` | none | Mail server login |
|
||||
| `SMTP_PASS` | none | Mail server password |
|
||||
| `SMTP_FROM` | `SMTP_USER` | The From line |
|
||||
| `CONTACT_TO` | none | Hosted only. Where the website's contact form is delivered. |
|
||||
|
||||
## Switches and the server
|
||||
|
||||
| Variable | Default | What it does |
|
||||
|---|---|---|
|
||||
| `SIGNUPS_DISABLED` | open | `1` hides facility sign-up and refuses the sign-up endpoint. |
|
||||
| `APP_PORT` | `3000` | The port on the server the app is published on. Compose reads it; the container always listens on 3000. |
|
||||
| `PHOTO_DIR` | set by compose | Where signatures and photos are written. Back it up with the database. |
|
||||
| `TURNSTILE_SECRET` | none | Cloudflare Turnstile on sign-in, sign-up and password reset. Enforced only when set. |
|
||||
| `NEXT_PUBLIC_TURNSTILE_SITEKEY` | none | Turnstile's site key. Build-time. Set both or neither. |
|
||||
| `TURNSTILE_OPTIONAL` | none | `1` lets production run without Turnstile. For local tests; a Community instance does not need it. |
|
||||
| `DB_POOL_MAX` | the driver's default | Local development only. `1` makes every database call wait for the one before. Never set it on a server. |
|
||||
|
||||
## Documents, errors, statistics and chat
|
||||
|
||||
These are all `NEXT_PUBLIC_` variables, so as the first section explains, they have no effect on a Docker install today.
|
||||
|
||||
| Variable | Default | What it does |
|
||||
|---|---|---|
|
||||
| `NEXT_PUBLIC_TERMS_URL` | none | Your terms page, linked from the staff sign-in and account screens. With none, no link shows. |
|
||||
| `NEXT_PUBLIC_PRIVACY_URL` | none | Your privacy notice, linked the same way |
|
||||
| `NEXT_PUBLIC_GLITCHTIP_DSN` | none | Your own GlitchTip or other Sentry-protocol address for error reports. With none, nothing is reported. |
|
||||
| `NEXT_PUBLIC_RELEASE` | none | A label stamped on error reports; also shown as `version` at `/api/app-info` when there is no `COMMUNITY_VERSION` file |
|
||||
| `NEXT_PUBLIC_UMAMI_SRC` | none | Your own Umami tracker script. With none, no statistics are sent. |
|
||||
| `NEXT_PUBLIC_UMAMI_SITE_ID` | none | Umami site id |
|
||||
| `NEXT_PUBLIC_UMAMI_APP_ID` | none | Umami id for the app |
|
||||
| `NEXT_PUBLIC_CHATWOOT_URL` | none | Your own Chatwoot. With this and the token set, a chat widget shows in the coordinator app. |
|
||||
| `NEXT_PUBLIC_CHATWOOT_TOKEN` | none | Chatwoot website token |
|
||||
|
||||
## Hosted only
|
||||
|
||||
Nothing in the Community edition reads these. Leave them blank.
|
||||
|
||||
| Variable | Used on threadcount.tech for |
|
||||
|---|---|
|
||||
| `JACKSON_URL`, `JACKSON_API_KEY` | Single sign-on for facilities |
|
||||
| `CF_ACCESS_TEAM_DOMAIN`, `CF_ACCESS_AUD` | Sign-in to ThreadCount's own staff tools |
|
||||
| `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `STRIPE_PRICE_MONTHLY`, `STRIPE_PRICE_ANNUAL`, `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` | Card payments |
|
||||
| `INVOICE_ENTITY`, `INVOICE_ABN` | Who invoices hosted plans |
|
||||
| `PLANS_LIVE` | Forcing plans on. Ignored when `EDITION=community`. |
|
||||
| `DEMO_DISABLED`, `DEMO_RESET_TOKEN` | The public demo facility |
|
||||
| `ANDROID_APP_FINGERPRINTS_COUNTER`, `ANDROID_APP_FINGERPRINTS_STAFF` | Android App Links for ThreadCount's own Play apps |
|
||||
| `LISTMONK_URL`, `LISTMONK_LIST_UUID` | The product-update mailing list |
|
||||
| `CHATWOOT_URL`, `CHATWOOT_API_TOKEN`, `CHATWOOT_ACCOUNT_ID`, `CHATWOOT_INBOX_ID` | Filing contact-form messages in the helpdesk |
|
||||
|
||||
threadcount.tech's own settings file has four more variables, for its internal administration. The Community edition does not contain that code.
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: Email
|
||||
section: selfhost
|
||||
order: 5
|
||||
summary: The SMTP settings, every email the product sends, what each screen does when no mail is configured, and how to test it.
|
||||
role: Self-hosting admin
|
||||
keywords: email, mail, smtp, password reset, approval link, notifications, ready to collect, supplier order, no-reply, from address, test email
|
||||
---
|
||||
|
||||
## The settings
|
||||
|
||||
Email is optional. It is set with five variables in `.env`:
|
||||
|
||||
| Setting | Required for mail | What it does |
|
||||
|---|---|---|
|
||||
| `SMTP_HOST` | Yes | Your mail server's hostname |
|
||||
| `SMTP_PORT` | No | Defaults to `587`. On `465` the connection uses TLS from the start; on any other port it starts plain and upgrades if the server offers it. |
|
||||
| `SMTP_USER` | Yes | The login for the mail server |
|
||||
| `SMTP_PASS` | Yes | The password for that login |
|
||||
| `SMTP_FROM` | No | The From line, e.g. `"ThreadCount <no-reply@example.health>"`. If blank, `SMTP_USER` is used. |
|
||||
|
||||
Mail counts as configured only when `SMTP_HOST`, `SMTP_USER` and `SMTP_PASS` are all set. A mail server that needs no login cannot be used.
|
||||
|
||||
These are read while the app runs, not when it is built, so a change needs a restart but no rebuild:
|
||||
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Links in emails are built from `NEXT_PUBLIC_SITE_URL`, which is compiled in. If the links are wrong, fix that setting and rebuild with `docker compose up -d --build`.
|
||||
|
||||
## What is sent
|
||||
|
||||
| Email | Sent to | When |
|
||||
|---|---|---|
|
||||
| Facility set up | The person who signed up | A facility is created |
|
||||
| Password reset | An admin or issuer | They ask on the sign-in page. The link works once and expires in 1 hour. |
|
||||
| Uniform request needing approval | The manager, with a link to approve | A request is raised in the staff app or at the counter, or moved to another manager |
|
||||
| Decision | The person the request is for | A manager approves or declines, or the linen room withdraws the request |
|
||||
| Ready to collect, or coming on the round | The person the request is for | The linen room marks the bag ready or puts it on a delivery round |
|
||||
| Waitlist offer | The person on the waitlist | A garment is offered to them, with the time it is held until |
|
||||
| Supplier order | The supplier's email under `Settings › Catalogue & suppliers` | An admin emails a raised order. Replies go to that admin's address. |
|
||||
|
||||
Staff notices go only to people whose staff app login has an email address. See [the staff app](/docs/apps/staff-app) and [requests from staff](/docs/counter/requests-from-staff).
|
||||
|
||||
When an admin adds a user, the product does not email them their password.
|
||||
|
||||
## With no mail configured
|
||||
|
||||
Nothing is sent, and the log records `[mail] no SMTP configured — not sending:` followed by the subject. The work itself is still recorded.
|
||||
|
||||
- **Sign-up.** The facility is created. The screen says no mail is configured, so the address has not been checked.
|
||||
- **Requests and decisions.** The request is raised and the decision is recorded. The screens report that nobody was emailed, rather than that the manager or wearer was told.
|
||||
- **Supplier orders.** The order is not emailed. The screen says "Email is not set up on this server — print the order instead."
|
||||
- **Password reset.** No link is sent, but the sign-in page still shows "Reset link sent". The only way back in is another admin setting a new password under `Settings › People & sign-in`.
|
||||
|
||||
> **Careful** Without mail, a facility whose only admin forgets their password cannot get back in through the product. Keep a second admin.
|
||||
|
||||
## When sending fails
|
||||
|
||||
If mail is configured but the server refuses a message, the action that caused the email still succeeds and `[mail] send failed:` is logged with the reason. Emailing a supplier order is the exception: the screen says the email could not be sent and the order is not marked as emailed.
|
||||
|
||||
## Test it
|
||||
|
||||
1. **Restart after setting the variables.** Run `docker compose up -d`.
|
||||
2. **Ask for a password reset for your own address.** On the sign-in page, enter your email and use the forgot-password link.
|
||||
3. **Check the inbox and the log.**
|
||||
|
||||
```sh
|
||||
docker compose logs app | grep '\[mail\]'
|
||||
```
|
||||
|
||||
If a reset email arrives and there is no `[mail]` line, mail works. At most 4 reset emails go to one address in an hour. Check that the link in the email starts with your own address, not `http://localhost:3000`.
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
title: First run
|
||||
section: selfhost
|
||||
order: 2
|
||||
summary: The first sign-up creates the facility and its admin; then groups, data, a second admin, closing sign-ups, and what the Community edition leaves out.
|
||||
screen: Settings
|
||||
role: Self-hosting admin
|
||||
keywords: first run, sign up, create account, facility, admin, staff groups, import, second admin, signups disabled, community, hosted, differences
|
||||
---
|
||||
|
||||
## Create the facility
|
||||
|
||||
There is no default username or password. Whoever creates an account first creates a facility and becomes its admin.
|
||||
|
||||
1. **Open your address.** `/` sends you to the sign-in page at `/auth`.
|
||||
2. **Choose to create the facility's account.** Sign-up is three steps.
|
||||
3. **Step 1, You.** Your first and last name, your work email and a password of at least 8 characters. The email is where a password reset goes, so it has to be right.
|
||||
4. **Step 2, Your facility.** The facility name, plus two optional answers. The setting (hospital, aged care or community) chooses a starting list of staff groups. The state sets the time zone that counts and month-end use.
|
||||
5. **Step 3, Confirm.** You are signed in as the facility's admin.
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Facility | Created with your facility name | Delete the account under `Settings › People & sign-in` |
|
||||
| User | You, role Admin, title Uniform Coordinator | Edit under `Settings › People & sign-in` |
|
||||
|
||||
The address you typed is not verified. If mail is set up, a welcome note goes to it. If it is not, the screen says so and asks you to make sure the address is right.
|
||||
|
||||
## Staff groups first
|
||||
|
||||
Open `Settings › Issuing rules` and find Staff groups. If you chose a setting at sign-up, a starting list is already there; rename or remove any of them. If you did not, the list is empty and the screen says everybody is on manager approval until you add groups.
|
||||
|
||||
Each group takes one route to its kit. The routes are explained in [groups and routes](/docs/people/groups-and-routes).
|
||||
|
||||
## Load your data
|
||||
|
||||
`Settings › Data` imports the catalogue, departments, staff register and opening stock from CSV. Templates for each file are on that screen, and the columns are in [CSV templates](/docs/reference/csv-templates).
|
||||
|
||||
## Add a second admin
|
||||
|
||||
Do this before you sign out.
|
||||
|
||||
1. **Open `Settings › People & sign-in`.** The Users list is near the bottom, for admins only.
|
||||
2. **Choose Add user.** Enter the name, email, a password of at least 8 characters and the role: Admin or Issuer.
|
||||
3. **Hand the password over yourself.** Passwords set here are not emailed.
|
||||
|
||||
An admin can later set a new password for another user from the same list. That is the way back in when mail is not configured: the forgot-password form sends nothing without mail, so a facility whose one admin forgets their password has nobody who can reset it. See [users](/docs/account/users).
|
||||
|
||||
## Close sign-ups
|
||||
|
||||
Once your facility exists, stop anyone else creating one on your server:
|
||||
|
||||
```sh
|
||||
# in .env
|
||||
SIGNUPS_DISABLED=1
|
||||
```
|
||||
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
With `SIGNUPS_DISABLED=1` the sign-in page no longer offers to create a facility, and the sign-up endpoint answers `403` with "New facility sign-ups are closed." Nothing in the product can reopen sign-ups while the variable is set.
|
||||
|
||||
> **Careful** While sign-ups are open, any visitor to your address can create their own facility on your database.
|
||||
|
||||
## What differs from hosted
|
||||
|
||||
The Community edition is built from the same code, with the parts that belong to threadcount.tech removed before release. Your instance has the coordinator app at `/app`, the phone counter at `/m` and the staff app at `/my`, in full.
|
||||
|
||||
| Area | Hosted | Community |
|
||||
|---|---|---|
|
||||
| Plans, staff ceiling, trials | Yes | None. Every facility has everything, with no limit on staff records. |
|
||||
| Single sign-on | Yes | Not included. Password plus an authenticator code. |
|
||||
| Health-service organisations | Yes | Not included |
|
||||
| Card payments | Yes | Not included |
|
||||
| Public website, guides, pricing, legal pages, demo | Yes | Not included. `/` goes to sign-in. |
|
||||
| Cloudflare Turnstile | Required | Optional. Without it the per-address limits stand alone. |
|
||||
| Error reports and usage statistics | Sent to ThreadCount | Sent nowhere |
|
||||
| Android App Links | Yes | Not included |
|
||||
| Email | ThreadCount's mail server | Yours, or none |
|
||||
|
||||
The published Android apps can still use your server: on the app's first screen, change the server, pick Self-hosted and enter your hostname. See [the counter app](/docs/apps/counter-app).
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
title: Install the Community edition
|
||||
section: selfhost
|
||||
order: 1
|
||||
summary: What the server needs, the four settings that must be set, starting it with Docker Compose, the HTTPS proxy in front, and how to tell it is up.
|
||||
role: Self-hosting admin
|
||||
keywords: install, self-host, docker, compose, community edition, server, port, proxy, caddy, https, health check, requirements
|
||||
---
|
||||
|
||||
## What you need
|
||||
|
||||
The Community edition runs as three containers from one `docker-compose.yml`. Before you start you need:
|
||||
|
||||
- A Linux server with Docker and Docker Compose. The README suggests 2 CPU and 2 GB of memory to start.
|
||||
- A hostname pointing at that server, for example `uniforms.example.health`.
|
||||
- An HTTPS reverse proxy in front of it (Caddy, nginx or Traefik).
|
||||
|
||||
HTTPS is not optional. The app runs with `NODE_ENV=production`, and in production the session cookie is marked `Secure`. A browser on another machine will not send that cookie over plain HTTP, so nobody can sign in.
|
||||
|
||||
The three services are:
|
||||
|
||||
| Service | Image | What it does |
|
||||
|---|---|---|
|
||||
| `db` | `postgres:16-alpine` | The database, in the named volume `db` |
|
||||
| `migrate` | built locally | Runs `npx prisma migrate deploy` once, then exits |
|
||||
| `app` | built locally | The product, on port 3000, photos in the named volume `photos` |
|
||||
|
||||
## Clone and set the four settings
|
||||
|
||||
```sh
|
||||
git clone https://github.com/pricehq/threadcount-community.git
|
||||
cd threadcount-community
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Open `.env` and set these four. The rest can stay blank.
|
||||
|
||||
| Setting | What to put |
|
||||
|---|---|
|
||||
| `SESSION_SECRET` | A long random string: `openssl rand -base64 48`. The server refuses to start while it still says `change-me`. |
|
||||
| `POSTGRES_PASSWORD` | Any long password. Compose refuses to start without it. |
|
||||
| `NEXT_PUBLIC_SITE_URL` | The address people will type: `https://uniforms.example.health`. |
|
||||
| `EDITION` | `community` |
|
||||
|
||||
`NEXT_PUBLIC_SITE_URL` is compiled into the app when the image is built, and it is the base of every link in an email (password resets, approval links). If it is blank the build uses `http://localhost:3000`. If you change it later you must rebuild.
|
||||
|
||||
> **Careful** The image build does not read `.env`: only `NEXT_PUBLIC_SITE_URL` and `NEXT_PUBLIC_TURNSTILE_SITEKEY` are passed in as build arguments. Other `NEXT_PUBLIC_` values in `.env` do not reach a Docker install. See [the configuration reference](/docs/selfhost/configuration-reference).
|
||||
|
||||
## Build and start
|
||||
|
||||
```sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The first start builds the image, which takes a few minutes. Compose then starts `db` and waits for `pg_isready`, runs `migrate` to create the schema, and starts `app` only once `migrate` has finished without an error.
|
||||
|
||||
Watch progress with:
|
||||
|
||||
```sh
|
||||
docker compose ps
|
||||
docker compose logs -f app
|
||||
```
|
||||
|
||||
If the app stops at once with `Refusing to start:`, the message names the setting that is missing or unsafe. In the Community edition it checks two: `DATABASE_URL` and `SESSION_SECRET`. `DATABASE_URL` is filled in by `docker-compose.yml`, so you do not set it.
|
||||
|
||||
## The port and the proxy
|
||||
|
||||
Inside the container the app always listens on 3000. On the server it is published on `APP_PORT`, which defaults to `3000`. Change `APP_PORT` in `.env` if 3000 is taken.
|
||||
|
||||
Point your proxy at that port. A Caddyfile for Caddy is:
|
||||
|
||||
```
|
||||
uniforms.example.health {
|
||||
reverse_proxy 127.0.0.1:3000
|
||||
}
|
||||
```
|
||||
|
||||
Docker publishes the port on every interface of the server, not only `127.0.0.1`. Firewall it, or set `APP_PORT=127.0.0.1:3000` so only a proxy on the same machine can reach it.
|
||||
|
||||
The sign-in, sign-up and reset limits count per address. The app reads the address from the last entry of the `X-Forwarded-For` header, then from `X-Real-IP`. Caddy sets `X-Forwarded-For` for you. If neither header arrives, every visitor counts as the same address, and one person's failed attempts count against everyone.
|
||||
|
||||
## Check it is up
|
||||
|
||||
The app answers `/api/health` without signing in. It asks the database a question and replies:
|
||||
|
||||
| Answer | Meaning |
|
||||
|---|---|
|
||||
| `200` with `{"ok":true}` | The app is serving and the database answers |
|
||||
| `503` with `{"ok":false}` | The app is running but cannot reach the database |
|
||||
|
||||
```sh
|
||||
curl -fsS https://uniforms.example.health/api/health
|
||||
```
|
||||
|
||||
The image runs the same check itself every 30 seconds, so `docker compose ps` shows `app` as `healthy` once it passes.
|
||||
|
||||
`/api/app-info` is also public. It returns `"product": "threadcount"`, `"edition": "community"` and the release in `version`, which is read from the `COMMUNITY_VERSION` file. The Android apps call it before they will point at your server.
|
||||
|
||||
## Next
|
||||
|
||||
Open `https://uniforms.example.health`. The address `/` sends you to `/auth`. Go on to [first run](/docs/selfhost/first-run) to create the facility, then set up [email](/docs/selfhost/email) and [backups](/docs/selfhost/backups) before anyone relies on it.
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: Update to a new release
|
||||
section: selfhost
|
||||
order: 3
|
||||
summary: Back up, fetch the release, rebuild, and let the migration run before the new app starts. Why a plain git pull does not work.
|
||||
role: Self-hosting admin
|
||||
keywords: update, upgrade, release, new version, git pull, fetch, reset, rebuild, migrations, schema, changelog, version
|
||||
---
|
||||
|
||||
## How releases are published
|
||||
|
||||
Each Community release is one commit with no history behind it. It is exported from ThreadCount's own code and the parts that belong only to threadcount.tech are removed. Before it is pushed, the result must type-check, build with `EDITION=community` and pass a smoke test. The new commit replaces the previous one on the `main` branch.
|
||||
|
||||
The commit message names the date it was built. The same date and the source commit are written to the `COMMUNITY_VERSION` file in the checkout, in this form:
|
||||
|
||||
```
|
||||
community 2026-09-15 b36d739
|
||||
```
|
||||
|
||||
A running server reports that line as `version` at `/api/app-info`.
|
||||
|
||||
## Back up first
|
||||
|
||||
Before every update, take a database dump and a copy of the photos, as in [backups](/docs/selfhost/backups):
|
||||
|
||||
```sh
|
||||
docker/backup.sh /srv/backups/threadcount
|
||||
```
|
||||
|
||||
Migrations only go forwards. `prisma migrate deploy` applies new migrations and has no step that undoes one, so the way back to an older release is to restore the dump you took before updating.
|
||||
|
||||
## Fetch the release
|
||||
|
||||
Because each release replaces the last commit rather than adding to it, `git pull` refuses to merge the two. Fetch, then move your checkout to the new commit:
|
||||
|
||||
```sh
|
||||
cd /srv/threadcount
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
cat COMMUNITY_VERSION
|
||||
```
|
||||
|
||||
`.env` is ignored by git, so `git reset --hard` leaves it alone.
|
||||
|
||||
> **Careful** `git reset --hard` throws away any change you made to a file in the repository, `docker-compose.yml` included. Keep local settings in `.env`, or copy your changes somewhere before you reset.
|
||||
|
||||
## Rebuild and start
|
||||
|
||||
```sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
What happens, in order:
|
||||
|
||||
1. **The images are rebuilt.** The build takes `NEXT_PUBLIC_SITE_URL` and `NEXT_PUBLIC_TURNSTILE_SITEKEY` from `.env` again.
|
||||
2. **`db` is checked.** Compose waits until Postgres answers `pg_isready`.
|
||||
3. **`migrate` runs.** It runs `npx prisma migrate deploy` against the bundled database and applies any migration the database does not have yet.
|
||||
4. **`app` starts.** Compose starts the new app only if `migrate` exited successfully.
|
||||
|
||||
If a migration fails, `app` is not started. Read what went wrong with:
|
||||
|
||||
```sh
|
||||
docker compose logs migrate
|
||||
```
|
||||
|
||||
Then check the app is healthy:
|
||||
|
||||
```sh
|
||||
docker compose ps
|
||||
curl -fsS https://uniforms.example.health/api/health
|
||||
```
|
||||
|
||||
## What changed
|
||||
|
||||
The Community edition has no changelog of its own. The [changelog](/changelog) on threadcount.tech lists what changed for the people who use ThreadCount, newest first. It is written for the hosted service, so entries about plans, card payments, single sign-on or the website do not apply to your server.
|
||||
|
||||
## Phones after an update
|
||||
|
||||
The Android apps ask your server at `/api/app-info` for the oldest app version it still works with, given in `minApp`. A phone running an older app is told to update rather than failing. Phones using `/m` or `/my` in a browser get the new version the next time the page loads.
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: Set up in an afternoon
|
||||
section: start
|
||||
order: 2
|
||||
summary: From creating the facility to the first garment issued at the counter, in the order the first-run checklist asks for it.
|
||||
screen: Today
|
||||
role: Admin
|
||||
keywords: sign up, signup, create account, new facility, setup, onboarding, checklist, plan, trial, import, opening stock, first issue
|
||||
---
|
||||
|
||||
## Create the facility
|
||||
|
||||
Sign-up is three steps.
|
||||
|
||||
1. **You.** First name, last name, work email and a password of at least 8 characters. Password resets go to that email, so it has to be right.
|
||||
2. **Your facility.** The facility name, plus two optional answers. `Setting` (Hospital, Aged care, Community health or Other) chooses a starting list of staff groups. `State or territory` sets the time zone that counts and month-end are read in, and nothing else.
|
||||
3. **Plan**, or **Confirm** when the server is not offering plans. Where the server publishes terms or a privacy policy, the create button stays off until you tick that you agree.
|
||||
|
||||
The plan step offers two choices. Neither takes a card.
|
||||
|
||||
| Plan | Price | Limit |
|
||||
|---|---|---|
|
||||
| Hosted Small | Free | Up to 60 staff records |
|
||||
| Hosted Facility | 30-day trial | Then $1,290 a year |
|
||||
|
||||
Health Service is not offered at sign-up. A facility created while plans are not live is free with everything, for good. A Community edition server has no plans and no staff-record ceiling.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Facility | Created with your name as coordinator, the plan you chose, any seeded staff groups and the time zone | See [Delete an account](/docs/account/delete-an-account) |
|
||||
| User | You, as `Admin`, with the title Uniform Coordinator | Edit under `Settings › People & sign-in` |
|
||||
| Email | A welcome note to the address you typed | None |
|
||||
|
||||
Sign-up is refused for an email that already has an account, and after 5 sign-ups from one connection in an hour. `Open ThreadCount` then takes you to the dashboard with the welcome checklist showing.
|
||||
|
||||
## Staff groups
|
||||
|
||||
Staff groups are under `Settings › Issuing rules`, in the Staff groups list. Each group is on one route: `FTE table`, `Starting kit` or `Manager approval`. While a facility has no staff groups, everybody is on manager approval.
|
||||
|
||||
`Rename` moves every staff record filed under the group to the new name and keeps its route. A group with people in it cannot be removed. The rules for each route are on [Groups and routes](/docs/people/groups-and-routes).
|
||||
|
||||
## Load your data
|
||||
|
||||
`Settings › Data › Import from CSV` takes a spreadsheet saved as CSV.
|
||||
|
||||
1. **Choose what you are importing** from the list.
|
||||
2. **Press `Download template`** and fill it in.
|
||||
3. **Press `Import CSV`** and choose the file. Re-importing updates matching rows.
|
||||
|
||||
Import is shown to Admins only, and each user is limited to 20 imports in 10 minutes. Import the staff register and the catalogue first. The columns each template takes are on [CSV templates](/docs/reference/csv-templates). Add suppliers under `Settings › Catalogue & suppliers`, with their order email and lead time in days.
|
||||
|
||||
## Opening stock and the first issue
|
||||
|
||||
On `Stock › On hand`, set a reorder level for each size with the minus and plus buttons beside it. Then press `Adjust quantity` and choose `Opening balance`, which overwrites a line's opening balance and is for start-up only. Only an Admin can set an opening balance or a reorder level.
|
||||
|
||||
When the shelf is loaded, go to `Counter` and issue a garment to someone on the register. [Issue a garment](/docs/counter/issue-a-garment) walks through the counter.
|
||||
|
||||
## The first-run checklist
|
||||
|
||||
The dashboard shows a checklist of six things a new facility does once.
|
||||
|
||||
1. Add staff, or import the register
|
||||
2. Add garments
|
||||
3. Set reorder levels
|
||||
4. Record opening stock
|
||||
5. Issue a garment
|
||||
6. Bind a barcode or print labels
|
||||
|
||||
Each tick comes from the records, not from a click. For example, the first item is ticked once the staff register has a row in it. Every row still to do has a button to the screen that does it.
|
||||
|
||||
The checklist disappears once all six are ticked, or once the facility is 60 days old and three or more are ticked. An Admin can hide it sooner with `Dismiss`, and it stays hidden for the whole facility. It does not appear in the phone app.
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: The two roles
|
||||
section: start
|
||||
order: 3
|
||||
summary: What an Admin can do that an Issuer cannot, as the server enforces it, and what staff see when they sign in to the staff app.
|
||||
screen: Settings › People & sign-in
|
||||
role: Anyone
|
||||
keywords: roles, permissions, admin, issuer, access, user, staff sign-in, staff app, activation code, who can
|
||||
---
|
||||
|
||||
## Two roles, checked on the server
|
||||
|
||||
Every user of the linen-room app is either `Admin` or `Issuer`. The server checks the role on every change, so hiding a button is not the only protection. If an Issuer attempts a change they are not allowed to make, the server refuses it with `Admin only`, whichever screen it came from.
|
||||
|
||||
Your name and role are at the foot of the menu. A sign-in lasts 14 days, or 30 days if you tick to stay signed in on that computer. Changing a password ends every older sign-in for that user.
|
||||
|
||||
## What each role can do
|
||||
|
||||
An Admin can do everything an Issuer can, plus everything in the Cannot column. The one thing an Admin cannot do is remove or demote the last active Admin.
|
||||
|
||||
| Role | Can | Cannot |
|
||||
|---|---|---|
|
||||
| Issuer | Issue, return, exchange and take hand-ins at the counter | Add, edit or delete catalogue items, sizes or barcodes |
|
||||
| Issuer | Work ward requests, pickups and delivery rounds | Change reorder levels, supplier codes or catalogue prices |
|
||||
| Issuer | Apply a stock take, receive stock, add to the pre-loved pool | Set on hand, adjust or write off stock, or set opening balances |
|
||||
| Issuer | Create orders, mark them ordered or shipped, receive deliveries | Open the order list, print the order sheet, email a supplier, cancel an order |
|
||||
| Issuer | Read the staff register and Reports | Add, edit or delete staff, departments or locations, or print staff-app codes |
|
||||
| Issuer | Read Settings | Change settings, staff groups, suppliers, users or the plan |
|
||||
| Issuer | Change their own profile and password | Read `Activity`, import CSV, restore a backup, wipe or reset data |
|
||||
|
||||
## Managing users
|
||||
|
||||
Admins see the user list under `Settings › People & sign-in`. A new user starts as `Issuer` unless you choose `Admin`. The facility must always have at least one active Admin, so the server will not demote or remove the last one and replies `Keep at least one active admin`. See [Users](/docs/account/users).
|
||||
|
||||
## Staff sign-ins
|
||||
|
||||
Staff on the register are not users, and they never have either role. A staff member signs in to the staff app, at `/my`, with a separate account.
|
||||
|
||||
1. **An Admin prints a code** from the person's record on `People`. It is twelve characters in three groups.
|
||||
2. **The staff member activates it** at the staff sign-in with `First time? I have a code`, then chooses an email and password. A code printed 14 or more days ago is refused as expired.
|
||||
3. **After that they sign in** at the staff sign-in, or through the ordinary Log in box on the website.
|
||||
|
||||
A staff sign-in lasts 30 days. It is a different kind of session from a user's, so it cannot open the linen-room app. A user's session shows nothing in the staff app either.
|
||||
|
||||
## What staff can see
|
||||
|
||||
The staff app menu is `Home`, `Kit`, `Orders` and `Messages`. In it, staff can:
|
||||
|
||||
- see what they hold and raise a request for garments
|
||||
- send messages about their own requests, report damage and raise a dispute
|
||||
- join, leave or accept a waitlist place, and answer a kit check when one is open
|
||||
- change their own password
|
||||
|
||||
Two extra views come from the register, not from a role. If someone is named as another person's manager on the register, they also see approvals and their team. If someone is marked as a ward desk, they see the delivery round for their ward.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| User role | `Admin` or `Issuer`, set under `Settings › People & sign-in` | Set it back, as long as one active Admin remains |
|
||||
| Staff activation code | Printed from the person's record, stamped with the date | Clear the code; it expires after 14 days anyway |
|
||||
| Staff account | Created when the code is used | Remove it from the record, which ends its sign-ins |
|
||||
|
||||
If a staff member is made inactive on the register, they lose the staff app at once. When they try to sign in they are told `You're no longer on the register at this facility. Ask the linen room.`
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: ThreadCount in one page
|
||||
section: start
|
||||
order: 1
|
||||
summary: What ThreadCount records, the screens in the menu, who signs in, and where to find each first-month task.
|
||||
role: Anyone
|
||||
keywords: overview, introduction, menu, screens, what is threadcount, getting started, help, manual, docs
|
||||
---
|
||||
|
||||
## What it records
|
||||
|
||||
ThreadCount records uniform stock for one facility and keeps three things in step.
|
||||
|
||||
- **Who holds what.** Every garment issued, returned, exchanged or handed in is written against a person on the staff register, so each person's holding is always current.
|
||||
- **The shelf, by size.** Each garment in the catalogue has sizes, and each size has its own on-hand figure, reorder level and supplier code. Issues take stock off the shelf; deliveries and stock takes put it back or correct it.
|
||||
- **The order list.** Sizes at or below their reorder level are gathered into one group per supplier, raised as orders, and received against when the delivery arrives.
|
||||
|
||||
All three come from the same records. A garment issued at the counter changes the person's holding and the shelf figure, and if the size drops to its reorder level it appears on the order list.
|
||||
|
||||
## The menu
|
||||
|
||||
The menu down the left side lists the screens in this order.
|
||||
|
||||
| Screen | What it is for |
|
||||
|---|---|
|
||||
| `Today` | The day's queues: bags to collect, the delivery round, requests to pick, deliveries to receive and stock counts, with the first-run steps while a facility is setting up. |
|
||||
| `Counter` | Pick the person, scan or pick the garment, record the issue. |
|
||||
| `Stock` | On-hand figures by size, reorder levels and adjustments, stock counts, and locations. |
|
||||
| `Orders` | Supplier orders, the order list and receiving. |
|
||||
| `People` | The staff register and each person's record. `Requests` from the staff app sits with it. |
|
||||
| `Reports` | The finance reports, on three tabs. |
|
||||
| `Settings` | Facility, Issuing rules, Catalogue & suppliers, Places & cost centres, People & sign-in, Data & audit log, and Plan. |
|
||||
|
||||
`Delivery rounds` belongs with `Today`. The `?` in each screen's heading opens its page in this manual.
|
||||
|
||||
On a narrow screen the bar along the bottom holds `Today`, `Counter`, `Stock` and `More`. `More` holds Orders, People, Requests, Delivery rounds, Reports, Settings, Help and the counter app.
|
||||
|
||||
## Who signs in
|
||||
|
||||
The people who run the linen room sign in as users, and each user has one of two roles.
|
||||
|
||||
- **Admin** sets the facility up and makes the changes that affect everyone: the catalogue, reorder levels, the staff register, users and orders to suppliers.
|
||||
- **Issuer** works the counter: issues, returns, requests, stock takes and deliveries.
|
||||
|
||||
The person who creates the facility is its first Admin. Staff who wear the uniform are not users. They sign in to the staff app with a separate account that shows their own record and the requests they are part of. [The two roles](/docs/start/the-two-roles) sets out what each can do.
|
||||
|
||||
## Where the manual lives
|
||||
|
||||
The same pages appear in three places.
|
||||
|
||||
- On the website, under `/docs`.
|
||||
- In the app, under `Help`.
|
||||
- In the Community edition's source repository, `pricehq/threadcount-community`, in the `docs/manual` folder.
|
||||
|
||||
## How do I…
|
||||
|
||||
| Task | Page |
|
||||
|---|---|
|
||||
| Load the staff register and catalogue from a spreadsheet | [CSV templates](/docs/reference/csv-templates) |
|
||||
| Issue a garment at the counter | [Issue a garment](/docs/counter/issue-a-garment) |
|
||||
| Set the level at which a size is reordered | [Reorder levels](/docs/stock/reorder-levels) |
|
||||
| Count the shelf | [Stocktakes](/docs/stock/stocktakes) |
|
||||
| Order from a supplier | [Your first order](/docs/start/your-first-order) |
|
||||
| Book in a delivery that arrived short | [Receiving and back orders](/docs/stock/receiving-and-back-orders) |
|
||||
| Give a colleague a login | [Users](/docs/account/users) |
|
||||
| Get staff onto the staff app | [Staff app](/docs/apps/staff-app) |
|
||||
| Close off the month for finance | [Month-end pack](/docs/reports/month-end-pack) |
|
||||
| Take a backup of everything | [Export and backup](/docs/account/export-and-backup) |
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: Your first order
|
||||
section: start
|
||||
order: 4
|
||||
summary: From the order list to a delivery on the shelf, including what happens when it arrives short.
|
||||
screen: Orders › Order list
|
||||
role: Admin
|
||||
keywords: order, ordering, purchase order, supplier, reorder, raise, order list, csv, email supplier, receive, delivery, back order, invoice
|
||||
---
|
||||
|
||||
## Before you start
|
||||
|
||||
The order list depends on two things you set up once.
|
||||
|
||||
- **Reorder levels** on `Stock › On hand`. A size appears on the list when its on-hand figure is at or below its level. See [Reorder levels](/docs/stock/reorder-levels).
|
||||
- **Suppliers** under `Settings › Catalogue & suppliers`: the account number, the order email and the lead time in days. Each garment names its supplier. See [Suppliers](/docs/stock/suppliers).
|
||||
|
||||
Enter each size's supplier code on the garment's page. A line with no code shows `no code`, which links to that garment.
|
||||
|
||||
## The order list
|
||||
|
||||
On `Orders`, press `Order list`. Only Admins can use the button, the list and the order sheet.
|
||||
|
||||
The list has two kinds of group.
|
||||
|
||||
- **Stock groups**, one per supplier. Each line is a size at or below its reorder level. Its quantity tops the size up to twice its reorder level, allowing for what is on hand and what is already on order. A line tagged `runs out` will run out before a delivery ordered today would arrive.
|
||||
- **Draft groups**, one for each existing draft order. A draft is either a person's order from the counter or a replenishment draft. A person's order is never merged into the shelf's order.
|
||||
|
||||
In a stock group you can change any `Order qty`, `Remove` a line, or `Add a line` for any garment and size. If you have already placed the order on the supplier's website, type their order number into `Supplier order no.`. The field is optional.
|
||||
|
||||
## Raise, then send
|
||||
|
||||
Press `Raise`. The button says how many orders it will raise.
|
||||
|
||||
1. **Each stock group becomes one order** marked `Ordered`, with the supplier's order number as its reference. Lines left at zero are dropped.
|
||||
2. **Each draft is raised with its lines unchanged** and marked `Ordered`.
|
||||
3. **The screen lists the raised orders**, each with three ways to send it.
|
||||
|
||||
- `Print` opens the A4 order sheet with the supplier's product codes.
|
||||
- `CSV` downloads the order with the columns Supplier code, Description, Size, Qty and Unit cost.
|
||||
- `Email` sends the order to the supplier's order email. It is refused if the supplier has no email address, if email is not set up on the server, or if the order is a draft or cancelled.
|
||||
|
||||
## What is written
|
||||
|
||||
| Record | Change | Undo |
|
||||
|---|---|---|
|
||||
| Order | One new order per supplier, `Ordered`, with a code like `ORD-2026-0001` and an expected date the supplier's lead time away, or 14 days if none is set | An Admin can `Cancel order` while it is Draft, Ordered, Shipped or Back Order |
|
||||
| Draft order | Status changed to `Ordered` | Cancel, as above |
|
||||
| Order | The time it was emailed or printed | None |
|
||||
|
||||
## Receive the delivery
|
||||
|
||||
Open the order from `Orders`. When the supplier dispatches, you can press `Mark shipped`, though it is not required. When the boxes arrive, press `Receive delivery`.
|
||||
|
||||
1. **Enter the invoice number and arrival date.** A note and a photo of the invoice are optional.
|
||||
2. **Enter what arrived on each line.** Each line starts at the quantity still outstanding. `Scan items off the box (camera)` adds one for each scan.
|
||||
3. **Choose the destination.** `Shelf` puts the garments into stock. On an order for a staff member, `Pickup` puts them on the call list instead.
|
||||
4. **Check the cost.** If the invoiced cost is not the catalogue cost, choose `Keep`, or an Admin can choose `Update catalogue cost`.
|
||||
5. **Press `Receive`.**
|
||||
|
||||
The server refuses a line where more arrived than was outstanding, and refuses a delivery where nothing arrived.
|
||||
|
||||
## Back orders
|
||||
|
||||
Anything that did not arrive goes on a back order. The original order is marked `Received`. A new order with status `Back Order` is created for the shortfall. It keeps the same supplier reference and has the note `Back order — short on` followed by the original order's code. The original order lists it under Back orders.
|
||||
|
||||
When the rest arrives, receive the back order the same way. A received delivery cannot be reversed, so an Admin corrects the shelf with `Adjust quantity` instead. There is more detail on [Receiving and back orders](/docs/stock/receiving-and-back-orders) and [Order list](/docs/stock/order-list).
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Barcodes
|
||||
section: stock
|
||||
order: 2
|
||||
summary: Binding the supplier's barcode to each size, dealing with an unknown code once, printing ThreadCount's own labels, and the formats the scanners read.
|
||||
screen: Stock › On hand › a garment
|
||||
role: Admin
|
||||
keywords: barcode, scan, bind, unbind, unknown barcode, label, print labels, generate barcode, EAN-13, Code 128, scanner, GTIN
|
||||
---
|
||||
|
||||
## Supplier barcodes
|
||||
|
||||
Each size of a garment carries one barcode, and a code belongs to one size in the facility. Most garments arrive with the supplier's code on the swing tag, and that is the code to bind.
|
||||
|
||||
1. **Open the product.** `Stock › On hand`, then the garment's name.
|
||||
2. **Press Scan sizes.** The dialog starts on the first size with no barcode.
|
||||
3. **Scan each size's label.** After each scan it moves to the next unbound size. **Re-scan** on a row points it at that size instead.
|
||||
4. **Add a size while scanning.** Type the size into `Size that isn't on the item yet`, then scan. The size is added at the end of the list with its code.
|
||||
|
||||
The same can be done on the phone in the counter app, or in bulk from `Settings › Data` with the Supplier barcodes template.
|
||||
|
||||
## An unknown code
|
||||
|
||||
When a scan on `Stock › On hand` or `Stock › Count` matches nothing, the `Unknown barcode` dialog opens. An admin picks the garment, then taps the size, and the code is bound from then on: the next scan anywhere finds it. An issuer sees the code and is told only an admin can bind it. **New product from this barcode** opens `Add item` with the code waiting for its size.
|
||||
|
||||
`Scan to add` on `Stock › On hand` works the same way for a pile of garments: a known code offers **Open product**; an unknown one offers a new product or a binding.
|
||||
|
||||
The dialog checks the digits. A code that fails its check digit is flagged as a possible mis-read but can still be bound. A code of a non-standard length can also be bound.
|
||||
|
||||
With `Settings › Data › Look up unknown barcodes in public databases` ticked, `Scan to add` sends the barcode number, and nothing else, to UPCitemdb, then Open Products Facts, and shows any product name found. Only valid EAN-13, UPC-A, EAN-8 and GTIN-14 codes are looked up, up to 120 an hour per facility. It is off by default.
|
||||
|
||||
## ThreadCount barcodes
|
||||
|
||||
For garments that arrived unlabelled, **Generate barcodes** on the product page gives every size without a code one of ThreadCount's own. **Generate** on a single row does one size. Sizes that already carry a supplier code keep it.
|
||||
|
||||
A generated code is a 13-digit EAN-13 starting `29`, the GS1 range reserved for use inside one business, with a real check digit. Numbers come from a counter held for the facility, so two people labelling at once can't be given the same one.
|
||||
|
||||
Every size also resolves from an internal 9-digit number starting `93`. It is never shown or printed, and binding another garment's internal number to a size is refused.
|
||||
|
||||
## Typed and moved barcodes
|
||||
|
||||
On the product page each size has a barcode box. Type or scan the code and press Enter or **Save**. Nothing reformats what is typed; codes may carry letters. To take a code off, clear the box and confirm, or press **×**.
|
||||
|
||||
A code already on another garment is refused with where it is. Confirm the move, or press **Move … onto size … anyway** in Scan sizes, and the code leaves the old size for this one.
|
||||
|
||||
## Printing labels
|
||||
|
||||
**Print labels** on the product page shows the count in its name: one label for every garment on hand, across the sizes that carry a barcode. It opens an A4 sheet of labels, 2 across, in a new tab, with the print dialog up.
|
||||
|
||||
Each label carries the garment name, size, SKU, the bars with the code beneath, and the organisation name from the slips (or the facility name). A valid EAN-13 prints as EAN-13; any other code prints as Code 128. A code too long to print at a readable size on the label is flagged above the sheet. With nothing on hand, or no size labelled, the sheet says which instead of printing.
|
||||
|
||||
## Accepted formats
|
||||
|
||||
- The camera and the phone apps read EAN-13, EAN-8, UPC-A, UPC-E, Code 128, Code 39 and Code 93. QR codes are ignored.
|
||||
- A scanner that types the code and presses Enter works in the scan boxes on the desktop screens. See [keyboard and scanner](/docs/reference/keyboard-and-scanner).
|
||||
- A bound code can be up to 64 characters.
|
||||
|
||||
## What is written
|
||||
|
||||
| Action | Record · Change | Undo |
|
||||
|---|---|---|
|
||||
| Bind a code (scan, type or pick) | Barcode record: code, garment, size position | Clear the box, or press × |
|
||||
| Move a code | The same record now points at the new size | Move it back |
|
||||
| Generate | Barcode record marked generated; the facility's number counter moves on | Unbind; the number is not handed out again |
|
||||
| Remove a size | Its barcode is deleted with it | Bind the code again |
|
||||
| Print labels | Nothing | Nothing to undo |
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Catalogue, sizes and cuts
|
||||
section: stock
|
||||
order: 1
|
||||
summary: How a garment is entered once, why a size is a position in its list, what a cut is, and who a garment's staff groups let ask for it.
|
||||
screen: Stock › On hand
|
||||
role: Admin
|
||||
keywords: catalogue, garment, product, add item, sizes, size run, cut, gender, men's, women's, unisex, staff groups, discontinue, duplicate, price history
|
||||
---
|
||||
|
||||
## What a catalogue item holds
|
||||
|
||||
A catalogue item is one garment in one colour: a name, a cut, a SKU, a supplier, a unit cost, a product type, the staff groups it is for, notes, and a list of sizes. Stock, barcodes, reorder levels and supplier codes are all held per size, underneath the item.
|
||||
|
||||
Add one from `Stock › On hand` with **Add garment**, or import many from `Settings › Data` with the Catalogue template (see [CSV templates](/docs/reference/csv-templates)).
|
||||
|
||||
1. **Enter the garment.** Item name, cut, SKU, supplier, unit cost, product type and notes. The supplier list comes from `Settings › Catalogue & suppliers`; a supplier name the directory does not hold is added to it.
|
||||
2. **Add the sizes.** Type a size and press Enter, or pick from a run: `XS – 5XL`, `6 – 24` or `72 – 117`. Tap a size in the run again to take it off.
|
||||
3. **Give each size its barcode and opening stock.** Both are optional. Leave opening stock at 0 if the garments are arriving on an order.
|
||||
4. **Add to catalogue.** It is refused without a name, a size and a cost (0 is a cost), or when one barcode is on two sizes.
|
||||
|
||||
The product type decides whether a garment counts as a top or trousers, which is half a set under the [entitlement rule](/docs/people/entitlement-rule). Any other type is not part of a set.
|
||||
|
||||
## Cuts
|
||||
|
||||
A garment's cut is one of `Unisex`, `Men's` or `Women's`, set in the `Gender` field. A men's or women's garment shows `(M)` or `(W)` after its name on every screen.
|
||||
|
||||
A staff record carries a uniform style: `Men's`, `Women's`, `Either`, or blank. Blank offers every cut, exactly as `Either` does. A unisex garment is offered to everyone. The style is set on the [staff register](/docs/people/staff-register).
|
||||
|
||||
In a catalogue import, a gender starting with `m` is men's, one starting with `f` or `w` is women's, and anything else, blank included, is unisex.
|
||||
|
||||
## Staff groups
|
||||
|
||||
The `Staff groups` tick-list says which of the facility's groups a garment is for. **An empty list means every group**, and ticking `All groups` clears the others. Groups not on the list can't request the garment from the staff app, and need the coordinator override at the counter.
|
||||
|
||||
In a catalogue import, several groups are separated by `|` and `All` means every group. A blank group column on a re-import leaves the garment's groups as they were.
|
||||
|
||||
## A size is a position
|
||||
|
||||
ThreadCount records a size by its position in the item's size list, not by its name. Every issue, count, movement, barcode and reorder level points at a position. For that reason:
|
||||
|
||||
- A new size is always added at the end of the list, from **Edit product › Add a size** or from **Scan sizes**. It starts with no barcode.
|
||||
- Once anything is recorded against an item, its existing sizes can't be reordered or removed as a list.
|
||||
- **Remove** on a size row takes off one size. It is refused if that size has an issue, stock on hand, an open supplier order, a stock movement, a stocktake, a hand-in, a ward request, somebody waiting for it, a kit check answer or a record query against it. The refusal names which.
|
||||
- Removing a size deletes its reorder level and barcode, and moves every later size down one place. A garment's last size can't be removed; discontinue it instead.
|
||||
|
||||
> **In plain terms** Add sizes freely; remove them only while nothing has happened to them.
|
||||
|
||||
## Discontinue, duplicate, delete
|
||||
|
||||
- **Discontinue** takes a garment out of counts, flags and the order list. Its stock still counts in the on-hand value. **Reinstate** brings it back.
|
||||
- **Duplicate** makes a new item with the same description, cut, supplier, cost, sizes and reorder levels, and no barcodes, stock or history. It is refused if an item with that name already exists for the same groups.
|
||||
- **Delete**, from the multi-select bar, removes items with nothing recorded against them. Anything with history or stock on hand is discontinued instead.
|
||||
|
||||
A change of unit cost, from the product page, the bulk `Apply price` or a delivery, adds an entry to the garment's **Price history** with the old figure and who changed it. Past issues keep the price they were recorded at.
|
||||
|
||||
## What is written
|
||||
|
||||
| Action | Record · Change | Undo |
|
||||
|---|---|---|
|
||||
| Add item | New catalogue item; barcodes bound; opening stock per size; first price history entry when the cost is above 0 | Delete while nothing is recorded, otherwise Discontinue |
|
||||
| Change unit cost | Item cost; a price history entry | Change it back; the entry stays |
|
||||
| Add a size | Size appended to the list | Remove, while nothing is recorded against it |
|
||||
| Remove a size | Size, its reorder level and barcode deleted; later sizes move down one | Add it again; it goes on at the end |
|
||||
| Discontinue | Item marked discontinued | Reinstate |
|
||||
| Duplicate | New item with sizes and reorder levels | Delete |
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: The order list
|
||||
section: stock
|
||||
order: 5
|
||||
summary: What to order, grouped by supplier and net of what is on order, raised as one order per group with the supplier's order number, then printed, downloaded or emailed.
|
||||
screen: Orders › Order list
|
||||
role: Admin
|
||||
keywords: order list, purchase order, reorder, supplier order, raise, supplier code, order sheet, print, CSV, email supplier, supplier order number, order history
|
||||
---
|
||||
|
||||
## What appears
|
||||
|
||||
`Orders › Order list` puts two kinds of group on one screen: stock groups, one per supplier, and every draft order that has lines. The heading counts both.
|
||||
|
||||
A **stock group** holds each size at or below its [reorder level](/docs/stock/reorder-levels), topped up to twice the level, less what is on hand, less what is on order. On order counts placed orders and drafts other than replenishment drafts. A size needing nothing more is left off. The supplier is the garment's, or the first in `Settings › Catalogue & suppliers` when it has none.
|
||||
|
||||
Each line shows the supplier's code for that size, the garment, size, on hand, reorder level, on order and an editable `Order qty`. A line with no supplier code shows `no code`, linked to the product page where it is entered. A size that would run out before a delivery placed today is tagged `runs out` and sorted to the top. The group heading shows the supplier's account number, the number of lines and the value at catalogue cost.
|
||||
|
||||
- **Remove** takes a line off; a quantity of 0 is dropped when raised.
|
||||
- **Add a line** adds any current garment and size to that group.
|
||||
- Edits stay on this screen until the list is raised.
|
||||
|
||||
## Drafts and staff orders
|
||||
|
||||
Every draft order with lines is its own group, headed with its supplier and either the person it is for (with their cost centre) or `draft`. A draft made for a staff member from **New order** is raised as its own order and is never merged into a stock group, so each staff member's order stays separate from the shelf's.
|
||||
|
||||
A supplier's replenishment draft from Order flagged is also listed here as a draft. Its sizes are not netted off the stock group above it, so check the two against each other before raising.
|
||||
|
||||
Order in at the counter places its orders straight away, one per supplier, so they don't appear here.
|
||||
|
||||
## Raising the list
|
||||
|
||||
Every group has an optional `Supplier order no.` field: the number the supplier gives when the order is placed on their site.
|
||||
|
||||
**Raise N orders** does all groups in one go:
|
||||
|
||||
- A stock group becomes a new order for stock, status `Ordered`, with the supplier order number as its reference and an expected date of today plus the supplier's lead time, or 14 days when none is set.
|
||||
- A draft becomes `Ordered`, taking the supplier order number if one was typed.
|
||||
|
||||
If any group is refused, for example a draft somebody else has already placed, nothing is raised.
|
||||
|
||||
## The sheet, the CSV and the email
|
||||
|
||||
After raising, each new order is listed with three buttons. The same sheet is **Order sheet** on the order's own page, and the email is **Email supplier** there once the order is placed.
|
||||
|
||||
**Print** opens the A4 purchase order: the order number and supplier reference; the facility, its location and organisation; the supplier with contact, phone and email; the date and expected date; the account number; the person it was ordered for, with department and cost centre; and a row per line with a tick box, the supplier code, description, size, quantity, unit cost and total. Where a size has no supplier code, the garment's SKU is printed instead. It ends with lines for who ordered and the date placed. Opening the sheet records when the order was printed.
|
||||
|
||||
**CSV** downloads the order number, supplier and supplier order number, then `Supplier code`, `Description`, `Size`, `Qty` and `Unit cost` per line.
|
||||
|
||||
**Email** sends the order to the supplier's `Order email` from `Settings › Catalogue & suppliers`. The subject is `Purchase order ORD-2026-0042 (NW-48211) — Riverside General`, with the lines, account, delivery location and estimated value ex tax, asking the supplier to quote the order number on the invoice. Sending records when it was emailed. It is refused for a draft, a cancelled order, a supplier with no order email, and a server with no email set up; print the sheet instead.
|
||||
|
||||
## Filters and history
|
||||
|
||||
`Orders › All orders` lists every order. Filter by search (order number, reference, invoice, tracking, supplier, person or garment), supplier, garment, ordered-from and ordered-to dates, and `All`, `Draft`, `Open` or `Received`. `Open` means placed and not yet received or cancelled. **Export CSV** downloads the orders shown, with the filters applied.
|
||||
|
||||
The tiles count drafts to send, orders awaiting delivery with their value, overdue orders, and stock received this month at invoiced cost.
|
||||
|
||||
A product page lists every order line for that garment under `Orders` (date, order, supplier, size, quantity, unit cost then, supplier reference, invoice, status) and every change of unit cost under `Price history`.
|
||||
|
||||
## What is written
|
||||
|
||||
| Action | Record · Change | Undo |
|
||||
|---|---|---|
|
||||
| Raise, stock group | New order: stock, `Ordered`, reference, expected date, lines | Cancel order on the order page (Admin) |
|
||||
| Raise, draft | Status `Draft` to `Ordered`; reference if typed | Cancel order (Admin) |
|
||||
| Print sheet | The order's printed time | Nothing to undo |
|
||||
| Email | Email to the supplier; the order's emailed time | None; the supplier has it |
|
||||
| CSV | Nothing | Nothing to undo |
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: Receiving and back orders
|
||||
section: stock
|
||||
order: 6
|
||||
summary: Booking a delivery in against its order, recording the invoice, splitting short lines to a back order, and sending garments to the shelf or the pickup list.
|
||||
screen: Orders › an order › Receive delivery
|
||||
role: Admin or Issuer
|
||||
keywords: receive, delivery, goods received, invoice, back order, short delivery, partial delivery, pickup, shelf, invoiced cost, docket
|
||||
---
|
||||
|
||||
## Before a delivery can be received
|
||||
|
||||
Open the order from `Orders`. **Receive delivery** appears on an order that is `Ordered`, `Shipped` or `Back Order`. A draft has to be marked ordered first, and a received or cancelled order can't be received again. **Mark shipped** is optional and changes nothing about receiving.
|
||||
|
||||
The `Units received` tile shows how many units have arrived against how many were ordered.
|
||||
|
||||
## Ticking the lines
|
||||
|
||||
The `Receive delivery` dialog lists each line of the order:
|
||||
|
||||
- `Outstanding`: ordered less already received.
|
||||
- `Arrived`: filled in with the outstanding figure. Change it to what is in the box.
|
||||
- `Destination`: `Shelf`, or `Pickup` when the order is for a staff member. A staff member's order starts on `Pickup`; an order for stock has only `Shelf`.
|
||||
- `Invoiced cost`: the unit cost on the invoice, filled in with the catalogue cost.
|
||||
|
||||
**Scan items off the box (camera)** adds 1 to a line for each garment scanned, and names a garment that isn't on the order.
|
||||
|
||||
An arrived figure above the outstanding one is refused. Book surplus in with `Adjust quantity › Receive` on `Stock › On hand`, which records it as received without an order. At least one line needs a quantity.
|
||||
|
||||
## Invoice, date and price
|
||||
|
||||
1. **Enter the invoice number.** It is kept on the delivery and on the order.
|
||||
2. **Check the arrival date.** It starts on today.
|
||||
3. **Add a note** if something was wrong, and **Photo the invoice** if you want the invoice on file.
|
||||
4. **Check any price flag.** When an invoiced cost differs from the catalogue, the line shows both. **Keep** leaves the catalogue alone; **Update catalogue cost** (Admin) changes it and adds a price history entry.
|
||||
5. **Receive.**
|
||||
|
||||
Delivered units are valued at the invoiced cost from then on, on the order and in the order's CSV; anything still outstanding is valued at the catalogue cost.
|
||||
|
||||
## Short lines become a back order
|
||||
|
||||
Receiving closes the order as `Received`, whatever arrived. Anything short is moved onto a new order:
|
||||
|
||||
- Status `Back Order`, for the same supplier, person, cost centre and supplier reference.
|
||||
- Its note reads `Back order — short on` and the original order number.
|
||||
- Its expected date is today plus the supplier's lead time, or 14 days when none is set.
|
||||
|
||||
The two orders link to each other: the back order says which order it came from, and the original lists its back orders. A back order is received the same way, and anything short on it goes to another back order. Cancel a back order the supplier won't fill with **Cancel order** (Admin).
|
||||
|
||||
## Where the garments go
|
||||
|
||||
- **Shelf** lines are added to stock on hand for their sizes straight away.
|
||||
- **Pickup** lines are not put on the shelf. They become one pickup for the staff member, which appears on the [pickup call list](/docs/counter/pickup-call-list). Marking it picked up records the garments as issued to that person.
|
||||
|
||||
The order's `History` panel adds a `Delivery received` entry with the invoice number, each line and where it went, and an **Invoice photo** button when one was taken. A received order's details are locked.
|
||||
|
||||
> **Careful** There is no undo for a delivery once received; a wrong quantity is corrected on the shelf with Adjust quantity.
|
||||
|
||||
## What is written
|
||||
|
||||
| Action | Record · Change | Undo |
|
||||
|---|---|---|
|
||||
| Receive | A delivery record (date, invoice, note, photo) with a line per arrived size (quantity, destination, invoiced cost); the order set to `Received` with its invoice and received date, the note added to its notes | None; correct stock with Adjust quantity |
|
||||
| Short lines | New `Back Order` order linked to the original | Cancel order (Admin) |
|
||||
| Shelf lines | Stock on hand for those sizes goes up | Adjust quantity (Admin) |
|
||||
| Pickup lines | A pickup for the staff member with those lines | None from this screen |
|
||||
| Update catalogue cost | Catalogue unit cost; a price history entry | Change the cost on the product page |
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Reorder levels
|
||||
section: stock
|
||||
order: 3
|
||||
summary: A reorder level per size or the facility default, when a size is flagged, what Order flagged drafts, and how the forecast suggests a level.
|
||||
screen: Stock › On hand
|
||||
role: Admin
|
||||
keywords: reorder level, par, minimum, low stock, flagged, order flagged, replenishment, forecast, suggested reorder, lead time, weeks of cover
|
||||
---
|
||||
|
||||
## Where a level comes from
|
||||
|
||||
Every size has a reorder level. It is the size's own figure if one has been set, and the facility default otherwise. The default is `Settings › Catalogue & suppliers › Default reorder level`, which starts at `3`.
|
||||
|
||||
Set a size's own level in any of these places:
|
||||
|
||||
- **− and +** beside `Reorder at` on a size row, on `Stock › On hand` (open the item) or on the product page.
|
||||
- **Set reorder** on the multi-select bar, which sets the same level on every size of the selected products.
|
||||
- **Use** beside a forecast suggestion on the product page (below).
|
||||
- The `Reorder levels` template in `Settings › Data`, or the optional `reorder` column of `Opening balances`. See [CSV templates](/docs/reference/csv-templates).
|
||||
- **Duplicate** on a product copies its levels to the copy.
|
||||
|
||||
A level can't go below 0. Once a size has its own level, no screen returns it to the default; set it to the default figure instead.
|
||||
|
||||
## When a size is flagged
|
||||
|
||||
A size is flagged when what is on hand is at or below its reorder level. A size is left out while nothing has ever happened to it: no opening stock, no adjustment, no level of its own and no movement. Discontinued garments are never flagged.
|
||||
|
||||
Flags show in four places:
|
||||
|
||||
- `Stock › On hand`: the `At or below reorder` tile, the `Flagged` filter, an `N to reorder` tag on the item, and `REORDER` or `OUT` on each size.
|
||||
- The dashboard: the `Lines at reorder` tile and the `Reorder flags` panel, which lists the first 12 and marks a size with none on the shelf.
|
||||
- `Orders`: the `Suggested order` panel, which lists flagged sizes that are on no open order or draft, with a figure of twice the level less what is on hand (at least 1).
|
||||
- The [order list](/docs/stock/order-list), where they become lines to raise.
|
||||
|
||||
## Order flagged
|
||||
|
||||
**Order flagged** on `Stock › On hand`, and **Add to supplier drafts** on `Orders`, put every flagged size onto its supplier's replenishment draft. Both are open to Admins and Issuers.
|
||||
|
||||
For each flagged size the quantity is twice its reorder level, less what is on hand, less what is already on order. On order counts placed orders and other drafts, but not the replenishment draft being topped up. A size needing nothing more is skipped.
|
||||
|
||||
- The supplier is the garment's supplier, or the first supplier in `Settings › Catalogue & suppliers` when it has none.
|
||||
- A line already on the draft is raised to the new figure if that is larger, never added to.
|
||||
- A supplier with no replenishment draft gets a new one, dated today, expected after the supplier's lead time or 14 days when none is set.
|
||||
|
||||
Nothing reaches a supplier until the draft is marked ordered or raised from the order list.
|
||||
|
||||
On the phone, the count's variance screen says how many lines will fall to or below their level, and committing the count opens the Reorder screen.
|
||||
|
||||
## The forecast's suggested level
|
||||
|
||||
The product page's `Ordering` panel shows, for each size, a usage figure and a suggested level. It is worked out from issues already recorded:
|
||||
|
||||
1. **Usage.** Garments of that size issued in the last 13 weeks, averaged per week. If none were issued in 13 weeks, the last 26 are used. Pre-loved issues are not counted.
|
||||
2. **Lead time.** The supplier's lead time in days divided by 7, or 2 weeks when none is set.
|
||||
3. **Suggested level.** Weekly usage × (lead time in weeks + 2), rounded up.
|
||||
|
||||
The label reads like `3.1 wk cover · ~4/wk`: how many weeks the shelf lasts at that rate, and the weekly rate. With no issues in 26 weeks it reads `no usage yet` and nothing is suggested. A `runs out before delivery` tag appears when the weeks of cover are fewer than the lead time; the same size is tagged `runs out` on the order list.
|
||||
|
||||
A suggestion writes nothing. **Use** sets it as the size's level.
|
||||
|
||||
> **In plain terms** The suggestion covers the lead time plus 2 weeks at the recent rate of issue.
|
||||
|
||||
## What is written
|
||||
|
||||
| Action | Record · Change | Undo |
|
||||
|---|---|---|
|
||||
| − / +, Use | That size's reorder level | Set it again |
|
||||
| Set reorder (bulk) | The level on every size of each selected product | Set it again per size |
|
||||
| Default reorder level | Facility setting, read by every size without its own | Change it back |
|
||||
| Order flagged | Replenishment draft per supplier: created, or lines added or raised | Remove lines on the draft, or cancel it (Admin) |
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Stocktakes
|
||||
section: stock
|
||||
order: 4
|
||||
summary: Counting the shelf at the desk or on a phone, blind counts, variance in garments and dollars, the reasons a large gap needs, and what committing files.
|
||||
screen: Stock › Count
|
||||
role: Admin or Issuer
|
||||
keywords: stocktake, count, audit, stock count, blind count, variance, shrinkage, count sheet, reason, missing, condemned, laundry, commit, location, shelf
|
||||
---
|
||||
|
||||
## Counting at the desk
|
||||
|
||||
`Stock › Count` lists every size of every current garment with the figure ThreadCount holds (`System`) and a `Counted` box.
|
||||
|
||||
1. **Narrow the scope.** Filter by name, SKU, size or barcode, or pick a staff group. `Uncounted` hides lines already counted.
|
||||
2. **Count.** Scan a garment into the scan box and each scan adds 1 to its line; **Camera** does the same. Or type the figure into `Counted`.
|
||||
3. **Watch the tiles.** `Lines counted`, `Variances`, `Net value` and `Gaps needing a reason`, with a bar showing how much of the scope is counted.
|
||||
4. **Zero uncounted in scope** sets every uncounted line in the scope to 0, for a count where the rest of the shelf is empty.
|
||||
|
||||
The tally is kept in this browser for the signed-in person until it is filed or cleared, and the screen says when the last entry was made. **Clear counts** starts again. A code that matches nothing opens the [unknown barcode](/docs/stock/barcodes) dialog.
|
||||
|
||||
`Shelf` counts stock on hand. `Pre-loved pool` counts the pool of handed-in garments instead, carried at nil value. The desk count is scoped by group and filter; counting by location is done on a phone.
|
||||
|
||||
## Blind counts and the count sheet
|
||||
|
||||
`Blind` hides the `System` and `Variance` columns and the `Variances` and `Net value` tiles, so the counter can't see the expected figure. A counted line shows a tick. A line that needs a reason still asks for one.
|
||||
|
||||
**Print count sheet** prints the lines in scope, grouped by garment, with the size, the bound barcode, the system figure and an empty box. In blind mode the system figure is left off and the sheet is marked `BLIND COUNT`.
|
||||
|
||||
## Variance and reasons
|
||||
|
||||
A line's variance is counted less system. `Net value` is each variance times the garment's unit cost, added up: what filing the count would move in dollars.
|
||||
|
||||
A gap as large as `Settings › Issuing rules › A count gap needs a reason at` or larger, over or short, must carry a reason: `At laundry`, `Condemned`, `Missing` or `Other`. The setting starts at `5` and is never treated as less than 1. Lines still owing a reason are moved to the top of the list, and the count can't be filed until each has one. The server refuses the whole count if one arrives without.
|
||||
|
||||
## Committing
|
||||
|
||||
The button reads **File count** when every counted line matched and **Apply adjustments** when some didn't.
|
||||
|
||||
- Only counted lines are sent. Uncounted lines are left as they are.
|
||||
- Every counted line is filed, matching or not, so each size's `Last counted` date on `Stock › On hand` is right.
|
||||
- Each variance moves stock on hand by the difference. In `Pre-loved pool`, the pool is set to the counted figure.
|
||||
- The system figure is read again on the server when the count is filed.
|
||||
|
||||
## Filed counts
|
||||
|
||||
`Stocktake history`, below the count, lists filed counts newest first: date, who counted, lines counted, variances, and the net change in garments and dollars. Open one to see each variance with its dollar value. **CSV** downloads that count's variance lines with unit cost and variance value. The latest 200 filed counts are held on screen.
|
||||
|
||||
In the counter app, `Variance` charts each size's gap across the last 6 shelf counts.
|
||||
|
||||
## Counting on a phone
|
||||
|
||||
In the [counter app](/docs/apps/counter-app), `Stocktake` lists every location that has garments placed on it, counting the locations inside it, plus `Not on a shelf yet`. Sizes are placed on a shelf from the `Sizes` panel on a garment's page; locations are made in `Stock › Locations`.
|
||||
|
||||
1. **Pick the location.** Each line shows counted over expected, and the expected figure stays on screen.
|
||||
2. **Scan.** Each scan adds 1. A code placed on another shelf is refused with that shelf's name. **Undo** takes 1 off the current line; **Type a count instead** is for a label that won't scan.
|
||||
3. **Finish count.** The variance screen lists lines that don't match, with **Recount** and the reasons for large gaps.
|
||||
4. **Commit count.**
|
||||
|
||||
The tally is kept on the phone for that person and that location until committed, and is cleared when that person signs out of the counter app.
|
||||
|
||||
> **Careful** A phone commit files every line on that location, and a line nobody scanned is filed as 0.
|
||||
|
||||
## What is written
|
||||
|
||||
| Action | Record · Change | Undo |
|
||||
|---|---|---|
|
||||
| Counting (desk or phone) | Nothing on the server; the tally is kept on the device | Clear counts |
|
||||
| File count / Apply / Commit | A stocktake: date, who, lines counted, variances, shelf or pool, and the location for a phone count; a line per counted size with system, counted and reason | No undo; a filed count stays in history |
|
||||
| A variance on the shelf | Stock on hand moved by the difference | Count again, or Adjust quantity (Admin) |
|
||||
| A variance in the pool | The pre-loved pool set to the counted figure | Count again, or Adjust quantity › Pre-loved |
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title: Suppliers
|
||||
section: stock
|
||||
order: 7
|
||||
summary: The supplier directory, the contact, account, order email and lead time each supplier carries, the supplier's code for each size, and where each is used.
|
||||
screen: Settings › Catalogue & suppliers
|
||||
role: Admin
|
||||
keywords: supplier, vendor, supplier directory, lead time, account number, order email, contact, supplier code, product code, remove supplier
|
||||
---
|
||||
|
||||
## The supplier directory
|
||||
|
||||
`Settings › Catalogue & suppliers` lists every supplier the facility buys from, each in its own panel with the number of products and orders that use it.
|
||||
|
||||
1. **Type the name** into `New supplier`, for example `Northline Workwear`.
|
||||
2. **Press Add supplier.** A name already on the list, in any mix of capitals, is refused.
|
||||
|
||||
A supplier is also added when a garment is saved, bulk-changed or imported with a supplier name the directory doesn't hold. The match is made without regard to capitals, and the garment is stored with the directory's spelling, so `northline workwear` finds `Northline Workwear`.
|
||||
|
||||
A supplier's name can't be changed once added. **Export CSV** downloads the supplier, contact, phone, account number, lead time, and the number of products and orders for each.
|
||||
|
||||
## Each supplier's details
|
||||
|
||||
| Field | What it holds |
|
||||
|---|---|
|
||||
| `Contact person` | Who to ask for |
|
||||
| `Phone` | The supplier's phone number |
|
||||
| `Account no.` | The facility's account with the supplier |
|
||||
| `Order email` | Where purchase orders are emailed; blank means print or CSV only |
|
||||
| `Lead time (days)` | Days from ordering to delivery; blank means none set |
|
||||
|
||||
Changes save as you type. An order email that isn't an email address is refused, and it is stored in lower case. An Issuer sees the fields but can't change them.
|
||||
|
||||
## Where the details are used
|
||||
|
||||
- **Lead time** sets the expected delivery date: in `New order` when the supplier is picked, on orders raised from the [order list](/docs/stock/order-list), on replenishment drafts, and on back orders. With none set, those orders expect delivery in 14 days. The forecast reads it in weeks, and assumes 2 weeks when none is set (see [reorder levels](/docs/stock/reorder-levels)).
|
||||
- **Contact, phone and account number** print on purchase orders. The A4 order sheet also prints the order email, and the order list shows the account number beside each supplier's group.
|
||||
- **Order email** is the only address **Email** and **Email supplier** send to. Without it they are refused with a note to add one here.
|
||||
|
||||
## The supplier's code for each size
|
||||
|
||||
Suppliers number each size and colour of a garment separately. Record that code on the product page, in the `Ordering` panel, against each size (up to 60 characters). An Issuer sees the codes but can't change them.
|
||||
|
||||
The code is printed against the line on the A4 order sheet, in the order CSV and in the order email, so it can be keyed into the supplier's own site. Where a size has none, the sheet and the email use the garment's SKU. On the order list a missing code shows as `no code`, linked back to the product page.
|
||||
|
||||
The supplier code is separate from the barcode: it is what the supplier calls the size, and the [barcode](/docs/stock/barcodes) is what a scanner reads.
|
||||
|
||||
## Changing and removing a supplier
|
||||
|
||||
A garment's supplier is changed on its product page with **Edit product**, or for several at once with `Change supplier…` on the multi-select bar of `Stock › On hand`. Changing a garment's supplier doesn't change existing orders. An order's supplier can be changed on the order page until it is received or cancelled.
|
||||
|
||||
**×** on a supplier's panel removes it, and appears only when no product and no order uses it. The server refuses the removal otherwise.
|
||||
|
||||
> **In plain terms** A supplier that has ever been used stays in the directory, so its orders keep their contact and account details.
|
||||
|
||||
## What is written
|
||||
|
||||
| Action | Record · Change | Undo |
|
||||
|---|---|---|
|
||||
| Add supplier | Supplier record with its name | Remove it while nothing uses it |
|
||||
| Edit a detail | That field on the supplier | Edit it again |
|
||||
| Remove | Supplier record deleted | Add it again and re-enter the details |
|
||||
| Supplier code | The code on that size of the garment | Edit or clear it |
|
||||
@@ -0,0 +1,127 @@
|
||||
# Self-hosting ThreadCount (Community edition)
|
||||
|
||||
The Community edition is the hosted product with `EDITION=community` in its environment. This
|
||||
page says what that changes, how to run it, how to keep it, and what is not included.
|
||||
|
||||
## What `EDITION=community` changes
|
||||
|
||||
The Community edition is the product a single room uses, and nothing that belongs to the hosted
|
||||
service. Its source is an export of the hosted code with the hosted-only parts left out.
|
||||
|
||||
| | Hosted (threadcount.tech) | Community |
|
||||
|---|---|---|
|
||||
| Coordinator app (`/app`), phone counter (`/m`), staff app (`/my`) | Yes | Yes, in full |
|
||||
| Plans, staff ceiling, read-only for non-payment | Yes | None. Every facility behaves as a grandfathered one. |
|
||||
| Website, pricing, guides, legal pages | Yes | Not included. `/` goes to sign-in. |
|
||||
| Demo facility | Yes | Not included |
|
||||
| Health-service layer (organisations, shared catalogue) | Yes | Not included |
|
||||
| Single sign-on (SAML/OIDC) | Yes | Not included. Password plus authenticator code. |
|
||||
| Card payments | Where configured | Not included |
|
||||
| Cloudflare Turnstile on sign-in and sign-up | Required | Optional. Set both keys to enforce it; without it the per-address rate limits stand alone. |
|
||||
| Error reports | To ThreadCount's own GlitchTip, scrubbed | Nowhere, unless you set `NEXT_PUBLIC_GLITCHTIP_DSN` to your own |
|
||||
| Usage statistics | To ThreadCount's own Umami, scrubbed | Nowhere. The tracker only mounts on `*.threadcount.tech`. |
|
||||
| Transactional email | ThreadCount's SMTP | Your SMTP, or none |
|
||||
|
||||
Your instance is yours, and so is the privacy statement your staff read. The product's screens
|
||||
link to the terms and the privacy notice from a few places (the staff sign-in, account screens);
|
||||
set `NEXT_PUBLIC_TERMS_URL` and `NEXT_PUBLIC_PRIVACY_URL` to your own documents before you build,
|
||||
or they point at threadcount.tech's.
|
||||
|
||||
## Running it
|
||||
|
||||
`docker-compose.yml` runs three services: `db` (Postgres 16, in a named volume), `migrate` (a
|
||||
one-shot `prisma migrate deploy` that runs before the app on every `up`), and `app` (Next.js's
|
||||
standalone server, port 3000, photographs in a second named volume). Put TLS in front of port
|
||||
3000. A minimal Caddyfile:
|
||||
|
||||
```
|
||||
uniforms.example.health {
|
||||
reverse_proxy 127.0.0.1:3000
|
||||
}
|
||||
```
|
||||
|
||||
The image is built on your machine, not pulled, because `NEXT_PUBLIC_SITE_URL` and the optional
|
||||
Turnstile site key are compiled into the browser bundle. If you change either, rebuild:
|
||||
`docker compose up -d --build`.
|
||||
|
||||
### The first facility
|
||||
|
||||
Open the hostname. Create an account; that creates a facility and makes you its administrator.
|
||||
Under Settings, name your staff groups first (nothing works until a facility has them), then load
|
||||
the catalogue, departments, staff register, barcodes and opening stock from CSV under Settings ›
|
||||
Data. Add a second administrator under Settings › Account › Users before you sign out — a
|
||||
forgotten password with one admin and no SMTP locks the facility.
|
||||
|
||||
Then set `SIGNUPS_DISABLED=1` in `.env` and `docker compose up -d`. Your instance is now one
|
||||
facility, and nobody else can create another.
|
||||
|
||||
## Upgrading
|
||||
|
||||
Each release replaces the repository's history rather than adding to it, so a plain `git pull`
|
||||
refuses to merge. Fetch and move to the release instead. Your `.env` is not tracked and stays put.
|
||||
|
||||
```sh
|
||||
git fetch origin
|
||||
git reset --hard origin/main
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
`migrate` applies any new schema migrations before the new app starts; the old app keeps
|
||||
serving until then. Take a backup first (below). Releases that need more than that say so in
|
||||
their notes.
|
||||
|
||||
## Backups
|
||||
|
||||
`docker/backup.sh <directory>` writes one directory per run: the database as a custom-format
|
||||
`pg_dump` and the photographs as a tarball, keeping the last fourteen. Run it nightly from cron:
|
||||
|
||||
```
|
||||
30 3 * * * cd /srv/threadcount && docker/backup.sh /srv/backups/threadcount >> /var/log/threadcount-backup.log 2>&1
|
||||
```
|
||||
|
||||
Copy that directory somewhere off the machine. A backup on the same disk as the database is not a
|
||||
backup.
|
||||
|
||||
Separately, an administrator can download the whole facility as one JSON file from Settings ›
|
||||
Data at any time, and restore it into a fresh instance from the same screen. That file is the
|
||||
portable form; the `pg_dump` is the fast one.
|
||||
|
||||
### Restoring
|
||||
|
||||
```sh
|
||||
docker compose down
|
||||
docker volume rm threadcount_db threadcount_photos # only if you mean to replace everything
|
||||
docker compose up -d db
|
||||
docker compose exec -T db pg_restore -U threadcount -d threadcount --clean --if-exists < 2026-09-13-033001/threadcount.dump
|
||||
docker compose up -d
|
||||
docker compose cp 2026-09-13-033001/photos app:/data/ # after extracting photos.tgz
|
||||
```
|
||||
|
||||
## The Android apps
|
||||
|
||||
The two Play apps (ThreadCount, the counter; ThreadCount Staff) can point at your server. On the
|
||||
app's first screen tap "Server: threadcount.tech · Change", choose Self-hosted, and enter your
|
||||
hostname. The app checks it over HTTPS (it calls `/api/app-info`, which every ThreadCount server
|
||||
answers), saves it on the phone, and opens your counter or staff screens from then on. The choice is
|
||||
per phone; "Change" is always on the first screen, and the sign-in screens show which server they
|
||||
are talking to.
|
||||
|
||||
Two things stay tied to threadcount.tech's domain and do not carry over: emailed approval links
|
||||
opening straight in the staff app (they open in the browser instead, and work there), and saved
|
||||
passwords shared between the website and the app. The phone must be able to reach your server over
|
||||
HTTPS with a certificate it trusts; a self-signed certificate is refused.
|
||||
|
||||
Without the apps, the same screens work in a phone's browser: `https://your-host/m` for the
|
||||
counter (camera scanning works in Chrome and Edge) and `https://your-host/my` for staff.
|
||||
|
||||
## Environment reference
|
||||
|
||||
`.env.example` lists every variable the application reads, with a comment on each. The ones that
|
||||
matter for a Community instance are `SESSION_SECRET`, `POSTGRES_PASSWORD`, `NEXT_PUBLIC_SITE_URL`,
|
||||
`EDITION`, `NEXT_PUBLIC_TERMS_URL`, `NEXT_PUBLIC_PRIVACY_URL`, the `SMTP_*` group, and
|
||||
`SIGNUPS_DISABLED`. Leave the Turnstile and GlitchTip variables empty unless you run those yourself.
|
||||
|
||||
## Getting help
|
||||
|
||||
Open an issue on the repository. If you would rather someone else ran it, that is what
|
||||
[threadcount.tech/pricing](https://threadcount.tech/pricing) is for.
|
||||
Reference in New Issue
Block a user