Phase 2: Eliminate ApplicationDbContext from domain controllers

Migrated InvoicesController, QuotesController, JobsController, BillsController,
PurchaseOrdersController, and CustomersController to route all data access
through IUnitOfWork typed/generic repositories instead of injecting
ApplicationDbContext directly.

New typed repositories added: IJobRepository (GetScheduledJobsForDateAsync,
GetActiveJobsForMobileAsync, LoadForCostingAsync), INotificationLogRepository
(GetLatestForJobAsync, GetAllForJobAsync), IQuoteRepository (GetItemsWithCoatsAsync
with CatalogItem eager load + AsNoTracking), and IJobRepository.GetOrphanedConversionJobAsync.

All EF complex include chains relocated into repository methods; controllers now
call named query methods rather than composing raw IQueryable chains.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 21:20:39 -04:00
parent 80b0e547cc
commit 90bc0d965f
20 changed files with 730 additions and 878 deletions
@@ -25,7 +25,6 @@ public class CustomersController : Controller
private readonly INotificationService _notificationService;
private readonly ISubscriptionService _subscriptionService;
private readonly ITenantContext _tenantContext;
private readonly ApplicationDbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
public CustomersController(
@@ -35,7 +34,6 @@ public class CustomersController : Controller
INotificationService notificationService,
ISubscriptionService subscriptionService,
ITenantContext tenantContext,
ApplicationDbContext context,
UserManager<ApplicationUser> userManager)
{
_unitOfWork = unitOfWork;
@@ -44,7 +42,6 @@ public class CustomersController : Controller
_notificationService = notificationService;
_subscriptionService = subscriptionService;
_tenantContext = tenantContext;
_context = context;
_userManager = userManager;
}
@@ -555,11 +552,9 @@ public class CustomersController : Controller
try { await _notificationService.NotifySmsConsentGrantedAsync(customer); }
catch (Exception ex) { _logger.LogWarning(ex, "SMS consent confirmation failed for customer {Id}", customer.Id); }
var smsLog = await _context.NotificationLogs
.IgnoreQueryFilters()
.Where(n => n.CustomerId == customer.Id)
.OrderByDescending(n => n.SentAt)
.FirstOrDefaultAsync();
var logs = await _unitOfWork.NotificationLogs.FindAsync(
n => n.CustomerId == customer.Id, ignoreQueryFilters: true);
var smsLog = logs.OrderByDescending(n => n.SentAt).FirstOrDefault();
this.SetNotificationResultToast(smsLog);
}
@@ -679,11 +674,9 @@ public class CustomersController : Controller
try { await _notificationService.NotifySmsConsentGrantedAsync(customer); }
catch (Exception ex) { _logger.LogWarning(ex, "SMS consent confirmation failed for customer {Id}", customer.Id); }
var smsLog = await _context.NotificationLogs
.IgnoreQueryFilters()
.Where(n => n.CustomerId == customer.Id)
.OrderByDescending(n => n.SentAt)
.FirstOrDefaultAsync();
var logs = await _unitOfWork.NotificationLogs.FindAsync(
n => n.CustomerId == customer.Id, ignoreQueryFilters: true);
var smsLog = logs.OrderByDescending(n => n.SentAt).FirstOrDefault();
this.SetNotificationResultToast(smsLog);
}