Skip to content

Code audit fixes, a roomier Reports screen, and better menu and retail item management - #434

Merged
No0ne558 merged 17 commits into
mainfrom
claude/audit-and-ui
Oct 30, 2026
Merged

No0ne558 merged 17 commits into
mainfrom
claude/audit-and-ui

Conversation

@No0ne558

Copy link
Copy Markdown
Contributor

A code audit with its fixes, a Reports screen that leaves room for the report, and better ways to manage menu and retail items. One commit per change, each with tests; the audit's findings are written up in modern/docs/AUDIT-2026-10.md.

Audit fixes

  • Tax: a percent discount lowered the tax on lines it didn't come off ($10 food and $10 wine that can't be discounted, 50% off, taxed each on $7.50). With discounts capped at the items total, each discount's line on the receipt is now capped too.
  • Database: a row SQLite would always refuse no longer stops every later write: after five tries it goes to <database>.unsaved.jsonl and the manager is told; retries back off. Migration 13 (cash tips column) is one transaction, and a database left half-migrated by it opens. Indexes for lookups by time (made on opening, not a schema version, so a standby a version behind still opens it).
  • Standby: only plain table and column names go into SQL; five wrong take-over PINs and it waits (30 s, doubling to 15 min).
  • Network: a long message arriving in pieces isn't searched again from its start; a runaway line on the standby and pairing connections closes it. Terminals back off to 10 s between tries and give up a try after 10 s. Discovery ignores an impossible port.
  • Offline: a screen's check sent again after End of Day isn't booked twice.
  • Manager screens: numbers with a comma for the decimals ("18,5").
  • Import: a sheet with Cost and Price columns takes the price as the price.
  • Scanning: a UPC read as EAN-13 (a 0 in front) rings the item in on the order screen.
  • Page editor: "Opens on" lists every report.

Left for a decision (changes saved data or a larger rework), in the write-up: past tax worked out at today's rates in range reports, doubles in labor/tip pool/stock math, the standby copy and some reads on the main thread, adminChanged refreshing 33 properties, the kitchen display rebuilding every card.

Reports

  • The reports are a list by kind (Sales, Staff, Money, Stock, Guests, Checks) in the column that was empty beside the report; on a phone, one key with the report's name opens it over the report.
  • The days are one row to slide, folded away while reading further down. Multi-day choices are dimmed for one-day reports, and picking one goes back to Day (it showed Sales before).
  • A swipe across the report goes to the next or previous one; tables wider than the screen slide sideways; value columns fit what's in them.

Menu and retail items

  • ☰ List in the Menu Builder: every item in one table (name, category, price, tax, number/barcode), sorted by a heading, narrowed to a category, sold out or no code. Find matches any part of a name, number, barcode, category or kitchen name, with no limit.
  • Select → Price… / Tax…: set one price, or move each item's price by an amount or a percent (with a before → after check); set the tax for all. One Undo each.
  • More… opens the Menu panel on that item.
  • Track stock on the card: On hand, Low at, Cost (and margin). An ingredient of the item's own behind it, so sales count it down (a shop's too), void puts it back, sold out at none, Count Stock, deliveries and the Stock report all work.
  • A code nothing has, scanned with a manager on: Add an Item With It opens a new card with that barcode.
  • Export → As a Spreadsheet (.csv), under headings Import… reads back.
  • Hand-built menu pages: a new item's button goes by itself on the page with its category's items.

Tests

The full suite (681 test cases) passes locally on Ubuntu 26.04 with Qt 6.10. New tests cover each fix and feature; translations for es, fr, pt and zh are included (tools/i18n.py check clean).

🤖 Generated with Claude Code

https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8

No0ne558 and others added 17 commits October 29, 2026 20:45
A percent off was worked out on the lines that may be discounted, but its
share of each tax class was spread over every taxed line by sales. A 50%
discount on $10 of food beside $10 of wine that can't be discounted
taxed each on $7.50: too little tax on the wine, too much on the food.

