using System.Text.Json; using AnalyticsDAL.DTO.PerfKPIFeed; using AnalyticsDAL.Query.PerfKPIFeed; using GB5Shared.DTO.Framework.Login; using GB5Shared.QueryExecutor; namespace AnalyticsDAL.CustomCode.PerfKPIFeed; public class PerfKPIFeedDAL : IPerfKPIFeedDAL { private readonly IQueryExecutor _qe; public PerfKPIFeedDAL(IQueryExecutor queryExecutor) => _qe = queryExecutor; public async Task IngestAppraisalScoreAsync(AppraisalScoreFinalizedEvent evt, LoginDTO login, CancellationToken ct) { var isDuplicate = await _qe.ExecuteScalarAsync( login, PerfKPIFeedQB.CHECK_DUPLICATE_FEED, new { FeedSourceType = (short)0, SourceId = evt.AppraisalId, EmployeeId = evt.EmployeeId, TenantId = evt.TenantId }, cancellationToken: ct).ConfigureAwait(false); if (isDuplicate > 0) return; await _qe.ExecuteAsync( login, PerfKPIFeedQB.INSERT_FEED, new { FeedSourceType = (short)0, SourceId = evt.AppraisalId, EmployeeId = evt.EmployeeId, OUId = evt.OUId, KPITypeCode = "APPRAISAL_SCORE", KPIValue = evt.FinalPercentage, GradeLetter = evt.GradeLetter, PeriodStart = evt.PerformanceFrom, PeriodEnd = evt.PerformanceTo, TenantId = evt.TenantId, CreatedById = evt.UserId }, cancellationToken: ct).ConfigureAwait(false); } public async Task IngestOKRCycleAsync(OKRCycleClosedEvent evt, LoginDTO login, CancellationToken ct) { var employeeStats = await _qe.QueryAsync( login, PerfKPIFeedQB.GET_OKR_EMPLOYEE_PROGRESS, new { OKRCycleId = evt.OKRCycleId, TenantId = evt.TenantId }, cancellationToken: ct).ConfigureAwait(false); foreach (var stat in employeeStats) { var isDuplicate = await _qe.ExecuteScalarAsync( login, PerfKPIFeedQB.CHECK_DUPLICATE_FEED, new { FeedSourceType = (short)1, SourceId = evt.OKRCycleId, EmployeeId = stat.EmployeeId, TenantId = evt.TenantId }, cancellationToken: ct).ConfigureAwait(false); if (isDuplicate > 0) continue; await _qe.ExecuteAsync( login, PerfKPIFeedQB.INSERT_FEED, new { FeedSourceType = (short)1, SourceId = evt.OKRCycleId, EmployeeId = stat.EmployeeId, OUId = stat.OUId, KPITypeCode = "OKR_COMPLETION", KPIValue = stat.AvgProgress, GradeLetter = (string?)null, PeriodStart = evt.CycleStart, PeriodEnd = evt.CycleEnd, TenantId = evt.TenantId, CreatedById = evt.UserId }, cancellationToken: ct).ConfigureAwait(false); } } public async Task GetFeedListAsync(short feedSourceType, int employeeId, DateTime periodFrom, DateTime periodTo, LoginDTO login, CancellationToken ct) { var list = await _qe.QueryAsync( login, PerfKPIFeedQB.GET_FEED_LIST, new { FeedSourceType = feedSourceType, EmployeeId = employeeId, PeriodFrom = periodFrom, PeriodTo = periodTo, TenantId = login.ClientId }, cancellationToken: ct).ConfigureAwait(false); return JsonSerializer.Serialize(list); } private sealed class OKREmployeeProgressRow { public int EmployeeId { get; set; } public int OUId { get; set; } public decimal AvgProgress { get; set; } } }