using Data.SeaHavenIndustries; using Microsoft.EntityFrameworkCore; using SeaHaven.DataServices.Interfaces; namespace SeaHaven.DataServices.Implementation { public class WorkOrderBoardMutationDataService : IWorkOrderBoardMutationDataService { private readonly ApplicationDbContext _context; public WorkOrderBoardMutationDataService(ApplicationDbContext context) { _context = context; } public Task VendorExistsAsync(int vendorId, CancellationToken cancellationToken) => _context.Vendors.AnyAsync(v => v.Id == vendorId && v.IsDeleted != true, cancellationToken); public async Task GetMaxWorkOrderIdAsync(CancellationToken cancellationToken) => await _context.workOrders.MaxAsync(w => (int?)w.Id, cancellationToken) ?? 0; public Task GetTrackedWorkOrderAsync(int workOrderId, CancellationToken cancellationToken) => _context.workOrders .Include(workOrder => workOrder.Locations) .Include(workOrder => workOrder.WorkOrderContacts!) .ThenInclude(contact => contact.POC) .Include(workOrder => workOrder.PrimaryDispatch!) .ThenInclude(dispatch => dispatch.Vendor) .FirstOrDefaultAsync( w => w.Id == workOrderId && w.istemplate != true && (w.IsDeleted != true || w.IsDeleted == null), cancellationToken); public Task GetTrackedDispatchAsync(int dispatchId, int workOrderId, CancellationToken cancellationToken) => _context.Dispatches .Include(d => d.DispatchWorkOrders) .FirstOrDefaultAsync( d => d.Id == dispatchId && (d.WorkOrderId == workOrderId || d.DispatchWorkOrders!.Any(link => link.WorkOrderId == workOrderId)), cancellationToken); public Task GetTrackedDispatchByIdAsync(int dispatchId, CancellationToken cancellationToken) => _context.Dispatches .Include(d => d.DispatchWorkOrders) .FirstOrDefaultAsync(d => d.Id == dispatchId, cancellationToken); public void DetachWorkOrderFromDispatch(Dispatch dispatch, int workOrderId) { var links = dispatch.DispatchWorkOrders? .Where(link => link.WorkOrderId == workOrderId) .ToList(); if (links == null || links.Count == 0) { links = _context.DispatchWorkOrders .Where(link => link.DispatchId == dispatch.Id && link.WorkOrderId == workOrderId) .ToList(); } foreach (var link in links) _context.DispatchWorkOrders.Remove(link); if (dispatch.WorkOrderId != workOrderId) return; var remainingIds = (dispatch.DispatchWorkOrders ?? Enumerable.Empty()) .Where(link => link.WorkOrderId != workOrderId) .Select(link => link.WorkOrderId) .Distinct() .ToList(); if (remainingIds.Count == 0) { dispatch.WorkOrderId = null; return; } var preferredOwnerId = _context.workOrders .Where(workOrder => remainingIds.Contains(workOrder.Id) && workOrder.PrimaryDispatchId == dispatch.Id) .Select(workOrder => (int?)workOrder.Id) .FirstOrDefault(); dispatch.WorkOrderId = preferredOwnerId ?? remainingIds[0]; } public void TrackNewWorkOrder(WorkOrder workOrder) => _context.workOrders.Add(workOrder); public void TrackNewDispatch(Dispatch dispatch) => _context.Dispatches.Add(dispatch); public void TrackWorkOrderContact(int workOrderId, int contactId, string? notes) => _context.WorkOrderContacts.Add(new WorkOrderContacts { WorkorderId = workOrderId, ContactId = contactId, Notes = notes }); public void SetExpectedWorkOrderVersion(WorkOrder workOrder, byte[] version) => _context.Entry(workOrder).Property(w => w.RowVersion).OriginalValue = version; public void SetExpectedDispatchVersion(Dispatch dispatch, byte[] version) => _context.Entry(dispatch).Property(d => d.RowVersion).OriginalValue = version; public bool HasPendingChanges() => _context.ChangeTracker.HasChanges(); public async Task ExecuteTransactionalAsync(Func work, CancellationToken cancellationToken) { await using var transaction = _context.Database.IsRelational() ? await _context.Database.BeginTransactionAsync(cancellationToken) : null; try { await work(cancellationToken); if (transaction is not null) await transaction.CommitAsync(cancellationToken); } catch { if (transaction is not null) await transaction.RollbackAsync(cancellationToken); throw; } } public async Task SaveAsync(CancellationToken cancellationToken) { try { await _context.SaveChangesAsync(cancellationToken); return BoardSaveOutcome.Saved; } catch (DbUpdateConcurrencyException) { _context.ChangeTracker.Clear(); return BoardSaveOutcome.ConcurrencyConflict; } } } }