using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GB5Shared.Validation; using PayRollDAL.CustomeCode.EmployeeTransfer; using PayRollDAL.DTO.EmployeeTransfer; using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; namespace PayRollBLL.EmployeeTransfer { public class EmployeeTransferBLL : IEmployeeTransferBLL { private readonly IEmployeeTransferDAL _employeeTransferDAL; private readonly AutoNumber _autoNumber; private readonly IValidation _validation; public EmployeeTransferBLL( IEmployeeTransferDAL employeeTransferDAL, AutoNumber autoNumber, IValidation validation) { _employeeTransferDAL = employeeTransferDAL; _autoNumber = autoNumber; _validation = validation; } public async Task GetEmployeeTransfer(int employeeTransferId, LoginDTO loginDTO) { try { return await _employeeTransferDAL.GetEmployeeTransfer(employeeTransferId, loginDTO); } catch (Exception) { throw; } } // Save (insert or update) — branches on EmployeeTransferId being 0 (new). // // TEMPLOYEETRANSFERDETAIL.EMPLOYEETRANSFERDETAILID is application-assigned (GB4 // NHibernate generator="assigned", not IDENTITY), so detail rows need their own // autonumber allocation too — not just the header. On update, existing detail rows // are always deleted and re-inserted (see EmployeeTransferDAL.UpdateEmployeeTransfer), // so fresh detail ids are allocated there as well. // // A single autonumber call is made per save (count = 1 + detailCount for a new header, // or just detailCount for an update) so a single RollbackAutoNumber call can undo the // whole allocation on failure — RollbackAutoNumber only reverts the most recent block. public async Task SaveEmployeeTransfer(EmployeeTransferDTO employeeTransferDTO, LoginDTO loginDTO) { if (employeeTransferDTO == null) throw new ArgumentNullException(nameof(employeeTransferDTO)); AutoNumberDTO? autoNumberDTO = null; try { await _validation.NotEmpty(employeeTransferDTO.EmployeeTransferTransferNumber, nameof(employeeTransferDTO.EmployeeTransferTransferNumber)); int detailCount = employeeTransferDTO.EmployeeTransferDetailArray?.Count ?? 0; employeeTransferDTO.EmployeeTransferModifiedById = loginDTO.UserId; employeeTransferDTO.EmployeeTransferModifiedOn = DateTime.UtcNow; bool isNew = employeeTransferDTO.EmployeeTransferId == 0; if (isNew) { autoNumberDTO = await _autoNumber.GetAutoNumber(1 + detailCount, "EmployeeTransfer", loginDTO); employeeTransferDTO.EmployeeTransferId = autoNumberDTO.StartNumber; employeeTransferDTO.EmployeeTransferCreatedById = loginDTO.UserId; employeeTransferDTO.EmployeeTransferCreatedOn = DateTime.UtcNow; AssignDetailIds(employeeTransferDTO, autoNumberDTO.StartNumber + 1); ApplyDateStringFormats(employeeTransferDTO); await _employeeTransferDAL.SaveEmployeeTransfer(employeeTransferDTO, loginDTO); return $"{SuccessResponse.SaveSuccessMessage} {employeeTransferDTO.EmployeeTransferId}"; } else { if (detailCount > 0) { autoNumberDTO = await _autoNumber.GetAutoNumber(detailCount, "EmployeeTransfer", loginDTO); AssignDetailIds(employeeTransferDTO, autoNumberDTO.StartNumber); } ApplyDateStringFormats(employeeTransferDTO); await _employeeTransferDAL.UpdateEmployeeTransfer(employeeTransferDTO, loginDTO); return $"{SuccessResponse.UpdateSuccessMessage} {employeeTransferDTO.EmployeeTransferId}"; } } catch (ValidationException vex) { throw new Exception(vex.Message); } catch (Exception) { if (autoNumberDTO != null) { await _autoNumber.RollbackAutoNumber("EmployeeTransfer", autoNumberDTO.StartNumber, loginDTO); } throw; } } public async Task DeleteEmployeeTransfer(int employeeTransferId, LoginDTO loginDTO) { try { return await _employeeTransferDAL.DeleteEmployeeTransfer(employeeTransferId, loginDTO); } catch (Exception) { throw; } } public async Task GetSelectListEmployeeTransfer( int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO loginDTO, bool isCount = false) { try { return await _employeeTransferDAL.GetSelectListEmployeeTransfer(firstNumber, maxResult, criteriaDTO, loginDTO, isCount); } catch (Exception) { throw; } } public async Task GetEmployeeTransferList( int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO loginDTO, bool isCount = false) { try { return await _employeeTransferDAL.GetEmployeeTransferListAsync(firstNumber, maxResult, criteriaDTO, loginDTO, isCount); } catch (Exception) { throw; } } // ── Helpers ──────────────────────────────────────────────────────── private static void AssignDetailIds(EmployeeTransferDTO dto, int startId) { if (dto.EmployeeTransferDetailArray == null || dto.EmployeeTransferDetailArray.Count == 0) return; int id = startId; int slNo = 1; foreach (EmployeeTransferDetailDTO detail in dto.EmployeeTransferDetailArray) { detail.EmployeeTransferDetailId = id++; detail.EmployeeTransferId = dto.EmployeeTransferId; detail.EmployeeTransferDetailSlNo = slNo++; } } private static void ApplyDateStringFormats(EmployeeTransferDTO dto) { if (dto.EmployeeTransferTransferDate != default) dto.EmployeeTransferTransferDateStringFormat = dto.EmployeeTransferTransferDate.ToString("dd-MMM-yyyy"); if (dto.EmployeeTransferEffectiveFrom != default) dto.EmployeeTransferEffectiveFromStringFormat = dto.EmployeeTransferEffectiveFrom.ToString("dd-MMM-yyyy"); } } }