Clinical Sync Batch Engine: first commit
This commit is contained in:
@@ -13,6 +13,8 @@ public class ClinicalAlert
|
||||
public string? AcknowledgedBy { get; set; }
|
||||
public DateTimeOffset? ResolvedAt { get; set; }
|
||||
public DateTimeOffset TriggeredAt { get; set; }
|
||||
public Guid? ClientAlertId { get; set; }
|
||||
public bool SyncedFromGateway { get; set; }
|
||||
|
||||
public Encounter Encounter { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
public class ClinicalSite
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public string SiteCode { get; private set; } = string.Empty;
|
||||
public string Name { get; private set; } = string.Empty;
|
||||
public string? Address { get; private set; }
|
||||
public bool Active { get; private set; } = true;
|
||||
public DateTimeOffset CreatedAt { get; private set; }
|
||||
|
||||
public ICollection<WardGateway> Gateways { get; private set; } = [];
|
||||
|
||||
private ClinicalSite() { }
|
||||
|
||||
public ClinicalSite(string siteCode, string name, string? address = null)
|
||||
{
|
||||
SiteCode = siteCode;
|
||||
Name = name;
|
||||
Address = address;
|
||||
CreatedAt = DateTimeOffset.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
public class ClinicalSyncBatch
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public Guid GatewayId { get; private set; }
|
||||
public Guid SiteId { get; private set; }
|
||||
public Guid BatchReference { get; private set; }
|
||||
public ClinicalSyncBatchStatus Status { get; private set; } = ClinicalSyncBatchStatus.Received;
|
||||
public string Payload { get; private set; } = "{}";
|
||||
public DateTimeOffset SubmittedAt { get; private set; }
|
||||
public DateTimeOffset? ProcessedAt { get; private set; }
|
||||
|
||||
public WardGateway Gateway { get; private set; } = null!;
|
||||
public ICollection<ClinicalSyncConflict> Conflicts { get; private set; } = [];
|
||||
|
||||
private ClinicalSyncBatch() { }
|
||||
|
||||
public ClinicalSyncBatch(Guid gatewayId, Guid siteId, Guid batchReference, string payload)
|
||||
{
|
||||
GatewayId = gatewayId;
|
||||
SiteId = siteId;
|
||||
BatchReference = batchReference;
|
||||
Payload = payload;
|
||||
SubmittedAt = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public void MarkProcessing() => Status = ClinicalSyncBatchStatus.Processing;
|
||||
public void MarkApplied() { Status = ClinicalSyncBatchStatus.Applied; ProcessedAt = DateTimeOffset.UtcNow; }
|
||||
public void MarkConflict() { Status = ClinicalSyncBatchStatus.Conflict; ProcessedAt = DateTimeOffset.UtcNow; }
|
||||
public void MarkRejected() { Status = ClinicalSyncBatchStatus.Rejected; ProcessedAt = DateTimeOffset.UtcNow; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
public class ClinicalSyncConflict
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public Guid BatchId { get; private set; }
|
||||
public Guid ClientRef { get; private set; }
|
||||
public string ItemType { get; private set; } = string.Empty;
|
||||
public string ConflictReason { get; private set; } = string.Empty;
|
||||
public DateTimeOffset CreatedAt { get; private set; }
|
||||
|
||||
public ClinicalSyncBatch Batch { get; private set; } = null!;
|
||||
|
||||
private ClinicalSyncConflict() { }
|
||||
|
||||
public ClinicalSyncConflict(Guid batchId, Guid clientRef, string itemType, string conflictReason)
|
||||
{
|
||||
BatchId = batchId;
|
||||
ClientRef = clientRef;
|
||||
ItemType = itemType;
|
||||
ConflictReason = conflictReason;
|
||||
CreatedAt = DateTimeOffset.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
public class WardGateway
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public Guid SiteId { get; private set; }
|
||||
public string GatewayCode { get; private set; } = string.Empty;
|
||||
public string Department { get; private set; } = string.Empty;
|
||||
public GatewayStatus Status { get; private set; } = GatewayStatus.Offline;
|
||||
public int ReportedBufferDepth { get; private set; }
|
||||
public DateTimeOffset? LastHeartbeatAt { get; private set; }
|
||||
public DateTimeOffset? LastSyncAt { get; private set; }
|
||||
public DateTimeOffset CreatedAt { get; private set; }
|
||||
|
||||
public ClinicalSite Site { get; private set; } = null!;
|
||||
|
||||
private WardGateway() { }
|
||||
|
||||
public WardGateway(Guid siteId, string gatewayCode, string department)
|
||||
{
|
||||
SiteId = siteId;
|
||||
GatewayCode = gatewayCode;
|
||||
Department = department;
|
||||
CreatedAt = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public void RecordHeartbeat(GatewayStatus status, int bufferDepth, DateTimeOffset at)
|
||||
{
|
||||
Status = status;
|
||||
ReportedBufferDepth = bufferDepth;
|
||||
LastHeartbeatAt = at;
|
||||
}
|
||||
|
||||
public void MarkSynced(DateTimeOffset at)
|
||||
{
|
||||
LastSyncAt = at;
|
||||
ReportedBufferDepth = 0;
|
||||
if (Status == GatewayStatus.Degraded)
|
||||
Status = GatewayStatus.Online;
|
||||
}
|
||||
|
||||
public void MarkOffline()
|
||||
{
|
||||
Status = GatewayStatus.Offline;
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ public enum AlertType
|
||||
|
||||
public static class AlertTypeExtensions
|
||||
{
|
||||
#pragma warning disable CS0618 // Legacy alert types retained for historical DB strings
|
||||
public static string ToDbString(this AlertType t) => t switch
|
||||
{
|
||||
AlertType.SepsisWarning => "SEPSIS_WARNING",
|
||||
@@ -97,7 +98,9 @@ public static class AlertTypeExtensions
|
||||
AlertType.QsofaScreen => "QSOFA_SCREEN",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(t))
|
||||
};
|
||||
#pragma warning restore CS0618
|
||||
|
||||
#pragma warning disable CS0618 // Legacy alert types retained for historical DB strings
|
||||
public static AlertType FromDbString(string v) => v switch
|
||||
{
|
||||
"SEPSIS_WARNING" => AlertType.SepsisWarning,
|
||||
@@ -141,6 +144,7 @@ public static class AlertTypeExtensions
|
||||
"SOFA_WARNING" => AlertType.SofaWarning,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown alert type: '{v}'")
|
||||
};
|
||||
#pragma warning restore CS0618
|
||||
|
||||
// Threshold alerts are derived from observation codes in alert_thresholds — not free-form strings.
|
||||
public static AlertType CriticalFor(string observationCode) => observationCode switch
|
||||
@@ -184,6 +188,7 @@ public static class AlertTypeExtensions
|
||||
nameof(observationCode), $"No warning alert type for observation code '{observationCode}'")
|
||||
};
|
||||
|
||||
#pragma warning disable CS0618 // Legacy alert types retained for historical DB strings
|
||||
public static bool IsSuppressible(this AlertType t) => t switch
|
||||
{
|
||||
AlertType.SepsisWarning or AlertType.News2Emergency => false,
|
||||
@@ -197,6 +202,7 @@ public static class AlertTypeExtensions
|
||||
AlertType.SofaSepsis => false,
|
||||
_ => true // all Warning* types, News2Warning, QsofaScreen, SofaWarning, GcsWarning
|
||||
};
|
||||
#pragma warning restore CS0618
|
||||
|
||||
public static string? ObservationCodeForWarning(this AlertType t) => t switch
|
||||
{
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
public enum ClinicalSyncBatchStatus { Received, Processing, Applied, Conflict, Rejected }
|
||||
|
||||
public static class ClinicalSyncBatchStatusExtensions
|
||||
{
|
||||
public static string ToDbString(this ClinicalSyncBatchStatus s) => s switch
|
||||
{
|
||||
ClinicalSyncBatchStatus.Received => "RECEIVED",
|
||||
ClinicalSyncBatchStatus.Processing => "PROCESSING",
|
||||
ClinicalSyncBatchStatus.Applied => "APPLIED",
|
||||
ClinicalSyncBatchStatus.Conflict => "CONFLICT",
|
||||
ClinicalSyncBatchStatus.Rejected => "REJECTED",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(s))
|
||||
};
|
||||
|
||||
public static ClinicalSyncBatchStatus FromDbString(string v) => v switch
|
||||
{
|
||||
"RECEIVED" => ClinicalSyncBatchStatus.Received,
|
||||
"PROCESSING" => ClinicalSyncBatchStatus.Processing,
|
||||
"APPLIED" => ClinicalSyncBatchStatus.Applied,
|
||||
"CONFLICT" => ClinicalSyncBatchStatus.Conflict,
|
||||
"REJECTED" => ClinicalSyncBatchStatus.Rejected,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown sync batch status: '{v}'")
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
public enum GatewayStatus { Online, Degraded, Offline }
|
||||
|
||||
public static class GatewayStatusExtensions
|
||||
{
|
||||
public static string ToDbString(this GatewayStatus s) => s switch
|
||||
{
|
||||
GatewayStatus.Online => "ONLINE",
|
||||
GatewayStatus.Degraded => "DEGRADED",
|
||||
GatewayStatus.Offline => "OFFLINE",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(s))
|
||||
};
|
||||
|
||||
public static GatewayStatus FromDbString(string v) => v switch
|
||||
{
|
||||
"ONLINE" => GatewayStatus.Online,
|
||||
"DEGRADED" => GatewayStatus.Degraded,
|
||||
"OFFLINE" => GatewayStatus.Offline,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown gateway status: '{v}'")
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user