Files
adas-core/adas-core.Application/Services/RecordingAlertService.cs
T

170 lines
6.5 KiB
C#

using adas_core.Application.Exceptions;
using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.MongoModels;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
namespace adas_core.Application.Services;
public class RecordingAlertService(
Lazy<IPatientService> patientService,
IConfigObservationService configObservationService,
IRecordingAlertRepository recordingAlertRepository,
IRecordingAlertArchiveRepository recordingAlertArchiveRepository,
ILogger<RecordingAlertService> logger,
IClientMessageService clientMessageService,
ISubscribersService subscribersService,
IHttpContextAccessor httpContextAccessor,
ILocalAuditService auditService)
: IRecordingAlertService
{
public async Task Archive(Patient patient)
{
await ArchiveByPatientId(patient.Id);
}
public async Task ArchiveByPatientId(ObjectId id)
{
logger.LogDebug("Archive Recording Alerts by Patient Id {id}", id);
using (var cursor = await recordingAlertRepository.FindByPatientIdAsync(id))
{
while (await cursor.MoveNextAsync())
foreach (var current in cursor.Current)
await recordingAlertArchiveRepository.InsertOneAsync(current);
}
await DeleteByPatientId(id);
}
public async Task DeleteByPatientId(ObjectId id)
{
logger.LogDebug("Delete Recording Alerts by Patient Id {id}", id);
await recordingAlertRepository.DeleteByPatientId(id);
}
public async Task<List<PatientRecordingAlert>> FindLastRecordingAlert(ObjectId patientId, int num = 2)
{
return await recordingAlertRepository.AggregatedPatientLastObservations(patientId, num);
}
public Task SaveRequestAsync(ApiRequest apiRequest)
{
return Task.FromResult(Task.Run(async () => { await SaveRequest(apiRequest); }));
}
public async Task SaveRequest(ApiRequest apiRequest)
{
if (string.IsNullOrEmpty(apiRequest.PatientNumber) && string.IsNullOrEmpty(apiRequest.Location?.UnitName) &&
string.IsNullOrEmpty(apiRequest.Location?.Bed))
{
logger.LogDebug("Patient and Location are nulls in apiRequest RecordingAlerts");
return;
}
logger.LogDebug("patientNumber: {apiRequestpatientNumber} location: {apiRequestlocation}",
apiRequest.PatientNumber, apiRequest.Location);
logger.LogDebug("RequestType: {apiRequesttype}", apiRequest.Type);
switch (apiRequest.Type)
{
/*
* ORU_R01 - Unsolicited transmission of an observation message
* ORU_R40 - Unsolicited transmission of an alert observation message
*/
case "ORU_R01":
case "ORU_R40":
case "RecordingAlert":
var patient = await patientService.Value.FindPatientByApiRequest(apiRequest);
if (patient == null)
{
// NO PATIENTS OR LOCATIONS WERE FOUND
logger.LogWarning(
"Observation for patient: {apiRequestpatientNumber} with location: {apiRequestlocation} not found, ignoring",
apiRequest.PatientNumber, apiRequest.Location);
return;
}
// Recording Alerts
if (apiRequest.RecordingAlert != null && apiRequest.RecordingAlerts?.FirstOrDefault() == null)
apiRequest.RecordingAlerts = [apiRequest.RecordingAlert];
if (apiRequest.RecordingAlerts != null)
{
logger.LogDebug("INSERT {apiRequestrecordingAlerts} OBSERVATIONS",
apiRequest.RecordingAlerts.Count);
foreach (var obs in apiRequest.RecordingAlerts)
{
obs.PatientId = patient.Id;
obs.Id = ObjectId.GenerateNewId();
if (obs.Time == DateTime.MinValue) obs.Time = DateTime.UtcNow;
await InsertRecordingAlert(obs);
}
}
break;
default:
logger.LogWarning("ApiRequest type {apiRequesttype} sis not valid for Observations", apiRequest.Type);
throw new ApiRequestException("ApiRequest type " + apiRequest.Type + " is not valid for Observations");
}
}
public async Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId)
{
await recordingAlertRepository.UpdateManyObjectId(nameId, id, oldId);
}
private async Task InsertRecordingAlert(PatientRecordingAlert recAlert)
{
logger.LogDebug("Insert {recAlert}", recAlert);
await recordingAlertRepository.InsertOneAsync(recAlert);
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, recAlert);
await SendObsBroadcast(recAlert);
await DoRetentionActions(recAlert);
}
private async Task SendObsBroadcast(BasePatientObservation recAlert)
{
if (recAlert.Name == null) return;
var type = recAlert is PatientRecordingAlert ? OperationType.RecordingAlert : OperationType.Observation;
var patient = await patientService.Value.FindById(recAlert.PatientId);
if (patient?.PointOfCareId == null) return;
var subscribers = subscribersService.GetSubscribers()
.Where(s => s.LocationIds.Contains(patient.PointOfCareId.Value)).ToList();
foreach (var subscriber in subscribers) await clientMessageService.SendAsync(subscriber.Id, type, recAlert);
}
private async Task DoRetentionActions(PatientRecordingAlert recAlert)
{
var result = await configObservationService.RetentionActions(recAlert);
if (result is not { RetentionPolicyValue: not null } || recAlert.Name == null) return;
switch (result.RetentionPolicy)
{
case RetentionPolicy.DeleteOlderDays:
await recordingAlertRepository.DeleteOlderDaysAsync(recAlert.Name, result.RetentionPolicyValue.Value);
break;
case RetentionPolicy.DeleteOlderNumber:
await recordingAlertRepository.DeleteOlderNumberAsync(recAlert.Name, result.RetentionPolicyValue.Value);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}