Each discount now carries its own share of each class: a percent off on
the class's lines it applies to, a fixed amount over everything that may
be discounted. When discounts are capped at the items total, each one's
line on the receipt shrinks too, so they add up to what came off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
A failed batch went back on the queue and was tried again every two
seconds for good. A row SQLite would always refuse (a table a standby
doesn't have yet, a constraint) held up every later sale, and they piled
up in memory.

A row refused five times running for its own fault (not a full or busy
disk) is now written to <database>.unsaved.jsonl and taken out of the
line; the rest save at once, and the manager is told. Retries wait
longer each time, up to a minute. Each batch prepares one statement per
kind of row instead of one per row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
A stop between adding the column and moving the schema version left a
database every later start refused (the column was already there). Both
now happen in one transaction, and a database left that way by an older
ViewTouch opens: only its version moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
The writer puts table and column names into its statements as they are.
A standby takes them from the main server's messages, so a peer that
sent something else could change what runs. Names other than letters,
digits and _ are now refused and reported, never queued.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
Taking over as the main server asked for a manager's PIN with no limit
on tries: a paired screen could try every four-digit PIN. After five
wrong ones it now waits 30 seconds, twice as long each time after (up
to 15 minutes); the right PIN starts the count again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
…tart

Each piece of a long message (a welcome, a standby copy) searched the
whole buffer again for its end, so a 32 MB one arriving 64 KB at a time
did hundreds of times the work. Now only what's new is searched. A line
past the limit on a connection that doesn't check for one (the standby,
pairing) now closes it instead of growing without end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
A screen's offline check was recognized as already taken in only among
the open checks and today's closed ones. If End of Day ran before the
screen heard back, sending it again booked the sale a second time. The
saved days around it are looked at too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
Time punches, refunds, shifts, deliveries, problems and parties were
read by time with no index, so every lookup read the whole table: slow
for a store with years of data. Made on opening; an older ViewTouch (a
standby a version behind) opens the database the same with them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
A terminal that couldn't reach the store's computer tried every 2
seconds forever, and a try to an address nothing answered waited for
the system's own timeout (minutes). After five tries it now waits a
little longer each time, up to 10 seconds, and a try still not through
after 10 seconds is given up and made again. A store's answer with a
port that isn't one is ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
"18,5" for a gratuity, a pay rate or a fee read as 0 or was refused,
while prices already took a comma. Number fields now read it the same
way ("1,250.00" still has a thousands comma).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
The reports screen put its 27 report keys in three rows (seven on a
phone), the days in another, then the day bar: about a third of the
screen, and on a phone nearly all of it, before the first line of the
report.

- The reports are a list by kind (Sales, Staff, Money, Stock, Guests,
  Checks) at the report's right, in the column that was empty above
  ‹ Manager. On a phone, one key with the report's name opens the list
  over the report.
- The days are one row of keys to slide. Days that can't be read over
  several days are dimmed for reports that are one day at a time, and
  picking such a report goes back to one day (it showed Sales before).
- Reading further down folds the days' row away; scrolling back up
  brings it back.
- A swipe across the report goes to the next or the previous report.
- Value columns are as wide as what's in them; a table wider than the
  screen slides sideways instead of cutting its numbers short.
- Print, CSV and PDF sit beside the day (on a phone under ⋯).
- The page editor's "Opens on" lists every report (Turns, Checklists,
  Drivers and IRS 8027 were missing).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
The Menu Builder showed one category's items as tiles at a time, its
Find matched only a name or an exact number (30 at most), and Select
could move, color, sell out or remove items, but not change prices or
tax.

- ☰ List shows every item in one table: name, category, price, tax and
  number or barcode. A heading sorts by it (again: the other way); All
  Items, the category, Sold Out and No Number or Barcode narrow it.
  A row opens the item's card; in Select, it is chosen, and All chooses
  every row shown.
- Find matches any part of a name, number, barcode, category or kitchen
  name, with no limit.
- Select → Price… sets one price, or moves each item's own price by an
  amount or a percent, showing a few before → after first. Tax… sets the
  tax for all of them. One Undo each (changeMenuItems: priceAdd,
  pricePercent).
- The card's More… opens the Menu panel on that item, not on an empty
  list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
- Scanning a code nothing has, with a manager logged in, offers Add an
  Item With It: the Menu Builder opens on a new item with that barcode.
- A barcode read with a 0 in front (a scanner that reads a UPC as an
  EAN-13) now rings the item in, as the rest of ViewTouch already
  matched it.
- A spreadsheet with both a Cost and a Price column now imports the
  price as the price. The first of the two used to win, so a shop's
  sheet put what it paid on the menu. A sheet with only Cost still uses
  it as the price.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
A shop's item (a T-shirt, a bottle of wine) could only count its stock
by making an ingredient in Inventory and typing a recipe line for it in
the Menu panel.

The card now has Track stock, with On hand, Low at and Cost (and the
margin it leaves). Behind it is an ingredient of the item's own, one
used up for each sold, so everything the kitchen's stock does works for
it: counted down on a sale (also a shop's, paid without being sent),
back on a void, Running low, sold out by itself at none and back when
restocked, Count Stock, deliveries and the Stock report. Saving the card
without touching the count keeps what sold since it was opened. Turned
off, an item sold out for want of its stock is for sale again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
Export wrote only ViewTouch's own file, for another store's Import…, so
an owner couldn't go over prices in a spreadsheet. Export now also
offers As a Spreadsheet (.csv): every item with its category, price,
cost, tax, number, barcodes, stock and sold out, under headings Import…
reads back (Update prices brings changed prices in). Saved with a
byte-order mark, so Excel shows accented names right.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
On a store whose menu pages have buttons placed by hand, a new item
didn't show up anywhere until a manager added its button, one page at a
time (Also a button on). A new item's button now goes by itself on the
page with its category's items (the one with the most of them), in the
next free place, sized and styled like its neighbors. Removing an item
already removed its buttons. Self-filling pages need neither.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015JJaarV4sfTKegR57HYFZ8
@No0ne558
No0ne558 merged commit 2ee50c6 into main Oct 30, 2026
1 check failed
@No0ne558
No0ne558 deleted the claude/audit-and-ui branch October 30, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant