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
@@ -21,13 +21,13 @@
</h2>
<p>
Invoices are the formal request for payment you send to customers after their work is complete.
Each job can have one invoice. The system tracks payment status in real time you can see at a
Each job can have one invoice. The system tracks payment status in real time &mdash; you can see at a
glance which customers owe money, how much, and how long the balance has been outstanding.
</p>
<p>
Invoices can be emailed to customers directly from the system (when email is configured) and
downloaded as PDFs to print or send manually. Payments whether in full or in partial
installments are logged against the invoice, and the customer's outstanding balance on their
downloaded as PDFs to print or send manually. Payments &mdash; whether in full or in partial
installments &mdash; are logged against the invoice, and the customer's outstanding balance on their
account is updated automatically with every transaction.
</p>
<p>
@@ -64,14 +64,14 @@
<p>
Invoice numbers are generated in the format <code>INV-YYMM-####</code>
(for example, <code>INV-2503-0007</code>). Each job can only have one invoice if an invoice
(for example, <code>INV-2503-0007</code>). Each job can only have one invoice &mdash; if an invoice
already exists for a job, the Create Invoice button on the Job Details page is replaced with a
link to the existing invoice.
</p>
<div class="alert alert-permanent alert-info d-flex gap-2 mb-0" role="alert">
<i class="bi bi-lightbulb-fill flex-shrink-0 mt-1"></i>
<div>
You can create an invoice for a job at any time you do not need to wait until the job
You can create an invoice for a job at any time &mdash; you do not need to wait until the job
reaches a Completed or Delivered status. Some shops invoice on deposit when a job is
approved; others invoice on pickup. The system is flexible.
</div>
@@ -161,7 +161,7 @@
<i class="bi bi-cash-coin text-primary me-2"></i>Recording a Payment
</h2>
<p>
When a customer pays whether in full or as a partial payment you record it against the invoice.
When a customer pays &mdash; whether in full or as a partial payment &mdash; you record it against the invoice.
The system supports multiple partial payments on a single invoice.
</p>
<ol class="mb-3">
@@ -169,17 +169,17 @@
<li class="mb-2">
Fill in the payment details:
<ul class="mt-1">
<li><strong>Amount</strong> how much was received this time. Can be less than the full balance for partial payments.</li>
<li><strong>Payment Method</strong> Cash, Check, Credit/Debit Card, Bank Transfer / ACH, or Digital Payment.</li>
<li><strong>Payment Date</strong> defaults to today.</li>
<li><strong>Reference Number</strong> optional. Use for check numbers, transaction IDs, or wire reference numbers.</li>
<li><strong>Notes</strong> any additional notes about this payment.</li>
<li><strong>Amount</strong> &mdash; how much was received this time. Can be less than the full balance for partial payments.</li>
<li><strong>Payment Method</strong> &mdash; Cash, Check, Credit/Debit Card, Bank Transfer / ACH, or Digital Payment.</li>
<li><strong>Payment Date</strong> &mdash; defaults to today.</li>
<li><strong>Reference Number</strong> &mdash; optional. Use for check numbers, transaction IDs, or wire reference numbers.</li>
<li><strong>Notes</strong> &mdash; any additional notes about this payment.</li>
</ul>
</li>
<li class="mb-2">Click <strong>Save Payment</strong>.</li>
</ol>
<p>
The invoice status updates automatically to <strong>Partially Paid</strong> if there is still
The invoice status updates automatically &mdash; to <strong>Partially Paid</strong> if there is still
a remaining balance, or <strong>Paid</strong> if the full amount has been received. The customer's
outstanding balance on their account is reduced by the payment amount. All payments are shown in
a payment log on the invoice Details page.
@@ -199,8 +199,8 @@
<i class="bi bi-x-circle text-primary me-2"></i>Voiding an Invoice
</h2>
<p>
If an invoice was created in error for example, against the wrong job or with incorrect line
items that cannot be corrected you can void it to remove it from the customer's outstanding
If an invoice was created in error &mdash; for example, against the wrong job or with incorrect line
items that cannot be corrected &mdash; you can void it to remove it from the customer's outstanding
balance.
</p>
<ol class="mb-3">
@@ -215,7 +215,7 @@
<strong>Restrictions:</strong> Only invoices in <strong>Draft</strong> or <strong>Sent</strong>
status can be voided. If an invoice has payments recorded against it, you must delete those
payments first before you can void the invoice. Invoices that are Partially Paid or Paid
cannot be voided directly consider writing off the remaining balance instead if needed.
cannot be voided directly &mdash; consider writing off the remaining balance instead if needed.
</div>
</div>
</section>
@@ -238,7 +238,7 @@
<p>
If a customer's outstanding balance is approaching or has exceeded their credit limit, a warning
flag is shown on their customer record, on new jobs you try to create for them, and on new invoices.
This is a visual warning only the system does not automatically block new work but it provides
This is a visual warning only &mdash; the system does not automatically block new work &mdash; but it provides
a clear signal to follow up on payment.
</p>
<div class="alert alert-permanent alert-info d-flex gap-2 mb-0" role="alert">
@@ -263,7 +263,7 @@
<p>
When you create an invoice from a job, <strong>all unapplied deposits are automatically applied
as payments</strong> on the new invoice. The invoice's Amount Paid and status update accordingly
you may find the invoice is already partially or fully paid at creation time.
&mdash; you may find the invoice is already partially or fully paid at creation time.
</p>
<p>
Each deposit generates a receipt (receipt number format: <code>DEP-YYMM-####</code>) that can
@@ -281,7 +281,7 @@
</p>
<p>
To apply a gift certificate to an invoice, open the Invoice Details page and click
<strong>Apply Gift Certificate</strong>. Enter the certificate code the system looks up
<strong>Apply Gift Certificate</strong>. Enter the certificate code &mdash; the system looks up
the remaining balance and applies it as a payment up to the invoice amount.
</p>
</section>
@@ -307,7 +307,7 @@
<ol class="mb-3">
<li class="mb-2">Go to <strong>Settings &rsaquo; Billing</strong> (<a href="/Billing">/Billing</a>).</li>
<li class="mb-2">Click <strong>Connect with Stripe</strong> (or <em>Set Up Online Payments</em>).</li>
<li class="mb-2">You are redirected to Stripe create a new Stripe account or connect an existing one.</li>
<li class="mb-2">You are redirected to Stripe &mdash; create a new Stripe account or connect an existing one.</li>
<li class="mb-2">Complete Stripe&rsquo;s onboarding: enter your business details, add a bank account for payouts, and verify your identity as required by Stripe.</li>
<li class="mb-2">Once Stripe approves the account, you are returned to the app and Stripe Connect status shows <strong>Active</strong>.</li>
<li class="mb-2">Payment links now appear on Invoice Details and on the Online Payments page.</li>
@@ -326,8 +326,8 @@
Once Stripe Connect is active, open any Invoice Details page and use one of these options:
</p>
<ul class="mb-3">
<li class="mb-1"><strong>Copy Payment Link</strong> copies the URL to your clipboard so you can paste it into an email, text, or any other message.</li>
<li class="mb-1"><strong>Send Payment Link</strong> emails the payment link directly to the customer&rsquo;s email address on file, with a brief message and the invoice amount.</li>
<li class="mb-1"><strong>Copy Payment Link</strong> &mdash; copies the URL to your clipboard so you can paste it into an email, text, or any other message.</li>
<li class="mb-1"><strong>Send Payment Link</strong> &mdash; emails the payment link directly to the customer&rsquo;s email address on file, with a brief message and the invoice amount.</li>
</ul>
<p>
The link is unique to each invoice and does not expire as long as the invoice remains unpaid.
@@ -340,17 +340,17 @@
<i class="bi bi-bell text-primary me-2"></i>Automated Payment Reminders
</h2>
<p>
The system can automatically email customers when their invoices become overdue without you
The system can automatically email customers when their invoices become overdue &mdash; without you
having to remember to follow up manually. This feature is controlled from
<strong>Settings &rsaquo; Notifications &rsaquo; Automated Payment Reminders</strong>.
</p>
<ul class="mb-3">
<li class="mb-2">
<strong>Enable Payment Reminders</strong> turn the feature on or off for your company at any time.
<strong>Enable Payment Reminders</strong> &mdash; turn the feature on or off for your company at any time.
When off, no automated emails are sent.
</li>
<li class="mb-2">
<strong>Reminder Days</strong> a comma-separated list of day milestones past the due date at which
<strong>Reminder Days</strong> &mdash; a comma-separated list of day milestones past the due date at which
reminders are sent. The default is <code>7,14,30</code> (one reminder at 7 days overdue, another at
14, and a final one at 30).
</li>