using System; using System.Threading; using System.Threading.Tasks; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Promotion; using GB5Shared.Promotion; using Newtonsoft.Json; using WiBLL.WiProcess; using WiDAL.CustomCode.Promotion; using WiDAL.DTOs; namespace WiBLL.Promotion { // ============================================================ // WiProcessPromotionAdapter — IPromotableEntity for MWIPROCESS ("WIPROCESS"). No child rows of // its own. Natural key WiProcessCode (UK_MWIPROCESS_WIPROCESSCODE_TENANTID, a real unique // constraint, confirmed via schema). DepartmentId/DepartmentCode resolved via the new // IDepartmentCodeLookupDAL (small, dedicated lookup against MDEPARTMENT directly — Admin, the // owning module, lives in a separate Host process entirely, same reasoning as every other // cross-module code lookup this session). // // Registered locally inside WiModule (this module's own process, EngagementHost) — reached from // FrameworkBLL's RemoteHttpPromotionAdapter over HTTP via the PromotionBridge endpoints in // WiSL/Endpoints/Promotion. See GB5Shared/DTO/Promotion/PromotionBridgeDTOs.cs. // ============================================================ public class WiProcessPromotionAdapter : IPromotableEntity { public string EntityTypeCode => "WIPROCESS"; private readonly IWiProcessBLL _WiProcessBLL; private readonly IDepartmentCodeLookupDAL _DepartmentCodeLookup; private readonly IWiProcessCodeLookupDAL _WiProcessCodeLookup; public WiProcessPromotionAdapter( IWiProcessBLL wiProcessBLL, IDepartmentCodeLookupDAL departmentCodeLookup, IWiProcessCodeLookupDAL wiProcessCodeLookup) { _WiProcessBLL = wiProcessBLL; _DepartmentCodeLookup = departmentCodeLookup; _WiProcessCodeLookup = wiProcessCodeLookup; } private class PortablePayload { public string WiProcessCode { get; set; } = string.Empty; public string WiProcessName { get; set; } = string.Empty; public string? DepartmentCode { get; set; } public short DisplayOrder { get; set; } public string? Description { get; set; } public int IsActive { get; set; } public short SortOrder { get; set; } = 9999; } public async Task ExportForPromotionAsync( int originEntityId, LoginDTO login, CancellationToken ct) { var json = await _WiProcessBLL.GetById(originEntityId, login, ct).ConfigureAwait(false); var dto = JsonConvert.DeserializeObject(json) ?? throw new InvalidOperationException($"WiProcess {originEntityId} not found."); string? departmentCode = dto.DepartmentCode; if (string.IsNullOrWhiteSpace(departmentCode) && dto.DepartmentId != 0) { departmentCode = await _DepartmentCodeLookup.GetDepartmentCodeById(dto.DepartmentId, login, ct) .ConfigureAwait(false) ?? throw new InvalidOperationException( $"WiProcess {originEntityId} references DepartmentId {dto.DepartmentId}, which has no DepartmentCode — cannot promote."); } var payload = new PortablePayload { WiProcessCode = dto.WiProcessCode, WiProcessName = dto.WiProcessName, DepartmentCode = departmentCode, DisplayOrder = dto.DisplayOrder, Description = dto.Description, IsActive = dto.IsActive, SortOrder = dto.SortOrder }; return new PromotionBundleDTO { EntityTypeCode = EntityTypeCode, OriginEntityId = originEntityId, PayloadJson = System.Text.Json.JsonSerializer.Serialize(payload) }; } public Task ValidateForPromotionAsync( PromotionBundleDTO bundle, CancellationToken ct) { var payload = System.Text.Json.JsonSerializer.Deserialize(bundle.PayloadJson); if (payload is null) return Task.FromResult(PromotionValidationResultDTO.Block("WiProcess payload could not be parsed.")); var reasons = new System.Collections.Generic.List(); if (string.IsNullOrWhiteSpace(payload.WiProcessCode)) reasons.Add("WiProcess.WiProcessCode is required to promote."); if (string.IsNullOrWhiteSpace(payload.DepartmentCode)) reasons.Add("WiProcess.DepartmentId has no resolvable DepartmentCode — cannot promote."); var result = reasons.Count == 0 ? PromotionValidationResultDTO.Ok() : new PromotionValidationResultDTO { IsPromotable = false, BlockingReasons = reasons }; return Task.FromResult(result); } public async Task ImportPromotedAsync( PromotionBundleDTO bundle, byte destinationSourceType, int? existingDestinationId, LoginDTO login, CancellationToken ct) { var payload = System.Text.Json.JsonSerializer.Deserialize(bundle.PayloadJson) ?? throw new InvalidOperationException("WiProcess promotion payload could not be parsed."); var departmentId = -1; if (!string.IsNullOrWhiteSpace(payload.DepartmentCode)) { departmentId = await _DepartmentCodeLookup.GetDepartmentIdByCode(payload.DepartmentCode, login, ct) .ConfigureAwait(false) ?? throw new InvalidOperationException( $"No Department with DepartmentCode '{payload.DepartmentCode}' exists at this destination."); } var resolvedId = existingDestinationId ?? await _WiProcessCodeLookup.GetWiProcessIdByCode(payload.WiProcessCode, login, ct).ConfigureAwait(false) ?? 0; var dto = new WiProcessDTO { WiProcessId = resolvedId, WiProcessCode = payload.WiProcessCode, WiProcessName = payload.WiProcessName, DepartmentId = departmentId, DisplayOrder = payload.DisplayOrder, Description = payload.Description, IsActive = payload.IsActive, SortOrder = payload.SortOrder, SourceType = destinationSourceType }; await _WiProcessBLL.Save(dto, login, ct).ConfigureAwait(false); return dto.WiProcessId; // mutated in place by Save when isNew } } }