Hide email controls when no email on file; show SMS hint for quote/job events

- Quotes Create/Edit: hide 'Send via email' checkbox when customer has no
  email; show badge 'send via SMS from details' or 'SMS consent required'
  when customer has a mobile number. JS responds to customer dropdown change.
- Quotes Details: hide 'Send Quote via Email' button and approval email
  checkbox; hide SMS button when no mobile; show consent-required note.
- Jobs Details (Mark Complete modal): hide email checkbox; show
  'SMS notification will be sent' badge or consent-required note.
- Jobs Index (status modal): hide email row when customer has no email.
- Jobs Edit: hide 'Notify customer if status changes' when no email.
- Invoices Details: hide Send/Re-send buttons when no email (vs. disabled).

DTOs: added CustomerEmail + CustomerNotifyByEmail to JobDto/JobListDto;
added CustomerNotifyByEmail/CustomerMobilePhone/CustomerNotifyBySms to
QuoteDto. Mapped in JobProfile and QuotesController customer blocks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 17:32:08 -04:00
parent d3863c713b
commit acbd9f60be
1190 changed files with 338016 additions and 88 deletions
@@ -1279,6 +1279,9 @@ public class JobsController : Controller
dto.SendEmailOnStatusChange = (bool)(ViewBag.EmailDefaultOnStatusChange ?? false);
}
// Used by view to hide the email checkbox when the customer has no email address on file
ViewBag.CustomerEmail = job.Customer?.Email;
return View(dto);
}
catch (Exception ex)
@@ -533,6 +533,9 @@ public class QuotesController : Controller
quoteDto.CustomerContactLastName = customer.ContactLastName;
quoteDto.CustomerEmail = customer.Email;
quoteDto.CustomerPhone = customer.Phone;
quoteDto.CustomerNotifyByEmail = customer.NotifyByEmail;
quoteDto.CustomerMobilePhone = customer.MobilePhone;
quoteDto.CustomerNotifyBySms = customer.NotifyBySms;
}
}
@@ -1264,6 +1267,8 @@ public class QuotesController : Controller
ViewBag.CustomerContactName = $"{quote.Customer.ContactFirstName} {quote.Customer.ContactLastName}".Trim();
ViewBag.CustomerEmail = quote.Customer.Email ?? "";
ViewBag.CustomerPhone = quote.Customer.Phone ?? "";
ViewBag.CustomerNotifyBySms = quote.Customer.NotifyBySms;
ViewBag.CustomerMobilePhone = quote.Customer.MobilePhone ?? "";
}
var editCurrentUser = await _userManager.GetUserAsync(User);
@@ -2627,6 +2632,16 @@ public class QuotesController : Controller
.Where(c => !c.NotifyByEmail)
.Select(c => c.Id)
.ToHashSet();
// Customers with no email address on file — JS hides the email section entirely
ViewBag.CustomerNoEmailIds = customers
.Where(c => string.IsNullOrWhiteSpace(c.Email))
.Select(c => c.Id)
.ToHashSet();
// Customers who have given SMS consent with a mobile number on file
ViewBag.CustomerSmsConsentIds = customers
.Where(c => c.NotifyBySms && !string.IsNullOrWhiteSpace(c.MobilePhone))
.Select(c => c.Id)
.ToHashSet();
// Stored separately so views can restore the company default when switching away from an exempt customer
// (ViewBag.CompanyTaxPercent is set by the calling action if it has access to operatingCosts)
if (ViewBag.CompanyTaxPercent == null && customers.Any())
@@ -2817,6 +2832,9 @@ public class QuotesController : Controller
quoteDto.CustomerContactLastName = customer.ContactLastName;
quoteDto.CustomerEmail = customer.Email;
quoteDto.CustomerPhone = customer.Phone;
quoteDto.CustomerNotifyByEmail = customer.NotifyByEmail;
quoteDto.CustomerMobilePhone = customer.MobilePhone;
quoteDto.CustomerNotifyBySms = customer.NotifyBySms;
}
}