Skip to content

dev to main - #839

Merged
sridharkalaibala merged 17 commits into
mainfrom
develop
Sep 16, 2026
Merged

sridharkalaibala merged 17 commits into
mainfrom
develop

Conversation

@sridharkalaibala

Copy link
Copy Markdown
Contributor

What does this PR do?

Acceptance criteria covered

  • Linked issue has clear acceptance criteria, or this PR adds them first
  • This PR completes the listed criteria or names the remaining work

How was it tested?

Checklist

  • One focused change per PR
  • Only people are credited as authors/contributors; no AI tool attribution or signature footer is included
  • Commits are signed off (git commit -s, DCO)
  • Works fully offline (no new external network calls in the local edition)
  • Matches surrounding code style
  • No real customer, tax, payment, credential, token, or production data is included

Owner, holding a printed bill from Azure: "Table number, order type,
covers, total quantity all these information can organize better as per
international standards and may be two column or moving total quantity
to bottom."

Two different mistakes, and he is right about both.

FOUR FACTS TOOK FOUR LINES. Table, order type and covers are read at a
glance, not down a list, and stacked one per line they pushed the items
further down the paper than the things a guest is actually checking.
They now sit two to a line with a two-character gutter, because without
one the left value runs straight into the right label and prints
"6AOrder type".

Narrow paper keeps one to a line on purpose. A 58mm roll is 32
characters; halved that turns "Order type" into "Order ty.", and losing
a word to save a line is the wrong trade on the document the guest
keeps.

THE COUNT WAS IN THE WRONG PLACE ENTIRELY. Total quantity is not a fact
about the table, it is part of the arithmetic: how many things, what
they came to. It sat in the header beside the table number, which is
where the restaurant looks and not where the guest does. It now prints
immediately above the subtotal, and the test pins that nothing is
allowed between the two.

7 new tests, driven through the real renderer and read back out of the
bytes with escpos-preview. The switch-liveness test learned where the
count went rather than being loosened - it still refuses a switch that
changes nothing, it just no longer assumes every switch writes a header
row.

2809 desktop tests pass. Two api suites fail to load on main already,
from an earlier merge, and are untouched by this.
It asserted the exact contents of serviceRows, including
{ label: 'Total Qty', value: '5' }, so moving the count down to the
totals read as a deletion.

Taught rather than loosened. It still pins every other service row
exactly, and now also asserts the count is on the payload as totalQty,
is NOT in serviceRows, and actually prints - so the row cannot quietly
disappear altogether, which is the thing the original assertion was
there to prevent.
Four failures on develop, none of them from a feature, all of them the
same shape: a thing that is generated or counted, and a change that did
not regenerate it.

tests/unit/routes/items.routes.test.js mocked the validation middleware
and did not list validateSoldOut, so the route got `undefined` where a
handler belongs. router.post throws "argument handler must be a function"
at REQUIRE time, which fails the whole suite before a single test runs -
2 suites, 0 tests. The route itself is fine and is serving in production.

tests/unit/middleware/items.validation.test.js fakes the express-validator
chain link by link, and the sold-out validator uses isBoolean, which the
fake did not have. Same failure mode: not at the assertion, at require.
The fake now carries every link the real chain offers, so the next
validator does not do this again.

languages/server/_english.json was out of date; the tool that writes it
says so by name in the failure message.

The README's REST badge said 658 and there are 659 routes.

Whitespace, a generated file, a number and two test fakes. No behaviour.

All four are the cost of the same missing habit: when a change adds a
route, a message or a validator, something generated has to be
regenerated, and nothing says so until CI does.
Develop is green again, for the third time
Owner: "whenever new KOT received one tink sound with full sound i want.
need to place in kitchen. if possible read the items. Example Table 5 new
order. Ting! one chicken briyani, one chicken tikka masala."

A printer in a kitchen is silent and a ticket is small. A cook with their
hands in a pan does not see one arrive, and the first anybody knows is a
waiter asking where the food is. A speaker says it across the room
without anybody having to look at anything.

    Table 5, new order. One Chicken Biryani. One Chicken Tikka Masala.

