Skip to content

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:

  1. Checks live stock via K3_article_variant::getFreeStock(true) → getRealStock(true) → \K3retail\Call\GetRealStock — a real, live SOAP call to NAV
  2. Creates/updates a local Customer record
  3. Saves a purely local ClickAndCollect record (own table, no NAV write)
  4. 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 $tables config array maps each sync table to its WSDL service and response shape (e.g. orderStatus → table 11176106, itemAvailability → table 11176114)
  • Buffer::sync() loops the configured tables, calling getSyncBuffer() to read pending entries then deleteSyncBuffer() 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 GetRealStock usage above) — matches the confirmed legacy pattern, not a NAV-side reservation object.
  • ReservationStatusId on SubmitReservation remains 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 own GetSyncBuffer/DeleteSyncBuffer implementation (ZWE-495) — lockfile-guarded, per-table config, cron-driven.

SubmitOrder Core Webshop Endpoints Legacy Integration