- InventoryItem.IsIncoming: marks powder ordered but not yet received; enables QR code
printing on work orders while the shipment is in transit
- InventoryController.CreateIncomingFromCatalog: POST endpoint creates a 0-balance inventory
record from a PowderCatalogItem and returns it in wizard-compatible shape
- item-wizard.js: custom coat tab now searches the platform powder catalog as a fallback;
catalog results show an 'Add as Incoming Order' option; createIncomingFromCatalog POSTs
to server and selects the new item without a page refresh
- QuoteItemCoatDto: CatalogItemId + AddAsIncoming fields so the wizard can signal server-side
incoming-item creation during quote save
- Inventory Create/Edit/Index views: IsIncoming badge and field
- IInventoryAiLookupService: minor interface update
- Migration: AddInventoryIsIncoming
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- PWA: manifest.json + minimal service worker so iOS/Android persist camera
permission after "Add to Home Screen"; theme-color and apple meta tags in layout
- PWA icons: 192x192 and 512x512 from transparent PCL logo; updated pcl-logo.png
- AI pricing: apply AdditionalCoatLaborPercent per extra coat on AI items,
matching the calculated-item path (was ignoring extra coats entirely)
- AI wizard: live price recalc when coats are added/removed; session-expiry
errors now show a clear "refresh and sign in" message instead of raw HTTP status;
smooth-scroll to follow-up/results sections on AI response
- Catalog lookup: exclude SKUs already in company inventory from results;
pass currentId on edit so own entry still appears; vendor-scoped search
with cross-vendor fallback; result count shown in multi-match modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Platform PowderCatalogItem table (IPlainRepository, no tenant filter) with
full spec fields: cure temp/time, finish, color families, clear coat flag,
coverage sq ft/lb, transfer efficiency, IsUserContributed
- Two EF migrations: AddPowderCatalogItem + AddPowderCatalogSpecFields
- PowderCatalogController (SuperAdminOnly): import from Prismatic JSON scrape,
Lookup AJAX endpoint (catalog-first, ranked by SKU exact match), stats view
with Tenant Contributed card
- Unified smart Lookup button on inventory Create/Edit: catalog hit fills all
fields via catalogSnapshot pattern; AI augments cure/finish data from product
URL if subscription enabled; catalog miss falls through to AI lookup
- In-browser label scanner (_LabelScanModal): getUserMedia live camera feed,
jsQR auto-detects QR codes in rAF loop; "Scan Label Text" fallback sends
captured frame to Claude vision via /Inventory/ScanLabel
- ScanLabel endpoint handles both QR URL path (LookupByUrlAsync) and vision
path (ScanLabelAsync); auto-inserts unrecognized products as
IsUserContributed=true; returns wasInCatalog/addedToCatalog flags
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When AI Lookup fetches a manufacturer product page, it now extracts the
og:image (Open Graph) meta tag before stripping HTML tags. The image URL
is returned in InventoryAiLookupResult.ImageUrl and automatically shown
as a preview on the Create/Edit form alongside the other filled fields.
The preview includes a Remove button to clear the image, and the Wrong
Match? button clears it along with the other AI-filled fields.
On the inventory Details page a product image card is rendered above the
Stock & Pricing card whenever ImageUrl is set. The field is nullable so
existing records and powders without an image are unaffected.
New field: InventoryItem.ImageUrl (nvarchar, nullable).
Migration: AddInventoryItemImageUrl.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>