THE TING FIRST, AND THE WORDS WAIT FOR IT rather than starting on a
timer. A speaker still ringing while it talks loses its first two words,
and the first two words are the table number - the one part nobody can
work out from the rest. A third tone, deliberately not either of the
existing two: a cook must never have to decide whether that was their
ticket or the counter's online order.

SAID WHEN THE TICKET IS CLAIMED, not after it prints. A jammed or empty
printer is exactly when a kitchen most needs to hear that a table
ordered; the silent failure this exists for is a ticket nobody knows
about. Behind the same claim that stops a ticket printing twice, so a
poll that sees the job again does not say it again.

SIX LINES, THEN HOW MANY ARE LEFT. Six courses from a table of six
arrive within seconds - kot-manager already debounces printing for that
reason. Read in full it is a minute of talking, and a kitchen that has
stopped listening does not hear the next one either. The paper still has
the detail.

NAMES AND COUNTS ONLY. Not notes, not descriptions, not prices. What
makes announcements fail is never that they said too little.

OFF BY DEFAULT AND PER MACHINE, not per shop. Only the machine at the
pass has the speaker. A shop-wide switch would make the counter talk in
front of customers, somebody would mute the counter, and on many installs
that is the same Windows volume the kitchen speaker is on. A till that
started announcing orders after an update is a support call.

English, by the owner's choice: "All english as of now."

A test caught a real mistake: bracketed text was being stripped from
names to drop decoration like "(Half)", which turned "Gobi (65)" into
"Gobi" - a different dish. The shop's name is the shop's.

Twelve tests, on the sentence and the switch, because those are the parts
that can be wrong without anybody noticing until service. The tone and
the speech engine belong to a sound card and a Windows voice, which a
test cannot stand in for honestly - this needs one try on the kitchen
machine before anybody trusts it.
A shop changed its address and its till kept printing the old one on
every bill. Not for a moment - for ten months. Its branch document still
carried updated_date equal to created_date, and every settings change it
had ever made was correct in the cloud, correct on the web, and invisible
to the machine at the counter.

Nothing had failed. The sync gateway offers a device only the rows whose
watermark has moved:

  { updated_date: { $gt: since.ts } }
  { $expr: { $gt: ['$updated_date', '$_syncMeta.at'] } }

and the settings write goes through the NATIVE driver, so the schema's
timestamps: { updatedAt: 'updated_date' } never fires. Nothing else set
it either. The row was simply never eligible to travel, and there is no
error for that.

Two lines, on both branch writes - the feature switches and the
locale/currency block. Fixing one and not the other would be worse than
fixing neither, because half a settings screen that syncs looks like a
settings screen that works.

5 tests, and they assert on what actually reaches updateOne rather than
on a helper the save path might not call. One of them pairs every write
with the collection it opened, so a new branch write that forgets the
stamp fails rather than joining the pattern. Checked by deleting one of
the two stamps and watching it fail.

This is the family this codebase keeps producing: a thing written,
correct, and read by nobody. Same as the module packaged where nothing
could require it, and the guard whose regex could never match.

Found because a shop's own bill printed the wrong address after the
cloud had been right for an hour.
Owner: "whenever market price or quick sale we want print the price in
the KOT... lets customer wants to have fish for rs500 so that kitchen
will prepare according to that."

Five hundred rupees of fish is a particular fish. For a dish priced at
the table the price IS the specification, and a kitchen cannot pick the
right one from the name alone.

For an ordinary dish off the card it is noise. A cook does not choose a
biryani differently because it costs 220, and a ticket with money on
every line is one where the line that matters stops standing out. So the
till marks two kinds of line and no others: a dish priced at the table,
and a one-off invented for this bill.

A quick sale needed naming separately. It HAS a catalogue price - it was
created a moment ago - so the dynamic test alone would have missed it,
and its price was still agreed with a guest rather than chosen on a card.

