Reservation / Cart Flow (Reserve & Collect)¶
Reserve & Collect - ZWE-445
Tracked on ZWE-445 — Document reservation/cart flow (Reserve & Collect), raised by Jasper: no cart or reservation endpoint (ShoppingCartRequest, SubmitReservation, GetItemAvailability) was confirmed as checked in ZWE-389's endpoint inventory, so it's tracked separately here.
Confirmed against the legacy codebase
Legacy codebase access (blocked when this page was first written, same gap as ZWE-390) is now available (zwerfkei-backoffice-legacy). This page has been updated with the traced, confirmed flow rather than inference from the WSDL alone.
Answering the open question from NAV Scope docs (ZWE-389)¶
"No cart or reservation endpoint at all is checked... Does that functionality run outside Navision?"
Yes and no — traced precisely below. The current site's "Reserveer & haal op" button calls Shoppingcart::save_click_and_collect() (application/modules/shoppingcart/controllers/Shoppingcart.php), which:
- Checks live stock via
K3_article_variant::getFreeStock(true)→getRealStock(true)→\K3retail\Call\GetRealStock— a real, live SOAP call to NAV - Creates/updates a local
Customerrecord - Saves a purely local
ClickAndCollectrecord (own table, no NAV write) - Shows a confirmation modal
So the flow touches Navision only for a live stock check — the reservation itself never leaves the webshop database. ShoppingCartRequest and SubmitReservation are not called anywhere in this flow, or anywhere else in the codebase:
ShoppingCartRequest and SubmitReservation are confirmed unused. Every actively-called NAV/LS operation has a small wrapper class in application/components/k3retail/classes/ (SubmitOrder.php, GetProduct.php, GetItemAvailability.php, GetSyncBuffer.php, DeleteSyncBuffer.php, etc.). No ShoppingCartRequest.php or SubmitReservation.php exists in that directory — confirming they're dead code paths on the current site, not just missed by Olaf's week-long log-based inventory.
GetItemAvailability is NOT unused — the earlier "stale since 2016" claim on this page was wrong. Table 11176114 (itemAvailability) is one of the tables in K3retail\Buffer\Buffer::$tables, synced by Buffer::sync(), which is invoked by an actual cron job (application/modules/cli/controllers/Cron.php) running in a tight loop (within ~50s per invocation). Buffer::sync() calls both getSyncBuffer() and deleteSyncBuffer() per table — so this endpoint is actively polled and cleared. The 2016-01-27 dates seen in the response payload reflect NAV's own internal last-updated timestamp for that stock record (unchanged since then), not an unused code path — the endpoint responding with old data doesn't mean it isn't being called.
Reference: the legacy read-then-delete pattern (Buffer.php)¶
Relevant beyond this ticket - application/components/k3retail/todo/Buffer.php is a real, production-proven implementation of exactly the GetSyncBuffer/DeleteSyncBuffer flow the new backend needs (see ZWE-495):
- A static
$tablesconfig array maps each sync table to its WSDL service and response shape (e.g.orderStatus→ table11176106,itemAvailability→ table11176114) Buffer::sync()loops the configured tables, callinggetSyncBuffer()to read pending entries thendeleteSyncBuffer()to commit each one- A lockfile (
tmp/nav.lock, 3600s TTL) prevents overlapping runs - Driven by cron via
cli/controllers/Cron.php, looping for up to ~50 seconds per invocation to drain the queue quickly without overlapping the next cron tick
Worth reviewing directly with Jasper on the flow-alignment call - this is exactly the kind of proven reference the new NavSyncBufferReader/DeleteSyncBuffer design should draw from, rather than designing the schedule from scratch.
ShoppingCartRequest (LS Retail)¶
Request (LSShoppingCartRequestHeader):
| Field | Type | Notes |
|---|---|---|
ContactNo / CustomerNo |
string | customer identification |
CountryCode / CurrencyCode |
string | |
LoyaltySchemeCode / LoyaltyCardNo |
string | loyalty program linkage |
CouponCode |
string | |
LSShoppingCartRequestLine[] |
nested | ItemNo, VariantCode, Quantity per line |
Response (LSShoppingCartResponse): ResponseCode, ResponseText, plus an echoed LSShoppingCartResponseHeader.
SubmitReservation (LS Retail)¶
Request (LSReservationHeader):
| Field | Type | Notes |
|---|---|---|
Id |
int | |
StoreId / StoreNo |
int / string | pickup store |
ReservationStatusId |
int | status enum, values not yet confirmed |
FirstName / LastName / Email / PhoneNumber |
string | contact fields directly on the reservation, not via a customer account |
LSReservationLine[] |
nested | ItemNo, VariantCode, Quantity, UnitPrice per line |
Response: empty result shape in the WSDL — no fields defined, not yet tested live to confirm what (if anything) comes back.
GetItemAvailability (NAV)¶
Same paged-buffer shape as the core webshop endpoints (queueEntryNo/pageIndex/pageSize), see Core Webshop Endpoints for the general pattern.
Response (NavItemAvailability, repeated):
| Field | Type | Notes |
|---|---|---|
ItemNo |
string | |
VariantCode |
string | can be empty (item-level row) or a specific variant |
LocationCode |
string | e.g. ZWERFKEI — confirms a location dimension exists, unlike the new backend's current product_stock table |
Quantity |
decimal | |
Date |
dateTime | last-updated timestamp on this record — reflects when NAV last changed the stock value, not when the endpoint was last called (see the Buffer.php finding above) |
Example response (real, live):
<GetItemAvailability_Result>
<return_value>213024</return_value>
<response>
<NavItemAvailability>
<ItemNo>001000003</ItemNo>
<VariantCode/>
<LocationCode>ZWERFKEI</LocationCode>
<Quantity>0</Quantity>
<Date>2016-01-27T14:43:51.347Z</Date>
</NavItemAvailability>
<NavItemAvailability>
<ItemNo>001000003</ItemNo>
<VariantCode>000</VariantCode>
<LocationCode>ZWERFKEI</LocationCode>
<Quantity>0</Quantity>
<Date>2016-01-27T08:35:05.017Z</Date>
</NavItemAvailability>
</response>
</GetItemAvailability_Result>
Optimization ideas for the new platform¶
- The confirmed flow is the one to replicate, not
ShoppingCartRequest/SubmitReservation. Reserve & Collect on the new platform should follow the same shape as the legacy site: a webshop-domain reservation record (own table, own status), with NAV touched only for a live stock check at reservation time — not a NAV-side cart or reservation object. ShoppingCartRequest's loyalty/coupon fields (LoyaltySchemeCode,LoyaltyCardNo,CouponCode) suggest an older omnichannel/loyalty design, confirmed unused by the current site — safe to leave out of scope for the rebuild.- Model Reserve & Collect as a webshop-domain concept (an order/cart variant with a pickup-store flag), touching NAV only for the live stock check (mirrors
GetRealStockusage above) — matches the confirmed legacy pattern, not a NAV-side reservation object. ReservationStatusIdonSubmitReservationremains unconfirmed and is now known to be moot — since the operation isn't called anywhere, there's no legacy precedent to check its values against. Not worth pursuing further unless a future design deliberately reintroduces a NAV-side reservation.Buffer.php's read-then-delete pattern (see above) is the reference design for the new backend's ownGetSyncBuffer/DeleteSyncBufferimplementation (ZWE-495) — lockfile-guarded, per-table config, cron-driven.