diff --git a/src/PowderCoating.Application/Services/PricingCalculationService.cs b/src/PowderCoating.Application/Services/PricingCalculationService.cs
index 226aaa0..8c8e2a1 100644
--- a/src/PowderCoating.Application/Services/PricingCalculationService.cs
+++ b/src/PowderCoating.Application/Services/PricingCalculationService.cs
@@ -252,11 +252,27 @@ public class PricingCalculationService : IPricingCalculationService
};
}
- // AI items use ManualUnitPrice directly (set to either the AI estimate or the user's price override).
- // The AI already factored in all costs — skip the pricing engine entirely.
+ // AI items use ManualUnitPrice as the single-coat base price.
+ // Apply the same additional-coat charge as the calculated-item path so that
+ // adding a 2nd or 3rd coat in step 3 increases the price by AdditionalCoatLaborPercent%
+ // per coat — matching what catalog/calculated items charge.
if (item.IsAiItem && item.ManualUnitPrice.HasValue)
{
var aiUnitPrice = item.ManualUnitPrice.Value;
+
+ int additionalAiCoats = 0;
+ if (item.Coats != null)
+ {
+ for (int i = 1; i < item.Coats.Count; i++)
+ {
+ if (!item.Coats[i].NoExtraLayerCharge)
+ additionalAiCoats++;
+ }
+ }
+ if (additionalAiCoats > 0)
+ aiUnitPrice = Math.Round(
+ aiUnitPrice * (1m + additionalAiCoats * (costs.AdditionalCoatLaborPercent / 100m)), 2);
+
var aiTotal = aiUnitPrice * item.Quantity;
return new QuoteItemPricingResult
{
diff --git a/src/PowderCoating.Infrastructure/Services/AiQuoteService.cs b/src/PowderCoating.Infrastructure/Services/AiQuoteService.cs
index 8f8086e..fb79bf0 100644
--- a/src/PowderCoating.Infrastructure/Services/AiQuoteService.cs
+++ b/src/PowderCoating.Infrastructure/Services/AiQuoteService.cs
@@ -540,6 +540,16 @@ Respond with the JSON object only.";
var complexityCharge = subtotalBeforeComplexity * complexityPct;
var subtotal = subtotalBeforeComplexity + complexityCharge;
+ // Additional coat charge — each coat beyond the first adds AdditionalCoatLaborPercent % of
+ // the subtotal, matching the formula in PricingCalculationService.CalculateQuoteItemPriceAsync.
+ // The coat count here comes from the wizard's step-2 field (aiCoatCount), so the preview
+ // reflects whatever multi-coat configuration the user specified before clicking Analyze.
+ if (request.CoatCount > 1)
+ {
+ var additionalCoatCharge = subtotal * (request.CoatCount - 1) * (costs.AdditionalCoatLaborPercent / 100m);
+ subtotal += additionalCoatCharge;
+ }
+
var markupAmount = (materialCost + consumablesSurcharge) * (costs.GeneralMarkupPercentage / 100m);
// Apply shop minimum
diff --git a/src/PowderCoating.Web/Controllers/InventoryController.cs b/src/PowderCoating.Web/Controllers/InventoryController.cs
index 69f8de2..3756c98 100644
--- a/src/PowderCoating.Web/Controllers/InventoryController.cs
+++ b/src/PowderCoating.Web/Controllers/InventoryController.cs
@@ -1029,12 +1029,13 @@ public class InventoryController : Controller
}
///
- /// Searches the platform-level PowderCatalogItems table by SKU or color name and returns
- /// up to 10 matches as JSON. Called by the inventory Create/Edit form before falling back
- /// to the AI Lookup, avoiding unnecessary API calls for known products.
+ /// Searches the platform-level PowderCatalogItems table by SKU or color name.
+ /// Excludes catalog entries already present in the company's inventory (by ManufacturerPartNumber).
+ /// Pass currentId when editing an existing item so its own catalog entry is not filtered out.
+ /// Called by the inventory Create/Edit form before falling back to AI Lookup.
///
[HttpGet]
- public async Task CatalogLookup(string? q, string? vendor)
+ public async Task CatalogLookup(string? q, string? vendor, int? currentId = null)
{
if (string.IsNullOrWhiteSpace(q) || q.Length < 2)
return Json(Array.Empty