Skip to main content

Pre-order lifecycle

A pre-order moves through six states. The two events doing the heavy lifting are order placement (deposit + reservation + vault token) and stock arrival (status → ready, customer emailed a tokenised payment link, or vault-charged automatically on shipment).

The six statuses

StatusWhat it means
pendingPre-order created, deposit captured. Stock not yet available.
awaiting_stockExplicit wait-for-stock state. Transitions to ready once stock arrives.
readyStock has arrived; pre-order is ready to fulfil. With an outstanding balance, the Pay Remaining Balance email is queued for the drainer cron.
partial_completeSome items completed, others still ready/pending (multi-line pre-orders).
completeBalance fully captured and pre-order fulfilled.
cancelledCustomer or admin cancelled — MSI reservation reverted, deposit refunded if configured.

Event flow

1. Customer adds pre-order item to cart

  • The PDP info block (Block/Product/View/PreorderInfo.php) renders the deposit breakdown and availability date.
  • For configurable / bundle / grouped products, the eligibility is checked via AJAX (Controller/Product/CheckPreorder.php).
  • The cart plugin (Plugin/Checkout/Cart/AddPlugin.php) tags the quote item with is_preorder so it survives all the way to the order item.

2. Customer reaches checkout

  • Pre-order line items render with a Pre-Order pill in minicart, cart, checkout summary, and the order success page.
  • Totals collector adds the pre-order fee line where configured.
  • PreorderFeeConfigProvider injects deposit data into the checkout config so the JS layer doesn't recompute.

3. Order placement

When the order is placed, Observer/CreatePreorderAfterOrderPlace.php fires on checkout_submit_all_after (which fires after the order has been persisted — using sales_order_place_after would trip the foreign-key constraint):

  1. Creates the byte8_preorder row + items via PreorderManagement::createFromOrder.
  2. Resolves the vault token from the order's payment method (Model/Service/VaultTokenResolver.php) and stores it on the pre-order — when present, this is what makes shipment-day balance capture automatic.
  3. Places an MSI reservation for the pre-ordered quantity (Model/Inventory/ReservationManager.php) so warehouse sees the right available-to-promise number.

The order confirmation email goes out enhanced with a pre-order summary callout + per-item indicators. See Email configuration.

4. Stock arrives

Three triggers can flip a pre-order to ready:

  • MSI stock savePlugin/Inventory/SourceItemsSavePlugin.php (afterExecute on SourceItemsSaveInterface) catches the save, identifies SKUs that became IN_STOCK with qty > 0, and calls PreorderManagement::updateAvailability for each. See MSI integration.
  • Legacy stock-item saveObserver/CheckPreorderAvailability.php on cataloginventory_stock_item_save_after for non-MSI stores.
  • Manual scanbyte8:preorder:scan-stock CLI runs the same code path on demand. Recommended as a 5–10 minute cron fallback against bulk imports or vendor-sync edge cases. See CLI commands.

updateAvailability matches both pending and awaiting_stock items, flips each to ready, and — when every sibling on the parent is now ready or complete — calls markPreorderReady to flag the row for the email drainer (next step).

Admins can also force this transition manually via Mark Ready in the pre-order grid, on the order-view Pre-Order tab, or via mass action.

5. Customer pays balance

When markPreorderReady runs on a pre-order with total_remaining_amount > 0:

  1. Status flips to ready, the completion token is generated/persisted on byte8_preorder.completion_token, and ready_notification_sent_at is cleared. No email is sent inline — the action takes ~5ms.
  2. byte8_preorder_send_ready_notifications cron (every minute, see Cron jobs) drains the queue: sends the Your Pre-Order is Ready — Pay the Remaining Balance email with a tokenised completion link built against the storefront base URL.
  3. The customer clicks the link (/preorder/order/complete/preorder_id/{id}/token/{token}) — no login required, token validated via hash_equals. They pay the balance via Mollie / Stripe / your configured gateway.
  4. On success, the completion-order observer (ProcessCompletionOrder) records the payment, sets completion_order_id, and calls completePreorder once the balance hits zero.

This is the flag-and-drain pattern — deliberately decouples status transition from SMTP latency so bulk paths (mass Mark Ready, MSI bulk import) stay fast and resilient to email infrastructure hiccups.

6. Shipment-day vault capture (when a token is stored)

If byte8_preorder.vault_token_public_hash is populated, the configured vault capture trigger (shipment / tracking-added / manual) fires:

  • Plugin/Sales/Model/Order/ShipmentPlugin.php (or TrackPlugin.php) marks the pre-order as vault_capture_pending.
  • Cron/ProcessVaultCaptures.php (every 5 min) picks it up and charges via VaultCaptureService.
  • On success — pre-order moves to complete, capture recorded in byte8_preorder_payment.
  • On failure — cron retries with backoff. After max_attempts, the customer receives the vault_capture_failed email pointing them to the same tokenised completion link.

Where to configure each step

StepConfiguration
Deposit % / fixed / fullPayments configuration
Vault capture trigger + retriesVault capture configuration
All emailsEmail configuration

Where to inspect a pre-order

  • Admin grid: Sales → Operations → Pre-Orders. Per-row actions: View, Mark Ready, Capture Vault, Force Complete, Cancel. See Pre-order grid.
  • Order-view tab: Sales → Orders → 000000XXX → Pre-Order tab. Same actions, in the context of the order. See Order-view Pre-Order tab.
  • Mass actions: Available on both the pre-order grid and the sales order grid. See Mass actions.
  • CLI: bin/magento preorder:list — filter by status, vault state, balance, email. See CLI commands.
  • Customer account: My pre-orders — customer-facing list with cancel + pay-balance links.