A dish whose daily price was set this morning prints no price, because
then the card prices it like any other dish. That is the whole point of a
shop updating it when they open.

NOT IN THE NOTE, though that was the suggestion. The note is what a
waiter typed. Putting anything else in it is exactly the bug that printed
a marketing paragraph to a kitchen this morning, and it would be the same
mistake with a different field.

"Rs" rather than the rupee sign: a kitchen printer that lacks the glyph
prints a box or a random character, and a wrong number on a ticket is
worse than a plain one. Bold, because on these lines the amount is part
of what to cook.

Eleven tests. One of them caught my own test helper eating the double E
in SEER: it stripped the letters ESC/POS uses as command parameters,
which are the same letters dishes are spelled with.
…is-worth

The kitchen is told what it is worth, where that matters
The packaging check caught this on the promotion PR, which is exactly
where it is meant to: the three files added for the kitchen announcement
were required at runtime and absent from build.files.

    src/order-alert.js requires src/kitchen-call.js
    src/kot-manager.js requires src/kitchen-announce.js
    src/main.js requires src/kitchen-announce.js

A packaged installer would have started and then failed with "Cannot find
module" on a customer machine, and nowhere else - not here, not in CI,
not on any machine running from source. That is the whole reason this
check exists, and the reason it runs before a release rather than after
one.

Found the night this was going to a client.
The kitchen files are packaged, or the installer cannot find them
Three things the owner asked about, and one he did not, which was the one
that would have kept the speaker silent.

A PAUSE BETWEEN DISHES. Owner: "little pause between line items." The
announcement was one sentence with full stops in it. A full stop is a
shorter gap than a kitchen needs, so it is now one utterance per line and
the engine leaves a real gap between them - long enough to hold one dish
in your head before the next arrives.

INDIAN ENGLISH. Owner: "its indian english. not so fluent." An American
voice reads biryani, paneer and kuzhambu like somebody who has never
ordered one. Windows ships en-IN voices, Heera and Ravi, so one is
preferred where the machine has it, then en-GB, then any English. Chosen
once and remembered: getVoices() fills in asynchronously, and asking per
ticket is how the first announcement of a service comes out in the wrong
accent. It also listens for onvoiceschanged, because asking at load
usually returns an empty list.

AND THE ONE THAT MATTERED MOST. Chromium refuses to play audio until
somebody has interacted with the page. On a counter till that is
invisible - it is clicked all day. On the machine at the pass it is the
whole problem: it sits untouched for hours, which is exactly when a
ticket needs announcing, and the chime would have been refused with
nothing in any log to say why. The switch is set before the app is ready,
because afterwards it is ignored.

I also claimed the script only loaded on one page of ten and "fixed" it.
That was wrong: `dashboard` is not a screen, it is the shell the fifty
seven modules run inside. The change was reverted rather than left in as
churn.

Twenty one tests. They still do not cover the speaker or the voice: that
needs the kitchen machine, a Bluetooth speaker and one real ticket.
Owner: "KOT total items also print and voice read please. so that chef's
can hear well."

    ------------------------------------------------
    TOTAL ITEMS                                    4

and, before the list rather than after it:

    Table 5, new order.
    Three items.
    One Chicken Biryani.
    Two Butter Naan.

BEFORE, because a number heard first is one you can count against. A chef
told three plates are coming notices when they have heard two. After the
list it is a fact nobody can act on.

PLATES, NOT LINES. One biryani and two naan is three things to cook and
two lines on the ticket. A kitchen works in plates, and the printed total
and the spoken one count it the same way on purpose - a cook checking the
paper against what they heard must not find two different numbers.

The count is the whole ticket even when the announcement is cut to six
lines and summarised. That is precisely when it earns its place.

Four older tests changed expectations rather than failed: they asserted
the exact sentence, and the sentence now carries the count. The other 64
tests around the ticket renderer pass unchanged.
The kitchen can actually hear it: a voice, real pauses, and no gesture
@sridharkalaibala
sridharkalaibala merged commit e7eb48c into main Sep 16, 2026
21 checks passed
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