Files
PowderCoatingLogix/src/PowderCoating.Web/Views/Quotes/_CoatAccordionPartial.cshtml
T
spouliot 4ec55e7290 Restore all zeroed views + add bulk gift certificate creation
The HTML entity sweep script had a bug where it wrote empty files for any
view that contained no target Unicode characters, zeroing out 215 view files.
All views restored from the pre-sweep commit (cefdf3e).

Bulk gift certificate feature:
- BulkCreateGiftCertificateDto with Quantity (1-500), Amount, Reason, Expiry, Notes
- GenerateBulkGiftCertificatePdfAsync on IPdfService / PdfService: one Letter page
  per cert, reusing the same purple/gold branded ComposeGiftCertificateContent helper
- GiftCertificatesController: BulkCreate GET/POST, BulkResult GET, BulkDownloadPdf POST
- Views: BulkCreate.cshtml (form with live total preview), BulkResult.cshtml (table +
  Download All PDF button that POSTs cert IDs to avoid URL length limits)
- gift-certificate-bulk.js: live preview + spinner/disable on submit
- Index.cshtml: Bulk Create button added alongside New Certificate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 20:09:22 -04:00

263 lines
17 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@model (int ItemIndex, List<PowderCoating.Application.DTOs.Quote.CreateQuoteItemCoatDto> Coats)
@{
var itemIndex = Model.ItemIndex;
var coats = Model.Coats ?? new List<PowderCoating.Application.DTOs.Quote.CreateQuoteItemCoatDto>();
// Debug: Log coat count
var coatCountForDebug = coats.Count;
// If no coats exist, initialize with one default Single Stage coat
if (!coats.Any())
{
coats.Add(new PowderCoating.Application.DTOs.Quote.CreateQuoteItemCoatDto
{
CoatName = "Single Stage",
Sequence = 1,
CoverageSqFtPerLb = 30,
TransferEfficiency = 65
});
}
}
<!-- DEBUG: Item @itemIndex has @coats.Count coat(s) (original count: @coatCountForDebug) -->
<div class="row g-3 mb-3">
<div class="col-12">
<label class="form-label fw-semibold d-block mb-2">
<i class="bi bi-paint-bucket me-1"></i>Coating Layers
</label>
<div class="accordion" id="coatsAccordion_@itemIndex">
@for (int coatIndex = 0; coatIndex < coats.Count; coatIndex++)
{
var coat = coats[coatIndex];
var isExpanded = coatIndex == 0; // First coat expanded by default
<div class="accordion-item coat-accordion-item" data-coat-index="@coatIndex">
<h2 class="accordion-header" id="coatHeading_@(itemIndex)_@(coatIndex)">
<div class="d-flex align-items-center">
<button class="accordion-button @(isExpanded ? "" : "collapsed") flex-grow-1" type="button"
data-bs-toggle="collapse" data-bs-target="#coat_@(itemIndex)_@(coatIndex)"
aria-expanded="@(isExpanded ? "true" : "false")" aria-controls="coat_@(itemIndex)_@(coatIndex)">
<span class="coat-header-text">@(coat.CoatName ?? $"Coating Layer {coatIndex + 1}")</span>
</button>
@if (coats.Count > 1)
{
<button type="button" class="btn btn-sm btn-outline-danger ms-2 me-2"
onclick="removeCoat(@itemIndex, @coatIndex); event.stopPropagation();"
title="Remove this coating layer">
<i class="bi bi-trash"></i>
</button>
}
</div>
</h2>
<div id="coat_@(itemIndex)_@(coatIndex)" class="accordion-collapse collapse @(isExpanded ? "show" : "")"
aria-labelledby="coatHeading_@(itemIndex)_@(coatIndex)"
data-bs-parent="#coatsAccordion_@itemIndex">
<div class="accordion-body">
<input type="hidden" name="QuoteItems[@itemIndex].Coats[@coatIndex].Sequence" value="@coat.Sequence" />
<div class="row g-3 mb-3">
<div class="col-md-12">
<label class="form-label fw-semibold">Coat Type <span class="text-danger">*</span></label>
<select name="QuoteItems[@itemIndex].Coats[@coatIndex].CoatName"
class="form-select coat-name-input"
onchange="updateCoatHeader(@itemIndex, @coatIndex)"
required>
<option value="Primer" selected="@(coat.CoatName == "Primer")">Primer</option>
<option value="Single Stage" selected="@(coat.CoatName == "Single Stage")">Single Stage</option>
<option value="Base Coat" selected="@(coat.CoatName == "Base Coat")">Base Coat</option>
<option value="Top Coat" selected="@(coat.CoatName == "Top Coat")">Top Coat</option>
<option value="Additional Stage" selected="@(coat.CoatName == "Additional Stage")">Additional Stage</option>
</select>
</div>
</div>
<!-- Radio: Stock vs Custom -->
@{
var hasInventoryItem = coat.InventoryItemId.HasValue && coat.InventoryItemId.Value > 0;
var isCustom = !string.IsNullOrEmpty(coat.ColorName) || coat.PowderCostPerLb.HasValue;
var coatType = hasInventoryItem ? "stock" : (isCustom ? "custom" : "stock");
}
<div class="btn-group mb-3 w-100" role="group">
<input type="radio" class="btn-check"
name="coatPowderType_@(itemIndex)_@(coatIndex)"
id="coatStock_@(itemIndex)_@(coatIndex)" value="stock"
@(coatType == "stock" ? "checked" : "")
onchange="toggleCoatPowderSelection(@itemIndex, @coatIndex, 'stock')">
<label class="btn btn-outline-primary" for="coatStock_@(itemIndex)_@(coatIndex)">
<i class="bi bi-box-seam me-1"></i>In-Stock Powder
</label>
<input type="radio" class="btn-check"
name="coatPowderType_@(itemIndex)_@(coatIndex)"
id="coatCustom_@(itemIndex)_@(coatIndex)" value="custom"
@(coatType == "custom" ? "checked" : "")
onchange="toggleCoatPowderSelection(@itemIndex, @coatIndex, 'custom')">
<label class="btn btn-outline-primary" for="coatCustom_@(itemIndex)_@(coatIndex)">
<i class="bi bi-bag-plus me-1"></i>Custom Powder
</label>
</div>
<!-- Stock Powder Section -->
<div id="coatStockSection_@(itemIndex)_@(coatIndex)" style="display: @(coatType == "stock" ? "block" : "none")">
<div class="row g-3 mb-3">
<div class="col-md-12">
<label class="form-label">Select Powder from Inventory</label>
<select name="QuoteItems[@itemIndex].Coats[@coatIndex].InventoryItemId"
id="coatInventorySelect_@(itemIndex)_@(coatIndex)"
class="form-select inventory-coat-select"
data-selected-value="@(coat.InventoryItemId ?? 0)"
onchange="onCoatInventorySelected(@itemIndex, @coatIndex)">
<option value="">-- Select Powder --</option>
</select>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label">Coverage Rate</label>
<div class="input-group input-group-sm">
<input type="number"
name="QuoteItems[@itemIndex].Coats[@coatIndex].CoverageSqFtPerLb"
id="coatCoverage_@(itemIndex)_@(coatIndex)"
class="form-control" value="@coat.CoverageSqFtPerLb"
min="1" max="500" step="0.1"
onchange="calculateCoatPowderNeeded(@itemIndex, @coatIndex)">
<span class="input-group-text">sq ft/lb</span>
</div>
</div>
<div class="col-md-6">
<label class="form-label">Transfer Efficiency</label>
<div class="input-group input-group-sm">
<input type="number"
name="QuoteItems[@itemIndex].Coats[@coatIndex].TransferEfficiency"
id="coatEfficiency_@(itemIndex)_@(coatIndex)"
class="form-control" value="@coat.TransferEfficiency"
min="1" max="100" step="1"
onchange="calculateCoatPowderNeeded(@itemIndex, @coatIndex)">
<span class="input-group-text">%</span>
</div>
</div>
</div>
</div>
<!-- Custom Powder Section -->
<div id="coatCustomSection_@(itemIndex)_@(coatIndex)" style="display: @(coatType == "custom" ? "block" : "none")">
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label">Color Name</label>
<input type="text"
name="QuoteItems[@itemIndex].Coats[@coatIndex].ColorName"
id="coatColorName_@(itemIndex)_@(coatIndex)"
value="@coat.ColorName"
class="form-control"
placeholder="e.g., Gloss Black RAL 9005"
onchange="updateCoatHeader(@itemIndex, @coatIndex)" />
</div>
<div class="col-md-6">
<label class="form-label">Vendor</label>
<select name="QuoteItems[@itemIndex].Coats[@coatIndex].VendorId"
id="coatVendorSelect_@(itemIndex)_@(coatIndex)"
class="form-select coat-vendor-select"
data-selected-value="@(coat.VendorId ?? 0)">
<option value="">-- Select Vendor --</option>
</select>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label">Powder to Order</label>
<div class="input-group input-group-sm">
<input type="number"
name="QuoteItems[@itemIndex].Coats[@coatIndex].PowderToOrder"
id="coatPowderToOrder_@(itemIndex)_@(coatIndex)"
value="@coat.PowderToOrder"
class="form-control" min="0" step="1"
placeholder="Auto-calculated" />
<span class="input-group-text">lbs</span>
</div>
<small class="text-muted">Auto-filled from powder needed (rounded up)</small>
</div>
<div class="col-md-6">
<label class="form-label">Powder Cost</label>
<div class="input-group input-group-sm">
<span class="input-group-text">$</span>
<input type="number"
name="QuoteItems[@itemIndex].Coats[@coatIndex].PowderCostPerLb"
value="@coat.PowderCostPerLb"
class="form-control" min="0" step="0.01"
placeholder="0.00" />
<span class="input-group-text">per lb</span>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-4">
<label class="form-label">Coverage Rate</label>
<div class="input-group input-group-sm">
<input type="number"
name="QuoteItems[@itemIndex].Coats[@coatIndex].CoverageSqFtPerLb"
id="coatCustomCoverage_@(itemIndex)_@(coatIndex)"
class="form-control" value="@coat.CoverageSqFtPerLb"
min="1" max="500" step="0.1"
onchange="calculateCoatPowderNeeded(@itemIndex, @coatIndex)">
<span class="input-group-text">sq ft/lb</span>
</div>
</div>
<div class="col-md-4">
<label class="form-label">Transfer Efficiency</label>
<div class="input-group input-group-sm">
<input type="number"
name="QuoteItems[@itemIndex].Coats[@coatIndex].TransferEfficiency"
id="coatCustomEfficiency_@(itemIndex)_@(coatIndex)"
class="form-control" value="@coat.TransferEfficiency"
min="1" max="100" step="1"
onchange="calculateCoatPowderNeeded(@itemIndex, @coatIndex)">
<span class="input-group-text">%</span>
</div>
</div>
</div>
</div>
<!-- Powder Needed Display (shown for calculated items only) -->
<div class="row g-3 mb-3">
<div class="col-md-12 coat-powder-needed-display" id="coatPowderNeededContainer_@(itemIndex)_@(coatIndex)">
<label class="form-label fw-semibold">Powder Needed for This Coat (Total Batch)</label>
<div class="bg-success bg-opacity-10 border border-success rounded p-3 text-center">
<strong id="coatPowderNeeded_@(itemIndex)_@(coatIndex)" class="fs-5 text-success">0.00 lbs</strong>
</div>
<small class="text-muted">
<i class="bi bi-info-circle"></i> This calculation is for the entire batch (all items × surface area)
</small>
</div>
</div>
<!-- Coat Notes -->
<div class="row g-3">
<div class="col-md-12">
<label class="form-label">Notes (Optional)</label>
<textarea name="QuoteItems[@itemIndex].Coats[@coatIndex].Notes"
class="form-control" rows="2"
placeholder="Special instructions for this coating layer...">@coat.Notes</textarea>
</div>
</div>
</div>
</div>
</div>
}
</div>
<!-- Add Coating Layer Button -->
<div class="mt-3">
<button type="button" class="btn btn-sm btn-outline-success"
onclick="addCoat(@itemIndex)">
<i class="bi bi-plus-circle me-1"></i> Add Coating Layer
</button>
<small class="text-muted ms-2">
<i class="bi bi-info-circle"></i>
First coat = 100% labor, each additional = +30% labor
</small>
</div>
</div>
</div>