using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.Login; using GB5Shared.EventLogPublish; using GB5Shared.Telemetry; using Microsoft.Extensions.Logging; using PERMBLL.Interfaces; using PERMDAL.Interfaces; using System.Text.Json; using static GB5Shared.GB5Constant.Constant; namespace PERMBLL.Implementations; public class AppraisalBLL : IAppraisalBLL { private readonly IAppraisalDAL _dal; private readonly IPermNotificationService _notification; private readonly KeyInvalidate _keyInvalidate; private readonly EventLogPublish _eventLog; private readonly ILogger _logger; public AppraisalBLL( IAppraisalDAL dal, IPermNotificationService notification, KeyInvalidate keyInvalidate, EventLogPublish eventLog, ILogger logger) { _dal = dal; _notification = notification; _keyInvalidate = keyInvalidate; _eventLog = eventLog; _logger = logger; } public async Task GetAppraisalAsync(int appraisalId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-appraisal", new { appraisalId }); var dto = await _dal.GetAppraisalAsync(appraisalId, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(dto); } catch (Exception ex) { GB5Trace.MarkFailed("get-appraisal-failed", ex); _logger.LogError(ex, "GetAppraisal failed for AppraisalId {AppraisalId}", appraisalId); throw; } } public async Task GetAppraisalListAsync( int planId, int ouId, short? status, int page, int pageSize, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-appraisal-list", new { planId, ouId, status, page }); var list = await _dal.GetAppraisalListAsync(planId, ouId, status, page, pageSize, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(list); } catch (Exception ex) { GB5Trace.MarkFailed("get-appraisal-list-failed", ex); _logger.LogError(ex, "GetAppraisalList failed for PlanId {PlanId}", planId); throw; } } public async Task SubmitAppraisalAsync(int appraisalId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("submit-appraisal", new { appraisalId }); int rows = await _dal.UpdateAppraisalStatusAsync(appraisalId, 1, 0, login, ct).ConfigureAwait(false); if (rows == 0) return "Appraisal not found or not in Pending status."; GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.SUBMITPERMAPPRAISALEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "Appraisal Submitted", new { AppraisalId = appraisalId }, EventTypeConstant.SUBMITPERMAPPRAISALEVENTTYPEID, appraisalId, login, ct: ct).ConfigureAwait(false); return GB5Shared.Resource.Response.SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("submit-appraisal-failed", ex); _logger.LogError(ex, "SubmitAppraisal failed for AppraisalId {AppraisalId}", appraisalId); throw; } } public async Task AcceptAppraisalAsync(int appraisalId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("accept-appraisal", new { appraisalId }); int rows = await _dal.UpdateAppraisalStatusAsync(appraisalId, 2, 1, login, ct).ConfigureAwait(false); if (rows == 0) return "Appraisal not found or not in Submitted status."; GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.ACCEPTPERMAPPRAISALEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "Appraisal Accepted", new { AppraisalId = appraisalId }, EventTypeConstant.ACCEPTPERMAPPRAISALEVENTTYPEID, appraisalId, login, ct: ct).ConfigureAwait(false); try { int empId = await _dal.GetAppraisalOwnerIdAsync(appraisalId, login, ct).ConfigureAwait(false); if (empId > 0) await _notification.NotifyAppraisalStatusChangedAsync(appraisalId, empId, 2, login, ct).ConfigureAwait(false); } catch (Exception notifyEx) { GB5Trace.MarkFailed("notify-accept-failed", notifyEx); _logger.LogWarning(notifyEx, "SignalR notification failed for accepted appraisal {AppraisalId}", appraisalId); } return GB5Shared.Resource.Response.SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("accept-appraisal-failed", ex); _logger.LogError(ex, "AcceptAppraisal failed for AppraisalId {AppraisalId}", appraisalId); throw; } } public async Task RejectAppraisalAsync(int appraisalId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("reject-appraisal", new { appraisalId }); int rows = await _dal.UpdateAppraisalStatusAsync(appraisalId, 3, 1, login, ct).ConfigureAwait(false); if (rows == 0) return "Appraisal not found or not in Submitted status."; GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.REJECTPERMAPPRAISALEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "Appraisal Rejected", new { AppraisalId = appraisalId }, EventTypeConstant.REJECTPERMAPPRAISALEVENTTYPEID, appraisalId, login, ct: ct).ConfigureAwait(false); try { int empId = await _dal.GetAppraisalOwnerIdAsync(appraisalId, login, ct).ConfigureAwait(false); if (empId > 0) await _notification.NotifyAppraisalStatusChangedAsync(appraisalId, empId, 3, login, ct).ConfigureAwait(false); } catch (Exception notifyEx) { GB5Trace.MarkFailed("notify-reject-failed", notifyEx); _logger.LogWarning(notifyEx, "SignalR notification failed for rejected appraisal {AppraisalId}", appraisalId); } return GB5Shared.Resource.Response.SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("reject-appraisal-failed", ex); _logger.LogError(ex, "RejectAppraisal failed for AppraisalId {AppraisalId}", appraisalId); throw; } } }