Release: an order says when it will usually be ready - #792
Merged
Merged
Conversation
They place an order, get a token number, and then hear nothing. The list of this phone's orders said "With the kitchen" and that was the whole of it - which is the moment somebody walks up to the counter to ask, the one interruption an ordering channel exists to remove. Every food app they have used shows a time. Nothing here knows when food is actually finished: no cook marks a ticket done, so there is no ready signal and this does not invent one. It is an estimate from two things the shop really has told us - the slowest dish on the order, and the queue that was ahead of it - and the word "usually" does real work in the sentence. The slowest dish and not the sum of them. A kitchen does not cook the biryani, then the naan, then the dal; several hands work at once and the order leaves the pass when the slowest thing is done. Adding them up would quote an hour for a meal that takes twenty-five minutes, and an estimate always wrong in the same direction stops being read. Frozen at the moment it is made, and stored on the order. A figure recomputed on every refresh would creep as other orders arrive, and a promise that moves while somebody watches it is worse than one that is a little wrong. It stays silent wherever it would be guessing: a shop that has stated no prep times, an order still waiting for the shop to accept it (which says a length instead, because a clock time before anybody has started cooking is a fiction), a cancelled order, and a time that has already passed - an estimate counting backwards at somebody still waiting is worse than none. Found while wiring it: the estimate was computed after the document that uses it, which is a temporal dead zone and would have thrown on every single online order.
A customer is told when the kitchen usually has it ready
Two things, both about the moment a customer changes their mind. MORE FOOD NEEDS NOBODY'S PERMISSION. An extra naan costs the kitchen a naan it is glad to sell: nothing is wasted, nothing already cooked is thrown away, and the only answer anybody was ever going to give is yes. Holding that in a queue until somebody notices is a customer waiting on a decision that was not one. Taking something away is the opposite - the biryani may be in the pan, and whether it can be called back is a judgement only somebody in the kitchen can make. So the window now gates only the taking away. Inside it nothing has started and the order is still the customer's, exactly as before. Outside it, a request carrying both has its halves answered separately: the naan is already being made by the time the shop reads the question about the biryani. A delivery or a hotel room is still refused outright in both directions, because that is somebody else's money in the total rather than a question about the kitchen. AND THE CARD SAYS WHAT IT WOULD DO. It listed only the lines that moved, so "Chicken Biryani: 2 to 1" told a person nothing about whether that was most of the order or a detail of it - they had to open the sales screen to find out, by which time they were no longer deciding in a hurry. Every line is drawn now, the untouched ones stepped back, with what it was and what it would become side by side. And every request said "Asked to change", whether a customer had dropped one naan or emptied the order. Now that adding never becomes a request, every one of them is something being taken away and the card can say which: cancel the whole order, remove everything on it, remove an item, remove some items, or simply asked for fewer. A line going to nothing says REMOVED rather than "1 to 0", which is a sentence nobody reads at a glance. A request made before this shipped can still be sitting in the queue carrying an addition, so the card still reads one.
Owner: "we need year pattern required in the sales bill number example attached have 26 in the year. and then number increasing would be okay. you suggest per day increase or year wise reset better tell me international standards." And on the answer: "i accept recommandation and may configurable if people from EU and international. Blocker fix that. i dont know how its got SB1d14 and all." SB1D14-000051 is S, the branch's code, this till's gateway-assigned code, and a running number. The till code is what stops two tills in one shop minting the same number; it has been there since bill numbers went atomic. THE RULE. India, CGST Rule 46(b): a consecutive serial number, NOT EXCEEDING SIXTEEN CHARACTERS, of letters, digits, "-" and "/", UNIQUE FOR A FINANCIAL YEAR. The reference invoice he sent is exactly sixteen - VR26-27VIR006782 - because whoever built that hit the same wall. The EU VAT Directive asks only for a sequential number, with no length limit and no prescribed reset, so the year and the reset are settings and the charset is not. Not per day. A daily reset repeats numbers inside the year unless the date is in the number, and a date costs six to eight of the sixteen. It also destroys what an auditor actually uses: one consecutive run per year has visible gaps when something is cancelled, and three hundred and sixty-five short runs do not. utils/bill-number.js builds the number and shortens the RUNNING NUMBER when something has to give - never the year, which uniqueness depends on, and never the till code, without which two tills collide. With no year asked for it produces exactly what the template literal it replaced produced, pinned over 72 combinations. WHOSE MIDNIGHT. A bill rung up at 00:30 on 1 April in Chennai belongs to the new financial year. A cloud instance running in UTC would still call it March and number it into a year that closed half an hour ago. The period is worked out in the shop's own clock. THE ROLL-OVER IS ONE ATOMIC STEP. A read, a compare and a write would be three, and a year turns over at midnight in a restaurant that is still serving. One pipeline update on the counter row, so two tills billing in that second cannot both be given number one. Checked against a real mongod, not a mock of one. A counter written before any of this reads as "no period" rather than as a mismatch, or the first bill on every shop in the estate would restart at one. And it found a real one: the counter sale formatted its own number while the customer's ordering page called generateSalesIdForBranch, with both drawing on one counter. A shop turning the year on would have had it on its online orders and not on its counter bills, and the reset would have had the till reissuing numbers it had already given out. Both now come through one door. Off by default. Ninety shops are mid-year with a running series on their invoices; switching them on an upgrade would change the shape of every number overnight and restart the count in the middle of a year. A shop turns it on, best on the first day of its own year.
…ay-carry A bill number a tax invoice may carry
Adding is never a request, and a request says what it would do
Stage 5 of the print roadmap - "the customer knows". The thank-you page asked the shop one question, once, as it opened: is this paid yet. Everything that happened to the order after that - a person accepting it, a ticket coming out of a kitchen printer, the shop refusing it at 2am - happened behind the customer's back, and the only way to find out was to walk to the counter and ask. The stage's own warning is what shaped this: "Do not ship a stage nothing can move off. If Ready is unreachable because nobody presses anything, a frozen tracker is worse than none." Three of the four rungs everyone has seen on a delivery app are unreachable here. Nothing marks an order ready. Nothing says a cook started; we know a ticket PRINTED. And a shop on automatic never decides anything, so "Accepted" would describe a decision nobody made. So there is no ladder. There is a TRAIL: what has already happened, each with the moment it happened, newest last. A trail cannot freeze, because it never claims anything about what comes next - a shop whose kitchen printer is off simply has a shorter trail, not a stuck one. Placed, from created_date. Accepted, only where order_state_by names the person who worked the queue. In the kitchen, only where a till reported that a printer produced paper. Refused and cancelled as endings, drawn after the history rather than in place of it: a customer who cancelled two minutes late needs to know the kitchen had already started. The one thing named before it happens is a held order's acceptance, because order-approval.js allows pending to move nowhere else. It carries the shop's own recent answering speed, median over a fortnight, worded as a description of the past. No cooking time: nothing in the product knows when food is finished, and an invented ETA is the number a customer waits against and then comes to the counter about. Keys and times on the wire, words on the page, because /order carries its own Tamil dictionary keyed by the English sentence and a sentence built on the server arrives as English nothing can translate. The history page is fixed by the same shape: it called every accepted order "With the kitchen", including ones whose ticket never printed. The page polls with backoff and asks NOTHING while the phone is in a pocket, resuming the moment somebody looks.
The thank-you page resolved the shop through knownBranchId() and the order through rememberedOrders(). Both live in indexedDB.js. This page does not load indexedDB.js and never has. Both calls were written behind `typeof ... === "function"` guards, so nothing threw and nothing showed: the shop id came out empty, the function returned before its first request, and everything behind it - the bill when the shop marks the order paid, the offer to pay by UPI - has silently done nothing on that page since the day it was written. A guard that turns a missing dependency into a quiet nothing is how a shipped feature runs for months without ever running once, and the trail would have joined it. Loading indexedDB.js here is not the fix: it starts a timer that refetches the shop's whole menu every ten seconds, behind a page whose only job is to show a token. So the page answers from what it already holds. The order comes from ?order= on the way in from the history page, or from the sale id on the receipt this phone was handed at checkout. The shop comes from posnic_store, which indexedDB.js writes on every menu load. The two spellings of that key are pinned together, because a rename on one side would put this page straight back where it was.
Owner: "let restaurent owner decide that. give option auto cancel or auto
accept. based ont time he defines it. by default dont accpept or reject."
waiting-order-policy.js was written, tested and merged, and decided
perfectly for nobody. Two dead ends, one on top of the other:
setPolicy() on the desktop OrderAlert was called from nowhere, so the
policy was always { onSilence: 'nothing', decideAfterMinutes: 0 } and
decide() could only ever answer "nothing". There was no setting to feed
it either. So "auto cancel after ten minutes" has never once happened.
And when it did speak, the till emitted posnic:order-decided on the
process bus, WHICH NOTHING LISTENED TO - and then deleted the order from
its pending map. The alarm went quiet with the order still sitting there
and the customer still waiting. An alarm that stops is a promise that
somebody dealt with it, and that promise was false. That is the exact
failure this whole area exists to prevent, and it was built in.
The rule now fires in the API. The till is a sound module, and its own
comment says deciding belongs where the order lives; it is also the wrong
half, because a shop served from the cloud has no till and its held
orders would sit for ever. Both halves read the same pure policy for
different fields: the till reads alert and reach and makes a noise, the
server reads decide and moves the order. Two copies, because the API
ships outside the asar archive, pinned by a behavioural test over a
thousand combinations.
It goes through decideOnOrder, the same door a person at the queue uses,
so an automatic acceptance prints its kitchen ticket exactly the way a
tapped one does rather than by a second path that would drift from it.
AND IT READS THE ORDER BACK BEFORE IT ANNOUNCES ANYTHING. decideOnOrder
narrows its write by whatever tenant the process was last serving and
answers success on what it asked for rather than on what changed, so a
write that matched nothing still says yes. Stopping the alarm on that
would be the same bug arriving by a different door.
Nothing happens unless a shop asked. Absent settings mean nothing, both
halves of the rule are required, an order older than twelve hours is left
for a person, and an aggregator's own deadline is never overrun.
Settings sit under New online orders, beside "When an order arrives", and
are hidden entirely while a shop is on automatic.
…-order A customer is told what happened, and never what might
The shop's declared default, actually firing
salesChannels.load() called PosnicPro.settings.showSilenceRule(). The channels screen is lifted out and run on its own in tests/online-ordering-screen.test.js, where PosnicPro.settings does not exist, so load() threw on the reach across. Not only a harness problem. A load() that throws leaves Delivery Partners with no partners and Restaurant with no venues or charges - and collect() reads those same rows back out of the DOM, so the next Save would write the empty screen over the real ones. That is the shape of the channel settings split bug, arriving through a namespace instead of a tab id. So the helper moves onto the module whose screen the control is on, and its handler is bound beside the other channel-screen handlers.
…its-own And drawing the channels screen does not depend on another namespace
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.
Promotes develop to main. One merged pull request.
Merge with a merge commit, never a squash. The repository ruleset enforces that, so the button should only offer it.
(An earlier version of this description said it also carried #791. It does not - #791 is still open against develop. Corrected rather than left to be found at the button.)
#790 - when the food will be ready
A customer places an order, gets a token number, and hears nothing. The list of this phone's orders said "With the kitchen" and that was the whole of it, which is the moment somebody walks up to the counter to ask.
It now says "Usually ready by about 8:05", estimated from the slowest dish on the order plus the queue that was ahead of it - not the sum of the dishes, because a kitchen cooks several at once and the order leaves the pass when the slowest thing is done.
Nothing here knows when food is actually finished: no cook marks a ticket done, so there is no ready signal and none is invented. The word "usually" is doing real work.
It stays silent wherever it would be guessing: a shop that has stated no prep times, an order the shop has not accepted yet (which says a length instead, because a clock time before anybody has started cooking is a fiction), a cancelled order, and a time that has already passed.
Worth knowing before you merge
It shows nothing on any shop today. Production carries 272 dishes and not one prep time, so the estimate has nothing to work from - which is exactly the honest fallback behaving as designed. It starts speaking the moment somebody uses Tools → How long a section takes from the last release, which is three clicks.
Verified before opening
Root suite 2,645 of 2,648 on the develop tip; the three remaining are the release-artifact tests that need
frontend/publicbuilt, which CI does. API suite 10,754 of 10,754.