Previously the quick quote omitted the oven charge entirely, so saved quotes
were under-priced relative to full quotes from the same items.
Pricing: CalculatePricing now calculates ovenBatchCost = (cycleMin/60) × OvenOperatingCostPerHour
using DefaultOvenCycleMinutes (fallback 50 min), then adds it to the total as a quote-level
charge matching how PricingCalculationService handles oven costs.
Save path: SaveQuickQuoteRequest gains OvenBatchCost + OvenCycleMinutes; the Quote record
now stores OvenBatchCost, OvenCycleMinutes, and Total = ItemsSubtotal + OvenBatchCost.
Display: results card shows a sub-line under the estimate price:
"incl. oven 1 batch 50 min: $12.00"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
iOS ignores manifest icons for home screen; requires apple-touch-icon link tag.
Generated 180x180 PNG with white background + padding so the transparent logo
renders correctly instead of filling black.
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>
- Add /SmsAgreements SuperAdmin page listing per-company SMS terms acceptance
status, with stats cards, filter/search, and a full acceptance history modal
(terms version, accepted by, timestamp, IP, user agent)
- Add SMS Agreements nav link under Tenants & Billing in the platform sidebar
- Update HelpKnowledgeBase and Help docs (Quotes, Settings) to document
quote approval via SMS and the reuse of existing approval tokens
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Progress widget dismiss now POSTs to Dashboard/DismissProgressWidget, writing
GuidedActivationDismissedAt to the DB so the widget stays hidden across devices
and cache clears (localStorage alone wasn't enough). BuildShopProgressWidgetAsync
suppresses the widget server-side when AllDone + dismissed.
New SuperAdmin page at /OnboardingProgress shows the activation funnel across
all tenant companies: wizard status, chosen path, milestone progress bar, key
dates (first job/quote, first invoice, workflow completed, widget dismissed),
and a status badge (Not Started / In Progress / Complete / Dismissed). Nav link
added under Users & Activity in the Platform Management sidebar.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Email delivery failures and PDF generation errors now show a permanent
warning/error toast that requires manual dismissal, so users cannot
accidentally miss critical action-blocking feedback.
- ToastHelper: WarningPermanent TempData key + Warning/WarningPermanent
extension methods on both ITempDataDictionary and Controller
- SetNotificationResultToast: NotificationStatus.Failed now uses
ToastWarningPermanent (previously auto-dismissed in 5 s)
- InvoicesController.Send: TempData["Warning"] → TempData["WarningPermanent"]
when PDF generation or email dispatch fails
- InvoicesController.DownloadPdf: TempData["Error"] → TempData["ErrorPermanent"]
with the actual exception message so root cause is visible
- _Layout.cshtml: WarningPermanent hidden div
- toast-notifications.js: WarningPermanent handler (timeOut: 0)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After password login, users are routed through /Passkey/EnrollPrompt
before reaching the dashboard. The page shows an Enable / Maybe later
choice using the auth layout for a clean full-screen experience.
Users who already have a passkey are skipped past instantly.
Removes the floating bottom-right card from _Layout — the dedicated
page is a better UX touchpoint (one moment, right after login, rather
than a floating card on every page).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shop floor workers can log in once with a password, enroll a passkey,
and use Face ID / Windows Hello / fingerprint for all future logins.
- UserPasskey entity + AddUserPasskeys migration (Fido2 v4.0.1)
- PasskeyController: RegisterOptions, Register, LoginOptions, Login,
Manage, Remove endpoints
- Login page: platform-aware button (Face ID / Windows Hello / etc.)
hidden automatically if browser doesn't support WebAuthn
- Post-login floating prompt to enroll on first use; session-dismissed
- Passkeys & Biometrics link in user dropdown menu
- Manage page: list registered devices, add new, remove individual
- passkey.js: targeted base64url conversion (only challenge + user.id
+ credential IDs) — fixes "Required parameters missing" error caused
by blindly converting rp.id and other string fields to ArrayBuffers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GenerateAiProfileDraft endpoint builds suggested AI Profile text from
existing company config (ovens, workers, inventory categories, rates)
- "Generate from my settings" button wired in Company Settings AI Profile tab
- Add "hrs" unit label to Billable Hours/Month input in Company Settings and Setup Wizard Step 3
- Hide AI Quick Quote widget (commented out in _Layout) pending next release
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New AI Quick Quote floating button: staff type a verbal description to
get an instant price estimate for phone/walk-in customers; detected
color names are fuzzy-matched against inventory for stock status;
saves draft quote under a Walk-In / Phone customer with one click
- Inline customer change on Quote Details and Job Details: always-visible
native select with inline confirmation banner (no TomSelect dependency);
ChangeCustomer AJAX endpoints on QuotesController and JobsController
- Quote Edit page: customer dropdown is now editable (lock removed)
- Fix AutoMapper missing CatalogCategory -> UpdateCategoryDto mapping
that caused a crash on the catalog category Edit page
- Help docs and AI knowledge base updated for all three features
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>