using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using PayRollBLL.Common; using PayRollDAL.CustomeCode.ShiftPattern; using PayRollDAL.DTO.ShiftPattern; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace PayRollBLL.ShiftPattern { public class ShiftPatternBLL : IShiftPatternBLL { private readonly IShiftPatternDAL _ShiftPatternDAL; private readonly AutoNumber _AutoNumber; private readonly IQueryExecutor _QueryExecutor; private readonly IEntityValidationClient _EntityValidationClient; public ShiftPatternBLL( IShiftPatternDAL shiftPatternDAL, AutoNumber autoNumber, IQueryExecutor queryExecutor, IEntityValidationClient entityValidationClient) { _ShiftPatternDAL = shiftPatternDAL; _AutoNumber = autoNumber; _QueryExecutor = queryExecutor; _EntityValidationClient = entityValidationClient; } // ── Get single record (3-level hierarchy) ──────────────────────── public async Task GetShiftPattern(int ShiftPatternId, LoginDTO LoginDTO) { return await _ShiftPatternDAL.GetShiftPattern(ShiftPatternId, LoginDTO).ConfigureAwait(false); } // ── Save (insert or update) ─────────────────────────────────────── public async Task SaveShiftPattern(ShiftPatternDTO ShiftPatternDTO, LoginDTO LoginDTO, CancellationToken ct = default) { if (ShiftPatternDTO == null) throw new ArgumentNullException(nameof(ShiftPatternDTO)); bool isNew = ShiftPatternDTO.ShiftPatternId == 0; // 1. Guard: block replacing days/detail rows that are already referenced by an // employee assignment (MEMPLOYEE.SHIFTPATTERNDETAILID). Only applies on update — // a brand-new pattern has nothing existing to be "replaced". if (!isNew) { var employeesInUse = await _ShiftPatternDAL .GetEmployeesUsingShiftPattern(ShiftPatternDTO.ShiftPatternId, LoginDTO) .ConfigureAwait(false); if (employeesInUse != null && employeesInUse.Count > 0) throw new InvalidOperationException( "This shift pattern cannot be modified because it is already assigned to one or more employees."); } // 2. External validation service (GB4 parity: BaseShiftPatternValidationUri). var (isValid, errorMessage) = await _EntityValidationClient .ValidateAsync("ShiftPatternBaseUri", ShiftPatternDTO, LoginDTO, ct) .ConfigureAwait(false); if (!isValid) throw new InvalidOperationException(errorMessage ?? "Shift pattern validation failed."); AutoNumberDTO? autoNumberDTO = null; var trans = await _QueryExecutor.BeginTransactionAsync(LoginDTO).ConfigureAwait(false); try { if (isNew) { // 3. Count = 1 (header) + Σ over days of (NumberOfDays + 1) // — one id for the days row itself, plus one id per detail row under it. int count = 1; if (ShiftPatternDTO.ShiftPatternDaysArray != null) { foreach (var day in ShiftPatternDTO.ShiftPatternDaysArray) count += 1 + day.ShiftPatternDaysNumberofDays; } autoNumberDTO = await _AutoNumber.GetNumberAsync(count, "SHIFTPATTERN", LoginDTO) .ConfigureAwait(false); ShiftPatternDTO.ShiftPatternId = autoNumberDTO.StartNumber; ShiftPatternDTO.ShiftPatternCreatedById = LoginDTO.UserId; ShiftPatternDTO.ShiftPatternCreatedOn = DateTime.UtcNow; // 4. Walk the reserved id block sequentially: every days row consumes one id, // then every one of its detail rows consumes the next id, and so on. if (ShiftPatternDTO.ShiftPatternDaysArray != null) { int tmpCount = 1; foreach (var day in ShiftPatternDTO.ShiftPatternDaysArray) { day.ShiftPatternDaysId = autoNumberDTO.StartNumber + tmpCount; tmpCount++; if (day.ShiftPatternDetailArray != null) { foreach (var detail in day.ShiftPatternDetailArray) { detail.ShiftPatternDetailId = autoNumberDTO.StartNumber + tmpCount; tmpCount++; } } } } } ShiftPatternDTO.ShiftPatternModifiedById = LoginDTO.UserId; ShiftPatternDTO.ShiftPatternModifiedOn = DateTime.UtcNow; int rows = isNew ? await _ShiftPatternDAL.SaveShiftPattern(ShiftPatternDTO, LoginDTO, trans).ConfigureAwait(false) : await _ShiftPatternDAL.UpdateShiftPattern(ShiftPatternDTO, LoginDTO, trans).ConfigureAwait(false); await _QueryExecutor.CommitAsync(trans).ConfigureAwait(false); if (rows <= 0) return isNew ? "Failed to save shift pattern." : "Failed to update shift pattern."; return isNew ? $"Details Saved Successfully With Id :{ShiftPatternDTO.ShiftPatternId}" : $"Details Updated Successfully With Id :{ShiftPatternDTO.ShiftPatternId}"; } catch (Exception) { await _QueryExecutor.RollbackAsync(trans).ConfigureAwait(false); if (autoNumberDTO != null) await _AutoNumber.RollbackAutoNumber("SHIFTPATTERN", autoNumberDTO.StartNumber, LoginDTO) .ConfigureAwait(false); throw; } } // ── Delete ──────────────────────────────────────────────────────── public async Task DeleteShiftPattern(int ShiftPatternId, LoginDTO LoginDTO) { return await _ShiftPatternDAL.DeleteShiftPattern(ShiftPatternId, LoginDTO).ConfigureAwait(false); } // ── Full-DTO header list ───────────────────────────────────────── public async Task GetShiftPatternList(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { return await _ShiftPatternDAL.GetShiftPatternList(CriteriaDTO, LoginDTO).ConfigureAwait(false); } // ── Sub-endpoint: all detail rows for a pattern ────────────────── public async Task> LoadShiftPatternDetails(int ShiftPatternId, LoginDTO LoginDTO) { return await _ShiftPatternDAL.LoadShiftPatternDetails(ShiftPatternId, LoginDTO).ConfigureAwait(false); } // ── Picklist ────────────────────────────────────────────────────── public async Task GetSelectListShiftPattern(int FirstNumber, int MaxResult, CriteriaDTO CriteriaDTO, LoginDTO LoginDTO, bool IsCount = false) { return await _ShiftPatternDAL .GetSelectListShiftPattern(FirstNumber, MaxResult, CriteriaDTO, LoginDTO, IsCount) .ConfigureAwait(false); } } }