using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using Newtonsoft.Json; using PayRollDAL.CustomeCode.GateEntry; using PayRollDAL.DTO.GateEntry; using System; using System.Collections.Generic; using System.Threading.Tasks; using static GB5Shared.GB5Constant.Constant; namespace PayRollBLL.GateEntry { public class GateEntryBLL : IGateEntryBLL { private readonly IGateEntryDAL _GateEntryDAL; private readonly AutoNumber _AutoNumber; private readonly VoucherNumberService _VoucherNumberService; private readonly IQueryExecutor _QueryExecutor; public GateEntryBLL( IGateEntryDAL gateEntryDAL, AutoNumber autoNumber, VoucherNumberService voucherNumberService, IQueryExecutor queryExecutor) { _GateEntryDAL = gateEntryDAL; _AutoNumber = autoNumber; _VoucherNumberService = voucherNumberService; _QueryExecutor = queryExecutor; } // ── Get single record ───────────────────────────────────────────── public async Task GetGateEntry(int gateEntryId, LoginDTO loginDTO) { return await _GateEntryDAL.GetGateEntry(gateEntryId, loginDTO).ConfigureAwait(false); } // ── Save (insert or update) ─────────────────────────────────────── // Transaction is managed here in BLL so that the VNO counter increment // and the entity INSERT share the same transaction — matching GB4's // VnoGenerationDLL.GetNextVno() behaviour: rollback reverts both the // number counter and the entity row, so the same number is regenerated // on retry instead of being skipped. public async Task SaveGateEntry(GateEntryDTO gateEntryDTO, LoginDTO loginDTO) { if (gateEntryDTO == null) throw new ArgumentNullException(nameof(gateEntryDTO)); bool isNew = gateEntryDTO.GateEntryId == 0; AutoNumberDTO? autoNumberDTO = null; var trans = await _QueryExecutor.BeginTransactionAsync(loginDTO).ConfigureAwait(false); try { if (isNew) { // Application-generated header ID; detail IDs are IDENTITY (DB-generated) autoNumberDTO = await _AutoNumber.GetNumberAsync(1, "GATEENTRY", loginDTO) .ConfigureAwait(false); gateEntryDTO.GateEntryId = autoNumberDTO.StartNumber; gateEntryDTO.GateEntryCreatedById = loginDTO.UserId; gateEntryDTO.GateEntryCreatedOn = DateTime.UtcNow; // Always auto-generate GateEntryNumber using the fixed GateEntry series. // Uses WebServiceConstant.PRSGATEENTRYSAVE (-1399999832) — the MBIZTRANSACTIONTYPE // record seeded for GateEntry — NOT the entity's BIZTransactionTypeId, which is // a different FK (the gate entry type: IN/OUT/Purchase/etc., can be -1 for NONE). // Generating inside the shared transaction matches GB4's VnoGenerationDLL behaviour: // rollback reverts the counter so the same number is re-issued on retry. string? generatedNumber = await _VoucherNumberService .GetNextVoucherNumberAsync( gateEntryDTO.BIZTransactionTypeId, gateEntryDTO.GateEntryDate, loginDTO, transaction: trans) .ConfigureAwait(false); if (generatedNumber != null) gateEntryDTO.GateEntryNumber = generatedNumber; gateEntryDTO.GateEntryModifiedById = loginDTO.UserId; gateEntryDTO.GateEntryModifiedOn = DateTime.UtcNow; } else { gateEntryDTO.GateEntryModifiedById = loginDTO.UserId; gateEntryDTO.GateEntryModifiedOn = DateTime.UtcNow; } int rows = isNew ? await _GateEntryDAL.SaveGateEntry(gateEntryDTO, loginDTO, trans).ConfigureAwait(false) : await _GateEntryDAL.UpdateGateEntry(gateEntryDTO, loginDTO, trans).ConfigureAwait(false); await _QueryExecutor.CommitAsync(trans).ConfigureAwait(false); if (rows <= 0) return isNew ? "Failed to save gate entry." : "Failed to update gate entry."; return isNew ? "Details saved successfully." : "Details updated successfully."; } catch (Exception) { await _QueryExecutor.RollbackAsync(trans).ConfigureAwait(false); // AutoNumber counter is auto-committed, roll it back separately if (autoNumberDTO != null) await _AutoNumber.RollbackAutoNumber("GATEENTRY", autoNumberDTO.StartNumber, loginDTO) .ConfigureAwait(false); throw; } } // ── Delete ──────────────────────────────────────────────────────── public async Task DeleteGateEntry(int gateEntryId, LoginDTO loginDTO) { int rows = await _GateEntryDAL.DeleteGateEntry(gateEntryId, loginDTO).ConfigureAwait(false); return rows > 0 ? "Details deleted successfully." : "Gate entry not found or already deleted."; } // ── Picklist ────────────────────────────────────────────────────── public async Task GetSelectListGateEntry( int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO loginDTO) { return await _GateEntryDAL .GetSelectListGateEntry(firstNumber, maxResult, criteriaDTO, loginDTO) .ConfigureAwait(false); } // ── Resolve raw scanner input → fully-formed detail JSON ────────── public async Task ResolveGateEntryDetails( List inputs, LoginDTO loginDTO) { if (inputs == null || inputs.Count == 0) return JsonConvert.SerializeObject(new List()); var results = await _GateEntryDAL .ResolveGateEntryDetails(inputs, loginDTO) .ConfigureAwait(false); return JsonConvert.SerializeObject(results); } } }