using System.Collections.Generic; using System.Text.Json; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Qualifier; using GB5Shared.FastEndPoint; using GB5Shared.GOP.Qualifier; using static GB5Shared.GB5Constant.Constant; namespace FrameworkSL.Endpoints.GOP.Qualifier { // ============================================================ // GetEnrichedDetail — generic, on-demand qualifier enrichment for // the Entity Viewer: "does entity X have any display-time qualifiers // configured, and if so, what extra fields do they produce for this // instance?" // // Same QualifierExecutionContext/IQualifierFacadeImpl call shape as // QualifierNodeExecutor (GOP pipeline), Stage=9 (OnDemand) instead of // the pipeline's Stage=1, Scope=6 (UI) instead of Stage=1's Scope=1 — // the two documented-but-previously-unused convention values that // exist for exactly this purpose. // // No Document payload — this is a pure instance lookup by EntityId; // any DataSource-mode qualifier method reads @EntityId directly (see // DataSourceExecutor, already binds ctx.EntityId as a query parameter). // // Single call, empty-if-none: QualifierFacadeImpl.ExecuteStageAsync // already returns Success([], ...) instantly when zero bindings exist // for (EntityCode, Stage, Scope) — no separate "has qualifiers?" probe // needed. // ============================================================ public class GetEnrichedDetail : BaseEndpoint> { private const byte StageOnDemand = 9; private const byte ScopeUi = 6; private readonly IQualifierFacadeImpl _QualifierFacade; public GetEnrichedDetail(IQualifierFacadeImpl qualifierFacade) => _QualifierFacade = qualifierFacade; public override void Configure() { Get("/Qualifier/GetEnrichedDetail"); AllowAnonymous(); } public record Params( [property: QueryParam] string EntityCode, [property: QueryParam] int EntityId, [property: FromHeader] string Login ); // No caching — this is meant to reflect live, current qualifier output. protected override string? GetCacheKey(Params req, LoginDTO loginDTO) => null; protected override async Task> ExecuteAsync( Params req, LoginDTO loginDTO, CancellationToken ct) { try { var ctx = new QualifierExecutionContext { ClientId = loginDTO.ClientId, EntityId = req.EntityId, EntityCode = req.EntityCode, Stage = StageOnDemand, Scope = ScopeUi, Document = JsonDocument.Parse("{}"), Facts = new QualifierFactBag(), CorrelationId = req.EntityId.ToString(), CancellationToken = ct }; var result = await _QualifierFacade.ExecuteStageAsync(ctx, loginDTO, ct); var enriched = result.Facts.TryGetValue("Document", out var doc) && doc is IReadOnlyDictionary docFacts ? docFacts : new Dictionary(); return await GB5Shared.ResponseStandard.Response .CreateSuccessResponse(enriched, CacheKeyLevel.NOT_REQUIRED, loginDTO); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response .CreateExceptionError(ex, CacheKeyLevel.NOT_REQUIRED, loginDTO, ex.Message, 500); } } } }