Answer how long a spool sat and what is sitting idle, from the ledger that exists to say so - #119
Merged
Merged
Conversation
…with (#36) A parcel ended at `packaging_tasks.shipped_at` with a carrier code and nothing else: no zone, no promise, no arrival, so no «В срок» and no «Точность» anybody measured. New context `contexts/logistics` (migration 0028: `shipments`, `shipment_events`). A shipment opens at the API edge when a parcel ships, pinning the zone and its transit days from the order's own rate snapshot - a zone edited afterwards moves the next promise and never this one (ADR-0020, applied to a promise). An order with no pinned rates, or a postcode no zone claims, gets a transit time and no promise: null, never nought days. Every change of state is an event and the status is what the last event says; `delivered_at` is written by the `delivered` event alone, an arrival before the dispatch is refused, and a closed parcel takes no more events. The scorecards count what was measured. «В срок» is over delivered parcels that carried a promise, with the counts beside the share; «Точность» groups by the pinned promise, so a zone whose transit days changed mid-window is two rows rather than one blurred average; «Повреждений» is recorded events, and the foot says so. Not served, each with its reason in the code: «Средняя цена» and «Что и почём» (money behind a production gate), «Оценка» (no chosen weights), «Отгрузка сегодня» (the packaging board's), «Куда» (on the order). `LogisticsPage.tsx` draws the lanes, the shipment with its history, the carriers and the delivery accuracy. DESIGN-KIT §1 now reads twenty-one of twenty-one, and the screen-inventory gate gained its zero case. Verified: 14 unit + 5 API tests (the ship route opens the shipment; an operator records the delivery and a customer may not; no money on the schemas); `alembic upgrade`, `check` (no drift), `downgrade`, re-`upgrade` on the dev database; six backend gates each exit=0; referential-integrity, schema-contract, migration and docs gates pass. Frontend from the lockfile: `tsc --build --force`, lint, test (35 files, 330 passed), build, and a regenerated API client, each exit=0; five screen tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… that exists to say so (#35) Issue #35's second slice: «Оборачиваемость» and «Залежалое». Both are the question a location overwritten in place destroys and the movement ledger was written to keep - so they are folds over `material_movements`, never a column somebody maintains. Turnover is the mean days between a lot's `stock.received` row and its first outbound row (mounted, issued or written off; a cell-to-cell move is not outbound), per family, over lots that *left* the shelf. The ones still there are counted beside the mean and never inside it, so an untouched shelf does not read as a fast one. Dead stock is lots in stock with mass left and no movement for the window, costed as purchase price pro rata to what remains **only where receiving recorded a price**; unpriced lots are counted and add nothing, rather than being costed at nought. Served as `GET /store/turnover` under the router's VIEW_PRODUCTION and `GET /store/dead-stock` behind VIEW_FINANCIALS on top - the `/jobs/variances` shape §2.4 asked for. `StoreMeasures.tsx` never requests the money half without the permission; its test reads the network log to prove it. Verified: 4 unit tests (both folds and the three-instant read) and 2 API tests (the floor may read turnover and is refused dead stock; the manager gets it costed); the existing store API tests pass; six backend gates each exit=0; docs gates pass with DESIGN-KIT §2.4 updated. Frontend from the lockfile: `tsc --build --force`, lint, test (36 files, 333 passed), build, and a regenerated API client, each exit=0; three screen tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
dimmus
force-pushed
the
claude/store-measures
branch
from
September 25, 2026 10:59
9cea5d0 to
29a79fd
Compare
dimmus
added a commit
that referenced
this pull request
Sep 26, 2026
… read the two settings nothing read (#35) (#120) `inventory.require_drying` and `inventory.drying_valid_hours` have been in the settings catalogue since the settings screen was built, and nothing read either. This is the read. One nullable column, `material_lots.dried_at` (migration 0029), written only when a spool comes out of the dryer. The state is computed at read time from that instant, the clock and the two settings: not_required (PLA, or the rule off), drying, unknown (never marked — not measured, so not lapsed), dry with hours left, expired. Never stored, so a spool nobody looked at cannot go on reading as dry, and shortening the window on the settings screen shortens every mark; the API test edits the setting mid-test to prove it. Two writes, `POST /store/lots/{id}/dry` and `/dried`, both ledger rows. The second is refused for a spool that was never sent, which is what keeps `dried_at` meaning what its name says. The spool keeps its cell in the dryer so the map does not offer its slot to anybody. `GET /store/cells/{address}` serves `StoredLot` — the lot, its family, its receipt and the state — and `CellDetail.tsx` draws the kit's «Сушка» column with «не сушилась» and «просрочена» kept apart. «Высушена» is offered for anything physically in the dryer even after the rule is switched off, or the spool would be stuck there. Also corrects two comments that described the store before #119 landed, and extends the docs gate's number-word table past thirty. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue #35, the turnover and dead stock rows. Stacked on #118 (which is stacked on #117); merge those first and this diff shrinks to its own commit.
What it computes.
contexts/inventory/store_measures.pyjoins each lot to three instants frommaterial_movements— itsstock.receivedrow, its first outbound row, its last row of any kind — and folds:idle_days(60 by default), costed aspurchase_price × remaining / initialonly where receiving recorded a price. Unpriced lots are counted and add nothing to the total, rather than being costed at nought.The money split.
GET /store/turnoveris grams and days under the router'sVIEW_PRODUCTION;GET /store/dead-stocksits behindVIEW_FINANCIALSon top, refused whole to an operator.StoreMeasures.tsxnever requests it without the permission — the screen test asserts that in the network log — and draws nothing in its place.Verified
exit=0; docs gates pass (DESIGN-KIT §2.4 now says what is built and what is owed: drying state, stocktake, the non-filament classes).tsc --build --force,lint,test(36 files, 333 passed),buildeachexit=0; API client regenerated.Two traps recorded in HANDOFF:
record_movementdoes not flush andnext_sequencereads the ledger, so two rows before one flush claim the same rung; andlint-importsreported a broken contract while another process was writing files and kept all six when re-run alone.🤖 Generated with Claude Code