feature: Ward Gateway Service (Local-First Clinical Path)
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public class LocalWarningEvaluator
|
||||
{
|
||||
private readonly GatewayDbContext _db;
|
||||
private readonly ILogger<LocalWarningEvaluator> _logger;
|
||||
|
||||
public LocalWarningEvaluator(GatewayDbContext db, ILogger<LocalWarningEvaluator> logger)
|
||||
{
|
||||
_db = db;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<bool> TryEvaluateAsync(
|
||||
Guid observationId, Guid encounterId, Guid patientId,
|
||||
string observationCode, decimal value, ThresholdCacheEntry threshold)
|
||||
{
|
||||
if (!IsWarningBreach(value, threshold)) return false;
|
||||
if (IsCriticalBreach(value, threshold)) return false;
|
||||
|
||||
var alertType = AlertTypeExtensions.WarningFor(observationCode);
|
||||
var clientAlertId = Guid.NewGuid();
|
||||
var triggeredAt = DateTimeOffset.UtcNow;
|
||||
var details = BuildWarningDetails(observationCode, value, threshold);
|
||||
|
||||
var exists = await _db.ClinicalAlerts.AnyAsync(a =>
|
||||
a.EncounterId == encounterId
|
||||
&& a.AlertType == alertType
|
||||
&& (a.Status == AlertStatus.Open || a.Status == AlertStatus.Acknowledged));
|
||||
if (exists) return false;
|
||||
|
||||
var alert = new LocalClinicalAlert
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
ClientAlertId = clientAlertId,
|
||||
EncounterId = encounterId,
|
||||
PatientId = patientId,
|
||||
ObservationId = observationId,
|
||||
AlertType = alertType,
|
||||
Severity = AlertSeverity.Warning,
|
||||
Details = details,
|
||||
Status = AlertStatus.Open,
|
||||
TriggeredAt = triggeredAt
|
||||
};
|
||||
_db.ClinicalAlerts.Add(alert);
|
||||
|
||||
BufferedSyncWriter.Enqueue(_db, BufferedSyncItemType.Alert, new
|
||||
{
|
||||
clientAlertId,
|
||||
encounterId,
|
||||
alertType = alertType.ToDbString(),
|
||||
severity = AlertSeverity.Warning.ToDbString(),
|
||||
details,
|
||||
generatedAt = triggeredAt
|
||||
}, $"alert:{clientAlertId}", encounterId, triggeredAt);
|
||||
|
||||
_logger.LogInformation(
|
||||
"WARNING alert {AlertId} created locally for encounter {EncounterId}",
|
||||
alert.Id, encounterId);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsWarningBreach(decimal value, ThresholdCacheEntry t) =>
|
||||
(t.WarningHigh.HasValue && value > t.WarningHigh.Value) ||
|
||||
(t.WarningLow.HasValue && value < t.WarningLow.Value);
|
||||
|
||||
private static bool IsCriticalBreach(decimal value, ThresholdCacheEntry t) =>
|
||||
(t.CriticalLow.HasValue && value < t.CriticalLow.Value) ||
|
||||
(t.CriticalHigh.HasValue && value > t.CriticalHigh.Value);
|
||||
|
||||
private static string BuildWarningDetails(string code, decimal value, ThresholdCacheEntry t) =>
|
||||
t.WarningHigh.HasValue && value > t.WarningHigh.Value
|
||||
? $"{code} value {value} is above warning high of {t.WarningHigh}."
|
||||
: $"{code} value {value} is below warning low of {t.WarningLow}.";
|
||||
}
|
||||
Reference in New Issue
Block a user