Skip to content

Collection and delivery slots

Two things a busy store needs once it limits how much online work it takes:

  • Ready from another day. A store that is full, closed or too late to prepare an order today is still offered for collection, "Ready from Wednesday 15 October", instead of disappearing from checkout.
  • Slots. A location can let customers choose a time: a collection slot at the store ("Thursday 10:00-12:00"), or a delivery window for the shop's own vans ("Thursday 18:00-20:00"). Each window takes a number of orders; checkout shows the next few days and greys out the full windows.

Badger Commerce Enterprise

Both need the storeFulfilment capability and Store capacity limits turned on (Settings › Orders › Fulfilment; see Store operations). Without them nothing changes: collection is "ready in about 2 hours" today or not offered, as before, and no slots are shown, whatever the locations say.

Ready from another day

With capacity on, a collection store is offered on the first day within a week, today first, in the store's own time zone, that:

  • it is open by its opening hours and special hours;
  • isn't one of the shop's non-working days (bank holidays, the shop's own closed days), unless special hours open it that day;
  • it isn't temporarily closed at (for today, when the preparation time ends; for a later day, its opening time);
  • has collection capacity left that day;
  • and, for today, the preparation time ends before it closes.

Today keeps today's words ("Ready in about 2 hours"). A later day reads Ready from Wednesday 15 October at checkout, and (ready from Wednesday 15 October) after "Collect from Leeds: in stock" on the product page and basket. A store with no such day in the week isn't offered, and the product page says it is fully booked (or closed for now).

What happens next uses that day:

What Ready today Ready from a later day
Capacity booked at payment Today That day
readyBy on the order's collection Placed + preparation time The store's opening time that day
"Ready to collect" email When staff mark it ready Not before the opening time that day: if staff mark it ready sooner, the email waits and the hold job sends it then
How long it's kept From when it's marked ready From the opening time that day, if marked ready before it
Confirmation email, order page, admin, portal, POS "Ready in about 2 hours" (checkout only) "Ready from Wednesday 15 October"

The day is stored on the order's delivery option (deliveryMethod.readyDate) and the time on its collection (collection.readyFrom).

Slots

Setting them up

Admin › Shop Settings › Locations › location › Collection & delivery slots (behind the Enterprise callout):

  • Collection slots and Store delivery slots (own vans): windows per weekday, each with a start, an end and how many orders it takes (Location.slots, one SlotTemplate per kind of work with its SlotWindows). A window ends after it starts on the same day. 0 takes none.
  • Lead time: a window stops taking orders this many minutes before it starts.
  • Days ahead: how far ahead customers can book, today included: 7 unless set, at most 14.
  • Store delivery service area (Location.serviceArea): where the vans go, one postcode start per line after the country code, GB LS1. LS1 covers LS1 6HD but not LS16 1AB; a postcode typed without its space still matches. Blank: nowhere. A radius isn't used yet: the platform has no postcode centroids to measure from.

MCP: manageLocations setSlots (capacityType CLICK_AND_COLLECT or STORE_DELIVERY, slots ['MON 10:00-12:00 6', ...] replacing that kind's windows or [] removing them, leadTimeMinutes, daysAhead, serviceArea ['GB LS1', ...]); locations get lists them under slots.

A store with collection slots offers them instead of "ready in about 2 hours" or "ready from". Store delivery is a delivery option whose method is Store delivery (own vans) (Admin › Catalogue › Delivery options › option › How it's delivered; DeliveryOptionBean.method DELIVER, beside SHIP and COLLECT). Its price, countries, postcodes and weights work as for any option.

Which windows are available

A window on a date can be chosen when:

  1. the date is within the days ahead, from the location's today;
  2. the location is open that day (hours and special hours) and it isn't a non-working day, unless special hours open it;
  3. the location isn't temporarily closed when the window starts;
  4. the window starts at least the lead time from now;
  5. the day's capacity for that kind of work isn't used up (the usual daily limits still apply, and a slot counts against them);
  6. the window has room.

Windows are the location's local times: on the day the clocks go back a 10:00 window is still 10:00 there, and lead times are measured in real time (SlotService).

At checkout

  • Collection. A store with collection slots is offered while it has a free window in its days ahead. Choosing it shows the picker under it.
  • Store delivery. The option is offered once the delivery address is known, from the first location (by sending preference, then name) whose service area covers the postcode, that has van slots, a free window and, with several stock locations, everything in the basket. Otherwise it isn't offered at all.

The picker is native radio buttons, a group per day (a fieldset and legend), so it works with the keyboard and screen readers and needs no Bootstrap script in either storefront generation. Full windows are shown but can't be chosen. It appears in the step-by-step checkout (Nova, Brock and the Bootstrap 4 theme, through fragment/slotPicker) and in the one-page checkout, where the shopper can't pay until a slot is chosen. The choice is checked when it's made and saved on the order as Order.deliverySlot {locationCode, type, date, start, end}; choosing another option or store clears it.

At payment

The slot is booked before the stock is taken, while the card is only held:

  • if the window filled up (or stopped being offered, or the lead time has passed) since it was chosen, nothing is taken, the card hold is cancelled (refunded for a wallet that captured straight away), the slot is cleared and the shopper is asked to choose another time;
  • if the slot is booked but the stock has gone, the slot is given back with the stock;
  • an order paid for through a path that never refuses (the older checkout, REST baskets) is booked into its window even when full.

A store delivery order's stock is taken at the van location, like a collection from that store (never sourced elsewhere), and its lines go to that location's fulfiller. Store delivery orders then show as ship tasks for that store.

Booking, release and reconciliation

A slot booking is the order's ledger row for that location, kind of work and day (capacity_bookings, one per order, location, kind and day) with the window on it, so an order holds at most one window a day at a location. It counts in the window's counter and in the day's counter (capacity_counters), each with its own conditional update, so two servers can't both take a window's last place. Booking the same window again changes nothing; booking another window that day moves the order. Cancelling the order (or releasing its stock) gives back both. The reconcile job puts window counts right from the ledger along with the day's (today and tomorrow).

Where the slot is shown

Where What
Order confirmation email "Collection: Wednesday 15 October, 10:00-12:00", "Delivery: ...", or "Ready from Wednesday 15 October"
Order confirmation page The same, under the order's summary
Collection arrival page "Your collection slot: Wednesday 15 October, 10:00-12:00."
Admin order view A Slot (or Ready from) card: kind, day, window, location
Fulfilment portal A slot pill on each queue card, slotted cards first and soonest first in the open columns (within the cards shown); the slot on the order page
Portal › Store today Today's load per window for each kind of work with slots
POS app slot and readyFrom on every task (see Mobile POS), and today's load per window as slots on the store status (see Mobile POS)
MCP locations get lists the slot templates and service area

Site data transfer

Slot templates and the service area travel with the locations in a site export; the delivery option's method travels with the delivery options. Bookings and orders' slots don't.

Limits

  • Courier capacity is still assumed unlimited; a van's capacity is its windows' capacity.
  • A store delivery order comes from one location; it isn't split, and stock isn't moved between stores for it.
  • Service areas are postcode prefixes only (no distance), and one per location.
  • The one-page checkout keeps the card form it mounted: if the payment was voided because the slot went, the shopper may need to reload the page before paying again with some payment methods.
  • Window counts further ahead than tomorrow are only reconciled once their day is tomorrow.

Code

Piece Where
Model SlotTemplate, SlotWindow, ServiceArea, CapacityType.STORE_DELIVERY (common/.../locations/); DeliverySlot (Order.deliverySlot); DeliveryOptionBean.readyDate, slotted, storeLocationCode, METHOD_DELIVER; CollectionDetails.readyFrom, readyEmailDueAt
Availability SlotService / SlotServiceImpl, CollectionPointService.readyFrom / canTakeCollection (commerce-core/.../delivery/)
Ledger StoreOperationsService.bookSlot / windowLoad; CapacityBooking.window, CapacityCounter.window, CapacityRepository window methods
Checkout LocalPickupServiceImpl, DeliveryServiceImpl (store delivery), DeliveryChooserExtension + fragment/slotPicker, UnifiedCheckoutServiceImpl (deliverySlot patch, slots on the selected option, checkout.msg.slotTaken), checkout.js
Payment StockAllocationServiceImpl (slot before stock, Allocation.slotTaken)
Collection PickupServiceImpl (readyFrom, held ready email in processHolds), CollectionOrderRepository.findReadyEmailDue / claimReadyEmail
Admin LocationAdminController (slotForms, slotTemplates, serviceArea), templates/admin/locations/edit.html; DeliveryOptionAdminRenderer (method); templates/admin/orders/view/deliverySlot.html
Portal, POS, MCP FulfilmentWorkService.QueueEntry.slot, StoreTodayController; PosTaskView.slot / readyFrom, PosTaskSlot, SlotService.loadToday → PosStoreSlot in rest/docs/api-spec/api.yaml; LocationTools