using Microsoft.EntityFrameworkCore; using ZB.MOM.WW.OtOpcUa.Configuration; using ZB.MOM.WW.OtOpcUa.Configuration.Entities; using ZB.MOM.WW.OtOpcUa.Configuration.Validation; namespace ZB.MOM.WW.OtOpcUa.Admin.Services; /// /// Equipment CRUD scoped to a generation. The Admin app writes against Draft generations only; /// Published generations are read-only (to create changes, clone to a new draft via /// ). /// public sealed class EquipmentService(OtOpcUaConfigDbContext db) { public Task> ListAsync(long generationId, CancellationToken ct) => db.Equipment.AsNoTracking() .Where(e => e.GenerationId == generationId) .OrderBy(e => e.Name) .ToListAsync(ct); public Task FindAsync(long generationId, string equipmentId, CancellationToken ct) => db.Equipment.AsNoTracking() .FirstOrDefaultAsync(e => e.GenerationId == generationId && e.EquipmentId == equipmentId, ct); /// /// Creates a new equipment row in the given draft. The EquipmentId is auto-derived from /// a fresh EquipmentUuid per decision #125; operator-supplied IDs are rejected upstream. /// public async Task CreateAsync(long draftId, Equipment input, CancellationToken ct) { input.GenerationId = draftId; input.EquipmentUuid = input.EquipmentUuid == Guid.Empty ? Guid.NewGuid() : input.EquipmentUuid; input.EquipmentId = DraftValidator.DeriveEquipmentId(input.EquipmentUuid); db.Equipment.Add(input); await db.SaveChangesAsync(ct); return input; } public async Task UpdateAsync(Equipment updated, CancellationToken ct) { // Only editable fields are persisted; EquipmentId + EquipmentUuid are immutable once set. var existing = await db.Equipment .FirstOrDefaultAsync(e => e.EquipmentRowId == updated.EquipmentRowId, ct) ?? throw new InvalidOperationException($"Equipment row {updated.EquipmentRowId} not found"); existing.Name = updated.Name; existing.MachineCode = updated.MachineCode; existing.ZTag = updated.ZTag; existing.SAPID = updated.SAPID; existing.Manufacturer = updated.Manufacturer; existing.Model = updated.Model; existing.SerialNumber = updated.SerialNumber; existing.HardwareRevision = updated.HardwareRevision; existing.SoftwareRevision = updated.SoftwareRevision; existing.YearOfConstruction = updated.YearOfConstruction; existing.AssetLocation = updated.AssetLocation; existing.ManufacturerUri = updated.ManufacturerUri; existing.DeviceManualUri = updated.DeviceManualUri; existing.DriverInstanceId = updated.DriverInstanceId; existing.DeviceId = updated.DeviceId; existing.UnsLineId = updated.UnsLineId; existing.EquipmentClassRef = updated.EquipmentClassRef; existing.Enabled = updated.Enabled; await db.SaveChangesAsync(ct); } public async Task DeleteAsync(Guid equipmentRowId, CancellationToken ct) { var row = await db.Equipment.FirstOrDefaultAsync(e => e.EquipmentRowId == equipmentRowId, ct); if (row is null) return; db.Equipment.Remove(row); await db.SaveChangesAsync(ct); } }