Sweep all .cshtml files for encoding corruption; add pre-commit guard

Replace all corruption variants with HTML entities across 226 view files:
- 3-char UTF-8-as-Win1252 sequences (ae-corruption)
- Standalone smart/curly quotes that break C# Razor expressions
- Partially re-corrupted variants where the 3rd byte was normalised to ASCII

tools/Fix-Encoding.ps1: re-runnable sweep; uses [char] code points so the
script itself never contains a literal non-ASCII character; supports -DryRun

.githooks/pre-commit: blocks commits containing the ae-corruption byte
signature (xc3xa2xe2x82xac); git core.hooksPath = .githooks so the
hook is repo-committed and active for all future work on this machine.

Build clean; 225 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 21:37:10 -04:00
parent 21b39161a3
commit a0bdd2b5b4
252 changed files with 1785 additions and 1633 deletions
@@ -1,4 +1,4 @@
@using PowderCoating.Application.DTOs.PurchaseOrder
@using PowderCoating.Application.DTOs.PurchaseOrder
@model CreatePurchaseOrderDto
@{
@@ -25,7 +25,7 @@
<h4 class="mb-0">
@if (fromLowStock)
{
<span><i class="bi bi-lightning-charge text-warning me-1"></i> New PO — From Low Stock</span>
<span><i class="bi bi-lightning-charge text-warning me-1"></i> New PO &mdash; From Low Stock</span>
}
else
{
@@ -35,7 +35,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="New Purchase Order"
data-bs-content="POs are saved as Draft and can be edited before submitting. Add line items from your inventory catalog or enter a custom description for items not in the system. Once submitted you can receive goods against the PO — receiving automatically updates inventory quantities. After receiving, use Create Bill to convert the PO into a payable bill.">
data-bs-content="POs are saved as Draft and can be edited before submitting. Add line items from your inventory catalog or enter a custom description for items not in the system. Once submitted you can receive goods against the PO &mdash; receiving automatically updates inventory quantities. After receiving, use Create Bill to convert the PO into a payable bill.">
<i class="bi bi-question-circle"></i>
</a>
</div>
@@ -70,7 +70,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="Order Details"
data-bs-content="Select the vendor you're ordering from. Order Date defaults to today — adjust if you're entering a past order. Expected Delivery is used to flag the PO as Overdue on the list view if goods haven't arrived by that date.">
data-bs-content="Select the vendor you're ordering from. Order Date defaults to today &mdash; adjust if you're entering a past order. Expected Delivery is used to flag the PO as Overdue on the list view if goods haven't arrived by that date.">
<i class="bi bi-question-circle"></i>
</a>
</div>
@@ -80,7 +80,7 @@
<label asp-for="VendorId" class="form-label fw-semibold">Vendor <span class="text-danger">*</span></label>
<select asp-for="VendorId" asp-items="@ViewBag.Vendors" class="form-select"
data-quick-add-url="/Vendors/Create" data-quick-add-title="Add New Vendor">
<option value="__new__">+ Add New Vendor…</option>
<option value="__new__">+ Add New Vendor&hellip;</option>
</select>
<span asp-validation-for="VendorId" class="text-danger small"></span>
</div>
@@ -147,12 +147,12 @@
<div class="col-md-6">
<label asp-for="Notes" class="form-label fw-semibold">Notes</label>
<textarea asp-for="Notes" class="form-control" rows="3"
placeholder="Visible on PO…"></textarea>
placeholder="Visible on PO&hellip;"></textarea>
</div>
<div class="col-md-6">
<label asp-for="InternalNotes" class="form-label fw-semibold">Internal Notes</label>
<textarea asp-for="InternalNotes" class="form-control" rows="3"
placeholder="Internal use only…"></textarea>
placeholder="Internal use only&hellip;"></textarea>
</div>
</div>
</div>
@@ -244,7 +244,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="left" data-bs-trigger="focus"
data-bs-title="Dates"
data-bs-content="Order Date is when the PO was placed. Expected Delivery is when goods are due if today's date is past this and the PO hasn't been fully received, the row shows as Overdue. Received date is set automatically when you record receipt of all items.">
data-bs-content="Order Date is when the PO was placed. Expected Delivery is when goods are due &mdash; if today's date is past this and the PO hasn't been fully received, the row shows as Overdue. Received date is set automatically when you record receipt of all items.">
<i class="bi bi-question-circle"></i>
</a>
</div>
@@ -256,7 +256,7 @@
<div class="d-flex justify-content-between mb-2">
<span class="text-muted">Expected Delivery</span>
<span class="@(Model.IsOverdue ? "text-danger fw-semibold" : "")">
@(Model.ExpectedDeliveryDate?.ToString("MM/dd/yyyy") ?? "")
@(Model.ExpectedDeliveryDate?.ToString("MM/dd/yyyy") ?? "&mdash;")
</span>
</div>
@if (Model.ReceivedDate.HasValue)
@@ -1,4 +1,4 @@
@using PowderCoating.Application.DTOs.PurchaseOrder
@using PowderCoating.Application.DTOs.PurchaseOrder
@model UpdatePurchaseOrderDto
@{
@@ -57,7 +57,7 @@
<label asp-for="VendorId" class="form-label fw-semibold">Vendor <span class="text-danger">*</span></label>
<select asp-for="VendorId" asp-items="@ViewBag.Vendors" class="form-select"
data-quick-add-url="/Vendors/Create" data-quick-add-title="Add New Vendor">
<option value="__new__">+ Add New Vendor…</option>
<option value="__new__">+ Add New Vendor&hellip;</option>
</select>
<span asp-validation-for="VendorId" class="text-danger small"></span>
</div>
@@ -114,12 +114,12 @@
<div class="col-md-6">
<label asp-for="Notes" class="form-label fw-semibold">Notes</label>
<textarea asp-for="Notes" class="form-control" rows="3"
placeholder="Visible on PO…"></textarea>
placeholder="Visible on PO&hellip;"></textarea>
</div>
<div class="col-md-6">
<label asp-for="InternalNotes" class="form-label fw-semibold">Internal Notes</label>
<textarea asp-for="InternalNotes" class="form-control" rows="3"
placeholder="Internal use only…"></textarea>
placeholder="Internal use only&hellip;"></textarea>
</div>
</div>
</div>
@@ -125,7 +125,7 @@
<div class="row g-2 align-items-end">
<div class="col-md-3">
<input type="text" name="searchTerm" value="@searchTerm" class="form-control form-control-sm"
placeholder="Search PO#, vendor, notes" />
placeholder="Search PO#, vendor, notes&hellip;" />
</div>
<div class="col-md-2">
<select name="statusFilter" class="form-select form-select-sm">
@@ -174,7 +174,7 @@
<i class="bi bi-cart-check"></i>
</div>
<div class="mobile-card-title">
<h6>@po.PoNumber @(po.IsOverdue ? " Overdue" : "")</h6>
<h6>@po.PoNumber @(po.IsOverdue ? " &mdash; Overdue" : "")</h6>
<small>@po.VendorName</small>
</div>
</div>
@@ -260,7 +260,7 @@
</span>
</td>
<td>@po.OrderDate.ToString("MM/dd/yyyy")</td>
<td>@(po.ExpectedDeliveryDate?.ToString("MM/dd/yyyy") ?? "")</td>
<td>@(po.ExpectedDeliveryDate?.ToString("MM/dd/yyyy") ?? "&mdash;")</td>
<td class="text-center">@po.ItemCount</td>
<td class="text-end fw-semibold">$@po.TotalAmount.ToString("N2")</td>
<td class="text-end">
@@ -1,8 +1,8 @@
@using PowderCoating.Application.DTOs.PurchaseOrder
@using PowderCoating.Application.DTOs.PurchaseOrder
@model ReceivePurchaseOrderDto
@{
ViewData["Title"] = $"Receive Goods — {ViewBag.PoNumber}";
ViewData["Title"] = $"Receive Goods &mdash; {ViewBag.PoNumber}";
int poId = (int)ViewBag.PoId;
}
@@ -17,7 +17,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="Receive Goods"
data-bs-content="Enter the quantity actually received for each line item. Use Receive All to fill in the full remaining quantity for every item. You can receive partial quantities — the PO becomes Partially Received and you can come back to record the rest later. Saving automatically adds the received quantities to inventory on hand and records purchase transactions.">
data-bs-content="Enter the quantity actually received for each line item. Use Receive All to fill in the full remaining quantity for every item. You can receive partial quantities &mdash; the PO becomes Partially Received and you can come back to record the rest later. Saving automatically adds the received quantities to inventory on hand and records purchase transactions.">
<i class="bi bi-question-circle"></i>
</a>
</div>
@@ -40,7 +40,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="Items to Receive"
data-bs-content="Remaining = Ordered minus Previously Received. Enter how many units arrived in this shipment — you can enter less than Remaining for a partial delivery. Rows already fully received are shown in green and cannot be edited. Only inventory catalog items will have their stock quantities updated on save.">
data-bs-content="Remaining = Ordered minus Previously Received. Enter how many units arrived in this shipment &mdash; you can enter less than Remaining for a partial delivery. Rows already fully received are shown in green and cannot be edited. Only inventory catalog items will have their stock quantities updated on save.">
<i class="bi bi-question-circle"></i>
</a>
</div>
@@ -108,7 +108,7 @@
else
{
<input type="hidden" name="Items[@i].QuantityToReceive" value="0" />
<span class="text-muted">—</span>
<span class="text-muted">&mdash;</span>
}
</td>
</tr>
@@ -132,7 +132,7 @@
<div class="mb-3">
<label asp-for="Notes" class="form-label fw-semibold">Notes</label>
<textarea asp-for="Notes" class="form-control" rows="3"
placeholder="Any notes about this receipt…"></textarea>
placeholder="Any notes about this receipt&hellip;"></textarea>
</div>
</div>
</div>
@@ -8,7 +8,7 @@
<a tabindex="0" class="help-icon" role="button"
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
data-bs-title="Create PO From Low Stock"
data-bs-content="These vendors have one or more inventory items that have fallen to or below their Reorder Point. Selecting a vendor pre-populates a new purchase order with all their low-stock items at their standard Reorder Quantity you can adjust quantities before saving. Items without a Primary Vendor assigned will not appear here.">
data-bs-content="These vendors have one or more inventory items that have fallen to or below their Reorder Point. Selecting a vendor pre-populates a new purchase order with all their low-stock items at their standard Reorder Quantity &mdash; you can adjust quantities before saving. Items without a Primary Vendor assigned will not appear here.">
<i class="bi bi-question-circle"></i>
</a>
</div>