Book 2 · Chapter 8 — Stock Operations¶
Scope. This chapter covers how the quantity-on-hand (QOH) of an inventory item at a store changes and how it is reconciled: stock takes & counts (freeze, count, variance), stock breaking / splitting (parent → child, auto-breaks, reverse splits, dispatches), stock processing (Sale/Short & Return/Excess reconciliation of count variances), stock & delivery loss (write-offs and employee charges), stock debtors / non-stock debtors (who owes for shortages), and the stock move report (the movement ledger).
It does not cover item CRUD / pricing (Chapter 7 — Maintain Items) nor GRN receiving (Chapter 9 — Purchasing & GRN). Those modules also write to the same ledger; this chapter explains how reconciliation movements are produced.
1. Purpose (plain language)¶
A distributor's warehouse never perfectly matches the numbers in the system. Boxes get broken down into pieces, deliveries get damaged, staff miscount, items go missing. Stock Operations is the toolkit Bizwiz gives a branch to keep the "on paper" stock equal to the "on the shelf" stock, and to assign blame (and money) when they differ.
There are five everyday jobs in this chapter:
-
Stock take / count — "Freeze what the system thinks we have, send people to physically count the shelves, then compare." The freeze captures a snapshot of QOH; counters key in what they actually see; the system produces a variance (counted − frozen).
-
Stock breaking (splitting) — "We have cartons but customers want single bottles." A mother item (e.g. a carton) is broken into a child item (e.g. loose bottles). This reduces the mother's QOH and increases the child's QOH. It can be done manually, requested from the shop floor, or triggered automatically when a sale needs child stock that isn't there. Reverse splits undo a break (child back to mother).
-
Stock processing — Once a count reveals a variance, someone must "process" it. A shortage (Sale/Short) is booked as if the missing stock was sold to the responsible staff member (they now owe money). An excess (Return/Excess) is booked as a return (stock added back, staff credited).
-
Stock loss & delivery loss — Deliberate write-offs. Stock loss removes damaged/lost store stock and optionally charges an employee. Delivery loss handles goods damaged in transit to a customer — it credits the customer's invoice balance and charges staff, but does not touch store QOH (the stock already left).
-
Stock debtors — The ledger of people who owe stock/money because of the above. Stock debtors are registered accountable staff (store-keepers, salesmen); non-stock debtors are ad-hoc users who picked up a variance charge without a master record. Debt can be split between people.
The Stock Move Report ties it all together: for any item/location it shows opening balance, every inflow (purchases, transfers, breaks-in, adjustments) and outflow (sales, transfers, breaks-out, losses), and the closing balance.
The single unifying fact for this whole chapter:
QOH is not stored as a column. It is the running sum of
wa_stock_moves.qauntityfor an item at a location. Every operation in this chapter — a break, a count adjustment, a loss — reconciles by writing one or more rows intowa_stock_moves. Each row also snapshots the resulting balance innew_qoh.
The rest of this chapter is the technical layer.
2. Users & roles (+ permission strings)¶
All screens live under the Inventory → Stock Take and Inventory → Stocks Break sidebar
groups (resources/views/admin/includes/sidebar_includes/inventory.blade.php). Access is gated
either by the legacy $my_permissions['<model>___<action>'] map or the newer
can('<action>', '<model>') helper. The super-admin role (config('app.allowed_role')) sees
everything.
Stock takes & counts¶
| Screen | Permission | Route name |
|---|---|---|
| Create Stock Take Sheet | stock-take___view |
admin.stock-takes.create-stock-take-sheet |
| Assign Stock Count Users | stock-take-user-assignment___view |
admin.stock-counts-users-assingment |
| Enter Stock Counts | stock-counts___view |
admin.stock-counts |
| Live Stock Count | stock-counts___add |
admin.live-stock-count |
| Detailed Variance Report | stock-count-variance___detailed-view |
admin.stock-count-variance.index |
| Summary Variance Report | stock-count-variance___summary-view |
admin.stock-count-variance.summary |
| Blocked Users | stock-count-blocked-users___view |
admin.stock-count-blocked-users.index |
| Exemption Schedules | stock-count-blocked-users-exemption-schedules___view |
admin.stock-count-blocked-users.exemption-schedules |
Stock breaking¶
| Screen | Permission | Route name |
|---|---|---|
| Stock Breaking | stock-breaking___view / ___add / ___edit |
stock-breaking.index (resource) |
| Split Requests | display-split-requests___view / ___approve / ___reject |
stock-breaking.split-requests |
| Auto Breaks | stock-auto-breaks___view |
stock-auto-breaks.index |
| Reverse Splits | reverse-splits___view / ___add / ___approve / ___reject |
reverse-splitting.index (resource) |
| Pending / Dispatched / Completed Dispatches | stock-auto-breaks___dispatch |
stock-auto-breaks.dispatch.* |
| Summary | stock-breaking___summary |
stock-breaking.summary |
Additional break permissions: stock-breaking___split-on-behalf (break for another branch),
stock-breaking___create-dispatch, stock-auto-breaks___view-all / reverse-splits___view-all
(bypass the "only my bin" restriction).
Stock processing, debtors, losses¶
| Screen | Permission | Route name |
|---|---|---|
| Sale (Short) | stock-processing-sales___view (parent stock-processing___view) |
stock-processing.sales |
| Return (Excess) | stock-processing-return___view |
stock-processing.return |
| Uncompleted Entries | stock-uncompleted-sales___view |
stock-uncompleted-sales.index |
| Stock Debtors | stock-debtors___view / ___add / ___split |
stock-debtors.index |
| Non-Stock Debtors | stock-non-debtors___view |
stock-non-debtors.index |
| Stock Loss (Store) | can('view'/'create'/'approve'/'reject', 'stock-loss') |
inventory.stock-loss.* |
| Delivery Loss (Customer) | can('view'/'create'/'approve'/'reject', 'delivery-loss') |
inventory.delivery-loss.* |
| Stock Move Report | stock-move-report___view / ___export |
stock-move-report.index |
Permission definitions live in app/Permissions/Inventory.php.
Typical operators: warehouse/store keepers key counts and initiate breaks; a stock-count
supervisor freezes sheets and assigns counters; branch managers/accountants process variances,
approve losses, and manage the debtors ledger. Role 152 (store keeper) is special-cased in
several controllers to scope views to the user's own store (e.g.
StockTakesController@index).
3. Processes (trigger → states → routes → outcome)¶
3.1 Stock take & count (freeze → count → variance → process)¶
flowchart TD
A["Create Stock Take Sheet<br/>StockTakesController@freezeTable"] -->|snapshot QOH| B[(wa_stock_check_freezes<br/>+ wa_stock_check_freeze_items)]
B --> C[Assign Count Users<br/>StockTakeUserAssignmentController]
C --> D["Enter Stock Counts<br/>StockCountsController@updateStockCounts"]
D --> E[(wa_stock_counts)]
E --> F[Variance = counted - frozen QOH<br/>WaStockCountVariation]
F --> G{Variance sign}
G -->|negative shortage| H[Sale / Short processing]
G -->|positive excess| I[Return / Excess processing]
H --> J["(wa_stock_moves: -qty)<br/>+ stock_debtor_trans"]
I --> K["(wa_stock_moves: +qty)<br/>+ stock_debtor_trans credit"]
Step 1 — Freeze (create sheet). From Create Stock Take Sheet the user picks a
store, one or more inventory categories, and a UOM/count type. StockTakesController@addStockCheckFile
(:149-386) creates a WaStockCheckFreeze header (wa_stock_check_freezes: store, user,
category-id list, UOM, count_type, expires_at) and one WaStockCheckFreezeItem row per
item (wa_stock_check_freeze_items), each capturing the quantity_on_hand at freeze time —
the immutable "system says" snapshot. The freeze does not stop sales; it records a baseline.
Two settings adjust the frozen figure before it is stored:
- EXCLUDE_OVERFLOW_STOCKS_FROM_STOCK_COUNT_SHEET — subtracts overflow-store moves
(wa_stock_moves_C, wa_stock_moves_supreme, wa_overflow_stock_moves) so the sheet only
reflects main-store stock (:160-208).
- DEDUCT_UNDISPATCHED_STOCKS_FROM_STOCK_COUNT_SHEET — deducts route/invoice stock that is
staged but not yet physically dispatched (from salesman_shift_store_dispatch_items,
wa_internal_requisition_items), storing the breakdown in
wa_stock_check_freeze_undispatched_items (:214-295).
(freezeTable() is a separate maintenance action that truncates the store-C freeze tables.)
Step 2 — Assign counters. StockTakeUserAssignmentController (models
StockTakeUserAssignment, StockTakeUserAssignmentAssignee) allocates specific items/bins to
specific users so counting can be divided up and audited. Assignments can be one-time or
is_persistent (recur daily until end_date); supports CSV/batch upload of item allocations
into display_bin_user_item_allocations.
Step 3 — Enter counts. Enter Stock Counts (StockCountsController@updateStockCounts,
:92-250) or Live Stock Count (LiveStockCountController, which freezes-and-shows a single
item on demand for spot counts, count_type='live_count') persists the physically counted
quantity into wa_stock_counts (WaStockCount) and immediately writes a variance row.
Step 4 — Variance. Variance is stored in WaStockCountVariation
(wa_stock_count_variation) with quantity_recorded (counted), current_qoh (frozen snapshot),
variation, count_type (daily_freeze/live_count), and is_processed. The formula
(StockCountsController.php:230-234) is:
variance = (current_qoh < 0) ? quantity_recorded + current_qoh
: quantity_recorded - current_qoh
-5 (shortage); counted 105 → +5 (excess). Reported two ways:
Detailed (StockCountVarianceReportController@index, line-level, attach a reference note via
updateReference + referenceHistory, plus undispatchedBreakdown that itemises route/POS/
invoice stock counted-but-undispatched) and Summary (@summary).
Step 5 — Process / apply. There are two distinct "apply" paths:
- Direct QOH adjustment — StockCountsController@compareCountsVsStockCheckProcess
(:396-547) computes adjustment = counted − system_qoh, and for each non-zero adjustment
writes a wa_stock_moves row (stock_adjustment_id = 2, signed qauntity, new_qoh =
prior sum + adjustment), two wa_gl_trans rows (DR/CR against usage/stock/price-variance
accounts, valued at standard_cost × adjustment), and a WaStockCountDeviation audit row;
it then clears the temporary wa_stock_counts / wa_stock_count_process rows. This is the
count subsystem directly reconciling QOH + posting GL.
- Debtor processing — alternatively the variance flows to Stock Processing (§3.3), where a
negative variance becomes a Sale/Short (staff charged) and a positive one a Return/Excess;
processing marks WaStockCountVariation.is_processed = 1.
Blocked users / exemptions. StockCountBlockedUsersController blocks counters with
incomplete counts (users.is_blocked), supports unblockAll/unblockSelected, and manages
block_users_exemption_schedules that excuse specified store-keepers (role 152) for the next day.
⚠️ Opening-balances & store-C/supreme/overflow variants are separate stacks.
OpeningBalancesStockTakeController,StoreCStockTakeController,SupremeStoreStockTakeController,OverflowStockTakeControllermirror this flow with their ownopening_balances_*,store_c_stock_*,supreme_store_stock_*,overflow_stock_*tables. They are gated by store-type settings (e.g.ACTIVATE_OVERFLOW_STORE) and are out of core scope here — flagged in §7.
3.2 Stock breaking (parent → child)¶
"Breaking" converts a mother/parent item into a child item using a conversion factor
(child units per parent unit; e.g. 1 carton = 12 bottles). Every break writes two
wa_stock_moves rows: parent −source_qty and child +destination_qty.
There are four entry points, all landing on the same ledger:
stateDiagram-v2
[*] --> PENDING: manual save (request_type=save)
PENDING --> PROCESSED: manual store / update (creates stock moves)
PROCESSED --> DISPATCHED: createDispatch
DISPATCHED --> COMPLETED: receive
[*] --> AB_pending: AutoBreakingService (sale needs child)
AB_pending --> AB_processed: initiateDispatch
AB_processed --> AB_dispatched: processDispatch
AB_dispatched --> AB_received: receive
(a) Manual break — stockBreakingController (resource stock-breaking). store() validates
source/destination, creates a WaStockBreaking header + WaStockBreakingItem lines and,
unless merely saved as a draft, immediately writes the two ledger moves
(stockBreakingController.php:898-938). prepopulateItems() / getDestinationSalesQty() are
suggestion engines that recommend what to break based on child minimum
(minimum-quantity-of-child-item) and recent sales velocity
(average-sales-days-to-compute-stock-break, default 2 days).
(b) Shop-floor split request — display-bin users request a break (mobile or web
requestSplitsWeb). Requests queue as PosStockBreakRequest (status=pending). A manager
reviews them under Split Requests and approveSplitRequests()
(MobileInventoryManagementController.php:285-321) writes the two moves and one grouped
WaStockBreaking.
(c) Auto break — AutoBreakingService::attemptAutoBreak() fires during sales-order
processing when the ordered child QOH is insufficient but a configured mother item has stock. It
creates a WaStockBreaking (PROCESSED), writes parent −qty / child +qty moves
(AutoBreakingService.php:376-450), and logs a RouteAutoBreak audit row. These then flow
through the dispatch lifecycle in RouteAutoBreakController (pending → dispatched → received),
which coordinates the physical movement between mother-bin and child-bin via
StockBreakDispatch / StockBreakDispatchItem but does not re-touch QOH (the ledger
was already written at break time).
(d) Reverse split — ReverseSplitsController undoes a break. store() creates a
ReverseSplit (status=pending, no QOH change). On approve()
(ReverseSplitsController.php:328-358) it writes the inverse moves: mother +expected_qty,
child −requested_qty, with a REVERSE_STOCKBREAKING document number. reject() sets
status=rejected.
Summary (RouteAutoBreakController@summary) aggregates both manual (WaStockBreakingItem)
and auto (RouteAutoBreak) breaks by date/mother item for reporting.
3.3 Stock processing (Sale/Short & Return/Excess)¶
StockAdjustmentController turns an unprocessed count variance into a booked movement plus a
debtor charge.
Sale (Short) — variance < 0 (physical < system):
stock_processing_sales_store generates an SAS-##### document (series
STOCK_ADJUSTMENT_SALES), creates a StockDebtorTran header + StockDebtorTranItem lines, and
for each item writes a negative wa_stock_moves row
(StockAdjustmentController.php:316-367). If current QOH ≥ needed qty the whole shortage is
processed; if QOH is partial it books what's available and leaves quantity_pending > 0
(is_processed = 0). GL: debit Debtors Control, credit Sales Revenue + VAT. The debtor now
owes the value. An ESD/eTIMS tax invoice is auto-signed (signInvoice()).
Return (Excess) — variance > 0 (physical > system):
stock_processing_return_store generates SAR-##### (series STOCK_ADJUSTMENT_RETURN), always
writes a positive wa_stock_moves row (StockAdjustmentController.php:850-871), and creates
negative-value debtor lines (a credit). If the UOM is a display bin, the excess is attributed to
the allocated non-debtor user via display_bin_user_item_allocations. GL is the reverse of a
sale.
Uncompleted Entries — StockUncompletedProcessingController@process re-attempts the
partially-processed SAS lines (quantity_pending > 0) once stock is replenished, writing the
remaining negative moves (:172-221).
stateDiagram-v2
[*] --> Unprocessed: variance created (is_processed=0)
Unprocessed --> Processed: full qty available (is_processed=1)
Unprocessed --> Partial: partial qty (quantity_pending>0)
Partial --> Processed: Uncompleted process re-run
3.4 Stock loss (store) & delivery loss (customer)¶
Both are create → pending → approve/reject workflows with optional employee charges and (setting-gated) signed acknowledgement documents.
Stock Loss (StockLossController): records lost/damaged store stock (SL-######). On
approve() it writes a negative wa_stock_moves row per item
(StockLossController.php:308-331, −qty_lost) and creates an EmployeePenalty
(polymorphic → StockLoss) for each charged employee. reject() makes no QOH change.
Delivery Loss (DeliveryLossController): loss in transit to a customer, tied to a sales
invoice (WaInternalRequisition), document DL-######. On approve() it creates a negative
WaDebtorTran (credits the customer's invoice balance,
DeliveryLossController.php:328-366), creates employee penalties, and posts GL via
DeliveryLossGlPostingService. It does NOT write wa_stock_moves — the stock already left
the store when it was invoiced, so only the customer balance and staff liability move.
3.5 Stock debtors & non-stock debtors¶
StockDebtorsController maintains the ledger of who owes for shortages.
- Stock debtors = registered accountable staff (StockDebtor master + StockDebtorTran /
StockDebtorTranItem). Balance = SUM(stock_debtor_trans.total).
- Non-stock debtors = users with variance charges but no master record (tracked via
stock_debtor_trans.stock_non_debtor_id).
- Splits: split, split_non_debtors, nonDebtor_Debtor_split,
nonDebtor_nonDebtor_split distribute a debt across multiple people using an
SDS-##### (STOCK_DEBT_SPLIT) document — a negative tran on the source, positive trans on
recipients. move_non_stock_debtors demotes a registered debtor to a non-debtor (keeps the
liability, removes the master row).
These screens move money/liability, not QOH — the QOH already moved during stock processing.
3.6 Stock Move Report¶
StockMoveReportController reads wa_stock_moves and classifies each movement by its foreign
keys into inflows/outflows: purchases_in (has wa_purchase_order_id), transfers_in/out (has
wa_inventory_location_transfer_id), sales_out (has wa_internal_requisition_id), and
others_in/out (breaks, losses, adjustments — no PO/transfer/requisition link). For each
item/location it computes opening (sum of moves before the from-date) + inflows − outflows =
closing (StockMoveReportController.php:61-299), with optional UOM conversion when
INVENTORY_SETUP = 'UOM BASED'. Exportable to Excel. Gated in the sidebar by the
identify-sales-orders-from-normal-orders setting.
4. Tables touched & key data¶
The ledger (central):
- wa_stock_moves (WaStockMove) — the QOH ledger. Key columns: wa_inventory_item_id,
wa_location_and_store_id, stock_id_code, qauntity (signed movement, note the
mis-spelling), new_qoh (balance snapshot after this move), document_no, and the
source FKs (wa_purchase_order_id, wa_internal_requisition_id,
wa_inventory_location_transfer_id, stock_adjustment_id, wa_pos_cash_sales_id) used to
categorise movements. QOH(item, store) = SUM(qauntity) over matching rows.
Stock take / count:
- wa_stock_check_freezes / wa_stock_check_freeze_items (WaStockCheckFreeze /
WaStockCheckFreezeItem) — freeze header + per-item frozen quantity_on_hand snapshot (plus
undispatched_quantity when that setting is on).
- wa_stock_check_freeze_undispatched_items — audit breakdown of undispatched qty deducted from
the freeze (source_type = Route/Invoice/POS).
- wa_stock_counts (WaStockCount) — physical counts keyed by users (temporary; cleared on
process).
- wa_stock_count_variation (WaStockCountVariation) — quantity_recorded, current_qoh,
variation, count_type, is_processed.
- wa_stock_count_deviations (WaStockCountDeviation) — post-process audit trail of applied
adjustments (batch_date, before/after qty).
- wa_stock_count_process (WaStockCountProcess) — count processing status (selected_type).
- wa_gl_trans (WaGlTran) — GL journal rows posted when counts are directly applied.
- stock_take_user_assignments / stock_take_user_assignment_assignees — counter allocation;
block_users_exemption_schedules / _users — count-block exemptions.
Stock breaking:
- wa_stock_breaking / wa_stock_breaking_items (WaStockBreaking / WaStockBreakingItem) —
manual/auto break header + lines (source_item_id, source_qty, destination_item_id,
destination_qty, conversion_factor, status, dispatched).
- route_auto_breaks (RouteAutoBreak) — auto-break audit trail.
- reverse_splits (ReverseSplit) — reverse-split requests.
- pos_stock_break_requests (PosStockBreakRequest) — shop-floor split requests.
- stock_break_dispatches / stock_break_dispatch_items (StockBreakDispatch /
StockBreakDispatchItem) — physical mother-bin → child-bin dispatch lifecycle.
Processing / debtors / losses:
- stock_debtors / stock_debtor_trans / stock_debtor_tran_items (StockDebtor /
StockDebtorTran / StockDebtorTranItem).
- stock_losses / stock_loss_items / stock_loss_employee_charges (StockLoss /
StockLossItem / StockLossEmployeeCharge).
- delivery_losses / delivery_loss_items / delivery_loss_employee_charges (DeliveryLoss /
DeliveryLossItem / DeliveryLossEmployeeCharge).
- employee_penalties (EmployeePenalty, polymorphic to StockLoss/DeliveryLoss).
- wa_debtor_trans (WaDebtorTran) — customer balance adjustment for delivery loss.
5. Interactions with other modules¶
QOH is shared. The wa_stock_moves ledger written by this chapter is the same QOH that:
- Sales / POS reads to check availability and decrements on a sale
(wa_internal_requisition_id / wa_pos_cash_sales_id moves).
- GRN / Purchasing (Ch 9) increments on receiving (wa_purchase_order_id moves).
- Inter-branch transfers move between stores (wa_inventory_location_transfer_id moves).
Because QOH is a live sum, operations in this chapter have immediate cross-module effects:
| Operation | Effect on QOH | Who sees it |
|---|---|---|
| Stock take freeze | none (snapshot only) | reconciliation only |
Count → direct apply (compareCountsVsStockCheckProcess) |
± adjustment (counted − system) | Sales sees corrected QOH; GL posted |
| Count → Sale/Short processing | − child qty | Sales sees less available; debtor charged |
| Count → Return/Excess processing | + item qty | Sales sees more available |
| Manual/auto/request break | − mother, + child | Sales can now sell child units |
| Reverse split | + mother, − child | mother available again |
| Stock loss approve | − lost qty | Sales sees less; employee penalty |
| Delivery loss approve | no QOH change; customer credited, staff charged | AR / debtors |
Auto-break ↔ Sales. The tightest coupling: AutoBreakingService is invoked inside sales
order processing so a child-item sale can succeed by transparently breaking a mother item — the
sale and the break both hit the ledger in the same flow.
Stock processing ↔ Finance/GL & Tax. Sale/Short and Return/Excess post GL journals (Debtors
Control / Sales Revenue / VAT) and auto-sign an ESD/eTIMS tax invoice. Delivery loss posts GL via
DeliveryLossGlPostingService. Losses create EmployeePenalty rows consumed by HR/Payroll
for deduction.
Display bins ↔ POS. Split requests and excess attribution rely on
display_bin_user_item_allocations linking display-bin UOMs to specific POS users.
6. Alternatives & variants (manual vs automated, flavor differences)¶
- Breaking is manual, requested, or automatic. Manual (
stockBreakingController), shop-floor-requested (PosStockBreakRequest→ manager approval), or automatic during a sale (AutoBreakingService). All converge on identical parent−/child+ ledger moves. Reverse splits provide the undo path. - Break drafts. Manual breaks can be saved as a
PENDINGdraft (request_type=save, no ledger write) and later processed; auto/approved breaks are created directly asPROCESSED. - Two ways to settle a count. A variance can be directly applied to QOH+GL by the count
supervisor (
compareCountsVsStockCheckProcess), or routed through Stock Processing to charge a debtor. Confirm per deployment which path a given branch uses (they are not mutually exclusive in code). - Freeze adjustments are setting-gated.
EXCLUDE_OVERFLOW_STOCKS_FROM_STOCK_COUNT_SHEETandDEDUCT_UNDISPATCHED_STOCKS_FROM_STOCK_COUNT_SHEETchange what "system QOH" means on the sheet;SHOW_SYSTEM_QOH_ON_PRINTED_STOCK_TAKE_SHEETtoggles whether counters see the system figure on the printed sheet;activate-subbinsgroups the sheet by subbin. - Signed-acknowledgement gate.
ENFORCE_SIGNED_ACKNOWLEDGEMENT_FOR_LOSS_CHARGEStoggles whether an employee-charge document upload is required vs optional on stock/delivery loss. - UOM-based inventory.
INVENTORY_SETUP = 'UOM BASED'enables multi-UOM conversion in the Stock Move Report (base/second/third UOM) and drives the count-type/UOM selection on freezes. - Sales-order feature flag. The Stock Move Report menu entry is gated by
identify-sales-orders-from-normal-orders. - Store-type stacks. Store-C, Supreme Store, Overflow Store, and Opening-Balances each have a
parallel stock-take controller + tables, activated per flavor (e.g.
ACTIVATE_OVERFLOW_STORE). Core "Stock Take" is the defaultStockTakesControllerstack. - Break suggestions are tunable per branch via
minimum-quantity-of-child-itemandaverage-sales-days-to-compute-stock-breaksettings.
7. Open questions to confirm¶
CODE-PROVEN (verified in this pass):
- QOH is a running sum of wa_stock_moves.qauntity; new_qoh snapshots the balance. (migration
2023_09_08_134414_create_wa_stock_moves_table.php; model WaStockMove.)
- Freeze snapshots per-item quantity_on_hand into wa_stock_check_freeze_items. (migration
2023_09_08_134414_create_wa_stock_check_freeze_items_table.php.)
- Every break/reverse/loss/processing operation writes signed ledger rows at the cited lines.
- Delivery loss does not write wa_stock_moves — only wa_debtor_trans + penalties.
- Variance formula and the direct count-apply path (wa_stock_moves + wa_gl_trans +
WaStockCountDeviation) verified at StockCountsController.php:230-234 and :396-547.
- Freeze QOH is adjusted by overflow/undispatched settings before snapshot
(StockTakesController.php:160-295).
INFERENCES (need a maintainer to confirm):
- The exact rule mapping a negative variance → Sale/Short and positive → Return/Excess is derived
from the store methods' filters; confirm whether a supervisor can override the sign/route, and
whether the direct-apply path and the debtor-processing path can both run on the same variance.
- Whether the RouteAutoBreak dispatch lifecycle (pending→dispatched→received) is purely a
physical-movement audit with no second QOH mutation (strongly implied, since the ledger is
written at break time) — confirm no receive() re-posts moves.
- How stock_id_code vs wa_inventory_item_id are used together in the QOH SUM (batch/lot
granularity?) — needs a maintainer to confirm the exact grouping key.
- Store-C / Supreme / Overflow / Opening-Balances variants were not traced in depth this
pass; confirm they use their own *_stock_moves equivalent or share wa_stock_moves.
- deviationReport / WaStockCountDeviation and compareCountsVsStockCheck relationships were
observed by route name but not line-traced.
8. Source references¶
Navigation & routes
- resources/views/admin/includes/sidebar_includes/inventory.blade.php (Stock Take menu
:866-1038; Stocks Break menu :374-445; Debtors/Processing/Loss :939-1035).
- routes/web.php — stock breaking :1585-1595; reverse splits :1591-1593; stock-takes
:3855-3861; live count :3864-3871; stock counts + variance :3873-3884; user assignment
:3887-3910; blocked users :3893-3899; debtors :3947-3966; processing :3968-3994;
auto-breaks :5652-5663; break summary/split-requests :5664-5670; stock-move-report
:5461-5463.
- routes/modules/inventory.php — stock loss :71-84; delivery loss :87-98.
Controllers
- app/Http/Controllers/Admin/StockTakesController.php — freeze/sheet; snapshot :149-386,
overflow exclusion :160-208, undispatched deduction :214-295.
- app/Http/Controllers/Admin/StockTakeUserAssignmentController.php — counter allocation.
- app/Http/Controllers/Admin/StockCountsController.php — enter counts :92-250, variance
formula :230-234, direct QOH+GL apply :396-547, deviation report :370-384.
- app/Http/Controllers/Admin/LiveStockCountController.php — spot counts (live_count).
- app/Http/Controllers/Admin/StockCountVarianceReportController.php — variance reports,
undispatched breakdown :207-230.
- app/Http/Controllers/Admin/StockCountBlockedUsersController.php — blocked users/exemptions.
- app/Http/Controllers/Admin/stockBreakingController.php — manual break; QOH moves :898-938,
update :1116-1156, dispatch :1187-1304.
- app/Http/Controllers/Admin/RouteAutoBreakController.php — auto-break dispatch lifecycle,
summary :376-487.
- app/Http/Controllers/Admin/ReverseSplitsController.php — reverse split; QOH moves :328-358.
- app/Http/Controllers/Admin/MobileInventoryManagementController.php — split requests; approve
QOH moves :285-321.
- app/Services/AutoBreakingService.php — auto break; QOH moves :376-450.
- app/Http/Controllers/Admin/StockAdjustmentController.php — Sale/Short :316-367,
Return/Excess :850-871, ESD signing :1094-1169.
- app/Http/Controllers/Admin/StockUncompletedProcessingController.php — uncompleted :172-221.
- app/Http/Controllers/Admin/StockDebtorsController.php — debtors & splits.
- app/Http/Controllers/Admin/StockLossController.php — store loss; approve QOH :308-331.
- app/Http/Controllers/Admin/DeliveryLossController.php — delivery loss; approve :328-366.
- app/Http/Controllers/Admin/StockMoveReportController.php — move report :61-299.
Models (App\Model\* and App\Models\*)
- Ledger: WaStockMove.
- Freeze/count: WaStockCheckFreeze, WaStockCheckFreezeItem, WaStockCount,
WaStockCountVariation, WaStockCountDeviation, WaStockCountProcess,
StockTakeUserAssignment, StockTakeUserAssignmentAssignee.
- Breaking: WaStockBreaking, WaStockBreakingItem, RouteAutoBreak, ReverseSplit,
PosStockBreakRequest, StockBreakDispatch, StockBreakDispatchItem.
- Debtors/loss: StockDebtor, StockDebtorTran, StockDebtorTranItem, StockLoss,
StockLossItem, StockLossEmployeeCharge, DeliveryLoss, DeliveryLossItem,
DeliveryLossEmployeeCharge, EmployeePenalty, WaDebtorTran.
Migrations
- database/migrations/2023_09_08_134414_create_wa_stock_moves_table.php.
- database/migrations/2023_09_08_134414_create_wa_stock_check_freezes_table.php.
- database/migrations/2023_09_08_134414_create_wa_stock_check_freeze_items_table.php.
- database/migrations/2024_05_14_075547_create_wa_stock__count_variation_table.php.
- database/migrations/2023_09_08_134414_create_wa_stock_counts_table.php.
- database/migrations/2023_09_08_134414_create_wa_stock_count_deviations_table.php.
- database/migrations/2025_11_12_100335_add_count_type_to_stock_tables.php (adds count_type).
- database/migrations/2026_07_14_100000_create_wa_stock_check_freeze_undispatched_items_table.php.
Key settings (slugs / flags)
- Breaking: minimum-quantity-of-child-item, average-sales-days-to-compute-stock-break.
- Freeze/count: EXCLUDE_OVERFLOW_STOCKS_FROM_STOCK_COUNT_SHEET,
DEDUCT_UNDISPATCHED_STOCKS_FROM_STOCK_COUNT_SHEET,
SHOW_SYSTEM_QOH_ON_PRINTED_STOCK_TAKE_SHEET, activate-subbins, ACTIVATE_OVERFLOW_STORE.
- Loss: ENFORCE_SIGNED_ACKNOWLEDGEMENT_FOR_LOSS_CHARGES.
- Reports: INVENTORY_SETUP (UOM BASED), identify-sales-orders-from-normal-orders.
Permissions
- app/Permissions/Inventory.php.