Reorganize Operating Costs tab into individual section cards

Replaces single large card with six labeled section cards (Rates & Costs,
Facility Overhead, Equipment, Pricing & Profit, Rush Charges, Complexity)
to reduce visual density and improve scannability.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-15 21:03:43 -04:00
parent b2a1b9a0be
commit 91a5dbe30c
@@ -344,9 +344,12 @@
<!-- Operating Costs Tab -->
<div class="tab-pane fade" id="operating-costs" role="tabpanel">
<form id="operatingCostsForm">
<!-- Header -->
<div class="card mt-3">
<div class="card-body">
<h5 class="card-title">Operating Costs Configuration
<h5 class="card-title mb-1">Operating Costs Configuration
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-title="Operating Costs"
@@ -354,18 +357,22 @@
<i class="bi bi-question-circle"></i>
</a>
</h5>
<p class="text-muted">Configure your operating costs for accurate job quoting calculations.</p>
<p class="text-muted mb-0">Configure your operating costs for accurate job quoting calculations.</p>
</div>
</div>
<form id="operatingCostsForm">
<!-- Rates & Costs -->
<h6 class="border-bottom pb-2 mb-3">Rates &amp; Costs
<div class="card mt-3 border-0 shadow-sm">
<div class="card-header bg-transparent fw-semibold">
<i class="bi bi-currency-dollar text-primary me-1"></i> Rates &amp; Costs
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-title="Rates &amp; Costs"
data-bs-content="&lt;strong&gt;Standard Labor Rate&lt;/strong&gt; is the baseline $/hr for all coating work — sandblasting and masking are multiplied from this. &lt;strong&gt;Powder Coating Cost/sq ft&lt;/strong&gt; is the fallback material rate used when you don't select a specific powder inventory item on a quote item. &lt;strong&gt;Additional Coat Labor&lt;/strong&gt; is the percentage of the base labor cost charged for each coat after the first (e.g. 30% means a 2nd coat adds 30% more labor).">
<i class="bi bi-question-circle"></i>
</a>
</h6>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3">
<div class="mb-3">
@@ -430,16 +437,21 @@
</div>
</div>
</div>
</div>
</div>
<!-- Facility Overhead -->
<h6 class="border-bottom pb-2 mb-3 mt-3">Facility Overhead
<div class="card mt-3 border-0 shadow-sm">
<div class="card-header bg-transparent fw-semibold">
<i class="bi bi-building text-primary me-1"></i> Facility Overhead
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-title="Facility Overhead"
data-bs-content="Enter your monthly shop rent and combined utility costs. The system divides these by your estimated billable hours to derive a per-hour overhead rate, which is then added to every quote proportionally to the estimated job time. This ensures fixed facility costs are recovered across all jobs rather than absorbed into your markup.">
<i class="bi bi-question-circle"></i>
</a>
</h6>
</div>
<div class="card-body">
<div class="row align-items-start">
<div class="col-md-3">
<div class="mb-3">
@@ -469,7 +481,7 @@
<input type="number" step="1" class="form-control facility-overhead-input" id="monthlyBillableHours" name="MonthlyBillableHours" value="@(Model.OperatingCosts?.MonthlyBillableHours ?? 160)" min="1" max="10000">
<span class="input-group-text">hrs</span>
</div>
<small class="text-muted">Typical: 160 hrs (4 wks × 40 hrs)</small>
<small class="text-muted">Typical: 160 hrs (4 wks &times; 40 hrs)</small>
</div>
</div>
<div class="col-md-3">
@@ -484,16 +496,21 @@
</div>
</div>
</div>
</div>
</div>
<!-- Equipment Operating Costs -->
<h6 class="border-bottom pb-2 mb-3 mt-3">Equipment Operating Costs
<div class="card mt-3 border-0 shadow-sm">
<div class="card-header bg-transparent fw-semibold">
<i class="bi bi-tools text-primary me-1"></i> Equipment Operating Costs
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-title="Equipment Operating Costs"
data-bs-content="The hourly cost of running each piece of equipment, including energy and depreciation. These are added to quote items based on the prep services selected. The &lt;strong&gt;Default Oven Rate&lt;/strong&gt; is used on quotes where no named oven is chosen — add individual shop ovens below if you have multiple ovens with different capacities and costs.">
<i class="bi bi-question-circle"></i>
</a>
</h6>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<div class="mb-3">
@@ -527,16 +544,21 @@
</div>
</div>
</div>
</div>
</div>
<!-- Pricing & Overhead -->
<h6 class="border-bottom pb-2 mb-3 mt-4">Pricing &amp; Profit
<!-- Pricing & Profit -->
<div class="card mt-3 border-0 shadow-sm">
<div class="card-header bg-transparent fw-semibold">
<i class="bi bi-graph-up-arrow text-primary me-1"></i> Pricing &amp; Profit
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-title="Pricing &amp; Profit"
data-bs-content="&lt;strong&gt;Markup mode&lt;/strong&gt; adds a % on top of material costs only (labor and equipment pass through at cost). &lt;strong&gt;Margin mode&lt;/strong&gt; targets a gross margin % of the total selling price — e.g. 30% margin on a $100 cost base gives a $142.86 price. Note: margin % and markup % are not the same number. &lt;strong&gt;Shop Minimum&lt;/strong&gt; sets a floor price for any job.">
<i class="bi bi-question-circle"></i>
</a>
</h6>
</div>
<div class="card-body">
@{
var currentPricingMode = (int)(Model.OperatingCosts?.PricingMode ?? PowderCoating.Core.Enums.PricingMode.MarkupOnMaterial);
}
@@ -547,14 +569,14 @@
<input class="form-check-input" type="radio" name="pricingModeRadio" id="pricingModeMarkup" value="0"
@(currentPricingMode == 0 ? "checked" : "") onchange="onPricingModeChange()">
<label class="form-check-label" for="pricingModeMarkup">
<strong>Markup</strong> add % to material costs
<strong>Markup</strong> &mdash; add % to material costs
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="pricingModeRadio" id="pricingModeMargin" value="1"
@(currentPricingMode == 1 ? "checked" : "") onchange="onPricingModeChange()">
<label class="form-check-label" for="pricingModeMargin">
<strong>Margin</strong> target gross margin % of selling price
<strong>Margin</strong> &mdash; target gross margin % of selling price
</label>
</div>
</div>
@@ -592,16 +614,21 @@
</div>
</div>
</div>
</div>
</div>
<!-- Rush Charges -->
<h6 class="border-bottom pb-2 mb-3 mt-3">Rush Charges
<div class="card mt-3 border-0 shadow-sm">
<div class="card-header bg-transparent fw-semibold">
<i class="bi bi-lightning-charge text-primary me-1"></i> Rush Charges
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-title="Rush Charges"
data-bs-content="When a quote is marked as a &lt;strong&gt;Rush Job&lt;/strong&gt;, this charge is automatically added to the total. Choose &lt;strong&gt;Percentage&lt;/strong&gt; to add a % of the subtotal (e.g. 25% rush surcharge) or &lt;strong&gt;Fixed Amount&lt;/strong&gt; to add a flat fee (e.g. $75 rush fee). The rush charge appears as its own line on the quote.">
<i class="bi bi-question-circle"></i>
</a>
</h6>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
@@ -611,7 +638,6 @@
<label class="btn btn-outline-primary" for="rushChargeTypePercentage">
<i class="bi bi-percent"></i> Percentage
</label>
<input type="radio" class="btn-check" name="rushChargeTypeRadio" id="rushChargeTypeFixed" value="FixedAmount" checked="@((Model.OperatingCosts?.RushChargeType) == "FixedAmount")">
<label class="btn btn-outline-primary" for="rushChargeTypeFixed">
<i class="bi bi-currency-dollar"></i> Fixed Amount
@@ -630,7 +656,6 @@
<small class="text-muted">Percentage of subtotal added for rush jobs</small>
</div>
</div>
<div id="rushChargeFixedInput" style="display: @((Model.OperatingCosts?.RushChargeType) == "FixedAmount" ? "block" : "none")">
<div class="mb-3">
<label for="rushChargeFixedAmount" class="form-label">Rush Charge Amount</label>
@@ -643,9 +668,11 @@
</div>
</div>
</div>
</div>
</div>
<!-- Part Complexity Multipliers -->
<div class="card mb-4 border-0 shadow-sm">
<div class="card mt-3 border-0 shadow-sm">
<div class="card-header bg-transparent fw-semibold">
<i class="bi bi-layers text-primary me-1"></i> Part Complexity Multipliers
<a tabindex="0" class="help-icon" role="button"
@@ -694,15 +721,14 @@
</div>
</div>
<div class="d-flex justify-content-end mt-4">
<div class="d-flex justify-content-end mt-4 mb-2">
<button type="submit" class="btn btn-primary" id="btnSaveOperatingCosts">
<i class="bi bi-save"></i> Save Operating Costs
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Oven Cost Add/Edit Modal (outside all forms to avoid form interaction issues) -->
<div class="modal fade" id="ovenModal" tabindex="-1" aria-labelledby="ovenModalTitle" aria-hidden="true">
<div class="modal-dialog">