using System; using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using AdminDAL.CustomCode.AllocationType; using AdminDAL.CustomCode.BIZTransactionType; using AdminDAL.DTO.BIZTransactionType; using AdminDAL.DTO.InventorySetting; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.EntityHandler; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using Microsoft.Extensions.Logging; using static GB5Shared.GB5Constant.Constant; namespace AdminBLL.BIZTransactionType { public class BIZTransactionTypeBLL : IBIZTransactionTypeBLL { private readonly IBIZTransactionTypeDAL _BIZTransactionTypeDAL; private readonly AutoNumber _AutoNumber; private readonly IQueryExecutor _QueryExecutor; private readonly BaseEntityAppService _baseEntityAppService; private readonly ILogger _Logger; public BIZTransactionTypeBLL( IBIZTransactionTypeDAL IBIZTransactionTypeDAL, AutoNumber AutoNumber, IQueryExecutor queryExecutor, BaseEntityAppService baseEntityAppService, ILogger logger) { _BIZTransactionTypeDAL = IBIZTransactionTypeDAL; _AutoNumber = AutoNumber; _QueryExecutor = queryExecutor; _baseEntityAppService = baseEntityAppService; _Logger = logger; } public async Task GetSelectListBIZTransactionTypeBasedOnRights(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _BIZTransactionTypeDAL.GetSelectListBIZTransactionTypeBasedOnRights(CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } public async Task GetFormSettings(int MenuId, int BIZTransactionTypeId, LoginDTO LoginDTO) { try { return await _BIZTransactionTypeDAL.GetFormSettings(MenuId, BIZTransactionTypeId, LoginDTO); } catch (Exception) { throw; } } public async Task GetBizTransactionTypeList(CriteriaDTO CriteriaDTO, int OrganizationUnitId, LoginDTO LoginDTO) { try { return await _BIZTransactionTypeDAL.GetBizTransactionTypeList(CriteriaDTO, OrganizationUnitId, LoginDTO); } catch (Exception) { throw; } } public async Task GetBizTransactionTypeConfig(int BizTransactionTypeId, int StoreId, int TariffId, LoginDTO LoginDTO) { try { return await _BIZTransactionTypeDAL.GetBizTransactionTypeConfig(BizTransactionTypeId, StoreId, TariffId, LoginDTO); } catch (Exception) { throw; } } public async Task GetBizTransactionTypeSettings(int BizTransactionTypeId, LoginDTO LoginDTO, CancellationToken ct = default) { try { return await _BIZTransactionTypeDAL.GetBizTransactionTypeSettings(BizTransactionTypeId, LoginDTO, ct); } catch (Exception) { throw; } } public async Task> GetBIZTransactionType(int BIZTransactionTypeId, LoginDTO LoginDTO) { try { return await _BIZTransactionTypeDAL.GetBIZTransactionType(BIZTransactionTypeId, LoginDTO); } catch (Exception) { throw; } } // ── SaveBIZTransactionType ─────────────────────────────────────────────────── // // Mirrors GB4 BIZTransactionTypeBLL.SaveBIZTransactionTypeNew. Preserves: AutoNumber // generation for new records, the "Redmine 20969" duplicate guard (a new // BizTransaction/OU/Period combination can't already exist — checked against the LOGGED-IN // user's WorkOUId/WorkPeriodId, not the DTO's own OrganizationUnitId/PeriodId, exactly as // GB4 does), and audit-field population. // // NOT ported (genuine GB5 capability gaps — called out, not silently invented): // - GB4's AuthorizationFrameBLL.CheckUserRights(WebServiceConstant.ADMIN_BIZTRANSACTIONTYPE_SAVE, ...) // rights gate. No GB5 endpoint in this codebase currently performs this kind of // per-action rights check at the BLL/endpoint level (they all use AllowAnonymous()) — // consistent with every other already-migrated Save endpoint, not a gap unique to this one. // - GB4 explicitly saves "WithoutWorkFlow" (GenericDal.SaveWithoutWorkFlow / // SaveOrUpdateWithoutWorkFlow) for this entity. ExecuteSaveAsync's workflow step // naturally resolves to the equivalent no-op when no MWORKFLOWCONFIG row targets // OBJECTBIZTRANSACTIONTYPE — there is no explicit "skip workflow" switch to port because // GB5's pipeline doesn't have one; it depends on no workflow being configured for this // entity, matching the expected real-world configuration for master-data "type" entities. public async Task SaveBIZTransactionType(BIZTransactionTypeDTO dto, LoginDTO loginDTO, DbTransaction? sameTransaction = null, CancellationToken ct = default) { if (dto == null) throw new ArgumentNullException(nameof(dto)); bool isNew = dto.BIZTransactionTypeId == 0; bool isExternalTx = sameTransaction != null; var trans = sameTransaction ?? await _QueryExecutor.BeginTransactionAsync(loginDTO); try { if (isNew) { // ── AutoNumber ─────────────────────────────────────────────────── var autoNumber = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.BIZTRANSACTIONTYPE, loginDTO); dto.BIZTransactionTypeId = autoNumber.StartNumber; // ── Redmine 20969 duplicate guard (new records only) ──────────── var existingCount = await _BIZTransactionTypeDAL.CheckBizTransactionTypeExists( dto.BIZTransactionId, loginDTO.WorkOUId, loginDTO.WorkPeriodId, loginDTO, trans); if (existingCount != 0) { throw new InvalidOperationException( $"Already Biztransactiontype exists for the Biztransaction {dto.BIZTransactionName}"); } } // ── Audit fields (GB4: GenericDal.StandardFieldAssiging) ──────────── var now = DateTime.UtcNow; if (isNew) { dto.BIZTransactionTypeCreatedById = loginDTO.UserId; dto.BIZTransactionTypeCreatedOn = now; } dto.BIZTransactionTypeModifiedById = loginDTO.UserId; dto.BIZTransactionTypeModifiedOn = now; await _baseEntityAppService.ExecuteSaveAsync( EntityConstant.OBJECTBIZTRANSACTIONTYPE, EventTypeConstant.SAVEBIZTRANSACTIONTYPEEVENTTYPEID, dto, loginDTO, async tx => { return isNew ? await _BIZTransactionTypeDAL.SaveBIZTransactionType(dto, loginDTO, tx) : await _BIZTransactionTypeDAL.UpdateBIZTransactionType(dto, loginDTO, tx); }, null, -1, // GB4 saves this entity "WithoutWorkFlow" and with no BizTransactionClass concept of its own -1, trans, isNewEntity: isNew); if (!isExternalTx) await _QueryExecutor.CommitAsync(trans); _Logger.LogInformation( "BIZTransactionType {Action} — Id: {BIZTransactionTypeId}, Name: {BIZTransactionTypeName}", isNew ? "Created" : "Updated", dto.BIZTransactionTypeId, dto.BIZTransactionTypeName); return dto.BIZTransactionTypeId; } catch (Exception) { if (!isExternalTx) await _QueryExecutor.RollbackAsync(trans); throw; } } } }