Fix encoding corruption in Bills and Expenses views
Replace literal Unicode chars (em dash, ellipsis, angle quotes, box-drawing) with HTML entities to prevent corruption from AI tools and Windows encoding. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -62,7 +62,7 @@
|
|||||||
<form method="get" class="row g-2 align-items-end">
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<input type="search" name="search" value="@ViewBag.Search" class="form-control"
|
<input type="search" name="search" value="@ViewBag.Search" class="form-control"
|
||||||
placeholder="Search by #, vendor, memo, amount…" />
|
placeholder="Search by #, vendor, memo, amount…" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<select name="type" class="form-select">
|
<select name="type" class="form-select">
|
||||||
@@ -156,13 +156,13 @@
|
|||||||
}
|
}
|
||||||
else if (entry.EntryType == "Expense")
|
else if (entry.EntryType == "Expense")
|
||||||
{
|
{
|
||||||
<span class="text-muted">—</span>
|
<span class=”text-muted”>—</span>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td><span class="badge bg-@entry.StatusColor">@entry.StatusLabel</span></td>
|
<td><span class="badge bg-@entry.StatusColor">@entry.StatusLabel</span></td>
|
||||||
<td class="text-end">@entry.Total.ToString("C")</td>
|
<td class="text-end">@entry.Total.ToString("C")</td>
|
||||||
<td class="text-end fw-medium @(entry.BalanceDue > 0 ? "text-danger" : "text-muted")">
|
<td class="text-end fw-medium @(entry.BalanceDue > 0 ? "text-danger" : "text-muted")">
|
||||||
@(entry.EntryType == "Bill" ? entry.BalanceDue.ToString("C") : "—")
|
@(entry.EntryType == “Bill” ? entry.BalanceDue.ToString(“C”) : “—”)
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if (entry.EntryType == "Bill")
|
@if (entry.EntryType == "Bill")
|
||||||
@@ -209,7 +209,7 @@ else
|
|||||||
asp-route-status="@ViewBag.StatusFilter"
|
asp-route-status="@ViewBag.StatusFilter"
|
||||||
asp-route-search="@ViewBag.Search"
|
asp-route-search="@ViewBag.Search"
|
||||||
asp-route-page="@((int)ViewBag.Page - 1)"
|
asp-route-page="@((int)ViewBag.Page - 1)"
|
||||||
asp-route-pageSize="@ViewBag.PageSize">‹ Prev</a>
|
asp-route-pageSize="@ViewBag.PageSize">‹ Prev</a>
|
||||||
</li>
|
</li>
|
||||||
@for (var p = 1; p <= (int)ViewBag.TotalPages; p++)
|
@for (var p = 1; p <= (int)ViewBag.TotalPages; p++)
|
||||||
{
|
{
|
||||||
@@ -228,11 +228,11 @@ else
|
|||||||
asp-route-status="@ViewBag.StatusFilter"
|
asp-route-status="@ViewBag.StatusFilter"
|
||||||
asp-route-search="@ViewBag.Search"
|
asp-route-search="@ViewBag.Search"
|
||||||
asp-route-page="@((int)ViewBag.Page + 1)"
|
asp-route-page="@((int)ViewBag.Page + 1)"
|
||||||
asp-route-pageSize="@ViewBag.PageSize">Next ›</a>
|
asp-route-pageSize="@ViewBag.PageSize">Next ›</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="text-center text-muted small">
|
<p class="text-center text-muted small">
|
||||||
Showing @(((int)ViewBag.Page - 1) * (int)ViewBag.PageSize + 1)–@(Math.Min((int)ViewBag.Page * (int)ViewBag.PageSize, (int)ViewBag.TotalCount))
|
Showing @(((int)ViewBag.Page - 1) * (int)ViewBag.PageSize + 1)–@(Math.Min((int)ViewBag.Page * (int)ViewBag.PageSize, (int)ViewBag.TotalCount))
|
||||||
of @ViewBag.TotalCount entries
|
of @ViewBag.TotalCount entries
|
||||||
</p>
|
</p>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
ViewData["Title"] = "New Expense";
|
ViewData["Title"] = "New Expense";
|
||||||
ViewData["PageIcon"] = "bi-receipt";
|
ViewData["PageIcon"] = "bi-receipt";
|
||||||
ViewData["PageHelpTitle"] = "New Expense";
|
ViewData["PageHelpTitle"] = "New Expense";
|
||||||
ViewData["PageHelpContent"] = "Use this for purchases paid immediately — credit card swipes, cash payments, debit transactions. For vendor invoices paid later, use Bills instead. Select the expense account (what was bought) and the payment account (where the money came from).";
|
ViewData["PageHelpContent"] = "Use this for purchases paid immediately — credit card swipes, cash payments, debit transactions. For vendor invoices paid later, use Bills instead. Select the expense account (what was bought) and the payment account (where the money came from).";
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="d-flex justify-content-start mb-4">
|
<div class="d-flex justify-content-start mb-4">
|
||||||
@@ -40,13 +40,13 @@
|
|||||||
<a tabindex="0" class="help-icon" role="button"
|
<a tabindex="0" class="help-icon" role="button"
|
||||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||||
data-bs-title="Expense Account"
|
data-bs-title="Expense Account"
|
||||||
data-bs-content="The expense category this purchase belongs to — e.g. Supplies, Materials, Utilities, Fuel. This account is debited when the expense is saved. Choose the most specific account that fits to keep your reports accurate.">
|
data-bs-content="The expense category this purchase belongs to — e.g. Supplies, Materials, Utilities, Fuel. This account is debited when the expense is saved. Choose the most specific account that fits to keep your reports accurate.">
|
||||||
<i class="bi bi-question-circle"></i>
|
<i class="bi bi-question-circle"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2 align-items-center">
|
<div class="d-flex gap-2 align-items-center">
|
||||||
<select asp-for="ExpenseAccountId" asp-items="ViewBag.ExpenseAccounts" class="form-select" id="expenseAccountSelect">
|
<select asp-for="ExpenseAccountId" asp-items="ViewBag.ExpenseAccounts" class="form-select" id="expenseAccountSelect">
|
||||||
<option value="">— Select Account —</option>
|
<option value="">— Select Account —</option>
|
||||||
</select>
|
</select>
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary text-nowrap" id="expAiSuggestBtn" title="AI-suggest expense account">
|
<button type="button" class="btn btn-sm btn-outline-primary text-nowrap" id="expAiSuggestBtn" title="AI-suggest expense account">
|
||||||
<i class="bi bi-stars me-1"></i>AI Suggest
|
<i class="bi bi-stars me-1"></i>AI Suggest
|
||||||
@@ -66,12 +66,12 @@
|
|||||||
<a tabindex="0" class="help-icon" role="button"
|
<a tabindex="0" class="help-icon" role="button"
|
||||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||||
data-bs-title="Paid From"
|
data-bs-title="Paid From"
|
||||||
data-bs-content="The bank or cash account the money came out of — e.g. Business Checking, Petty Cash, Company Credit Card. This account is credited when the expense is saved. Used for bank reconciliation.">
|
data-bs-content="The bank or cash account the money came out of — e.g. Business Checking, Petty Cash, Company Credit Card. This account is credited when the expense is saved. Used for bank reconciliation.">
|
||||||
<i class="bi bi-question-circle"></i>
|
<i class="bi bi-question-circle"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<select asp-for="PaymentAccountId" asp-items="ViewBag.PaymentAccounts" class="form-select">
|
<select asp-for="PaymentAccountId" asp-items="ViewBag.PaymentAccounts" class="form-select">
|
||||||
<option value="">— Select Account —</option>
|
<option value="">— Select Account —</option>
|
||||||
</select>
|
</select>
|
||||||
<span asp-validation-for="PaymentAccountId" class="text-danger small"></span>
|
<span asp-validation-for="PaymentAccountId" class="text-danger small"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,8 +84,8 @@
|
|||||||
<label asp-for="VendorId" class="form-label fw-medium">Vendor <span class="text-muted small">(optional)</span></label>
|
<label asp-for="VendorId" class="form-label fw-medium">Vendor <span class="text-muted small">(optional)</span></label>
|
||||||
<select asp-for="VendorId" asp-items="ViewBag.Vendors" class="form-select"
|
<select asp-for="VendorId" asp-items="ViewBag.Vendors" class="form-select"
|
||||||
data-quick-add-url="/Vendors/Create" data-quick-add-title="Add New Vendor">
|
data-quick-add-url="/Vendors/Create" data-quick-add-title="Add New Vendor">
|
||||||
<option value="">— None —</option>
|
<option value="">— None —</option>
|
||||||
<option value="__new__">+ Add New Vendor…</option>
|
<option value="__new__">+ Add New Vendor…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<select asp-for="JobId" asp-items="ViewBag.Jobs" class="form-select">
|
<select asp-for="JobId" asp-items="ViewBag.Jobs" class="form-select">
|
||||||
<option value="">— None —</option>
|
<option value="">— None —</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── AI Suggest Account ────────────────────────────────────────────────
|
// -- AI Suggest Account ------------------------------------------------
|
||||||
let _expAiSuggestedAccountId = null;
|
let _expAiSuggestedAccountId = null;
|
||||||
|
|
||||||
document.getElementById('expAiSuggestBtn').addEventListener('click', async function () {
|
document.getElementById('expAiSuggestBtn').addEventListener('click', async function () {
|
||||||
|
|||||||
@@ -40,12 +40,12 @@
|
|||||||
<a tabindex="0" class="help-icon" role="button"
|
<a tabindex="0" class="help-icon" role="button"
|
||||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||||
data-bs-title="Expense Account"
|
data-bs-title="Expense Account"
|
||||||
data-bs-content="The expense category this purchase belongs to — e.g. Supplies, Materials, Utilities, Fuel. This account is debited when the expense is saved. Choose the most specific account that fits to keep your reports accurate.">
|
data-bs-content="The expense category this purchase belongs to — e.g. Supplies, Materials, Utilities, Fuel. This account is debited when the expense is saved. Choose the most specific account that fits to keep your reports accurate.">
|
||||||
<i class="bi bi-question-circle"></i>
|
<i class="bi bi-question-circle"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<select asp-for="ExpenseAccountId" asp-items="ViewBag.ExpenseAccounts" class="form-select">
|
<select asp-for="ExpenseAccountId" asp-items="ViewBag.ExpenseAccounts" class="form-select">
|
||||||
<option value="">— Select Account —</option>
|
<option value="">— Select Account —</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
@@ -54,12 +54,12 @@
|
|||||||
<a tabindex="0" class="help-icon" role="button"
|
<a tabindex="0" class="help-icon" role="button"
|
||||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||||
data-bs-title="Paid From"
|
data-bs-title="Paid From"
|
||||||
data-bs-content="The bank or cash account the money came out of — e.g. Business Checking, Petty Cash, Company Credit Card. This account is credited when the expense is saved. Used for bank reconciliation.">
|
data-bs-content="The bank or cash account the money came out of — e.g. Business Checking, Petty Cash, Company Credit Card. This account is credited when the expense is saved. Used for bank reconciliation.">
|
||||||
<i class="bi bi-question-circle"></i>
|
<i class="bi bi-question-circle"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<select asp-for="PaymentAccountId" asp-items="ViewBag.PaymentAccounts" class="form-select">
|
<select asp-for="PaymentAccountId" asp-items="ViewBag.PaymentAccounts" class="form-select">
|
||||||
<option value="">— Select Account —</option>
|
<option value="">— Select Account —</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
@@ -70,8 +70,8 @@
|
|||||||
<label asp-for="VendorId" class="form-label fw-medium">Vendor</label>
|
<label asp-for="VendorId" class="form-label fw-medium">Vendor</label>
|
||||||
<select asp-for="VendorId" asp-items="ViewBag.Vendors" class="form-select"
|
<select asp-for="VendorId" asp-items="ViewBag.Vendors" class="form-select"
|
||||||
data-quick-add-url="/Vendors/Create" data-quick-add-title="Add New Vendor">
|
data-quick-add-url="/Vendors/Create" data-quick-add-title="Add New Vendor">
|
||||||
<option value="">— None —</option>
|
<option value="">— None —</option>
|
||||||
<option value="__new__">+ Add New Vendor…</option>
|
<option value="__new__">+ Add New Vendor…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<select asp-for="JobId" asp-items="ViewBag.Jobs" class="form-select">
|
<select asp-for="JobId" asp-items="ViewBag.Jobs" class="form-select">
|
||||||
<option value="">— None —</option>
|
<option value="">— None —</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<form method="get" class="row g-2 align-items-end">
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<input type="search" name="search" value="@ViewBag.Search" class="form-control"
|
<input type="search" name="search" value="@ViewBag.Search" class="form-control"
|
||||||
placeholder="Search memo or vendor…" />
|
placeholder="Search memo or vendor…" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<select name="accountId" class="form-select">
|
<select name="accountId" class="form-select">
|
||||||
|
|||||||
Reference in New Issue
Block a user