Files
backend_fiesta/docs/STORE_OPEN_APP.md
2026-10-09 17:22:27 +05:30

5.4 KiB

Store open / closed — the app contract

A shop can now close itself for the day. When it does, customers must not be able to order from it.

Two things to build: show the closed state, and handle the refusal if someone orders anyway. Everything else is done.


1. Four new fields on the store list

GET https://fiesta.nearle.app/live/api/v1/mob/tenants/getcustomertenants
      ?customerid=&tenant=0&latitude=&longitude=&categoryid=

Every store in details[] now carries:

{
  "isopen": true,
  "closeduntil": "",
  "isaccepting": true,
  "closedreason": ""
}

Read isaccepting, not isopen

This is the one thing to get right.

field what it is
isaccepting the answer. Can this store take an order right now?
isopen the raw switch — what the shopkeeper last pressed
closeduntil the first day back, "YYYY-MM-DD", or ""
closedreason why not, written to show the customer. "" when open

They differ. A shop that closed on Friday "until Monday" has isopen: false every day including Monday — the flag is never flipped back. On Monday the server works out that the date has passed and sets isaccepting: true.

Branch the UI on isaccepting. isopen and closeduntil are there if you want to say more, not to decide with.

closedreason is already written for the customer

"This store is closed today"
"This store is closed today and reopens on 12 Oct"
"This store is not currently available"

Show it as it comes. Don't build the sentence from closeduntil — the server already handles the cases where there is no date, where the branch has been switched off by Nearle rather than by the shop, and where the date is unreadable.


2. A closed store is still returned

It is not filtered out of the list. You decide whether to grey it or hide it.

I would grey it. A shop that vanishes reads to a regular customer as gone for good; one marked "Closed today — reopens 12 Oct" brings them back tomorrow. But it is your call, and the data supports either.

What the store must not do is look ordinary. If isaccepting is false, whatever you render has to stop a customer getting as far as a basket.


3. Delivery windows follow automatically

GET /v1/mob/deliveryslots/available?tenantid=&locationid=

A closed store now returns an empty list, plus the reason:

{ "code": 200, "status": true, "details": [], "closedreason": "This store is closed today" }

You already handle an empty details as "no windows here" — see DELIVERY_SLOTS_APP.md §2 — so this needs nothing new. It stops a customer picking tomorrow morning from a shop that is shut and only finding out at checkout.


4. The refusal

POST /v1/mob/orders/createorder

If the store is closed, the order is refused:

{
  "code": 409,
  "status": false,
  "message": "This store is closed today and reopens on 12 Oct"
}

Handle this properly rather than as a generic failure. It is not a bug or an edge case — it happens to real people in normal use: a customer with the app open when the shopkeeper closes, or a screen left open since this morning.

On 409: show the message, and refresh the store list so the UI catches up.

The server checks on every order because /v1/mob/* carries no session — anything arriving is a claim. Hiding the store in the app is presentation; this is the enforcement.


5. Nothing changes for an open store

Every store on the platform has isopen: true and isaccepting: true right now. There was no backfill and there will not be one. A shop that never touches the switch behaves exactly as it does today.


6. Done on our side

tenantlocations.isopen + closeduntil ✅ live, default open
Four fields on getcustomertenants ✅ live, verified on all 9 stores
PUT /v1/web/tenants/storeopen (guarded) ✅ live — 401 unauthenticated, absent from /v1/mob
createorder refuses a closed store ✅ built, 409 with the shop's wording
Closed store returns no delivery windows ✅ built
Merchant console: switch in the shop profile header ✅ live
Nearle console: "Trading" column per branch ✅ live
Auto-reopen on the date ✅ computed on read — no job, nothing to miss

Verified against production: the four fields, and that the write endpoint is live and guarded.

Not yet exercised against production: the 409 and the empty window list. Both are covered by unit tests and need a real store closed to confirm end to end. If you want to test, ask for tenant 1141 / branch 1179 to be closed — it is a test store with delivery windows already set.


7. Two rules worth knowing

Closed with no date stays closed. A power cut has no end date. The shop reopens when a person says so, not on a timer. closeduntil: "" with isaccepting: false is a normal state, not missing data.

"Closed until the 12th" means open ON the 12th. The date names the first day back, which is how the phrase reads in English. The console says "Reopens on" so nobody has to work it out.


Questions

The rule lives in one function server-side (models/storeopen.go), and the store list, order creation and the delivery-window endpoint all call it. So if anything about open/closed looks inconsistent between those three, it is one place to fix and not three to reconcile. Ask rather than working around it in the app — a local override is how the two sides drift apart.