170 lines
6.5 KiB
C#
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();
|
|
}
|
|
}
|
|
} |