Skip to main content
FomiVIP
Service Cases

Cold-Chain Grocery Delivery: Time Slots and Inventory Pre-Holds

Cold-chain delivery added a new constraint to our fresh-grocery mini program: time slots. Vans have fixed capacity, so a conditional UPDATE guards against overselling, orders pre-hold a seat for 15 minutes, and slot release shares one transaction with stock. Capacity 24 came from the driver.

February 10, 2023Case StudyInventoryLogistics

Our fresh-grocery mini program had run for years when we added cold-chain delivery in spring 2023. The new thing wasn't a page — it was time slots.

Where the Three Slot Tiers Came From

The client runs three vans: a morning-market tier from 5 to 7 a.m., a late-morning tier, and an afternoon tier. Each van's capacity is fixed; when it's full, orders roll to the next tier. Before, we only decremented product stock. Now there's another layer: the vegetables may be there, but if the van is full, the order can't be accepted.

Version one treated slots as a product attribute: check remaining seats at checkout, decrement if enough. The classic bug — read-then-write — meant two people picking the last slot of the day could both succeed.

We switched to a conditional update:

UPDATE delivery_slot SET booked = booked + 1 WHERE id = :slot AND booked < capacity

If zero rows are affected, we reply "this slot is full — try the next one", and the frontend grays out full slots in the picker. Two columns, capacity and booked, plus a slot_date: three rows per day.

Pre-Hold and Release

Ordering doesn't mean paying instantly. Creating an order pre-holds one seat; 15 minutes without payment releases it, with a scheduled job sweeping every 10 minutes. Same idea as the 2018 inventory pre-hold — except that time we held products, this time we hold vans.

One detail: canceling an order must release both product stock and the slot, and the two have to happen in one transaction. Version one wrote them separately; once, stock was released but the slot wasn't — the tier showed full while a seat sat empty until evening. We added the transaction, then re-audited 2,000-plus historical orders and found 3 similar cases.

Where the Number 24 Came From

The afternoon tier's capacity went from 30 to 24, and not by guesswork. For the first three days we recorded actual load per van: cold-chain boxes take more room than expected, and with 30 orders, five or six always ended up wedged in the aisle — the driver said they tip over in transit. At 24, the remaining 6 positions are reserved for what he calls "awkward packages".

We later added a max_cold column tracking how many cold-chain boxes fit, counted separately from regular packages. What a slot can exceed isn't the total order count — it's the cold-box count. Version one never anticipated this constraint; we only understood it after the driver posted a photo of his trunk in the group chat.

About Rescheduling

The client originally wanted users to change their delivery slot after ordering. We didn't build it; we went with "cancel and reorder". The reason is practical: rescheduling means releasing the old slot and holding the new one, and any failure in between leaves you holding neither or both. Cancel-and-reorder adds two steps, but every step is simple and easy to debug.

When someone actually calls asking to change, support cancels for them in the backend, places a new order, and manually re-applies the discount. Seven or eight times a month — cheaper than building a rescheduling flow.

Those 3 Inconsistent Orders

The transaction fix surfaced 3 historical orders where product stock was released but the slot wasn't — all old data from before the nightly batch job. We manually decremented booked and added a note to each. After the 2,000-plus-order audit, the script output a 4-column table; we printed it, signed it, and filed it in the project folder.

The morning tier still loads at 5 a.m.; the 4:40 export job now has a failure alert — a paper jam sends a message, and drivers read the plain-text version on their phones instead of copying by hand. The max_cold column was added in March 2023; since then, no more aisle-cramming on the afternoon tier, and the driver never posted another trunk photo.

The Driver's Sheet

Before departure, drivers need a sorting sheet split into three blocks by slot, each block ordered by delivery sequence. We built an export: one slot per A4 page, 11pt type, addresses on a single line, signature space at the bottom.

The morning tier is the tightest: load at 5, print by 4:40. One day the printer jammed at 4:45 and the driver copied 8 rows off the screen by hand. We later added an "export as plain text" button in the backend that works on a phone too.

Launched February 10; the first week brought two changes: the afternoon tier's capacity from 30 to 24 because it genuinely didn't fit, and the "full" message — originally "unavailable", which the client found too blunt, changed to "This slot is full — how about another time?"

Consulting · Free initial chat

Need advice for your scenario?

Tell us your business context and current systems, and we'll give an actionable approach.

Contact us

Mon–Fri 9:00–18:00 · We respond on business days within one business day.

WeChat (Business Only)
WeChat (Business Only)二维码

Scan and add our WeChat for consulting

Or fill out the requirements form