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>
This commit is contained in:
2026-05-14 20:09:22 -04:00
parent 3eda91f170
commit 4ec55e7290
240 changed files with 73116 additions and 0 deletions
@@ -0,0 +1,74 @@
@model PowderCoating.Application.DTOs.Powder.JobPowderSummaryDto
@if (!Model.Coats.Any())
{
<p class="text-muted small">No coats with powder estimates on this job.</p>
}
else
{
<div class="table-responsive">
<table class="table table-sm mb-0">
<thead>
<tr class="table-light">
<th>Item / Coat</th>
<th class="text-end">Est.</th>
<th class="text-end">Actual</th>
<th class="text-end">Var.</th>
</tr>
</thead>
<tbody>
@foreach (var coat in Model.Coats)
{
<tr>
<td class="small">
<span class="text-muted">@coat.ItemDescription</span>
<br />@coat.CoatName
@if (!string.IsNullOrEmpty(coat.ColorName))
{
<span class="text-muted"> · @coat.ColorName</span>
}
</td>
<td class="text-end small">@(coat.EstimatedLbs.HasValue ? $"{coat.EstimatedLbs:0.##}" : "—")</td>
<td class="text-end small">
@if (coat.IsRecorded)
{
<span class="text-success fw-semibold">@coat.ActualLbs!.Value.ToString("0.##")</span>
}
else
{
<span class="text-muted fst-italic">pending</span>
}
</td>
<td class="text-end small">
@if (coat.VarianceLbs.HasValue)
{
var cls = coat.VarianceLbs > 0 ? "text-danger" : "text-success";
var sign = coat.VarianceLbs > 0 ? "+" : "";
<span class="@cls">@sign@coat.VarianceLbs.Value.ToString("0.##")</span>
}
else
{
<span class="text-muted">—</span>
}
</td>
</tr>
}
</tbody>
@if (Model.Coats.Count > 1)
{
<tfoot>
<tr class="fw-semibold table-light">
<td>Total</td>
<td class="text-end">@Model.TotalEstimatedLbs.ToString("0.##") lbs</td>
<td class="text-end @(Model.TotalActualLbs > 0 ? "text-success" : "")">
@(Model.TotalActualLbs > 0 ? $"{Model.TotalActualLbs:0.##} lbs" : "—")
</td>
<td class="text-end @(Model.TotalVarianceLbs > 0 ? "text-danger" : Model.TotalVarianceLbs < 0 ? "text-success" : "")">
@(Model.TotalActualLbs > 0 ? $"{(Model.TotalVarianceLbs > 0 ? "+" : "")}{Model.TotalVarianceLbs:0.##} lbs" : "—")
</td>
</tr>
</tfoot>
}
</table>
</div>
}