The sync propagation now also backfills the catalog link: any inventory item
with no PowderCatalogItemId that matches a catalog row by Manufacturer +
ManufacturerPartNumber (the catalog SKU) gets linked and picks up the catalog
price/product data. Only links on a confident match (exact SKU + matching
vendor, or a single unambiguous candidate), so it never mis-links.
This backfills items created before linking existed, automatically, on every
environment (dev and prod) with no manual step or one-off script — legacy items
link on the next sync, new items still link at create time. Cost basis,
quantity, notes, and image remain untouched.
Tests: links an unlinked item by manufacturer+part number; leaves it unlinked
when the part number has no catalog match. Full suite 278 green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quotes now reflect the current catalog price instead of a tenant's stale
typed-in cost, without disturbing accounting.
- InventoryItem gains CatalogReferencePrice + CatalogPriceUpdatedAt: the
QUOTING price (current replacement cost), kept separate from UnitCost/
AverageCost (the cost basis that drives valuation/COGS).
- The catalog sync (PowderCatalogUpsertService.PropagateToLinkedInventoryAsync,
run at the end of every upsert) refreshes linked inventory items with the
catalog's current price and product data (description, cure, SDS/TDS, color
families, coverage, SG, transfer eff, requires-clear-coat). It NEVER touches
cost, quantity, notes, image, location, or stock levels, and never nulls a
tenant value with a catalog null. EF persists only actual changes.
- CatalogReferencePrice is also set at link time (catalog receive, incoming-
from-catalog, identity match on create) so a freshly added powder quotes at
the current price immediately.
- Pricing now uses CatalogReferencePrice ?? UnitCost: the quote/job powder
pickers and PricingCalculationService (in-stock usage and powder-to-order
billing). Falls back to UnitCost for non-catalog/manual powders, so nothing
regresses. One current price for the whole quantity — no on-hand/to-order
split. Per-coat snapshot still locks the price at quote creation.
Tests: propagation updates reference price + specs but not cost/qty/notes/
image, and skips a $0 catalog price. Full suite 276 green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>