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:
@@ -5,7 +5,7 @@
|
||||
ViewData["Title"] = "Create Invoice";
|
||||
ViewData["PageIcon"] = "bi-receipt";
|
||||
ViewData["PageHelpTitle"] = "Create Invoice";
|
||||
ViewData["PageHelpContent"] = "Invoices start as Drafts — you can freely edit them until you click Send. Once sent, the invoice is locked and the customer is emailed. Line items are pre-populated from the job's items but you can add, edit, or remove any line before sending. Partial payments are supported after sending.";
|
||||
ViewData["PageHelpContent"] = "Invoices start as Drafts — you can freely edit them until you click Send. Once sent, the invoice is locked and the customer is emailed. Line items are pre-populated from the job's items but you can add, edit, or remove any line before sending. Partial payments are supported after sending.";
|
||||
var jobNumber = ViewBag.JobNumber as string;
|
||||
var customerName = ViewBag.CustomerName as string;
|
||||
var customers = ViewBag.Customers as List<Customer>;
|
||||
@@ -130,7 +130,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Invoice Details"
|
||||
data-bs-content="Invoice Date is the date of issue — this is what appears on the printed invoice and determines when payment terms start counting. Due Date drives overdue status and A/R aging reports. Payment Terms is free text (e.g., 'Net 30') that prints on the invoice; it defaults from the customer's settings but you can override it here.">
|
||||
data-bs-content="Invoice Date is the date of issue — this is what appears on the printed invoice and determines when payment terms start counting. Due Date drives overdue status and A/R aging reports. Payment Terms is free text (e.g., 'Net 30') that prints on the invoice; it defaults from the customer's settings but you can override it here.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -143,7 +143,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Invoice Date"
|
||||
data-bs-content="The date the invoice is issued. This appears on the printed document and is the reference date for payment terms — e.g., Net 30 means payment is due 30 days after this date. Defaults to today.">
|
||||
data-bs-content="The date the invoice is issued. This appears on the printed document and is the reference date for payment terms — e.g., Net 30 means payment is due 30 days after this date. Defaults to today.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -196,7 +196,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Line Items"
|
||||
data-bs-content="Each row is a billable line on the invoice. Pre-populated from the job's items. Qty × Unit Price = Total per line; you can override the Total directly too. Color is optional — it appears under the description on the printed invoice. Add manual lines for anything not in the job (e.g., pickup fee, rush charge).">
|
||||
data-bs-content="Each row is a billable line on the invoice. Pre-populated from the job's items. Qty × Unit Price = Total per line; you can override the Total directly too. Color is optional — it appears under the description on the printed invoice. Add manual lines for anything not in the job (e.g., pickup fee, rush charge).">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -321,7 +321,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Notes"
|
||||
data-bs-content="Customer Notes appear on the printed and emailed invoice — use these for payment instructions, thank-you messages, or job-specific reminders. Internal Notes are only visible to staff here in the app and never sent to the customer.">
|
||||
data-bs-content="Customer Notes appear on the printed and emailed invoice — use these for payment instructions, thank-you messages, or job-specific reminders. Internal Notes are only visible to staff here in the app and never sent to the customer.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -354,7 +354,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Totals"
|
||||
data-bs-content="Subtotal = sum of all line item totals. Discount is a flat dollar amount deducted before tax — use it for customer-specific deals or courtesy adjustments. Tax % is applied to (Subtotal − Discount). Both default from the company settings but can be overridden per invoice.">
|
||||
data-bs-content="Subtotal = sum of all line item totals. Discount is a flat dollar amount deducted before tax — use it for customer-specific deals or courtesy adjustments. Tax % is applied to (Subtotal − Discount). Both default from the company settings but can be overridden per invoice.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -584,7 +584,7 @@
|
||||
onmousedown="event.preventDefault();merchComboSelect(this)"
|
||||
onmouseenter="this.style.background=document.documentElement.getAttribute('data-bs-theme')==='dark'?'#2c3a5a':'#f0f4ff'"
|
||||
onmouseleave="this.classList.contains('mc-active')?null:this.style.background=''">
|
||||
${i.name}${i.sKU ? ' <span class="text-muted">[' + i.sKU + ']</span>' : ''} <span class="text-muted">— ${formatCurrency(i.defaultPrice)}</span>
|
||||
${i.name}${i.sKU ? ' <span class="text-muted">[' + i.sKU + ']</span>' : ''} <span class="text-muted">— ${formatCurrency(i.defaultPrice)}</span>
|
||||
</div>`
|
||||
).join('')
|
||||
).join('');
|
||||
@@ -656,7 +656,7 @@
|
||||
}
|
||||
|
||||
function addGiftCertLineItem(btn) {
|
||||
// Bootstrap teleports modals to <body> — navigate relative to the button
|
||||
// Bootstrap teleports modals to <body> — navigate relative to the button
|
||||
const modalEl = btn ? btn.closest('.modal') : document.getElementById('gcModal');
|
||||
const q = sel => modalEl ? modalEl.querySelector(sel) : document.querySelector(sel);
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
var emailOptedOut = hasEmail && !Model.CustomerNotifyByEmail;
|
||||
var smsPhone = !string.IsNullOrWhiteSpace(Model.CustomerMobilePhone) ? Model.CustomerMobilePhone : Model.CustomerPhone;
|
||||
var hasSms = !string.IsNullOrWhiteSpace(smsPhone) && Model.CustomerNotifyBySms;
|
||||
var showSendModal = hasEmail && !emailOptedOut && hasSms; // both channels — show choice modal
|
||||
var directSendSms = !hasEmail && hasSms; // SMS only — skip modal
|
||||
var showSendModal = hasEmail && !emailOptedOut && hasSms; // both channels — show choice modal
|
||||
var directSendSms = !hasEmail && hasSms; // SMS only — skip modal
|
||||
var hasAvailableCredits = ViewBag.AvailableCreditMemos != null && ((IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem>)ViewBag.AvailableCreditMemos).Any();
|
||||
var canIssueRefund = !isDraft && !isVoided && Model.AmountPaid > 0;
|
||||
var canApplyCredit = !isVoided && Model.BalanceDue > 0 && hasAvailableCredits;
|
||||
@@ -80,7 +80,7 @@
|
||||
<div class="alert alert-warning alert-permanent d-flex align-items-center gap-2 mb-4">
|
||||
<i class="bi bi-envelope-slash fs-5"></i>
|
||||
<span>
|
||||
<strong>@Model.CustomerName</strong> has no email address on file — you'll be prompted to enter one when sending.
|
||||
<strong>@Model.CustomerName</strong> has no email address on file — you'll be prompted to enter one when sending.
|
||||
<a asp-controller="Customers" asp-action="Edit" asp-route-id="@Model.CustomerId" class="alert-link">Add one in customer settings</a>.
|
||||
</span>
|
||||
</div>
|
||||
@@ -179,12 +179,12 @@
|
||||
<div class="col-md-4">
|
||||
<label class="text-muted small mb-1">Due Date</label>
|
||||
<p class="mb-0 @(Model.Status == InvoiceStatus.Overdue ? "text-danger fw-bold" : "")">
|
||||
@(Model.DueDate.HasValue ? Model.DueDate.Value.ToString("MMMM d, yyyy") : "—")
|
||||
@(Model.DueDate.HasValue ? Model.DueDate.Value.ToString("MMMM d, yyyy") : "—")
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="text-muted small mb-1">Sent Date</label>
|
||||
<p class="mb-0">@(Model.SentDate.HasValue ? Model.SentDate.Value.ToString("MMMM d, yyyy") : "—")</p>
|
||||
<p class="mb-0">@(Model.SentDate.HasValue ? Model.SentDate.Value.ToString("MMMM d, yyyy") : "—")</p>
|
||||
</div>
|
||||
@if (!string.IsNullOrWhiteSpace(Model.CustomerPO))
|
||||
{
|
||||
@@ -350,7 +350,7 @@
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-muted">
|
||||
@(gcItem.Description.Contains("for ") ? gcItem.Description.Substring(gcItem.Description.IndexOf("for ") + 4).TrimEnd(')') : "—")
|
||||
@(gcItem.Description.Contains("for ") ? gcItem.Description.Substring(gcItem.Description.IndexOf("for ") + 4).TrimEnd(')') : "—")
|
||||
</td>
|
||||
<td class="text-end fw-semibold">@gcItem.TotalPrice.ToString("C")</td>
|
||||
<td>
|
||||
@@ -396,7 +396,7 @@
|
||||
<tr>
|
||||
<td>@p.PaymentDate.ToString("MM/dd/yyyy")</td>
|
||||
<td>@p.PaymentMethodDisplay</td>
|
||||
<td>@(p.Reference ?? "—")</td>
|
||||
<td>@(p.Reference ?? "—")</td>
|
||||
<td>
|
||||
@if (!string.IsNullOrEmpty(p.DepositAccountName))
|
||||
{
|
||||
@@ -404,10 +404,10 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-muted">—</span>
|
||||
<span class="text-muted">—</span>
|
||||
}
|
||||
</td>
|
||||
<td>@(p.RecordedByName ?? "—")</td>
|
||||
<td>@(p.RecordedByName ?? "—")</td>
|
||||
<td class="text-end fw-semibold text-success">@p.Amount.ToString("C")</td>
|
||||
<td class="text-end">
|
||||
@if (!isVoided)
|
||||
@@ -463,7 +463,7 @@
|
||||
<td>@r.RefundDate.ToString("MM/dd/yyyy")</td>
|
||||
<td>@r.RefundMethodDisplay</td>
|
||||
<td>@r.Reason</td>
|
||||
<td>@(r.Reference ?? "—")</td>
|
||||
<td>@(r.Reference ?? "—")</td>
|
||||
<td><span class="badge bg-@refundStatusColor">@r.Status</span></td>
|
||||
<td class="text-end fw-semibold text-danger">(@r.Amount.ToString("C"))</td>
|
||||
<td class="text-nowrap">
|
||||
@@ -575,7 +575,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="left" data-bs-trigger="focus"
|
||||
data-bs-title="Invoice Actions"
|
||||
data-bs-content="Workflow: Edit (Draft only) → Send Invoice (locks it, emails customer) → Record Payment. Partial payments are supported — record multiple payments until fully paid. Void cancels the invoice and reverses the customer balance without deleting history. Delete is only available for Drafts.">
|
||||
data-bs-content="Workflow: Edit (Draft only) → Send Invoice (locks it, emails customer) → Record Payment. Partial payments are supported — record multiple payments until fully paid. Void cancels the invoice and reverses the customer balance without deleting history. Delete is only available for Drafts.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -601,7 +601,7 @@
|
||||
}
|
||||
else if (showSendModal)
|
||||
{
|
||||
@* Both email + SMS available — let staff choose *@
|
||||
@* Both email + SMS available — let staff choose *@
|
||||
<button type="button" class="btn btn-primary w-100"
|
||||
data-bs-toggle="modal" data-bs-target="#sendChannelModal">
|
||||
<i class="bi bi-send me-2"></i>Send Invoice
|
||||
@@ -609,7 +609,7 @@
|
||||
}
|
||||
else if (directSendSms)
|
||||
{
|
||||
@* SMS only — send directly *@
|
||||
@* SMS only — send directly *@
|
||||
<button type="button" class="btn btn-primary w-100"
|
||||
onclick="submitSendInvoice(false, true)">
|
||||
<i class="bi bi-send me-2"></i>Send Invoice via SMS
|
||||
@@ -792,7 +792,7 @@
|
||||
{
|
||||
<div class="mb-2">
|
||||
<span class="badge bg-success-subtle text-success mb-2">
|
||||
<i class="bi bi-check-circle me-1"></i>Active — expires @Model.PaymentLinkExpiresAt!.Value.ToString("MMM d")
|
||||
<i class="bi bi-check-circle me-1"></i>Active — expires @Model.PaymentLinkExpiresAt!.Value.ToString("MMM d")
|
||||
</span>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" id="paymentLinkInput" class="form-control font-monospace"
|
||||
@@ -970,7 +970,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="left" data-bs-trigger="focus"
|
||||
data-bs-title="Payment Reference"
|
||||
data-bs-content="Optional identifier for reconciliation — e.g., the check number, last 4 digits of the card, ACH transaction ID, or Venmo/PayPal confirmation code. Appears in payment history so you can match payments to your bank statement.">
|
||||
data-bs-content="Optional identifier for reconciliation — e.g., the check number, last 4 digits of the card, ACH transaction ID, or Venmo/PayPal confirmation code. Appears in payment history so you can match payments to your bank statement.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -1189,7 +1189,7 @@
|
||||
</div>
|
||||
<div id="refundAlertCredit" class="alert alert-success small mb-3 d-none">
|
||||
<i class="bi bi-piggy-bank me-1"></i>
|
||||
The refund amount will be added to the customer's store credit balance immediately — no manual action needed.
|
||||
The refund amount will be added to the customer's store credit balance immediately — no manual action needed.
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Amount <span class="text-danger">*</span></label>
|
||||
@@ -1326,7 +1326,7 @@
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Select Credit Memo <span class="text-danger">*</span></label>
|
||||
<select name="CreditMemoId" class="form-select" required>
|
||||
<option value="">— Select —</option>
|
||||
<option value="">— Select —</option>
|
||||
@foreach (var item in (IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem>)ViewBag.AvailableCreditMemos)
|
||||
{
|
||||
<option value="@item.Value">@item.Text</option>
|
||||
@@ -1340,7 +1340,7 @@
|
||||
<input type="number" name="Amount" class="form-control" step="0.01" min="0.01"
|
||||
max="@Model.BalanceDue.ToString("F2")" value="@Model.BalanceDue.ToString("F2")" required />
|
||||
</div>
|
||||
<div class="form-text">Balance due: @Model.BalanceDue.ToString("C") — the system will cap at the memo's remaining balance.</div>
|
||||
<div class="form-text">Balance due: @Model.BalanceDue.ToString("C") — the system will cap at the memo's remaining balance.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -1422,7 +1422,7 @@
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Bad Debt Expense Account</label>
|
||||
<select name="expenseAccountId" class="form-select">
|
||||
<option value="">— Use default bad debt account —</option>
|
||||
<option value="">— Use default bad debt account —</option>
|
||||
@if (ViewBag.ExpenseAccounts != null)
|
||||
{
|
||||
@foreach (var item in (IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem>)ViewBag.ExpenseAccounts)
|
||||
@@ -1503,7 +1503,7 @@
|
||||
document.getElementById('gcAmountInput').value = max.toFixed(2);
|
||||
document.getElementById('gcAmountInput').max = max;
|
||||
const expiry = data.expiryDate ? ` · Expires ${data.expiryDate}` : '';
|
||||
result.innerHTML = `<div class="alert alert-success py-1 mb-0 small"><i class="bi bi-check-circle me-1"></i><strong>${data.certificateCode}</strong> — $${data.remainingBalance.toFixed(2)} remaining${expiry}</div>`;
|
||||
result.innerHTML = `<div class="alert alert-success py-1 mb-0 small"><i class="bi bi-check-circle me-1"></i><strong>${data.certificateCode}</strong> — $${data.remainingBalance.toFixed(2)} remaining${expiry}</div>`;
|
||||
}
|
||||
} catch { result.innerHTML = '<div class="alert alert-danger py-1 mb-0 small">Lookup failed.</div>'; }
|
||||
document.getElementById('gcLookupSpinner').style.display = 'none';
|
||||
@@ -1616,7 +1616,7 @@
|
||||
<td class="small">${escHtml(n.type.replace(/([A-Z])/g, ' $1').trim())}</td>
|
||||
<td class="small"><i class="bi ${channelIcon} me-1"></i>${escHtml(n.channel)}</td>
|
||||
<td class="small">${escHtml(n.recipientName)}<br><span class="text-muted">${escHtml(n.recipient)}</span></td>
|
||||
<td class="small">${n.subject ? escHtml(n.subject) : '<span class="text-muted">—</span>'}</td>
|
||||
<td class="small">${n.subject ? escHtml(n.subject) : '<span class="text-muted">—</span>'}</td>
|
||||
<td><span class="badge bg-${statusClass}">${escHtml(n.status)}</span>${expandBtn}</td>
|
||||
</tr>${errorRow}`;
|
||||
}).join('');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@model PowderCoating.Application.DTOs.Invoice.UpdateInvoiceDto
|
||||
@model PowderCoating.Application.DTOs.Invoice.UpdateInvoiceDto
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit Invoice";
|
||||
@@ -38,7 +38,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Invoice Details"
|
||||
data-bs-content="Invoice Date is the date of issue and the reference for payment terms. Due Date drives overdue status and A/R aging. Payment Terms prints on the invoice — changing it here only affects this invoice. Draft, Sent, and Overdue invoices can be edited; Paid and Partially Paid invoices are locked.">
|
||||
data-bs-content="Invoice Date is the date of issue and the reference for payment terms. Due Date drives overdue status and A/R aging. Payment Terms prints on the invoice — changing it here only affects this invoice. Draft, Sent, and Overdue invoices can be edited; Paid and Partially Paid invoices are locked.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -163,7 +163,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Notes"
|
||||
data-bs-content="Customer Notes appear on the printed and emailed invoice — use these for payment instructions, thank-you messages, or job-specific reminders. Internal Notes are only visible to staff in the app and are never sent to the customer.">
|
||||
data-bs-content="Customer Notes appear on the printed and emailed invoice — use these for payment instructions, thank-you messages, or job-specific reminders. Internal Notes are only visible to staff in the app and are never sent to the customer.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
@@ -196,7 +196,7 @@
|
||||
<a tabindex="0" class="help-icon" role="button"
|
||||
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
||||
data-bs-title="Totals"
|
||||
data-bs-content="Subtotal = sum of all line item totals. Discount is a flat dollar amount deducted before tax. Tax % is applied to (Subtotal − Discount). Both default from the company settings but can be overridden for this invoice.">
|
||||
data-bs-content="Subtotal = sum of all line item totals. Discount is a flat dollar amount deducted before tax. Tax % is applied to (Subtotal âˆ' Discount). Both default from the company settings but can be overridden for this invoice.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
@if (thisMonthOnly && statusFilter == InvoiceStatus.Paid)
|
||||
{
|
||||
<span class="badge bg-success fs-6 fw-normal">
|
||||
<i class="bi bi-funnel-fill me-1"></i>Paid — @DateTime.Now.ToString("MMMM yyyy")
|
||||
<i class="bi bi-funnel-fill me-1"></i>Paid — @DateTime.Now.ToString("MMMM yyyy")
|
||||
</span>
|
||||
}
|
||||
else if (thisMonthOnly)
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
{
|
||||
var net = inv.OnlineAmountPaid;
|
||||
var gross = inv.OnlineAmountPaid + inv.OnlineSurchargeCollected;
|
||||
var dateDisplay = inv.PaidDate.HasValue ? inv.PaidDate.Value.ToString("MMM d, yyyy") : (inv.UpdatedAt?.ToString("MMM d, yyyy") ?? "—");
|
||||
var dateDisplay = inv.PaidDate.HasValue ? inv.PaidDate.Value.ToString("MMM d, yyyy") : (inv.UpdatedAt?.ToString("MMM d, yyyy") ?? "—");
|
||||
var statusClass = inv.OnlinePaymentStatus switch
|
||||
{
|
||||
PowderCoating.Core.Enums.OnlinePaymentStatus.Paid => "bg-success-subtle text-success",
|
||||
@@ -117,7 +117,7 @@
|
||||
};
|
||||
var customerName = inv.Customer != null
|
||||
? (inv.Customer.CompanyName ?? $"{inv.Customer.ContactFirstName} {inv.Customer.ContactLastName}".Trim())
|
||||
: "—";
|
||||
: "—";
|
||||
<tr>
|
||||
<td>
|
||||
<a asp-action="Details" asp-route-id="@inv.Id" class="fw-semibold text-decoration-none">
|
||||
@@ -134,7 +134,7 @@
|
||||
@if (!string.IsNullOrEmpty(inv.StripePaymentIntentId))
|
||||
{
|
||||
<code class="small" title="@inv.StripePaymentIntentId">
|
||||
@inv.StripePaymentIntentId[..Math.Min(20, inv.StripePaymentIntentId.Length)]…
|
||||
@inv.StripePaymentIntentId[..Math.Min(20, inv.StripePaymentIntentId.Length)]…
|
||||
</code>
|
||||
}
|
||||
</td>
|
||||
@@ -185,12 +185,12 @@
|
||||
<tbody>
|
||||
@foreach (var r in Model.Refunds)
|
||||
{
|
||||
var invNum = r.Invoice?.InvoiceNumber ?? "—";
|
||||
var invNum = r.Invoice?.InvoiceNumber ?? "—";
|
||||
var invId = r.Invoice?.Id;
|
||||
var cust = r.Invoice?.Customer;
|
||||
var custName = cust != null
|
||||
? (cust.CompanyName ?? $"{cust.ContactFirstName} {cust.ContactLastName}".Trim())
|
||||
: "—";
|
||||
: "—";
|
||||
var statusClass = r.Status switch
|
||||
{
|
||||
PowderCoating.Core.Enums.RefundStatus.Issued => "bg-success-subtle text-success",
|
||||
|
||||
Reference in New Issue
Block a user