When a tenant uploads a logo it is stored in Azure Blob Storage and
LogoData (the legacy DB byte[]) is cleared. All PDF controllers were
still reading the now-null LogoData, so logos never appeared on any
PDF after upload. Fixed by injecting ICompanyLogoService into all six
affected controllers (Quotes, Invoices, Deposits, GiftCertificates,
PurchaseOrders, CatalogItems) and loading the blob-stored logo first
before falling back to the legacy DB field.
Also added structured logging to the AI photo promotion path in
QuotesController Create/Edit POST so upload failures are visible in
production logs instead of silently swallowed.
Added onclick safety net to the Create and Edit quote submit buttons
so dynamically-injected hidden fields (AiPhotoTempIds) are written
before iOS Safari collects the form data on submit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>