mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-01 09:53:15 +00:00
77 lines
3.4 KiB
C#
77 lines
3.4 KiB
C#
|
|
using System.Security.Claims;
|
||
|
|
using Data.SeaHavenIndustries;
|
||
|
|
using SeaHaven.DataServices.Interfaces;
|
||
|
|
using SeaHaven.DataServices.Models;
|
||
|
|
using SeaHaven.Services.Exceptions;
|
||
|
|
using SeaHaven.Services.Helpers;
|
||
|
|
using SeaHaven.Services.Interfaces;
|
||
|
|
|
||
|
|
namespace SeaHaven.Services.Implementation
|
||
|
|
{
|
||
|
|
public class SlaBreachAcknowledgementService : ISlaBreachAcknowledgementService
|
||
|
|
{
|
||
|
|
private readonly INotificationFeedDataService _feedData;
|
||
|
|
private readonly IWorkOrderAuditDataService _auditData;
|
||
|
|
private readonly IUserDataService _userData;
|
||
|
|
private readonly IWorkOrderAccountResolver _accountResolver;
|
||
|
|
private readonly TimeProvider _timeProvider;
|
||
|
|
|
||
|
|
public SlaBreachAcknowledgementService(
|
||
|
|
INotificationFeedDataService feedData,
|
||
|
|
IWorkOrderAuditDataService auditData,
|
||
|
|
IUserDataService userData,
|
||
|
|
IWorkOrderAccountResolver accountResolver,
|
||
|
|
TimeProvider timeProvider)
|
||
|
|
{
|
||
|
|
_feedData = feedData;
|
||
|
|
_auditData = auditData;
|
||
|
|
_userData = userData;
|
||
|
|
_accountResolver = accountResolver;
|
||
|
|
_timeProvider = timeProvider;
|
||
|
|
}
|
||
|
|
|
||
|
|
public async Task<SlaBreachAcknowledgementOutcome> AcknowledgeAsync(
|
||
|
|
ClaimsPrincipal user, int workOrderId, CancellationToken cancellationToken)
|
||
|
|
{
|
||
|
|
// The same audience as the feed: a row the caller cannot see cannot be acknowledged.
|
||
|
|
var accountId = _accountResolver.ResolveAccountFilter(user);
|
||
|
|
var (dispatcherId, _) = NotificationAudience.Resolve(user);
|
||
|
|
var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||
|
|
if (string.IsNullOrWhiteSpace(userId))
|
||
|
|
throw new WorkOrderBoardValidationException("Forbidden", "Acknowledging requires a signed-in user.");
|
||
|
|
|
||
|
|
var candidate = await _feedData.GetSlaCandidateAsync(
|
||
|
|
new NotificationFeedScope(accountId, dispatcherId), workOrderId, cancellationToken);
|
||
|
|
if (candidate == null)
|
||
|
|
return SlaBreachAcknowledgementOutcome.NotFound;
|
||
|
|
|
||
|
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||
|
|
var clock = SlaResponseWindows.Evaluate(candidate.Severity, candidate.CreatedAt, now);
|
||
|
|
if (clock is not { State: SlaState.Breached })
|
||
|
|
return SlaBreachAcknowledgementOutcome.NotBreached;
|
||
|
|
if (candidate.BreachAcknowledged)
|
||
|
|
return SlaBreachAcknowledgementOutcome.AlreadyAcknowledged;
|
||
|
|
|
||
|
|
var names = await _userData.GetDisplayNamesByIdsAsync(new[] { userId });
|
||
|
|
var name = names.TryGetValue(userId, out var displayName) && !string.IsNullOrWhiteSpace(displayName)
|
||
|
|
? displayName
|
||
|
|
: user.FindFirstValue(ClaimTypes.Name) ?? userId;
|
||
|
|
|
||
|
|
_auditData.EnqueueAuditLog(new WorkOrderAuditLog
|
||
|
|
{
|
||
|
|
WorkOrderId = workOrderId,
|
||
|
|
UserId = userId,
|
||
|
|
FieldName = SlaBreachAcknowledgementAudit.FieldName,
|
||
|
|
OldValue = clock.DeadlineAt.ToString("o"),
|
||
|
|
NewValue = candidate.Severity,
|
||
|
|
Action = $"SLA breach acknowledged by {name}",
|
||
|
|
EventType = "system",
|
||
|
|
ActorType = "internal",
|
||
|
|
CreatedAt = now
|
||
|
|
});
|
||
|
|
await _auditData.PersistAsync(cancellationToken);
|
||
|
|
return SlaBreachAcknowledgementOutcome.Acknowledged;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|