Fix catalog item pricing and rogue margin-points text

Catalog DefaultPrice is always the base price — removed the IncludePrepCost
gate that was adding prep service labor on top of catalog items. PrepServices
on catalog items exist for scheduling purposes only, not pricing.

Also fixed Razor syntax bug in Details.cshtml where @(expr).ToString("F1")
rendered the raw decimal followed by the literal string ".ToString("F1")"
instead of the formatted value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 16:43:42 -04:00
parent 810d5a5dc1
commit 9292f3169c
2 changed files with 3 additions and 11 deletions
@@ -391,16 +391,8 @@ public class PricingCalculationService : IPricingCalculationService
baseSubtotal = baseUnitPrice * item.Quantity;
_logger.LogInformation("Catalog base: ${Price} × {Qty} = ${Base}", baseUnitPrice, item.Quantity, baseSubtotal);
// Optionally add prep service labor cost for catalog items (opt-in toggle in wizard)
// AI items exclude prep cost — it's already baked into the AI estimate
if (!item.IsAiItem && item.IncludePrepCost && item.PrepServices != null && item.PrepServices.Any())
{
var totalPrepMinutes = item.PrepServices.Sum(ps => ps.EstimatedMinutes);
var prepLaborCost = (totalPrepMinutes / 60m) * costs.StandardLaborRate;
baseSubtotal += prepLaborCost;
totalLaborCost += prepLaborCost;
_logger.LogInformation("Catalog item prep cost: {Min}min × ${Rate}/h = ${Cost}", totalPrepMinutes, costs.StandardLaborRate, prepLaborCost);
}
// Catalog DefaultPrice is always the base — prep service labor is never added on top.
// PrepServices on catalog items are used for scheduling only, not pricing.
// Custom (non-inventory) powder coats must be purchased separately — add their material
// cost on top of the catalog base price. Inventory powder is assumed baked into DefaultPrice.
@@ -1230,7 +1230,7 @@
var priceBeforeDiscount = pb.Total + pb.DiscountAmount;
var marginBeforeDiscount = priceBeforeDiscount > 0 ? ((priceBeforeDiscount - totalDirectCost) / priceBeforeDiscount * 100m) : 0m;
<div class="small text-muted">
Without discount: @marginBeforeDiscount.ToString("F1")% — discount cost you @(marginBeforeDiscount - effectiveMargin).ToString("F1") margin points
Without discount: @marginBeforeDiscount.ToString("F1")% — discount cost you @((marginBeforeDiscount - effectiveMargin).ToString("F1")) margin points
</div>
}
}