Unit tracking on goods receipt: serial numbers and charges (lot + MHD) as iDempiere attribute set instances
Port of the blut24 ASI mechanics to the LogShip catalogue. Three attribute sets are created lazily by name (LogShip Seriennummer / Charge / Seriennummer + Charge, all fields optional, FEFO via UseGuaranteeDateForMPolicy); a product is tracked when its M_AttributeSet_ID points at one of them.
Server: attributeTracking.ts (set bootstrap + cache, ASI create/lookup, line expansion) hooked into POST /api/inouts/store — a receive line may carry tracking { attributeSetId, serials[], charges[] } and is expanded into one qty-1 line per serial, one line per charge (identical set/org/lot/MHD charges reused), remainder untracked; serials already in stock are rejected with a 400 before anything is written. New routes products/[id]/tracking (enable/switch/clear), products/[id]/units, materials/tracking-overview, inouts/check-serials, ag-grid/products-v2 (grid body shared via productsGrid.ts); product-lookup and orders/[id]/order-line return the tracking flags and C_UOM_ID.
Desktop receive: per-line tracking chip, enable dialog, capture modal with scan/paste input, CSV import (serial;lot;mhd[;qty], header optional), several lot/MHD groups per position, in-stock serial warnings, warn + confirm on incomplete capture. Mobile receive: serial scan mode (every scan = one serial until the qty is reached), one lot/MHD per position via native inputs with the scanner-focus pause, mode picker, incomplete-capture confirm; fixes the stray "On" before <script setup>. Staff-only products clone /materials/products-v2 with Tracking + Einheiten columns and a units side panel; menu entries only in the staff branches. Recipe added to reference/recipes.md.
Unit tracking: MHD-only mode (LogShip MHD attribute set, no lot)
Fourth lazily created set "LogShip MHD" (IsGuaranteeDate + FEFO, no IsLot) and mode 'mhd' across the server util, tracking route, products-v2 filter, the composable (label, badge "MHD n/qty"), the desktop enable dialog (mhd can be widened to charge or both), the mobile mode picker and the products-v2 mode select; translation key tracking_mhd in all four locales. ensureTrackingSets re-resolves a cached map that lacks a mode and the tracking route refuses to clear a product when the requested mode's set cannot be resolved.
Generate shipments: Simple/Advanced tabs with merchant cards, admin top-bar modal, mobile parity
Simple mode (default) shows one card per merchant (org) with the fulfillable / open order counts from the dashboard universe (openso-count-by-warehouse now also returns `fulfillable` per warehouse/org via the same stock rule as unfulfillable-count). All merchants are in scope by default, cards can be picked to narrow the run; one button generates for the merchants' warehouses with plain defaults and prints every shipment right away. Advanced keeps the full parameter form; the merchant cards act as an org filter for the selected/all warehouse scopes and the sequential queue (new `orgIds`).
The page body moved to components/sales/GenerateShipmentsPanel.vue so the admin quick link in TopMegaBar can open it in a big modal (GenerateShipmentsModal.vue, kept alive across closes). Runs set a shared busy flag: the modal asks before closing, the page guards route leave, both warn on unload; keep-open notices show on the Advanced tab when a queue-driven filter is on and while any run is going. Mobile generate-shipments gets the same Simple/Advanced split and merchant cards.