Repository navigation
The store-grain count keeps a part roll: count and reconciliation quantities are Decimal(12,3) - #35
Merged
Merged
Conversation
…econciliation quantities are Decimal(12,3) The count, its variance and its reconciliation were Int while the balance is Decimal(12,3) and the snapshot a float. Exercised first against the Int columns (storeCountFractional.integration.test.ts), Prisma truncated silently: a count of 12.5 yards was stored as 12, and two scans of 0.1 and 0.2 as 0 and 0, so an accurate count read as 0.3 missing. A count of "lots" reached Prisma as NaN and answered 500. - Migration 20261021120000_store_count_decimal widens the six columns in place (integer -> numeric), so existing rows keep their values. - lib/inventory/storeCount.ts: scans summed and the variance taken to the stock precision (float noise is not a variance), and every count and reconciliation sent as numbers (JSON sends a Decimal as text). - parseCount (lib/inventory/qtyInput.ts) reads a typed count; zero is a count. The count route and the corrected-count prompt use it, in place of Number() and parseInt. - The inventory runbook no longer says reconcile.ts writes stock (it only stamps a Reconciliation row), or that the variance reports read InventoryPosition (they read the snapshot). Tests: storeCountFractional.integration.test.ts (4, all failing on the Int columns; removing the rounding or the conversion each fails one), storeCount.test.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 tasks
goetchstone
enabled auto-merge (squash)
October 17, 2026 10:37
…store-count-decimal # Conflicts: # docs/domains/inventory.md
goetchstone
added a commit
that referenced
this pull request
Oct 17, 2026
…oposal quantity are Decimal(12,3) (#36) * A buyer's draft and a B2B proposal keep a part roll: BuyerDraftItem.qty and ProposalLineItem.quantity are Decimal(12,3) The last two whole-number quantity columns a part roll can reach (found by #35's rule-49 sweep). Exercised first against the Int columns (draftAndProposalQtyFractional.integration.test.ts, 6 of 7 failing): a draft typed as 12.5 yards was stored as 1, a real PO for 12.5 yards was drafted as 12, a buy priced 12 yards (96, not 100), a proposal line of 12.5 was stored and ordered as 12, and a typed "lots" answered 500. - Migration 20261022120000_draft_and_proposal_qty_decimal: both columns widen integer -> numeric in place, default 1. - Writers read a typed quantity with parseQty. A draft qty is zero or more (zero was already a legitimate draft qty); create still falls back to 1, edit refuses with a 400. The historical PO import keeps the ordered yards instead of truncating. A proposal quantity must be greater than zero, else 400. - Readers convert with toQty: draftItemForClient / draftSpend (lib/buyerDraftQty.ts) and proposalLineForClient (lib/proposalQty.ts) on every route that sends or prices a row; exports, the performance report, convert-to-order and the PDF convert inline. - The PDF's item page shows "each x qty = line" for any quantity but 1 (it was > 1, so half a yard showed a yard's price as the line). - Barcode quick-add reads its qty with parseQty, not parseInt; the draft wizard and proposal quantity boxes take decimals. - Runbooks: buyer-drafts.md (the int truncation is gone; zero-quantity import lines are skipped, not clamped to 1 as it said) and the proposals section of sales-orders.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * buyerDraftQty: say where the conversions live Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <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.
Summary
The store-grain count (Inventory › Physical count, the variance report and reconciliation) stays as the check that a POS cutover counted right, and a store's stock includes part rolls. Its quantity columns were
Intwhile the balance it is checked against isDecimal(12,3), so a part roll could not be counted. Exercised first against theIntcolumns, Prisma truncated silently:NaNand answered 500.This is one of the follow-ups left by ledger-plan PR 4 (
ROADMAP.md→ "Handheld floor"). It does not depend on #34: that PR adds the count by place and leaves these models and routes alone.What changes
20261021120000_store_count_decimal:PhysicalInventoryCount.quantityandReconciliation's five expected, counted and variance columns becomeDecimal(12,3). The widening is in place (integer -> numeric), so existing rows keep their values.lib/inventory/storeCount.ts:parseCount(lib/inventory/qtyInput.ts) reads a typed count, and zero is a count. The count route and the "correct the count" prompt use it instead ofNumber()andparseInt. A bad count is now a 400 that says what is wrong.docs/domains/inventory.md), checked against the source:reconcile.tsdoes not write stock. It only stamps aReconciliationrow, and nothing reads that back intoInventoryPosition.InventorySnapshot, notInventoryPosition.Trace / Verification
lib/adapters,lib/auth,paymentService,secureUploadorautomations.grep -rlnE "\.(physicalInventoryCount|reconciliation)\.(find|create|upsert|update|delete|count|aggregate|groupBy)" app/srcfinds 16 routes, all underpages/api/inventory. The 11 that read or send a quantity are changed here. The other 5 only delete rows (clear-all-data,clear-location,physical-count/[id],undo-reconciliation) or write a count of 1 (reconcile-unidentified), which a Decimal column takes as it is. The demo seed writes whole-number counts, which a Decimal column takes as they are.storeCountFractional.integration.test.tsran against theIntcolumns before the change, and all 4 tests failed for the reasons in the summary. All 4 pass after it.prisma migrate deployof every migration into an empty scratch database, thenprisma migrate diff --from-config-datasource --to-schema --exit-code: "No difference detected".BuyerDraftItem.qtyandProposalLineItem.quantitycan also receive a part roll. They are not changed here, and are tracked inROADMAP.md→ "Handheld floor". The rest are whole by nature: till counts, units per carton, item counts.Scan / gate state
npm run check:localstops at its integration step from an agent session: Prisma refuses the harness'sdb push --accept-data-losswithout the owner's consent. Each step was run directly instead.storeCount.test.tsfbc_test_dbwith this migration's SQL applied (no schema push)security:deps)Test plan
/app/inventory/physical-count, count a fabric product with quantity12.5. Scan history shows12.5.12.375. Reconciled items shows12.375.-1as a count. It is refused with "The count must be a number, zero or more."🤖 Generated with Claude Code