One tap says how hot, and the ticket prints it the same in every language - #772
Merged
Merged
Conversation
…uage Spice is what a restaurant is asked to change more often than anything else on its menu, and the only way to ask was typing it into the note: in whatever words, in whatever language, for a kitchen that then has to read prose off a ticket at speed. Three levels, one chilli more on each, on the dishes the shop says its kitchen can really cook to order. Not choosing is an answer and needs no button. A level prints identically on every ticket whatever language the order was placed in, and can be counted afterwards, which no amount of free text will ever allow. Per dish, because a kitchen that batch-cooks its gravy cannot make one portion mild, and a customer who asked for mild and got hot is worse off than one who never asked. It travels by the road the note already took: sale line, change record, approval queue, paper. The kitchen ticket is printed from changes[], not from sale.items, so a field stored on the sale and missing there never reaches the kitchen. The test asserts the rule rather than the spelling: every place that carries the note carries the level. Also fixes a bug found on the way. order/indexedDB.js builds the ordering bundle's whole catalogue in one object literal, and a field it does not name there never reaches the page. nutrition, tags, marks and claims have been sent by the server since the dish-facts release and all four stopped at that literal, so /order drew no numbers, no badges and no marks and its "Good for" filter had nothing to offer, while /menu showed all of it. The test asks the server what a dish carries rather than naming the fields, so a fifth fact fails until the page is told to keep it.
Contributor
|
Merged to Try it at https://develop.posnic.io, or run it yourself: git fetch origin develop && git checkout develop
npm install && npm --prefix api install
npm run dev # then http://localhost:3000When you have tested it, say what you did and what happened, and set Reporting that something is broken is as useful as fixing it. It is |
This was referenced Sep 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Owner: "when user order if food is speci food. we can have simple option like low, medium high with number chilly image like one, two, three chilli icons user can customize easy. we can add those into kitchen note. what you think?"
I think yes, with three decisions worth defending.
Three levels, and not choosing is one of them
Mild, medium, spicy. There is no fourth button for "however the kitchen makes it": that is the answer most people give and a default that has to be selected turns a tap into a question. Once a level is set, a plain link takes it back off - the only way to undo a radio is to offer the undo. Anybody who wants no chilli at all still has the note, which has not moved.
Per dish, not per menu
A kitchen that batch-cooks its gravy cannot make one portion mild, and a customer who asked for mild and got hot is worse off than one who never asked. So the offer exists only where it can be honoured, and only the kitchen knows where that is: one tick on the dish card, off by default.
A field, not a sentence in the note
The obvious build appends "less spicy" to the kitchen note, and it is wrong twice over. A customer reading a Tamil menu writes Tamil, so the ticket carries prose the kitchen may misread; a level prints identically on every ticket whatever language the order was placed in. And a number can be counted afterwards - a shop can learn that four orders in ten ask for mild, and cook accordingly - which no amount of free text will ever tell it.
ASCII on the paper, deliberately:
escpos-receipt.jsputs every character throughascii()and latin1, so an emoji would arrive as a question mark. The chillies are drawn on the phone; the paper gets the word and the count, because a cook who does not read English still reads 2 of 3.It travels by the road the note already took
The kitchen ticket is not printed from
sale.items- the poller builds its print jobs out ofchanges[].items. That is what made the note bug so hard to find last month: every layer worked and the paper was still wrong. A level stored on the sale and missing from the change record would be the same bug shipped again in the same month, so the test asserts the rule rather than a spelling: every place insale.repository.jsthat carries the customer's note carries the level beside it. Eight places; ondevelopall eight were bare.It also reaches the approval queue, because that screen is where an order is refused and "we cannot make that one mild" is a reason to refuse it - unusable if the request only appears on paper in the kitchen.
The bug this found, which is not about spice
order/indexedDB.jsbuilds the ordering bundle's entire catalogue in one object literal, and a field it does not name there never reaches the page, however correctly the server sent it.nutrition,tags,marksandclaimshave been sent since the dish-facts release. All four stopped at that literal. So on/orderthe dish sheet drew no numbers, no badges and no marks, and the "Good for" filter group had nothing to offer and hid itself - while/menu, which reads the same endpoint without a local store, showed all of it. Nothing failed, nothing was logged, and every test passed because they all read the source rather than running it.Verified against
develop's tip:dropped on HEAD: nutrition, tags, marks, claims.The test for it asks the server what a dish carries (
Object.keys(dishFacts.factsFor({}))) rather than naming fields here, so a fifth fact added tomorrow fails until the page is told to keep it.Two things the tests caught that reading would not have
Number(true)is 1. Every path here doesNumber(value), so a client sendingspice_level: truewould have had MILD printed on real paper for a request nobody made. All three implementations now refuse anything that is not a number or the text of one.A code example in a comment became a translation site. The i18n collision scanner reads
i18n.t('key', 'English')out of source, and a comment explaining that rule contained a literal example of it.one key, one meaningfailed on a key calledkey.Two copies of three words, on purpose
src/cannot require intoapi/: the API ships outside the asar asextraResources/server.js. Same reasonthe-ticket-says-where-the-order-came-from.test.jsgives for its own duplicated table. So the words are written twice andtests/the-ticket-says-how-hot.test.jsruns both implementations over every input -0 1 2 3 4 -1 '1' '2' '3' '' null undefined NaN true 'hot' {} []- and refuses a commit where they disagree.Checks
sale.repository.jsfrontend/publicbuilt, which CI doeslang_keys translated into all 17 packs; the ordering dictionary's Tamil added and the two byte copies verified identical after the commit hook