Add BillingEmail field for commercial customers; support comma-separated multi-email

- Customer entity + DTO: new BillingEmail field (accounting/invoicing address)
- Email fields now accept comma-separated lists; DTO validates each address individually
- NotificationService: SendToEmailListAsync helper fans out to all addresses in a list;
  NotifyQuoteSentAsync accepts optional overrideEmail so staff can send to an ad-hoc address
- Migration: AddCustomerBillingEmail
- Customer Create/Edit/Details views updated to show Billing Email field
- customer-billing-email.js: client-side helpers for billing email input

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-08 20:46:53 -04:00
parent 12f784f34c
commit fb979bc88d
10 changed files with 9812 additions and 56 deletions
@@ -74,7 +74,7 @@
</div>
<div class="col-md-6">
<label asp-for="Email" class="form-label">Email <span class="text-danger">*</span> <span class="text-muted fw-normal">(required if no phone number)</span></label>
<input asp-for="Email" type="email" class="form-control" placeholder="name@example.com" />
<input asp-for="Email" type="email" multiple class="form-control" placeholder="name@example.com (comma-separate multiple)" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="col-md-3">
@@ -87,6 +87,14 @@
<input asp-for="MobilePhone" type="tel" class="form-control" placeholder="(555) 123-4567" />
<span asp-validation-for="MobilePhone" class="text-danger"></span>
</div>
<div class="col-md-6" id="billingEmailRow" style="display:none;">
<label asp-for="BillingEmail" class="form-label">Billing / Accounting Email
<span class="text-muted fw-normal">(invoices sent here)</span>
</label>
<input asp-for="BillingEmail" type="email" multiple class="form-control" placeholder="accounting@company.com (comma-separate multiple)" />
<span asp-validation-for="BillingEmail" class="text-danger"></span>
<div class="form-text">When set, invoices are emailed here instead of the contact email.</div>
</div>
</div>
</div>
@@ -372,4 +380,5 @@
@section Scripts {
<partial name="_ValidationScriptsPartial" />
<script src="~/js/customer-billing-email.js"></script>
}
@@ -97,11 +97,37 @@
<div class="col-md-6">
<label class="text-muted small mb-1">Email</label>
<p class="mb-0">
<a href="mailto:@Model.Email" class="text-decoration-none">
<i class="bi bi-envelope me-1"></i>@Model.Email
</a>
@if (!string.IsNullOrEmpty(Model.Email))
{
<a href="mailto:@Model.Email" class="text-decoration-none">
<i class="bi bi-envelope me-1"></i>@Model.Email
</a>
}
else
{
<span class="text-muted">Not provided</span>
}
</p>
</div>
@if (Model.IsCommercial)
{
<div class="col-md-6">
<label class="text-muted small mb-1">Billing / Accounting Email</label>
<p class="mb-0">
@if (!string.IsNullOrEmpty(Model.BillingEmail))
{
<a href="mailto:@Model.BillingEmail" class="text-decoration-none">
<i class="bi bi-envelope-at me-1"></i>@Model.BillingEmail
</a>
<span class="badge bg-info bg-opacity-10 text-info ms-2 small">Invoices</span>
}
else
{
<span class="text-muted">Not set — invoices go to contact email</span>
}
</p>
</div>
}
<div class="col-md-6">
<label class="text-muted small mb-1">Phone</label>
<p class="mb-0">
@@ -78,7 +78,7 @@
</div>
<div class="col-md-6">
<label asp-for="Email" class="form-label">Email</label>
<input asp-for="Email" type="email" class="form-control" placeholder="name@example.com" />
<input asp-for="Email" type="email" multiple class="form-control" placeholder="name@example.com (comma-separate multiple)" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="col-md-3">
@@ -91,6 +91,14 @@
<input asp-for="MobilePhone" type="tel" class="form-control" placeholder="(555) 123-4567" />
<span asp-validation-for="MobilePhone" class="text-danger"></span>
</div>
<div class="col-md-6" id="billingEmailRow" style="display:none;">
<label asp-for="BillingEmail" class="form-label">Billing / Accounting Email
<span class="text-muted fw-normal">(invoices sent here)</span>
</label>
<input asp-for="BillingEmail" type="email" multiple class="form-control" placeholder="accounting@company.com (comma-separate multiple)" />
<span asp-validation-for="BillingEmail" class="text-danger"></span>
<div class="form-text">When set, invoices are emailed here instead of the contact email.</div>
</div>
</div>
</div>
@@ -436,4 +444,5 @@
@section Scripts {
<partial name="_ValidationScriptsPartial" />
<script src="~/js/customer-billing-email.js"></script>
}
@@ -0,0 +1,12 @@
(function () {
var select = document.getElementById('IsCommercial');
var row = document.getElementById('billingEmailRow');
if (!select || !row) return;
function toggle() {
row.style.display = select.value === 'true' ? '' : 'none';
}
toggle();
select.addEventListener('change', toggle);
})();