Fix — HTML entity rendering across 60 views

Razor's @() expression auto-encodes &, turning — into — which
rendered as literal text in the browser. Wrapped all such expressions in
@Html.Raw() so the em-dash entity is passed through unescaped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 09:27:45 -04:00
parent f018653c18
commit 64a9c1531b
60 changed files with 155 additions and 155 deletions
@@ -156,11 +156,11 @@ else
</a>
<span class="badge bg-secondary ms-1">@vend.Bills.Count bill@(vend.Bills.Count == 1 ? "" : "s")</span>
</td>
<td class="text-end aging-current">@(vend.TotalCurrent > 0 ? vend.TotalCurrent.ToString("C") : "&mdash;")</td>
<td class="text-end aging-1-30">@(vend.Total1to30 > 0 ? vend.Total1to30.ToString("C") : "&mdash;")</td>
<td class="text-end aging-31-60">@(vend.Total31to60 > 0 ? vend.Total31to60.ToString("C") : "&mdash;")</td>
<td class="text-end aging-61-90">@(vend.Total61to90 > 0 ? vend.Total61to90.ToString("C") : "&mdash;")</td>
<td class="text-end aging-over90">@(vend.TotalOver90 > 0 ? vend.TotalOver90.ToString("C") : "&mdash;")</td>
<td class="text-end aging-current">@Html.Raw(vend.TotalCurrent > 0 ? vend.TotalCurrent.ToString("C") : "&mdash;")</td>
<td class="text-end aging-1-30">@Html.Raw(vend.Total1to30 > 0 ? vend.Total1to30.ToString("C") : "&mdash;")</td>
<td class="text-end aging-31-60">@Html.Raw(vend.Total31to60 > 0 ? vend.Total31to60.ToString("C") : "&mdash;")</td>
<td class="text-end aging-61-90">@Html.Raw(vend.Total61to90 > 0 ? vend.Total61to90.ToString("C") : "&mdash;")</td>
<td class="text-end aging-over90">@Html.Raw(vend.TotalOver90 > 0 ? vend.TotalOver90.ToString("C") : "&mdash;")</td>
<td class="text-end fw-semibold">@vend.TotalBalance.ToString("C")</td>
</tr>
}
@@ -218,7 +218,7 @@ else
</a>
</td>
<td class="text-muted small">@bill.BillDate.ToString("MM/dd/yyyy")</td>
<td class="text-muted small">@(bill.DueDate?.ToString("MM/dd/yyyy") ?? "&mdash;")</td>
<td class="text-muted small">@Html.Raw(bill.DueDate?.ToString("MM/dd/yyyy") ?? "&mdash;")</td>
<td class="text-end fw-semibold @(bill.DaysOverdue > 30 ? "text-danger" : "")">@bill.BalanceDue.ToString("C")</td>
<td class="text-end"><span class="badge @ageBadge">@ageLabel</span></td>
<td></td>
@@ -156,11 +156,11 @@ else
</a>
<span class="badge bg-secondary ms-1">@cust.Invoices.Count inv.</span>
</td>
<td class="text-end aging-current">@(cust.TotalCurrent > 0 ? cust.TotalCurrent.ToString("C") : "&mdash;")</td>
<td class="text-end aging-1-30">@(cust.Total1to30 > 0 ? cust.Total1to30.ToString("C") : "&mdash;")</td>
<td class="text-end aging-31-60">@(cust.Total31to60 > 0 ? cust.Total31to60.ToString("C") : "&mdash;")</td>
<td class="text-end aging-61-90">@(cust.Total61to90 > 0 ? cust.Total61to90.ToString("C") : "&mdash;")</td>
<td class="text-end aging-over90">@(cust.TotalOver90 > 0 ? cust.TotalOver90.ToString("C") : "&mdash;")</td>
<td class="text-end aging-current">@Html.Raw(cust.TotalCurrent > 0 ? cust.TotalCurrent.ToString("C") : "&mdash;")</td>
<td class="text-end aging-1-30">@Html.Raw(cust.Total1to30 > 0 ? cust.Total1to30.ToString("C") : "&mdash;")</td>
<td class="text-end aging-31-60">@Html.Raw(cust.Total31to60 > 0 ? cust.Total31to60.ToString("C") : "&mdash;")</td>
<td class="text-end aging-61-90">@Html.Raw(cust.Total61to90 > 0 ? cust.Total61to90.ToString("C") : "&mdash;")</td>
<td class="text-end aging-over90">@Html.Raw(cust.TotalOver90 > 0 ? cust.TotalOver90.ToString("C") : "&mdash;")</td>
<td class="text-end fw-semibold">@cust.TotalBalance.ToString("C")</td>
</tr>
}
@@ -218,7 +218,7 @@ else
</a>
</td>
<td class="text-muted small">@inv.InvoiceDate.ToString("MM/dd/yyyy")</td>
<td class="text-muted small">@(inv.DueDate?.ToString("MM/dd/yyyy") ?? "&mdash;")</td>
<td class="text-muted small">@Html.Raw(inv.DueDate?.ToString("MM/dd/yyyy") ?? "&mdash;")</td>
<td class="text-end fw-semibold @(inv.DaysOverdue > 30 ? "text-danger" : "")">@inv.BalanceDue.ToString("C")</td>
<td class="text-end"><span class="badge @ageBadge">@ageLabel</span></td>
<td></td>
@@ -101,11 +101,11 @@
@item.CustomerName
</a>
</td>
<td class="small">@(item.Email ?? "&mdash;")</td>
<td class="small">@(item.Phone ?? "&mdash;")</td>
<td class="small">@Html.Raw(item.Email ?? "&mdash;")</td>
<td class="small">@Html.Raw(item.Phone ?? "&mdash;")</td>
<td class="text-end">@item.TotalJobs</td>
<td class="text-end">@item.LifetimeRevenue.ToString("C")</td>
<td>@(item.LastJobDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
<td>@Html.Raw(item.LastJobDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
<td class="text-end">
@if (item.DaysSinceLastJob < 0)
{
@@ -1604,7 +1604,7 @@
<div class="fw-medium">@color.DisplayLabel</div>
<div class="text-muted small">@color.SKU</div>
</td>
<td class="text-muted small">@(color.Manufacturer ?? "&mdash;")</td>
<td class="text-muted small">@Html.Raw(color.Manufacturer ?? "&mdash;")</td>
<td class="text-end">
<div>@color.TotalLbsUsed.ToString("N1") lbs</div>
<div class="progress mt-1" style="height:4px; min-width:80px;">
@@ -1749,7 +1749,7 @@
@c.BalanceDue.ToString("C")
</td>
<td class="text-end text-muted">@c.AvgInvoiceValue.ToString("C")</td>
<td class="text-muted small">@(c.LastInvoiceDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
<td class="text-muted small">@Html.Raw(c.LastInvoiceDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
<td class="pe-3">
<div class="d-flex align-items-center gap-2">
<div class="progress flex-grow-1" style="height:6px;">
@@ -1896,10 +1896,10 @@
<span class="badge @badgeClass">@r.RetentionStatus</span>
</td>
<td class="text-center small">
@(r.LastJobDate.HasValue ? r.LastJobDate.Value.ToString("MMM d, yyyy") : "&mdash;")
@Html.Raw(r.LastJobDate.HasValue ? r.LastJobDate.Value.ToString("MMM d, yyyy") : "&mdash;")
</td>
<td class="text-center small">
@(r.DaysSinceLastJob >= 0 ? r.DaysSinceLastJob + "d" : "&mdash;")
@Html.Raw(r.DaysSinceLastJob >= 0 ? r.DaysSinceLastJob + "d" : "&mdash;")
</td>
<td class="text-end">@r.TotalJobs</td>
<td class="text-end pe-3 fw-semibold">@r.LifetimeRevenue.ToString("C0")</td>
@@ -2235,7 +2235,7 @@
}
</td>
<td class="small">@inv.InvoiceDate.ToString("MMM d, yyyy")</td>
<td class="small">@(inv.DueDate.HasValue ? inv.DueDate.Value.ToString("MMM d, yyyy") : "&mdash;")</td>
<td class="small">@Html.Raw(inv.DueDate.HasValue ? inv.DueDate.Value.ToString("MMM d, yyyy") : "&mdash;")</td>
<td class="text-end">@inv.Total.ToString("C")</td>
<td class="text-end text-success">@inv.AmountPaid.ToString("C")</td>
<td class="text-end fw-semibold @(inv.BalanceDue > 0 ? "text-danger" : "")">@inv.BalanceDue.ToString("C")</td>
@@ -2349,7 +2349,7 @@
<div class="small text-muted">@p.ColorCode @(!string.IsNullOrEmpty(p.SKU) ? $"· {p.SKU}" : "")</div>
}
</td>
<td class="small text-muted">@(p.Manufacturer ?? "&mdash;")</td>
<td class="small text-muted">@Html.Raw(p.Manufacturer ?? "&mdash;")</td>
<td class="text-end">@p.TotalPurchasedLbs.ToString("N1")</td>
<td class="text-end">@p.TotalConsumedLbs.ToString("N1")</td>
<td class="text-end">
@@ -52,7 +52,7 @@
<div class="small text-muted">@item.SKU</div>
}
</td>
<td>@(item.ColorName ?? "&mdash;")</td>
<td>@Html.Raw(item.ColorName ?? "&mdash;")</td>
<td class="text-end">@item.CurrentStockLbs.ToString("N1")</td>
<td class="text-end">@item.TotalConsumedLbs.ToString("N1")</td>
<td class="text-end">@item.TotalPurchasedLbs.ToString("N1")</td>
@@ -85,12 +85,12 @@
}
</td>
<td>@item.InvoiceDate.ToString("MMM d, yyyy")</td>
<td>@(item.DueDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
<td>@Html.Raw(item.DueDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
<td class="text-end">@item.Total.ToString("C")</td>
<td class="text-end text-success">@item.AmountPaid.ToString("C")</td>
<td class="text-end fw-semibold">@item.BalanceDue.ToString("C")</td>
<td class="text-end @bucketClass">
@(item.DaysOverdue > 0 ? item.DaysOverdue.ToString() : "&mdash;")
@Html.Raw(item.DaysOverdue > 0 ? item.DaysOverdue.ToString() : "&mdash;")
</td>
<td><span class="badge @bucketClass bg-opacity-10 border">@item.AgingBucket</span></td>
<td><span class="badge bg-secondary-subtle text-secondary">@item.StatusDisplay</span></td>
@@ -116,7 +116,7 @@
{
<tr class="@(i.QuantityOnHand == 0 ? "table-danger" : "table-warning")">
<td>@i.Name</td>
<td>@(i.ColorName ?? "&mdash;")</td>
<td>@Html.Raw(i.ColorName ?? "&mdash;")</td>
<td class="text-end fw-semibold text-danger">@i.QuantityOnHand.ToString("N1")</td>
<td class="text-end">@i.ReorderPoint.ToString("N1")</td>
<td class="text-muted small">@i.UnitOfMeasure</td>
@@ -60,13 +60,13 @@
}
</td>
<td>
@(item.ColorName ?? "&mdash;")
@Html.Raw(item.ColorName ?? "&mdash;")
@if (!string.IsNullOrEmpty(item.ColorCode))
{
<span class="badge bg-secondary-subtle text-secondary ms-1">@item.ColorCode</span>
}
</td>
<td class="text-muted">@(item.Manufacturer ?? "&mdash;")</td>
<td class="text-muted">@Html.Raw(item.Manufacturer ?? "&mdash;")</td>
<td class="text-end">@item.TotalPurchasedLbs.ToString("N1")</td>
<td class="text-end">@item.TotalConsumedLbs.ToString("N1")</td>
<td class="text-end fw-semibold @varianceClass">@item.VarianceLbs.ToString("N1")</td>
@@ -79,8 +79,8 @@
<td>
@item.DisplayLabel
</td>
<td class="text-muted small">@(item.SKU ?? "&mdash;")</td>
<td class="text-muted small">@(item.Manufacturer ?? "&mdash;")</td>
<td class="text-muted small">@Html.Raw(item.SKU ?? "&mdash;")</td>
<td class="text-muted small">@Html.Raw(item.Manufacturer ?? "&mdash;")</td>
<td class="text-end fw-semibold">@item.TotalLbsUsed.ToString("N1")</td>
<td class="text-end">@item.TotalCost.ToString("C")</td>
<td class="text-end">@item.JobCount</td>
@@ -148,7 +148,7 @@
<tr>
<td class="ps-4">@line.AccountNumber <span class="text-muted">@line.AccountName</span></td>
<td class="text-end">@line.Amount.ToString("C")</td>
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "&mdash;" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
<td class="text-end text-muted small">@Html.Raw(Model.TotalRevenue == 0 ? "&mdash;" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
</tr>
}
<tr class="report-subtotal-row">
@@ -169,18 +169,18 @@
<tr>
<td class="ps-4">@line.AccountNumber <span class="text-muted">@line.AccountName</span></td>
<td class="text-end">@line.Amount.ToString("C")</td>
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "&mdash;" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
<td class="text-end text-muted small">@Html.Raw(Model.TotalRevenue == 0 ? "&mdash;" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
</tr>
}
<tr class="report-subtotal-row">
<td class="ps-4 fw-semibold">Total COGS</td>
<td class="text-end fw-semibold text-warning">(@Model.TotalCogs.ToString("C"))</td>
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "&mdash;" : (Model.TotalCogs / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
<td class="text-end text-muted small">@Html.Raw(Model.TotalRevenue == 0 ? "&mdash;" : (Model.TotalCogs / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
</tr>
<tr class="report-subtotal-row">
<td class="ps-2 fw-semibold">Gross Profit</td>
<td class="text-end fw-semibold @(Model.GrossProfit >= 0 ? "text-success" : "text-danger")">@Model.GrossProfit.ToString("C")</td>
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "&mdash;" : Model.GrossMarginPercent.ToString("F1") + "%")</td>
<td class="text-end text-muted small">@Html.Raw(Model.TotalRevenue == 0 ? "&mdash;" : Model.GrossMarginPercent.ToString("F1") + "%")</td>
</tr>
}
@@ -198,20 +198,20 @@
<tr>
<td class="ps-4">@line.AccountNumber <span class="text-muted">@line.AccountName</span></td>
<td class="text-end">@line.Amount.ToString("C")</td>
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "&mdash;" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
<td class="text-end text-muted small">@Html.Raw(Model.TotalRevenue == 0 ? "&mdash;" : (line.Amount / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
</tr>
}
<tr class="report-subtotal-row">
<td class="ps-4 fw-semibold">Total Expenses</td>
<td class="text-end fw-semibold text-danger">(@Model.TotalExpenses.ToString("C"))</td>
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "&mdash;" : (Model.TotalExpenses / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
<td class="text-end text-muted small">@Html.Raw(Model.TotalRevenue == 0 ? "&mdash;" : (Model.TotalExpenses / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
</tr>
</tbody>
<tfoot>
<tr class="report-net-row @(Model.NetIncome < 0 ? "report-net-negative" : "")">
<td class="ps-2">Net Income</td>
<td class="text-end @(Model.NetIncome >= 0 ? "text-success" : "text-danger")">@Model.NetIncome.ToString("C")</td>
<td class="text-end text-muted small">@(Model.TotalRevenue == 0 ? "&mdash;" : (Model.NetIncome / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
<td class="text-end text-muted small">@Html.Raw(Model.TotalRevenue == 0 ? "&mdash;" : (Model.NetIncome / Model.TotalRevenue * 100).ToString("F1") + "%")</td>
</tr>
</tfoot>
</table>
@@ -205,7 +205,7 @@ else
<td class="text-end fw-semibold">@c.TotalInvoiced.ToString("C")</td>
<td class="text-end text-success">@c.TotalPaid.ToString("C")</td>
<td class="text-end @(c.BalanceDue > 0 ? "text-warning" : "text-muted")">@c.BalanceDue.ToString("C")</td>
<td class="text-end text-muted small no-print">@(Model.TotalInvoiced == 0 ? "&mdash;" : (c.TotalInvoiced / Model.TotalInvoiced * 100).ToString("F1") + "%")</td>
<td class="text-end text-muted small no-print">@Html.Raw(Model.TotalInvoiced == 0 ? "&mdash;" : (c.TotalInvoiced / Model.TotalInvoiced * 100).ToString("F1") + "%")</td>
</tr>
}
</tbody>
@@ -263,9 +263,9 @@ else
</td>
<td class="text-muted small">@inv.CustomerName</td>
<td class="text-muted small">@inv.InvoiceDate.ToString("MM/dd/yyyy")</td>
<td class="text-muted small">@(inv.DueDate?.ToString("MM/dd/yyyy") ?? "&mdash;")</td>
<td class="text-muted small">@Html.Raw(inv.DueDate?.ToString("MM/dd/yyyy") ?? "&mdash;")</td>
<td class="text-end">@inv.SubTotal.ToString("C")</td>
<td class="text-end text-muted small">@(inv.TaxAmount > 0 ? inv.TaxAmount.ToString("C") : "&mdash;")</td>
<td class="text-end text-muted small">@Html.Raw(inv.TaxAmount > 0 ? inv.TaxAmount.ToString("C") : "&mdash;")</td>
<td class="text-end fw-semibold">@inv.Total.ToString("C")</td>
<td class="text-end text-success">@inv.AmountPaid.ToString("C")</td>
<td><span class="badge @statusBadge">@inv.Status</span></td>
@@ -76,7 +76,7 @@
@item.BalanceDue.ToString("C")
</td>
<td class="text-end">@item.AvgInvoiceValue.ToString("C")</td>
<td>@(item.LastInvoiceDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
<td>@Html.Raw(item.LastInvoiceDate?.ToString("MMM d, yyyy") ?? "&mdash;")</td>
</tr>
}
</tbody>
@@ -284,11 +284,11 @@ else
<td class="small text-muted">@inv.InvoiceDate.ToString("MM/dd/yyyy")</td>
<td><span class="badge @statusBadge">@inv.Status</span></td>
<td class="text-end">@inv.SubTotal.ToString("C")</td>
<td class="text-end text-muted small">@(isTaxable ? inv.TaxPercent.ToString("F2") + "%" : "&mdash;")</td>
<td class="text-end @(isTaxable ? "fw-semibold text-primary" : "text-muted")">@(isTaxable ? inv.TaxAmount.ToString("C") : "&mdash;")</td>
<td class="text-end text-muted small">@Html.Raw(isTaxable ? inv.TaxPercent.ToString("F2") + "%" : "&mdash;")</td>
<td class="text-end @Html.Raw(isTaxable ? "fw-semibold text-primary" : "text-muted")">@Html.Raw(isTaxable ? inv.TaxAmount.ToString("C") : "&mdash;")</td>
<td class="text-end fw-semibold">@inv.Total.ToString("C")</td>
<td class="text-end text-success no-print">@inv.AmountPaid.ToString("C")</td>
<td class="small text-muted">@(string.IsNullOrEmpty(inv.TaxAccountName) ? "&mdash;" : inv.TaxAccountName)</td>
<td class="small text-muted">@Html.Raw(string.IsNullOrEmpty(inv.TaxAccountName) ? "&mdash;" : inv.TaxAccountName)</td>
</tr>
}
</tbody>
@@ -117,7 +117,7 @@ else
<span class="text-danger small"><i class="bi bi-exclamation-triangle me-1"></i>Missing</span>
}
</td>
<td class="small">@(row.Address ?? "&mdash;")</td>
<td class="small">@Html.Raw(row.Address ?? "&mdash;")</td>
<td class="text-end">@row.BillsPaid.ToString("C")</td>
<td class="text-end">@row.ExpensesPaid.ToString("C")</td>
<td class="text-end fw-bold @(row.NeedsForm ? "text-danger" : "")">@row.TotalPaid.ToString("C")</td>