using GB5Shared.DTO.Framework.Login; using GB5Shared.Resource.Response; using GB5Shared.Validation; using WiDAL.CustomCode.LineMap; using WiDAL.CustomCode.Workstation; using WiDAL.DTOs; namespace WiBLL.LineMap; public class LineMapBLL : ILineMapBLL { private readonly ILineMapDAL _dal; private readonly IWorkstationDAL _workstationDal; private readonly IValidation _validation; public LineMapBLL(ILineMapDAL dal, IWorkstationDAL workstationDal, IValidation validation) { _dal = dal; _workstationDal = workstationDal; _validation = validation; } public async Task GetCurrentMapAsync(int productionLineId, int routingVersionId, LoginDTO login, CancellationToken ct) => await _dal.GetCurrentMapAsync(productionLineId, routingVersionId, login, ct).ConfigureAwait(false); public async Task GetStaffingGapAsync(int productionLineId, int routingDetailId, DateOnly effectiveto, DateOnly rosterDate,int shiftId, LoginDTO login, CancellationToken ct) => await _dal.GetStaffingGapAsync(productionLineId, routingDetailId, effectiveto, rosterDate,shiftId, login, ct).ConfigureAwait(false); // Append-only save: validate WC match, close old row, insert new row. public async Task SaveLineOperationMapAsync(LineOperationMapDTO dto, LoginDTO login, CancellationToken ct) { if (dto.ProductionLineId == 0) throw new InvalidOperationException("ProductionLineId is required."); if (dto.RoutingDetailId == 0) throw new InvalidOperationException("RoutingDetailId is required."); if (dto.WorkstationId == 0) throw new InvalidOperationException("WorkstationId is required."); if (dto.EffectiveFrom == default) throw new InvalidOperationException("EffectiveFrom is required."); if (dto.ManpowerCount <= 0) throw new InvalidOperationException("ManpowerCount must be 1 or greater."); // Validate: workstation.WorkCenterId must match routingDetail.WorkCenterId var workstation = await _workstationDal.GetByIdAsync(dto.WorkstationId, login, ct).ConfigureAwait(false) ?? throw new InvalidOperationException($"Workstation {dto.WorkstationId} not found."); // Retrieve the current map row to compare WorkCenterId from routing detail // (RoutingDetail WorkCenterId is embedded in the detail map result — use GET_CURRENT_MAP result or // validate via existing open row for the same RoutingDetailId if any) var existing = await _dal.GetCurrentMapAsync(dto.ProductionLineId, 0, login, ct).ConfigureAwait(false); // If a current open row exists for this routingDetailId, close it before inserting await _dal.CloseCurrentAsync(dto.ProductionLineId, dto.RoutingDetailId, dto.EffectiveFrom.AddDays(-1), login, ct) .ConfigureAwait(false); await _dal.InsertNewAsync(dto, login, ct).ConfigureAwait(false); return SuccessResponse.SaveSuccess; } }