Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace adas_core.Application.Customizations.BD;
|
||||
|
||||
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||
{
|
||||
private readonly ILogger<CalculatedObservations> _logger =
|
||||
serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
|
||||
private readonly Lazy<IObservationService> _observationService =
|
||||
serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||
|
||||
public Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||
{
|
||||
return Task.FromResult(obs)!;
|
||||
}
|
||||
|
||||
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
return Task.FromResult(treatment);
|
||||
}
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
return Task.FromResult(diagnosis);
|
||||
}
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
if (pumpObservation.Code == "IHE PCD-04")
|
||||
await CreatePumpAlarmObservation(pumpObservation);
|
||||
return pumpObservation;
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||
{
|
||||
return Task.FromResult(listToInsert);
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Task CreatePumpAlarmObservation(PumpObservation pumpObservation)
|
||||
{
|
||||
PatientObservation patientObservationAlarm = new()
|
||||
{
|
||||
CodingSystem = "ADAS_ALARM",
|
||||
Code = pumpObservation.AlarmState,
|
||||
Name = $"Alarm_Pump_{pumpObservation.AlarmType}",
|
||||
Value = pumpObservation.DeviceId != null
|
||||
? $"Device Id: {pumpObservation.DeviceId}"
|
||||
: $"Infusion Id {pumpObservation.InfusionId}",
|
||||
Time = pumpObservation.Time
|
||||
};
|
||||
|
||||
if (pumpObservation.PatientId.HasValue) patientObservationAlarm.PatientId = pumpObservation.PatientId.Value;
|
||||
|
||||
|
||||
//CheckAlarmConfig(patientObservationAlarm);
|
||||
try
|
||||
{
|
||||
_ = _observationService.Value.InsertObservation(patientObservationAlarm, mapObs: false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Error inserting Pump Observation Alarm. Exception: {e}", e);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace adas_core.Application.Customizations.CHUO;
|
||||
|
||||
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||
{
|
||||
private readonly ILogger<CalculatedObservations> _logger =
|
||||
serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
return await Task.FromResult(pumpObservation);
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
|
||||
}
|
||||
|
||||
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||
{
|
||||
_logger.LogTrace("Mapping {name} observation {obs}", obs.Name, obs);
|
||||
|
||||
return Task.FromResult<T?>(obs);
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||
{
|
||||
return Task.FromResult(listToInsert);
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
|
||||
}
|
||||
|
||||
//public Task<List<PatientObservation>> MapList(List<PatientObservation> obsToInsert)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,133 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace adas_core.Application.Customizations.HGM;
|
||||
|
||||
//Custom for Hospital Gregorio Marañón
|
||||
public class CalculatedObservations : ICalculatedObservations
|
||||
{
|
||||
private readonly List<string> _highFrequencyVentilation = [];
|
||||
private readonly List<string> _invasiveVentilation = [];
|
||||
private readonly ILogger<CalculatedObservations> _logger;
|
||||
private readonly List<string> _nonInvasiveVentilation = [];
|
||||
private readonly Lazy<IObservationService> _observationService;
|
||||
|
||||
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||
{
|
||||
var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>().Value;
|
||||
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||
|
||||
var highFrequencyVentilation = apiSettings.HighFrequencyVentilation ?? null;
|
||||
highFrequencyVentilation?.ForEach(x => _highFrequencyVentilation.Add(x.Trim()));
|
||||
|
||||
var invasiveVentilation = apiSettings.InvasiveVentilation ?? null;
|
||||
invasiveVentilation?.ForEach(x => _invasiveVentilation.Add(x.Trim()));
|
||||
|
||||
var nonInvasiveVentilation = apiSettings.NonInvasiveVentilation ?? null;
|
||||
nonInvasiveVentilation?.ForEach(x => _nonInvasiveVentilation.Add(x.Trim()));
|
||||
}
|
||||
|
||||
public async Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||
{
|
||||
if (string.IsNullOrEmpty(obs.Name)) return obs;
|
||||
|
||||
switch (obs.Name)
|
||||
{
|
||||
case "Resp_Mode":
|
||||
await CalculateVentilationMode(obs);
|
||||
break;
|
||||
}
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
return await Task.FromResult(pumpObservation);
|
||||
}
|
||||
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||
{
|
||||
return Task.FromResult(listToInsert);
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private async Task CalculateVentilationMode(BasePatientObservation obs)
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
var respTypeObs = new PatientObservation
|
||||
{
|
||||
Name = "Resp_Type",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
var strValue = pobs.Value.ToString();
|
||||
if (string.IsNullOrEmpty(strValue))
|
||||
respTypeObs.Value = nameof(RespirationType.None);
|
||||
else
|
||||
respTypeObs.Value = _highFrequencyVentilation.Contains(strValue)
|
||||
? nameof(RespirationType.HighFrequencyVentilation)
|
||||
: _invasiveVentilation.Contains(strValue)
|
||||
? respTypeObs.Value = nameof(RespirationType.Invasive)
|
||||
: _nonInvasiveVentilation.Contains(strValue)
|
||||
? respTypeObs.Value = nameof(RespirationType.NonInvasive)
|
||||
: nameof(RespirationType.None);
|
||||
|
||||
|
||||
var wasInserted = await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
|
||||
if (wasInserted)
|
||||
_logger.LogDebug("Calculated Resp_Type for patientid: {respTypeObsPatientid} value: {respType}",
|
||||
respTypeObs.PatientId, respTypeObs.Value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,641 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
using Serilog;
|
||||
|
||||
namespace adas_core.Application.Customizations.HPAZ;
|
||||
|
||||
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||
{
|
||||
private readonly Lazy<IAlarmService> _alarmService = serviceProvider.GetRequiredService<Lazy<IAlarmService>>();
|
||||
|
||||
|
||||
private readonly ApiSettings
|
||||
_apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>().Value; //apiSettings;
|
||||
|
||||
private readonly IConfigObservationService _configObservationService =
|
||||
serviceProvider.GetRequiredService<IConfigObservationService>(); //configObservationService;
|
||||
|
||||
private readonly ILogger<CalculatedObservations> _logger =
|
||||
serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
|
||||
//Use GroupedObservation to avoid circular dependency with _observationService
|
||||
private readonly Lazy<IObservationService> _observationService =
|
||||
serviceProvider.GetRequiredService<Lazy<IObservationService>>(); //observationService;
|
||||
|
||||
private readonly List<string> _pressBloodArteryMean = ["TAm"];
|
||||
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
return Task.FromResult<IEnumerable<PatientTreatment?>>(new List<PatientTreatment?>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the obs to an event or alarm depending on its type and inserts it if needed
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type</typeparam>
|
||||
/// <param name="source">Observation</param>
|
||||
/// <param name="onlyByName">True if the observation needs to generate an alert</param>
|
||||
/// <returns>Mapped observation</returns>
|
||||
public async Task<T?> Map<T>(T source, bool onlyByName) where T : BasePatientObservation
|
||||
{
|
||||
_logger.LogDebug("Mapping {obsName} mode observation {obs}", source.Name, source);
|
||||
|
||||
if (source is not BasePatientObservationValue obs) return source;
|
||||
|
||||
var name = obs is PatientObservationAlarm obsAlarm ? obsAlarm.Event : obs.Name;
|
||||
name ??= string.Empty;
|
||||
|
||||
|
||||
//No generamos alertas si viene onlyByName
|
||||
if (name == "Resp_Mode")
|
||||
obs = CalculateVentilationMode(obs);
|
||||
|
||||
if (name is "Sattc" or "FiO2") await CalculateSf(obs, name);
|
||||
|
||||
if (name is "FiO2" or "P_VAM" or "PaO2_Tidal") await CalculateOxygenationIndex(obs, name);
|
||||
|
||||
if (name is "FiO2" or "PaO2_Tidal") await CalculatePf(obs, name);
|
||||
|
||||
if (name == "TEST_ALARMA") await _alarmService.Value.CalculateAlarmTest(obs, name);
|
||||
|
||||
obs = await CheckObsWithSameTimeExistsAndIncrementTime(obs);
|
||||
|
||||
if (obs is PatientObservation pobs)
|
||||
{
|
||||
pobs = await CheckAlarmConfig(pobs);
|
||||
return pobs as T;
|
||||
}
|
||||
|
||||
return obs as T;
|
||||
}
|
||||
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pumpObservation.Status is PumpEnum.Status.Alarm or PumpEnum.Status.Warning)
|
||||
{
|
||||
PatientObservation? patientObservation = null;
|
||||
string? name = null;
|
||||
|
||||
//La oclusión es para todos los tipos
|
||||
var volumetricAirOcclusionAlarm = _apiSettings.VolumetricAirOcclusionAlarm ?? null;
|
||||
|
||||
if (volumetricAirOcclusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||
volumetricAirOcclusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "VolumetricAirOcclusion";
|
||||
//alerta oclusión aire para bombas volumétricas
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
|
||||
|
||||
var listInotropicMedicines = _apiSettings.InotropicMedicines ?? null;
|
||||
|
||||
if (listInotropicMedicines is { Count: > 0 } && pumpObservation.DrugName != null &&
|
||||
listInotropicMedicines.Contains(pumpObservation.DrugName)) //INOTRÓPICOS
|
||||
{
|
||||
var inotropicEndInfusionAlarm = _apiSettings.InotropicEndInfusionAlarm ?? null;
|
||||
|
||||
if (inotropicEndInfusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||
inotropicEndInfusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
//Inotrópicos próxima a fin de infusión
|
||||
// Y
|
||||
//proximo fin de infusión, oclusión, y presencia aire….
|
||||
//Solo inotrópicos
|
||||
//Está en la línea 19 del excel y abarca la que hay en la línea 9
|
||||
// TODO: revisar en los logs que nombre de type (Buscar por crud xmlns)
|
||||
name = "InotropicEndInfusion";
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var pumPressureAlarm = _apiSettings.PumPressureAlarm ?? null;
|
||||
|
||||
if (pumPressureAlarm != null && pumpObservation.AlarmType != null &&
|
||||
pumPressureAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "Pressure";
|
||||
//alerta de presión(la alerta de la bomba se programa + -30mmHg por encima de la presión de la línea).
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
|
||||
var endContinuousInfusionAlarm = _apiSettings.EndContinuousInfusionAlarm ?? null;
|
||||
|
||||
if (endContinuousInfusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||
endContinuousInfusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "EndContinuousInfusion";
|
||||
//próximo a fin de infusión /fin de infusión
|
||||
//información de bombas solo perfusión continua
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
|
||||
var volumetricAirInLineAlarm = _apiSettings.VolumetricAirInLineAlarm ?? null;
|
||||
|
||||
if (volumetricAirInLineAlarm != null && pumpObservation.AlarmType != null &&
|
||||
volumetricAirInLineAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||
{
|
||||
name = "VolumetricAirInLine";
|
||||
//alerta aire para bombas volumétricas (burbujas de aire para la bomba)
|
||||
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (patientObservation != null && name != null)
|
||||
{
|
||||
_ = _observationService.Value.InsertObservation(patientObservation);
|
||||
_ = _alarmService.Value.SendAlarm(patientObservation, name, AlarmEnum.Name.Pump,
|
||||
AlarmEnum.Severity.None, AlarmEnum.Type.Auto);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error mapping alarm pump observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
|
||||
return pumpObservation;
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
if (string.IsNullOrEmpty(newObservation.Name))
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error FixTimeInconsistencyWithLast new observation name is null or empty: {newObservation}.",
|
||||
newObservation);
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
var lasObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||
[newObservation.Name]);
|
||||
var lastObservation = lasObservations.FirstOrDefault();
|
||||
|
||||
if (lastObservation != null && DateTime.Compare(
|
||||
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||
newObservation.Time.Day, newObservation.Time.Hour,
|
||||
newObservation.Time.Minute, newObservation.Time.Second)
|
||||
) >= 0)
|
||||
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToMap)
|
||||
{
|
||||
var mappedObsList = listToMap
|
||||
.Select(obs => obs.DeepCopy())
|
||||
.Select(obs => _configObservationService.Map(obs).Result)
|
||||
.Where(obs => obs != null)
|
||||
.ToList();
|
||||
|
||||
// mappedObsList contains observation mapped
|
||||
// Check blue code
|
||||
|
||||
_ = CalculateBlueCodeList(mappedObsList);
|
||||
|
||||
|
||||
return Task.FromResult(listToMap);
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(alarmToInsert.EventId))
|
||||
obs.Code = alarmToInsert.EventId;
|
||||
|
||||
if (!string.IsNullOrEmpty(alarmToInsert.Event))
|
||||
obs.Name = alarmToInsert.Event;
|
||||
|
||||
obs.Value = alarmToInsert.Value;
|
||||
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
Task ICalculatedObservations.SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
private async Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code, AlarmEnum.Type type)
|
||||
{
|
||||
await _alarmService.Value.SendAlarm(obs, name, code, AlarmEnum.Severity.None, type);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initial check to ignore old observations generating blue codes
|
||||
/// </summary>
|
||||
/// <param name="obs">Observation</param>
|
||||
/// <returns>True if it needs to be ignored</returns>
|
||||
private bool CheckIfObservationIsOlderAndShouldBeIgnored(PatientObservation obs)
|
||||
{
|
||||
if (obs.Time.ToUniversalTime().AddMinutes(_apiSettings.IgnoreCalcObservationsOlderInMinutesThan) <
|
||||
DateTime.UtcNow)
|
||||
{
|
||||
Log.Debug(
|
||||
"ignoring calc old observation: name:{obsName} obs_time:{obsTime} system_time {DateTimeNow} id:{obsId}",
|
||||
obs.Name ?? "null", obs.Time, DateTime.Now, obs.Id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private async Task<PatientObservation> CheckAlarmConfig(PatientObservation pobs)
|
||||
{
|
||||
var configObs = await _configObservationService.Get(new PatientObservation
|
||||
{
|
||||
Name = pobs.Name,
|
||||
PatientId = pobs.PatientId
|
||||
});
|
||||
|
||||
pobs.Alarm = configObs?.Alarm ?? null;
|
||||
|
||||
return pobs;
|
||||
}
|
||||
|
||||
private static PatientObservation CreateAlarmObservation(string name, PatientObservation pobs)
|
||||
{
|
||||
return new PatientObservation
|
||||
{
|
||||
CodingSystem = "ADAS_ALARM",
|
||||
Code = name,
|
||||
Name = $"Alarm_{name}",
|
||||
Value = pobs.Value,
|
||||
PatientId = pobs.PatientId,
|
||||
Time = pobs.Time,
|
||||
Alarm = pobs.Alarm
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a blue code observation Lists needs to be generated and inserts it.
|
||||
/// </summary>
|
||||
/// <param name="obsList"></param>
|
||||
public async Task CalculateBlueCodeList(List<PatientObservation?>? obsList)
|
||||
{
|
||||
//Las 3 observaciones vienen siempre juntas en el mismo mensaje
|
||||
//Solo se comprueba si se cumplen 2 de las 3 condiciones
|
||||
|
||||
var condition = 0;
|
||||
var patientId = obsList?.FirstOrDefault()?.PatientId;
|
||||
if (patientId == null) return;
|
||||
|
||||
var fcObs = obsList?.FirstOrDefault(o => o is { Name: "FC" });
|
||||
var sattcObs = obsList?.FirstOrDefault(o => o is { Name: "Sattc" });
|
||||
var tamObs = obsList?.FirstOrDefault(o => o is { Name: "TAm" });
|
||||
|
||||
// FC < 60
|
||||
if (fcObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(fcObs) &&
|
||||
double.TryParse(fcObs.Value.ToString(), out var cardiacBeatRate) && cardiacBeatRate < 60)
|
||||
{
|
||||
Log.Debug("BlueCode condition: FC {fc} for patient: {obsPatientid} fc increase limit", cardiacBeatRate,
|
||||
fcObs.PatientId);
|
||||
condition++;
|
||||
}
|
||||
|
||||
// SpO2 < 80 (Sattc)
|
||||
if (sattcObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(sattcObs) &&
|
||||
double.TryParse(sattcObs.Value.ToString(), out var spO2Value) && spO2Value < 80)
|
||||
{
|
||||
Log.Debug("Blue code condition: SpO2 {sp} for patient: {obsPatientid} Sattc increase limit", spO2Value,
|
||||
sattcObs.PatientId);
|
||||
condition++;
|
||||
}
|
||||
|
||||
if (condition == 0) return;
|
||||
|
||||
// Early exit if 2 conditions are met
|
||||
if (condition == 2)
|
||||
{
|
||||
_ = SendBlueCode(fcObs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// TAm actual es un 50% por debajo de la medición de 30 seg antes
|
||||
if (tamObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(tamObs) &&
|
||||
double.TryParse(tamObs.Value.ToString(), out var tamObsValue))
|
||||
{
|
||||
// Buscamos el anterior
|
||||
var lastPressBloodObsList =
|
||||
await _observationService.Value.FindLastObservations(tamObs.PatientId, 1, _pressBloodArteryMean);
|
||||
var lastPressBloodObs = lastPressBloodObsList.FirstOrDefault();
|
||||
|
||||
// Diferencia entre la última observación es < 30 s
|
||||
if (lastPressBloodObs != null &&
|
||||
double.TryParse(lastPressBloodObs.Value.ToString(), out var lastPressBloodValue) &&
|
||||
(tamObs.Time - lastPressBloodObs.Time).TotalSeconds <= 35 &&
|
||||
tamObsValue <= lastPressBloodValue / 2)
|
||||
{
|
||||
Log.Debug("Blue code condition: TAm decrease limit over 30s for patient: {obsPatientid}",
|
||||
tamObs.PatientId);
|
||||
condition++;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition >= 2) _ = SendBlueCode(tamObs);
|
||||
}
|
||||
|
||||
|
||||
private async Task SendBlueCode(PatientObservation? pobs)
|
||||
{
|
||||
if (pobs == null)
|
||||
return;
|
||||
|
||||
Log.Debug("Blue code Alarm for patient: {obsPatientid}", pobs.PatientId);
|
||||
|
||||
var blueCodeObservation = CreateAlarmObservation("BlueCode", pobs);
|
||||
|
||||
blueCodeObservation = await CheckAlarmConfig(blueCodeObservation);
|
||||
|
||||
_ = _observationService.Value.InsertObservation(blueCodeObservation);
|
||||
|
||||
_ = SendAlarm(blueCodeObservation, "BlueCode", AlarmEnum.Name.Blue, AlarmEnum.Type.Auto);
|
||||
}
|
||||
|
||||
|
||||
//PRVC : donde aparezca cambiar y mostrar en su lugar: VCRP
|
||||
//FLUJO ALTO: poner OAF en su lugar
|
||||
private BasePatientObservationValue CalculateVentilationMode(BasePatientObservationValue obs)
|
||||
{
|
||||
var value = obs is PatientObservationAlarm oAlarm ? oAlarm.Value
|
||||
: obs is PatientObservation o ? o.Value : null;
|
||||
|
||||
|
||||
if (value != null && value.ToString()!.Contains("PRVC"))
|
||||
obs.Value = value.ToString()!.Replace("PRVC", "VCRP");
|
||||
else if (value != null && value.ToString()!.Contains("FLUJ.ALTO")) obs.Value = "OAF";
|
||||
|
||||
_logger.LogDebug("Calculating patient id: {id} ventilation mode: {obsName}, value : {obsValue}", obs.PatientId,
|
||||
obs.Name, obs.Value);
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
//TODO duplicado con el calculated del 12o, sacar a un utils
|
||||
private async Task<BasePatientObservationValue> CheckObsWithSameTimeExistsAndIncrementTime(
|
||||
BasePatientObservationValue obs)
|
||||
{
|
||||
if (obs is not PatientObservation pobs) return obs;
|
||||
|
||||
var existObsWithSameTime =
|
||||
await _observationService.Value.FindAnyWithSameDate(pobs.PatientId, pobs.Time, pobs.Name);
|
||||
|
||||
if (existObsWithSameTime != null && existObsWithSameTime.Any()) pobs.Time = pobs.Time.AddSeconds(1);
|
||||
|
||||
return pobs;
|
||||
}
|
||||
|
||||
//S/F Calc ( craneal saturation / FiO2
|
||||
private async Task CalculateSf(BasePatientObservationValue obs, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
PatientObservation? saturation = null;
|
||||
PatientObservation? fio2 = null;
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["FiO2", "Sattc"]);
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "FiO2":
|
||||
fio2 = (PatientObservation)obs;
|
||||
saturation = values.FirstOrDefault(o => o.Name == "Sattc");
|
||||
break;
|
||||
|
||||
case "Sattc":
|
||||
saturation = (PatientObservation)obs;
|
||||
fio2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fio2 != null && saturation != null && !fio2.Expired &&
|
||||
double.TryParse(fio2.Value.ToString(), out var fio) && !saturation.Expired &&
|
||||
double.TryParse(saturation.Value.ToString(), out var sat) && sat <= 97)
|
||||
{
|
||||
if (fio == 0)
|
||||
{
|
||||
_logger.LogError("Error calculating SF. FiO2: {fio}", fio);
|
||||
return;
|
||||
}
|
||||
|
||||
var sfValue = sat / fio;
|
||||
|
||||
sfValue = Math.Round(sfValue, 4);
|
||||
|
||||
var sfObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Name = "Sattc_FiO2",
|
||||
CodingSystem = "ADAS",
|
||||
Value = sfValue,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(sfObs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculate S/F observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Oxygenation index is calculated => P_VAM x FiO2 x 100 / PaO2_Tidal
|
||||
/// the method is called when it receives P_VAM or FiO2 or PaO2_Tidal and tries to take the other values to perform the
|
||||
/// calculation if they are not
|
||||
/// in database then does nothing.
|
||||
/// </summary>
|
||||
public async Task CalculateOxygenationIndex(BasePatientObservationValue obs, string name)
|
||||
{
|
||||
var toSearchList = new List<string>();
|
||||
PatientObservation? pVam = null;
|
||||
PatientObservation? fiO2 = null;
|
||||
PatientObservation? paO2 = null;
|
||||
|
||||
toSearchList.AddRange(new List<string> { "P_VAM", "FiO2", "PaO2_Tidal" });
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||
|
||||
try
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "P_VAM":
|
||||
pVam = (PatientObservation)obs;
|
||||
fiO2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||
break;
|
||||
|
||||
case "FiO2":
|
||||
fiO2 = (PatientObservation)obs;
|
||||
pVam = values.FirstOrDefault(o => o.Name == "P_VAM");
|
||||
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||
break;
|
||||
|
||||
case "PaO2_Tidal":
|
||||
paO2 = (PatientObservation)obs;
|
||||
fiO2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
pVam = values.FirstOrDefault(o => o.Name == "P_VAM");
|
||||
break;
|
||||
}
|
||||
|
||||
//Controlar que FiO2 no haya expirada al recogerla
|
||||
if (fiO2 != null && paO2 != null && pVam != null &&
|
||||
int.TryParse(pVam.Value.ToString(), out var pvam) &&
|
||||
int.TryParse(fiO2.Value.ToString(), out var fio2) &&
|
||||
int.TryParse(paO2.Value.ToString(), out var pao2))
|
||||
{
|
||||
if (pao2 == 0)
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error calculate Oxygenation Index observation. PaO2: {pao2}, observation: {obsName}", pao2,
|
||||
name);
|
||||
return;
|
||||
}
|
||||
|
||||
var oxygenationIndexValue = pvam * fio2 * 100 / pao2;
|
||||
|
||||
var oxygenationIndexObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Name = "Oxygenation_Index",
|
||||
CodingSystem = "ADAS",
|
||||
Value = oxygenationIndexValue,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(oxygenationIndexObs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculate Oxygenation Index observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
//P/F Calc ( PaO2_Tidal / FiO2
|
||||
private async Task CalculatePf(BasePatientObservationValue obs, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
PatientObservation? paO2 = null;
|
||||
PatientObservation? fio2 = null;
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||
["FiO2", "PaO2_Tidal"]);
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "FiO2":
|
||||
fio2 = (PatientObservation)obs;
|
||||
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||
break;
|
||||
|
||||
case "PaO2_Tidal":
|
||||
paO2 = (PatientObservation)obs;
|
||||
fio2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fio2 != null && paO2 != null && !fio2.Expired && !paO2.Expired &&
|
||||
double.TryParse(paO2.Value.ToString(), out var pa) &&
|
||||
double.TryParse(fio2.Value.ToString(), out var fi))
|
||||
{
|
||||
if (fi == 0)
|
||||
{
|
||||
_logger.LogError("Error Calculating PF. FiO2 value is 0. Observation:{obs}", obs);
|
||||
return;
|
||||
}
|
||||
|
||||
var sfValue = pa / fi;
|
||||
|
||||
sfValue = Math.Round(sfValue, 4);
|
||||
|
||||
var sfObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Name = "PaO2_FiO2",
|
||||
CodingSystem = "ADAS",
|
||||
Value = sfValue,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(sfObs);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculate P/F observation. Exception: {exMessage}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task<PatientObservation?> CreatePumpAlarmObservation(string name,
|
||||
PumpObservation pumpObservation)
|
||||
{
|
||||
var positionPump = pumpObservation.IsAux != null && !pumpObservation.IsAux.Value
|
||||
? $"Rack {pumpObservation.GatewayNumber} Bomba {pumpObservation.Number}"
|
||||
: $"Rack Aux {pumpObservation.GatewayNumber} Bomba {pumpObservation.Number}";
|
||||
|
||||
|
||||
|
||||
PatientObservation patientObservation = new()
|
||||
{
|
||||
CodingSystem = "ADAS_ALARM",
|
||||
Code = $"Pump_{name}",
|
||||
Name = $"Alarm_Pump_{name}",
|
||||
Value = pumpObservation.DrugName ?? positionPump,
|
||||
Time = pumpObservation.Time
|
||||
};
|
||||
|
||||
if (pumpObservation.PatientId != null)
|
||||
patientObservation.PatientId = pumpObservation.PatientId.Value;
|
||||
|
||||
return await CheckAlarmConfig(patientObservation);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,883 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.MongoModels;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace adas_core.Application.Customizations.HRYC;
|
||||
|
||||
public class CalculatedObservations : ICalculatedObservations
|
||||
{
|
||||
private readonly IOptions<ApiSettings> _apiSettings;
|
||||
private readonly List<string> _codesForInvasiveVentilation = [];
|
||||
|
||||
private readonly IConfigObservationService _configObservationService;
|
||||
|
||||
//private readonly Lazy<IBoxService> _boxService;
|
||||
private readonly List<string> _highFrequencyVentilation = [];
|
||||
private readonly Lazy<ILightBeaconService> _lightBeaconService;
|
||||
private readonly ILogger<CalculatedObservations> _logger;
|
||||
private readonly List<string> _nonInvasiveVentilation = [];
|
||||
private readonly Lazy<IObservationService> _observationService;
|
||||
private readonly Lazy<IPatientService> _patientService;
|
||||
|
||||
|
||||
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||
{
|
||||
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>(); //observationService;
|
||||
_patientService = serviceProvider.GetRequiredService<Lazy<IPatientService>>();
|
||||
_apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>(); //apiSettings;
|
||||
//_boxService = serviceProvider.GetRequiredService<Lazy<IBoxService>>();
|
||||
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
_lightBeaconService = serviceProvider.GetRequiredService<Lazy<ILightBeaconService>>();
|
||||
_configObservationService =
|
||||
serviceProvider.GetRequiredService<IConfigObservationService>(); //configObservationService;
|
||||
|
||||
|
||||
var highFrenquencyVentilation = _apiSettings.Value.HighFrequencyVentilation ?? null;
|
||||
highFrenquencyVentilation?.ForEach(x => _highFrequencyVentilation.Add(x.Trim()));
|
||||
|
||||
|
||||
var nonInvasiveVentilation = _apiSettings.Value.NonInvasiveVentilation ?? null;
|
||||
nonInvasiveVentilation?.ForEach(x => _nonInvasiveVentilation.Add(x.Trim()));
|
||||
|
||||
var codesForInvasiveVentilation = //TODO comprobar si se refiere a InvasiveVentilation
|
||||
_apiSettings.Value.InvasiveVentilation ?? null;
|
||||
codesForInvasiveVentilation?.ForEach(x => _codesForInvasiveVentilation.Add(x.Trim()));
|
||||
}
|
||||
|
||||
|
||||
public async Task<T?> Map<T>(T obs, bool onlyByName) where T : BasePatientObservation
|
||||
{
|
||||
_logger.LogTrace("Mapping {name} observation {obs}", obs.Name, obs);
|
||||
|
||||
switch (obs.Name)
|
||||
{
|
||||
case "Resp_Mode":
|
||||
_logger.LogTrace("Mapping Resp mode observation {obs}", obs);
|
||||
await CalculateVentilationMode(obs);
|
||||
break;
|
||||
case "Diuresis":
|
||||
case "Weight_Current":
|
||||
if (obs.Name == "Weight_Current") await CalculateWeight_DiffObservation(obs);
|
||||
await CalculateDiureis_WeightObservation(obs);
|
||||
break;
|
||||
case "AllergiesObs":
|
||||
await CalculateAllergiesObservation(obs);
|
||||
break;
|
||||
case "DrainagesObs":
|
||||
await CalculateDrainagesObservation(obs);
|
||||
break;
|
||||
case "PEEP":
|
||||
case "Pleateu_Pressure":
|
||||
await CalculateDelta_PressureObservation(obs);
|
||||
break;
|
||||
case "Daily_Balance":
|
||||
await CalculateDaily_BalanceObservation(obs);
|
||||
break;
|
||||
case "Hydric_Balance":
|
||||
await CalculateHydricBalanceCalculated(obs);
|
||||
obs = (T)await CalculateHydricBalance(obs);
|
||||
break;
|
||||
case "Hour_Balance":
|
||||
obs = (T)await CalculateHourBalance(obs);
|
||||
break;
|
||||
case "FR":
|
||||
await CalculateRespRate(obs);
|
||||
await CalculateIrox(obs);
|
||||
break;
|
||||
case "Vent_Rate":
|
||||
await CalculateRespRate(obs);
|
||||
break;
|
||||
case "SpO2":
|
||||
case "FiO2":
|
||||
await CalculateIrox(obs);
|
||||
break;
|
||||
case "NEWS":
|
||||
await CalculateNews(obs);
|
||||
break;
|
||||
}
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
return await Task.FromResult(pumpObservation);
|
||||
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
return Task.FromResult(new List<PatientTreatment?>().AsEnumerable());
|
||||
}
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
return Task.FromResult(diagnosis);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
if (string.IsNullOrEmpty(newObservation.Name))
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error FixTimeInconsistencyWithLast newObservation name ia null or empty. Observation: {newObservation}",
|
||||
newObservation);
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
var lastObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||
[newObservation.Name]);
|
||||
var lastObservation = lastObservations.FirstOrDefault();
|
||||
|
||||
if (lastObservation != null && DateTime.Compare(
|
||||
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||
newObservation.Time.Day, newObservation.Time.Hour,
|
||||
newObservation.Time.Minute, newObservation.Time.Second)
|
||||
) >= 0)
|
||||
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
public async Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||
{
|
||||
var ventRate = listToInsert.FirstOrDefault(obs => obs.Name == "MDC_VENT_RESP_RATE");
|
||||
var respRate = listToInsert.FirstOrDefault(obs => obs.Name == "MDC_RESP_RATE");
|
||||
|
||||
// Check if obs for Vent_Rate and FR is on the list to insert
|
||||
if (ventRate == null || respRate == null) return listToInsert;
|
||||
|
||||
var ventRateValue = double.TryParse(ventRate.Value.ToString(), out var v1) ? v1 : 0;
|
||||
// ventRate is on the list to insert but its value is 0
|
||||
if (ventRateValue == 0)
|
||||
{
|
||||
_logger.LogDebug("Find ventRate on PreMap request not processed because its value is 0");
|
||||
return listToInsert;
|
||||
}
|
||||
|
||||
var respRateValue = double.TryParse(ventRate.Value.ToString(), out var v2) ? v2 : 0;
|
||||
// respRate is on the list to insert but its value is 0
|
||||
if (respRateValue == 0)
|
||||
{
|
||||
_logger.LogDebug("Find respRate on PreMap request not processed because its value is 0");
|
||||
return listToInsert;
|
||||
}
|
||||
|
||||
|
||||
// Exists both obs and have value != 0
|
||||
// In that case we need to calculate Resp_Rate_Calculated just with the value of Vent_Rate
|
||||
try
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"Find on PreMap Vent_Rate and FR in the same request process Vent_Rate first to calculate Resp_Rate_Calculated");
|
||||
await _observationService.Value.InsertObservation(ventRate);
|
||||
listToInsert.Remove(ventRate);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Error while PreMap on insert obs: {ventRate} exception: {e}", ventRate, e);
|
||||
}
|
||||
|
||||
return listToInsert;
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IF news greater or equal than 5 and less than 7 is warning beacon and if greater or equal than 7 alert
|
||||
/// </summary>
|
||||
/// <param name="obs"></param>
|
||||
private async Task CalculateNews(BasePatientObservation obs)
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
var parsed = int.TryParse(pobs.Value.ToString(), out var valueParsed);
|
||||
var patient = await _patientService.Value.FindById(obs.PatientId);
|
||||
if (patient == null) return;
|
||||
//var beaconConfig = await _boxService.Value.GetBeaconConfig(new PatientLocation(patient.PointOfCare, patient.Bed));
|
||||
|
||||
//power off beacon
|
||||
|
||||
//recuperar la beacon del paciente y encenderla apagarla si el valor es > 5&6 o 7 alert
|
||||
|
||||
if ((parsed && valueParsed < 5) || !parsed)
|
||||
//await _balizaService.Value.PowerOffLed(beaconCnf);
|
||||
//await _observationService.Value.SendObsBroadcast(obs);
|
||||
await SendAlarm(obs, AlarmEnum.Name.NewsOff);
|
||||
else
|
||||
switch (valueParsed)
|
||||
{
|
||||
case >= 5 and < 7:
|
||||
_logger.LogDebug("beacon yellow alert by NEWS for patient: {patientid}", obs.PatientId);
|
||||
await SendAlarm(obs, AlarmEnum.Name.NewsWarning);
|
||||
//await _balizaService.Value.SendBeaconColor(patient, LightBeaconColor.YELLOW);
|
||||
break;
|
||||
case >= 7:
|
||||
_logger.LogDebug("beacon red alert by NEWS for patient: {patientid}", obs.PatientId);
|
||||
await SendAlarm(obs, AlarmEnum.Name.NewsAlert);
|
||||
//await _balizaService.Value.SendBeaconColor(patient, LightBeaconColor.RED);
|
||||
break;
|
||||
}
|
||||
|
||||
//if (obsAlarm == null) return;
|
||||
}
|
||||
|
||||
private async Task SendAlarm(BasePatientObservation obs, AlarmEnum.Name name)
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
PatientObservation nObs = new()
|
||||
{
|
||||
CodingSystem = "ADAS_ALARM",
|
||||
Code = name.ToString(),
|
||||
Name = $"Alarm_{name}",
|
||||
PatientId = pobs.PatientId,
|
||||
Time = pobs.Time
|
||||
};
|
||||
try
|
||||
{
|
||||
//ConfigObservations
|
||||
var configObs = await _configObservationService.Get(new PatientObservation
|
||||
{
|
||||
Name = nObs.Name,
|
||||
PatientId = obs.PatientId
|
||||
}
|
||||
);
|
||||
if (configObs == null)
|
||||
{
|
||||
_logger.LogError("Config observation is null on send alarm NEWS for {nObs}", nObs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (configObs is { Alarm.Enabled: true })
|
||||
{
|
||||
nObs.Alarm = configObs.Alarm;
|
||||
|
||||
if (configObs.Alarm.Beacon is { Enabled: true })
|
||||
{
|
||||
var patient = await _patientService.Value.FindById(obs.PatientId);
|
||||
if (patient != null)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"PatientId: {nObsPatientId}. Send Beacon alarmName {configObsAlarmBeaconBeaconColorValue}",
|
||||
nObs.PatientId, configObs.Alarm.Beacon.BeaconColor);
|
||||
nObs.Value = configObs.Alarm.Beacon.BeaconColor.ToString();
|
||||
SendBeaconCode(configObs.Alarm.Beacon.BeaconColor, patient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug(
|
||||
"Insert obs alarm for news at: {DateTimeNow} patientId: {nObsPatientId} color value: {nObsValue}",
|
||||
DateTime.Now, nObs.PatientId, nObs.Value);
|
||||
await _observationService.Value.InsertObservation(nObs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Exception sending alarm: {exMessage}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendBeaconCode(AlarmEnum.BeaconColor color, Patient patient)
|
||||
{
|
||||
if (!patient.PointOfCareId.HasValue)
|
||||
{
|
||||
_logger.LogError("Error sending beacon color on calculateObservations poc id on patient is null {Patient}",
|
||||
patient.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (color)
|
||||
{
|
||||
case AlarmEnum.BeaconColor.Blue:
|
||||
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Blue);
|
||||
break;
|
||||
case AlarmEnum.BeaconColor.Yellow:
|
||||
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Yellow);
|
||||
break;
|
||||
case AlarmEnum.BeaconColor.Red:
|
||||
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Red);
|
||||
break;
|
||||
case AlarmEnum.BeaconColor.None:
|
||||
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Off);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//(SpO2/FiO2)/FR IROX formula. Only calculate when all observations are in last 10 minutes.
|
||||
private async Task CalculateIrox(BasePatientObservation obs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var pob = (PatientObservation)obs;
|
||||
var obsToCalc = new List<PatientObservation> { pob };
|
||||
switch (pob.Name)
|
||||
{
|
||||
case "SpO2":
|
||||
|
||||
var fio2Frvalues = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||
["FiO2", "FR"]);
|
||||
if (fio2Frvalues.Count > 0) obsToCalc.AddRange(fio2Frvalues);
|
||||
|
||||
break;
|
||||
case "FiO2":
|
||||
var spo2Frvalues = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||
["SpO2", "FR"]);
|
||||
if (spo2Frvalues.Count > 0) obsToCalc.AddRange(spo2Frvalues);
|
||||
|
||||
break;
|
||||
case "FR":
|
||||
var fio2Spo2Values = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||
["FiO2", "SpO2"]);
|
||||
|
||||
if (fio2Spo2Values.Count > 0) obsToCalc.AddRange(fio2Spo2Values);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!obsToCalc.All(o => o.Time.CompareTo(DateTime.UtcNow.AddMinutes(10)) <= 0)) return;
|
||||
|
||||
var fio2 = obsToCalc.FirstOrDefault(o => o.Name == "FiO2");
|
||||
var fr = obsToCalc.FirstOrDefault(o => o.Name == "FR");
|
||||
var spo2 = obsToCalc.FirstOrDefault(o => o.Name == "SpO2");
|
||||
if (fio2 == null || fr == null || spo2 == null) return;
|
||||
|
||||
|
||||
if (!double.TryParse(spo2.Value.ToString(), out var nSpo2) ||
|
||||
!double.TryParse(fio2.Value.ToString(), out var nFio2) ||
|
||||
!double.TryParse(fr.Value.ToString(), out var nFr))
|
||||
{
|
||||
_logger.LogWarning("Error parsing values. fio2: {fio2}, fr: {fr}, spo2: {spo2}", fio2, fr, spo2);
|
||||
return;
|
||||
}
|
||||
|
||||
var spo2Value = nSpo2;
|
||||
var fio2Value = nFio2;
|
||||
var frValue = nFr;
|
||||
|
||||
if (spo2Value == 0 || fio2Value == 0 || frValue == 0) return;
|
||||
|
||||
|
||||
var value = nSpo2 / nFio2 / nFr;
|
||||
|
||||
var irox = new PatientObservation
|
||||
{
|
||||
Name = "IROX",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time,
|
||||
Value = value
|
||||
};
|
||||
await _observationService.Value.InsertObservation(irox);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Exception calculating IROX, error: {eMessage}", e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
RespRate solo se tiene que poner cuando no hay ningún ventRate en los últimos min y veinte segundos y el último no es un 0.
|
||||
|
||||
*/
|
||||
|
||||
//static readonly SemaphoreSlim semaphoreCalculateRespRate = new(1, 1);
|
||||
private async Task CalculateRespRate(BasePatientObservation obs)
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
_logger.LogDebug("CalculateRespRate {obsPatientid} wait {obsName} {obsTime} {pobsValue}", obs.PatientId,
|
||||
obs.Name, obs.Time, pobs.Value);
|
||||
if (Convert.ToDouble(pobs.Value) == 0) return;
|
||||
|
||||
if (Convert.ToDouble(pobs.Value) == 0) return;
|
||||
|
||||
var insert = true;
|
||||
if (obs.Name == "FR")
|
||||
{
|
||||
// Insertamos si no existe una obs Vent_Rate o si es existe tiene más de X" y su valor es > 0
|
||||
var lastVentRate =
|
||||
(await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["Vent_Rate"]))
|
||||
.FirstOrDefault();
|
||||
if (lastVentRate == null || (double.TryParse(lastVentRate.Value.ToString(), out var v) ? v : 0) == 0)
|
||||
{
|
||||
_logger.LogDebug("CalculateRespRate {id} lastVentRate: null", obs.PatientId);
|
||||
}
|
||||
else
|
||||
{
|
||||
var diff = DateTime.UtcNow.Subtract(lastVentRate.Time.ToUniversalTime());
|
||||
insert =
|
||||
lastVentRate.Time.ToUniversalTime().AddMinutes(_apiSettings.Value.CalculateRespRateVentExpires) <
|
||||
DateTime.UtcNow;
|
||||
_logger.LogDebug(
|
||||
"CalculateRespRate {patientid} lastVentRate: {value} - {time} passed {diff} {insert}",
|
||||
obs.PatientId, lastVentRate.Value, lastVentRate.Time, diff, insert ? "Inserted" : "Not inserted");
|
||||
}
|
||||
}
|
||||
|
||||
if (insert)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"CalculateRespRate {patientid} Insert Resp_Rate_Calculated with {name} - {time} value {value}",
|
||||
obs.PatientId, obs.Name, obs.Time, pobs.Value);
|
||||
var calculatedRespRate = new PatientObservation
|
||||
{
|
||||
Id = new ObjectId(),
|
||||
Name = "Resp_Rate_Calculated",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Name == "FR" ? obs.Time : obs.Time.AddSeconds(1),
|
||||
Value = pobs.Value,
|
||||
ParentData = new ParentDataClass { Name = obs.Name }
|
||||
};
|
||||
await _observationService.Value.InsertObservation(calculatedRespRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"CalculateRespRate {patientid} Insert Resp_Rate_Calculated with {name} - {time} value {value}",
|
||||
obs.PatientId, obs.Name, obs.Time, pobs.Value);
|
||||
}
|
||||
|
||||
_logger.LogDebug("CalculateRespRate {patientid} release {name} {time} {value}", obs.PatientId,
|
||||
obs.Name, obs.Time, pobs.Value);
|
||||
}
|
||||
|
||||
private async Task<BasePatientObservation> CalculateHydricBalance(BasePatientObservation obs)
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
|
||||
var lastHydricBalanceFromHour =
|
||||
await _observationService.Value.FindLastBeforeDate(pobs.PatientId, pobs.Time.AddMinutes(59),
|
||||
"Hydric_Balance");
|
||||
|
||||
if (lastHydricBalanceFromHour != null &&
|
||||
DateTime.Compare(new DateTime(lastHydricBalanceFromHour.Time.Year, lastHydricBalanceFromHour.Time.Month,
|
||||
lastHydricBalanceFromHour.Time.Day, lastHydricBalanceFromHour.Time.Hour, 0, 0)
|
||||
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0)
|
||||
pobs.Time = lastHydricBalanceFromHour.Time.AddSeconds(1);
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
private async Task<BasePatientObservation> CalculateHourBalance(BasePatientObservation obs)
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
|
||||
var lastHourBalanceFromHour =
|
||||
await _observationService.Value.FindLastBeforeDate(pobs.PatientId, pobs.Time.AddMinutes(59),
|
||||
"Hour_Balance");
|
||||
|
||||
if (lastHourBalanceFromHour != null &&
|
||||
DateTime.Compare(new DateTime(lastHourBalanceFromHour.Time.Year, lastHourBalanceFromHour.Time.Month,
|
||||
lastHourBalanceFromHour.Time.Day, lastHourBalanceFromHour.Time.Hour, 0, 0)
|
||||
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0)
|
||||
pobs.Time = lastHourBalanceFromHour.Time.AddSeconds(1);
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
private async Task CalculateHydricBalanceCalculated(BasePatientObservation obs)
|
||||
{
|
||||
//Hydric_Balance_Calculated
|
||||
//No guardamos como calculadas nunca horas futuras. En el obx siempre vienen con la hora y los minutos a 00
|
||||
|
||||
|
||||
var pobs = (PatientObservation)obs;
|
||||
var nowUniversalTime = DateTime.Now.ToUniversalTime();
|
||||
//La hora de la observación es mayor que la actual. No generamos la calculada
|
||||
if (DateTime.Compare(new DateTime(obs.Time.Year, obs.Time.Month, obs.Time.Day, obs.Time.Hour, 0, 0),
|
||||
new DateTime(nowUniversalTime.Year, nowUniversalTime.Month, nowUniversalTime.Day, nowUniversalTime.Hour,
|
||||
0, 0)) > 0
|
||||
)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"HYDRIC BALANCE: La hora de la observación es mayor que la actual. No generamos la calculada {obs}",
|
||||
obs);
|
||||
return;
|
||||
}
|
||||
|
||||
//Para la calculada. Si la última que tenemos es de la hora actual y lo que viene es de una hora anterior no entra como calculada.
|
||||
var lastHydricBalanceList = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||
["Hydric_Balance_Calculated"]);
|
||||
var lastHydricBalance = lastHydricBalanceList.FirstOrDefault();
|
||||
|
||||
if (lastHydricBalance != null && lastHydricBalance.Time.Hour == DateTime.UtcNow.Hour &&
|
||||
obs.Time.Hour != DateTime.UtcNow.Hour)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"HYDRIC BALANCE: ultima que tenemos es de la hora actual y lo que viene es de una hora anterior no entra como calculada {obs}",
|
||||
obs);
|
||||
return;
|
||||
}
|
||||
|
||||
//Si el último hydric balance es de una hora posterior a la observación que acaba de llegar no entra como calculada.
|
||||
if (lastHydricBalance != null &&
|
||||
DateTime.Compare(new DateTime(lastHydricBalance.Time.Year, lastHydricBalance.Time.Month,
|
||||
lastHydricBalance.Time.Day, lastHydricBalance.Time.Hour, 0, 0)
|
||||
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 1
|
||||
)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"HYDRIC BALANCE: Si el ultimo hydric balance es de una hora posterior a la observación que acaba de llegar no entra como calculada. {obs}",
|
||||
obs);
|
||||
return;
|
||||
}
|
||||
|
||||
var calculatedHydricBalance = new PatientObservation
|
||||
{
|
||||
Name = "Hydric_Balance_Calculated",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time.AddSeconds(1), //To discriminate updates.
|
||||
Value = pobs.Value,
|
||||
Units = obs.Units
|
||||
};
|
||||
|
||||
|
||||
if (lastHydricBalance != null && DateTime.Compare(
|
||||
new DateTime(lastHydricBalance.Time.Year, lastHydricBalance.Time.Month, lastHydricBalance.Time.Day,
|
||||
lastHydricBalance.Time.Hour, 0, 0)
|
||||
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0)
|
||||
calculatedHydricBalance.Time = lastHydricBalance.Time.AddSeconds(1);
|
||||
|
||||
await _observationService.Value.InsertObservation(calculatedHydricBalance);
|
||||
}
|
||||
|
||||
private async Task CalculateVentilationMode(BasePatientObservation obs)
|
||||
{
|
||||
_logger.LogDebug("CalculateVentilationMode {obs}", obs);
|
||||
var pobs = (PatientObservation)obs;
|
||||
|
||||
var respTypeObs = new PatientObservation
|
||||
{
|
||||
Name = "Resp_Type",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time
|
||||
};
|
||||
//https://epigram.teamwork.com/#/tasks/34765750
|
||||
if (obs.Code != null && _codesForInvasiveVentilation.Contains(obs.Code))
|
||||
{
|
||||
//añadir que sea solo cuando el valor es invasiva
|
||||
respTypeObs.Value = nameof(RespirationType.Invasive);
|
||||
respTypeObs.Time = obs.Time.AddSeconds(1);
|
||||
await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
|
||||
}
|
||||
else
|
||||
{
|
||||
var strValue = pobs.Value.ToString();
|
||||
if (strValue == null)
|
||||
return;
|
||||
|
||||
//si es en espera tendrá que insertar que es en espera
|
||||
if (!"EnESPERA".Equals(strValue))
|
||||
{
|
||||
respTypeObs.Value = _highFrequencyVentilation.Contains(strValue)
|
||||
? nameof(RespirationType.HighFrequencyVentilation)
|
||||
: _nonInvasiveVentilation.Contains(strValue)
|
||||
? respTypeObs.Value = nameof(RespirationType.NonInvasive)
|
||||
: nameof(RespirationType.Invasive);
|
||||
|
||||
await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CalculateWeight_DiffObservation(BasePatientObservation obs)
|
||||
{
|
||||
var toSearchList = new List<string>();
|
||||
|
||||
toSearchList.AddRange(new List<string> { "Weight_Current" });
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||
|
||||
var pWeight = values.FirstOrDefault(o => o.Name == "Weight_Current");
|
||||
|
||||
var newWeightObs = (PatientObservation)obs;
|
||||
|
||||
if (pWeight?.Value != null && double.TryParse(pWeight.Value.ToString(), out var weight) &&
|
||||
double.TryParse(newWeightObs.Value.ToString(), out var newWeight))
|
||||
{
|
||||
var weightDiffValue = Math.Round(newWeight - weight, 2);
|
||||
|
||||
var weightDiff = new PatientObservation
|
||||
{
|
||||
Name = "Weight_Diff",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time,
|
||||
Value = weightDiffValue,
|
||||
Units = obs.Units
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(weightDiff);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CalculateDiureis_WeightObservation(BasePatientObservation obs)
|
||||
{
|
||||
var toSearchList = new List<string>();
|
||||
|
||||
PatientObservation? diuresisObs;
|
||||
PatientObservation? weightObs;
|
||||
|
||||
toSearchList.AddRange(new List<string> { "Diuresis", "Weight_Current" });
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||
|
||||
if (obs.Name == "Diuresis")
|
||||
{
|
||||
diuresisObs = (PatientObservation)obs;
|
||||
weightObs = values.FirstOrDefault(o => o.Name == "Weight_Current");
|
||||
}
|
||||
else
|
||||
{
|
||||
weightObs = (PatientObservation)obs;
|
||||
diuresisObs = values.FirstOrDefault(o => o.Name == "Diuresis");
|
||||
|
||||
if (diuresisObs == null || CheckExpired(diuresisObs)) return;
|
||||
}
|
||||
|
||||
if (weightObs?.Value != null)
|
||||
if (double.TryParse(weightObs.Value.ToString(), out var nWeight) && nWeight != 0 &&
|
||||
double.TryParse(diuresisObs.Value.ToString(), out var diuresis))
|
||||
{
|
||||
var diruesisWeightValue = Math.Round(diuresis / nWeight, 2);
|
||||
|
||||
var diruesisWeight = new PatientObservation
|
||||
{
|
||||
Name = "Diuresis_Weight",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time,
|
||||
Value = diruesisWeightValue,
|
||||
Units = "ml/kg"
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(diruesisWeight);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CalculateAllergiesObservation(BasePatientObservation obs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
|
||||
var allergiesObs = new PatientObservation
|
||||
{
|
||||
Name = "Allergies",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time,
|
||||
MessageTime = pobs.MessageTime
|
||||
};
|
||||
|
||||
var patientAllergiesValues =
|
||||
new List<PatientAllergiesValue>((IEnumerable<PatientAllergiesValue>)pobs.Value);
|
||||
|
||||
var allergiesValues = patientAllergiesValues.GroupBy(o => o.Type)
|
||||
.Select(x =>
|
||||
new PatientAllergiesValue
|
||||
{
|
||||
Type = x.Key,
|
||||
Value = string.Join(", ", x.Select(v => v.Value)),
|
||||
Notes = string.Join(", ", x.Select(n => n.Notes))
|
||||
}).ToList();
|
||||
|
||||
|
||||
var farmacosType = false;
|
||||
var farmacosValues = new List<string>();
|
||||
var values = new List<string>();
|
||||
|
||||
foreach (var allergies in allergiesValues)
|
||||
{
|
||||
if (allergies.Value == null)
|
||||
continue;
|
||||
|
||||
var type = allergies.Type?.Replace("Alergia a ", "").Replace("Alergia ", "").ToUpper();
|
||||
|
||||
if (type != null)
|
||||
switch (type)
|
||||
{
|
||||
case "FÁRMACOS":
|
||||
farmacosType = true;
|
||||
farmacosValues.Add(allergies.Value.ToUpper());
|
||||
break;
|
||||
|
||||
default:
|
||||
values.Add(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (farmacosType)
|
||||
{
|
||||
values.Add($"FÁRMACOS ({string.Join(", ", farmacosValues)})");
|
||||
allergiesObs.Status = StatusEnum.Type.Alert;
|
||||
}
|
||||
|
||||
allergiesObs.Value = string.Join(", ", values);
|
||||
|
||||
await _observationService.Value.InsertObservation(allergiesObs);
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
_logger.LogError("CalculateAllergiesObservation {obs}", obs);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CalculateDrainagesObservation(BasePatientObservation obs)
|
||||
{
|
||||
var pobs = (PatientObservation)obs;
|
||||
|
||||
var patientDraingesValue = (PatientDrainagesValue)pobs.Value;
|
||||
|
||||
if (patientDraingesValue.Type == "Drenaje ventricular")
|
||||
{
|
||||
var dve = new PatientObservation
|
||||
{
|
||||
Name = "DVE",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time,
|
||||
Units = obs.Units
|
||||
};
|
||||
|
||||
var drainageHeight = new PatientObservation
|
||||
{
|
||||
Name = "Drainage_Height",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = obs.Time
|
||||
};
|
||||
|
||||
if (patientDraingesValue.Volume != null)
|
||||
{
|
||||
dve.Value = patientDraingesValue.Volume;
|
||||
await _observationService.Value.InsertObservation(dve);
|
||||
}
|
||||
|
||||
if (patientDraingesValue.Height != null)
|
||||
{
|
||||
drainageHeight.Value = patientDraingesValue.Height;
|
||||
await _observationService.Value.InsertObservation(drainageHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CalculateDelta_PressureObservation(BasePatientObservation obs)
|
||||
{
|
||||
var toSearchList = new List<string>();
|
||||
|
||||
PatientObservation? peep;
|
||||
PatientObservation? pleateuPressure;
|
||||
|
||||
toSearchList.AddRange(new List<string> { "PEEP", "Pleateu_Pressure" });
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||
var time = obs.Time;
|
||||
double pleateuPressureValue = 0;
|
||||
|
||||
if (obs.Name == "PEEP")
|
||||
{
|
||||
peep = (PatientObservation)obs;
|
||||
pleateuPressure = values.FirstOrDefault(o => o.Name == "Pleateu_Pressure");
|
||||
|
||||
if (pleateuPressure?.Time != null && time.CompareTo(pleateuPressure.Time) > 0) time = pleateuPressure.Time;
|
||||
}
|
||||
else
|
||||
{
|
||||
pleateuPressure = (PatientObservation)obs;
|
||||
peep = values.FirstOrDefault(o => o.Name == "PEEP");
|
||||
|
||||
if (peep?.Time != null && time.CompareTo(peep.Time) > 0) time = peep.Time;
|
||||
}
|
||||
|
||||
if (peep?.Value != null && pleateuPressure?.Value != null)
|
||||
{
|
||||
var peepSuccess = double.TryParse(peep.Value.ToString(), out var peepValue);
|
||||
if (!peepSuccess) peepValue = 0;
|
||||
|
||||
if (!peepSuccess) pleateuPressureValue = 0;
|
||||
|
||||
var deltaPressure = Math.Round(pleateuPressureValue - peepValue, 2);
|
||||
|
||||
|
||||
var deltaPressureObs = new PatientObservation
|
||||
{
|
||||
Name = "Delta_Pressure",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = time,
|
||||
Value = deltaPressure
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(deltaPressureObs);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CalculateDaily_BalanceObservation(BasePatientObservation obs)
|
||||
{
|
||||
if (obs.Time.ToLocalTime().Hour == 8)
|
||||
{
|
||||
var dailyBalanceCalculated = new PatientObservation
|
||||
{
|
||||
Name = "Daily_Balance_Calculated",
|
||||
CodingSystem = "ADAS",
|
||||
PatientId = obs.PatientId,
|
||||
Time = DateTime.Now,
|
||||
Units = obs.Units,
|
||||
Value = ((PatientObservation)obs).Value
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(dailyBalanceCalculated);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CheckExpired(PatientObservation obs)
|
||||
{
|
||||
if (obs.Expires == null) return false;
|
||||
|
||||
var timeExpire = obs.Time.ToLocalTime().AddSeconds(Convert.ToDouble(obs.Expires));
|
||||
|
||||
return DateTime.Now.CompareTo(timeExpire) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,695 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace adas_core.Application.Customizations.HUVH.UCIA;
|
||||
|
||||
public class CalculatedObservations : ICalculatedObservations
|
||||
{
|
||||
private const string CodingSystem = "ADAS";
|
||||
private readonly List<string>? _antibioticList;
|
||||
private readonly List<string>? _antidepressantsList;
|
||||
private readonly List<string>? _antihypertensivesList;
|
||||
private readonly List<string>? _antipsicoticList;
|
||||
private readonly List<string>? _anxiolyticsList;
|
||||
private readonly List<string>? _inotropicMedicines;
|
||||
private readonly ILogger<CalculatedObservations> _logger;
|
||||
private readonly Lazy<IMedicineService> _medicineService;
|
||||
private readonly List<string>? _neuroMedicationList;
|
||||
private readonly Lazy<IObservationService> _observationService;
|
||||
|
||||
private readonly List<string>? _sedationList;
|
||||
private readonly List<string>? _serumColloidList;
|
||||
private readonly List<string>? _serumCrystalloidList;
|
||||
|
||||
private readonly Lazy<ITreatmentService> _treatmentService;
|
||||
|
||||
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||
{
|
||||
_treatmentService = serviceProvider.GetRequiredService<Lazy<ITreatmentService>>();
|
||||
_medicineService = serviceProvider.GetRequiredService<Lazy<IMedicineService>>();
|
||||
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
|
||||
var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>(); //apiSettings;
|
||||
|
||||
_sedationList = apiSettings.Value.Sedation;
|
||||
_inotropicMedicines = apiSettings.Value.InotropicMedicines;
|
||||
_antibioticList = apiSettings.Value.AntibioticList;
|
||||
_anxiolyticsList = apiSettings.Value.AnxiolyticList;
|
||||
_antipsicoticList = apiSettings.Value.AntipsicoticList;
|
||||
_antidepressantsList = apiSettings.Value.AntidepressantsList;
|
||||
_neuroMedicationList = apiSettings.Value.NeuroMedicationList;
|
||||
_serumCrystalloidList = apiSettings.Value.SerumCrystalloidList;
|
||||
_serumColloidList = apiSettings.Value.SerumColloidList;
|
||||
_antihypertensivesList = apiSettings.Value.AntihypertensivesList;
|
||||
}
|
||||
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||
{
|
||||
if (obs.Name is "PSI" or "RASS" or "TS") _ = CalculateOverSedation(obs);
|
||||
|
||||
if (obs.Name is "Inspiratory_Pressure" or "Compliancia" or "Air_Flow") _ = CalculateVentilationMode(obs);
|
||||
|
||||
if (obs.Name is "ECMO_Location" or "Location_Drainage_Cannula" or "Location_Return_Cannula")
|
||||
obs = (T)await CalculateEcmoLocation(obs);
|
||||
|
||||
if (obs.Name is "EVN" or "ANI" or "ESCID") _ = CalculateOverAnalgesia(obs);
|
||||
|
||||
if (obs.Name is "Pmeset" or "PEEP") _ = CalculateDrivingPressure(obs);
|
||||
|
||||
if (obs.Name is "SpO2_FiO2_Ratio" or "FR") _ = CalculateRoxIndex(obs);
|
||||
|
||||
if (obs.Name is "Diuresis") _ = CalculateDiuresis(obs);
|
||||
|
||||
if (obs.Name is "Rehabilitation") obs = (T)await CalculateRehabilitationAlarm(obs);
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
public async Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
var order = treatment.PlacerOrder?.EntityIdentifier; //aquí almacenamos el número de orden
|
||||
if (string.IsNullOrEmpty(order)) return treatment;
|
||||
|
||||
//comprobamos el estado de los tratamientos anteriores
|
||||
var oldTreatments = await CheckExpiredPatientTreatments(treatment);
|
||||
|
||||
treatment.OrderControl = oldTreatments.Any() ? OrderControlType.Xo : OrderControlType.Nw;
|
||||
|
||||
if (treatment.EndTime != null)
|
||||
//el tratamiento ha expirado
|
||||
treatment.OrderControl = OrderControlType.Dc;
|
||||
|
||||
await CheckTreatmentMedicines(treatment);
|
||||
|
||||
return treatment;
|
||||
}
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
return await Task.FromResult(pumpObservation);
|
||||
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
//Esto viene del schedulerService para chequear los medicamentos activos
|
||||
CheckMedicationCategories(patientId, activeMedicines);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(id);
|
||||
return activeTreatments;
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
if (string.IsNullOrEmpty(newObservation.Name))
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error FixTimeInconsistencyWithLast. Observation name is null or empty. Observation: {newObservation}",
|
||||
newObservation);
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
var lastObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||
[newObservation.Name]);
|
||||
var lastObservation = lastObservations.FirstOrDefault();
|
||||
|
||||
if (lastObservation != null && DateTime.Compare(
|
||||
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||
newObservation.Time.Day, newObservation.Time.Hour,
|
||||
newObservation.Time.Minute, newObservation.Time.Second)
|
||||
) >= 0)
|
||||
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||
{
|
||||
return Task.FromResult(listToInsert);
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private async Task<BasePatientObservation> CalculateRehabilitationAlarm(BasePatientObservation obs)
|
||||
{
|
||||
//En rojo si el grado es de 0 a 2 incluidos, por más de 7 días
|
||||
|
||||
if (obs is not PatientObservation pobs || !int.TryParse(pobs.Value.ToString(), out var pobsValue) ||
|
||||
pobsValue > 2) return obs;
|
||||
|
||||
var result = await _observationService.Value.FindLastObservations(obs.PatientId, 6, ["Rehabilitation"]);
|
||||
|
||||
var obsInAlert = result.Count(o =>
|
||||
int.TryParse(o.Value.ToString(), out var oValue) && oValue is >= 0 and <= 2);
|
||||
if (obsInAlert == 6) pobs.Status = StatusEnum.Type.Alert;
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
private async Task CalculateDiuresis(BasePatientObservation obs)
|
||||
{
|
||||
// Calculado como el sumatorio de la Diuresis de las últimas 6h
|
||||
// entre el último peso medido del paciente y entre 6. Medido en ml/kg/h
|
||||
// Valor = sum(Diuresis últimas 6 horas) / Weight / 6
|
||||
|
||||
if (obs is not PatientObservation pobs)
|
||||
return;
|
||||
|
||||
double weightValue = 0;
|
||||
var numValues = pobs.Name switch
|
||||
{
|
||||
"Diuresis" => 2, // Si la observación entrante es "Diuresis", necesitamos las 2 últimas para completar 6h.
|
||||
"Weight" => 3, // Si la observación entrante es "Weight", necesitamos las 3 últimas de "Diuresis".
|
||||
_ => 0
|
||||
};
|
||||
|
||||
if (numValues == 0)
|
||||
return; // Si no es ni Diuresis ni Weight, no aplicamos cálculo.
|
||||
|
||||
// Obtener las observaciones de diuresis necesarias
|
||||
var diuresisObservations =
|
||||
await _observationService.Value.FindLastObservations(pobs.PatientId, numValues, ["Diuresis"]);
|
||||
var diuresisValues = diuresisObservations
|
||||
.Select(o => double.TryParse(o.Value.ToString(), out var value) ? value : 0)
|
||||
.ToList();
|
||||
|
||||
if (pobs.Name == "Diuresis")
|
||||
{
|
||||
// Si la observación entrante es Diuresis, la agregamos
|
||||
if (double.TryParse(pobs.Value.ToString(), out var currentDiuresis))
|
||||
diuresisValues.Insert(0, currentDiuresis);
|
||||
|
||||
// Buscar el último peso registrado
|
||||
var weightObservations =
|
||||
await _observationService.Value.FindLastObservations(pobs.PatientId, 1, ["Weight"]);
|
||||
var weightObs = weightObservations.FirstOrDefault();
|
||||
if (weightObs != null && double.TryParse(weightObs.Value.ToString(), out var wObsValue))
|
||||
weightValue = wObsValue;
|
||||
}
|
||||
else if (pobs.Name == "Weight" && double.TryParse(pobs.Value.ToString(), out var wValue))
|
||||
{
|
||||
// Si la observación entrante es Weight, asignamos su valor directamente.
|
||||
weightValue = wValue;
|
||||
}
|
||||
|
||||
// Validaciones antes de calcular
|
||||
if (diuresisValues.Count < 3)
|
||||
{
|
||||
_logger.LogWarning("Calculated Diuresis lacks sufficient values. Required: 3, Found: {count}",
|
||||
diuresisValues.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
if (weightValue <= 0)
|
||||
{
|
||||
_logger.LogWarning("Calculated Diuresis aborted due to invalid weight value: {weight}", weightValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cálculo del índice de diuresis
|
||||
var diuresisIndex = diuresisValues.Sum() / weightValue / 6;
|
||||
|
||||
var diuresisObs = new PatientObservation
|
||||
{
|
||||
PatientId = pobs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = "Calculated_Diuresis",
|
||||
Value = diuresisIndex
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(diuresisObs, mapObs: false);
|
||||
}
|
||||
|
||||
|
||||
private async Task CalculateRoxIndex(BasePatientObservation obs)
|
||||
{
|
||||
// Cálculo dividiendo el ratio SpO2/FiO2 entre la FR
|
||||
// Valor = (SpO2_FiO2_Ratio) / FR
|
||||
|
||||
if (obs is not PatientObservation pobs)
|
||||
return;
|
||||
|
||||
List<string>? requiredObservations = pobs.Name switch
|
||||
{
|
||||
"SpO2_FiO2_Ratio" => ["FR"], // Si la observación actual es SpO2_FiO2_Ratio, necesitamos FR
|
||||
"FR" => ["SpO2_FiO2_Ratio"], // Si la observación actual es FR, necesitamos SpO2_FiO2_Ratio
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (requiredObservations is null)
|
||||
return;
|
||||
|
||||
var result = await _observationService.Value.FindLastObservations(pobs.PatientId, 1, requiredObservations);
|
||||
var targetObs = result.FirstOrDefault();
|
||||
|
||||
if (targetObs == null || !double.TryParse(targetObs.Value.ToString(), out var targetValue))
|
||||
return;
|
||||
|
||||
// Determinar los valores necesarios para el cálculo
|
||||
var spo2FiO2Ratio = pobs.Name == "SpO2_FiO2_Ratio"
|
||||
? double.TryParse(pobs.Value.ToString(), out var ratio) ? ratio : 0
|
||||
: targetValue;
|
||||
|
||||
var fr = pobs.Name == "FR"
|
||||
? double.TryParse(pobs.Value.ToString(), out var frValue) ? frValue : 0
|
||||
: targetValue;
|
||||
|
||||
if (fr == 0) // Evita división por cero
|
||||
return;
|
||||
|
||||
var roxIndexObs = new PatientObservation
|
||||
{
|
||||
PatientId = pobs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = "Rox_Index",
|
||||
Value = spo2FiO2Ratio / fr
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(roxIndexObs, mapObs: false);
|
||||
}
|
||||
|
||||
private async Task CalculateDrivingPressure(BasePatientObservation obs)
|
||||
{
|
||||
//Diferencia entre la Pmeset y la PEEP
|
||||
//Calculo Valor = Pmeset - PEEP
|
||||
|
||||
try
|
||||
{
|
||||
if (obs is not PatientObservation pobs)
|
||||
return;
|
||||
|
||||
var targetObservation = pobs.Name switch
|
||||
{
|
||||
"Pmeset" => "PEEP",
|
||||
"PEEP" => "Pmeset",
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (targetObservation is null)
|
||||
return;
|
||||
|
||||
var resultList =
|
||||
await _observationService.Value.FindLastObservations(obs.PatientId, 1, [targetObservation]);
|
||||
var targetObs = resultList.FirstOrDefault();
|
||||
if (targetObs == null || !int.TryParse(targetObs.Value.ToString(), out var targetValue))
|
||||
return;
|
||||
|
||||
var peepValue = pobs.Name == "PEEP"
|
||||
? int.TryParse(pobs.Value.ToString(), out var peep) ? peep : 0
|
||||
: targetValue;
|
||||
var pmesetValue = pobs.Name == "Pmeset"
|
||||
? int.TryParse(pobs.Value.ToString(), out var pmeset) ? pmeset : 0
|
||||
: targetValue;
|
||||
|
||||
var drivingPressureObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = "Driving_Pressure",
|
||||
Value = pmesetValue - peepValue
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(drivingPressureObs, mapObs: false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CalculateOverAnalgesia(BasePatientObservation? obs, ObjectId? patientId = null)
|
||||
{
|
||||
// Mandar observación 'SOBREANALGESIA'
|
||||
// 0 <= EVN <= 3 o ESCID = 3 o ANI > 70
|
||||
// y
|
||||
// Perfusiones de morfina, remifentanilo y fentanilo sostenidas > 24h.
|
||||
|
||||
try
|
||||
{
|
||||
List<string> requiredObservations = ["EVN", "ESCID", "ANI"];
|
||||
|
||||
// Si patientId es null, la información proviene de una observación.
|
||||
// Si tiene valor, proviene de un tratamiento.
|
||||
if (!patientId.HasValue)
|
||||
{
|
||||
if (obs is not PatientObservation pobs || !int.TryParse(pobs.Value.ToString(), out _))
|
||||
return;
|
||||
|
||||
patientId = pobs.PatientId;
|
||||
}
|
||||
|
||||
var observations =
|
||||
await _observationService.Value.FindLastObservations(patientId.Value, 1, requiredObservations);
|
||||
|
||||
// Verificar si alguna observación cumple la condición
|
||||
var condition1 = observations.Any(observation =>
|
||||
int.TryParse(observation.Value.ToString(), out var obsValue) && observation.Name switch
|
||||
{
|
||||
"EVN" when obsValue is >= 0 and <= 3 => true,
|
||||
"ESCID" when obsValue == 3 => true,
|
||||
"ANI" when obsValue > 70 => true,
|
||||
_ => false
|
||||
});
|
||||
|
||||
if (!condition1)
|
||||
return;
|
||||
|
||||
// Verificar tratamientos activos y umbral de analgesia
|
||||
var treatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(patientId.Value);
|
||||
var patientTreatments = treatments.ToList();
|
||||
if (!patientTreatments.Any()) return;
|
||||
|
||||
var morfina =
|
||||
patientTreatments.FirstOrDefault(t => t != null && t.RequestedGiveCodes.Any(c => c.Text is "Morfina"));
|
||||
var remifentanilo = patientTreatments.FirstOrDefault(t =>
|
||||
t != null && t.RequestedGiveCodes.Any(c => c.Text is "Remifentanilo"));
|
||||
var fentanilo =
|
||||
patientTreatments.FirstOrDefault(t =>
|
||||
t != null && t.RequestedGiveCodes.Any(c => c.Text is "Fentanilo"));
|
||||
|
||||
if (morfina != null && !ExceedsAnalgesiaThreshold(morfina) &&
|
||||
remifentanilo != null && !ExceedsAnalgesiaThreshold(remifentanilo) &&
|
||||
fentanilo != null && !ExceedsAnalgesiaThreshold(fentanilo))
|
||||
return;
|
||||
|
||||
|
||||
var overAnalgesiaObs = new PatientObservation
|
||||
{
|
||||
PatientId = patientId.Value,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = "Over_Analgesia",
|
||||
Value = bool.TrueString
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(overAnalgesiaObs, mapObs: false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculating Over_Analgesia. Exception: {ex}", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private Task<BasePatientObservation> CalculateEcmoLocation(BasePatientObservation obs)
|
||||
{
|
||||
//Las opciones pueden ser VV, VA o ECMO.
|
||||
//Cuando llegue VV se muestra VV.
|
||||
//Cuando llegue VA se muestra VA.
|
||||
//Cuando llegue los siguientes parámetros, se debe mostrar ECMO: ECCO2r, VVDL, VA+V, VVDL+V, VV+V, VVA
|
||||
if (obs is not PatientObservation pobs)
|
||||
return Task.FromResult(obs);
|
||||
|
||||
var ecmoValues = new List<string> { "ECCO2r", "VVDL", "VA+V", "VVDL+V", "VV+V", "VVA" };
|
||||
|
||||
var obsValue = pobs.Value.ToString();
|
||||
|
||||
if (obsValue != null && ecmoValues.Contains(obsValue)) pobs.Value = "ECMO";
|
||||
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
private async Task CalculateVentilationMode(BasePatientObservation obs)
|
||||
{
|
||||
//- Si llega valor de PI pero NO COMPL, el tipo de ventilación es VMNI
|
||||
//- Si llega valor de PS pero no llega COMPL, el tipo de ventilación es VMNI
|
||||
//- Si llega COMPL, el tipo de ventilación es VMI
|
||||
//- Si llega Flujo, leer el tipo de ventilación de CCC(CNAF o CTAF)
|
||||
|
||||
var mode = string.Empty;
|
||||
|
||||
switch (obs.Name)
|
||||
{
|
||||
case "Inspiratory_Pressure":
|
||||
var complObs = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["Compliancia"]);
|
||||
if (!complObs.Any())
|
||||
mode = "VMNI";
|
||||
|
||||
break;
|
||||
case "Compliancia":
|
||||
mode = "VMI";
|
||||
break;
|
||||
case "Air_Flow":
|
||||
var cccVentMode =
|
||||
await _observationService.Value.FindByPatientIdAndCodingSystemAsync(obs.PatientId, "CCC",
|
||||
"Ventilation_Mode");
|
||||
|
||||
if (!await cccVentMode.AnyAsync())
|
||||
return;
|
||||
mode = cccVentMode.First().Value.ToString() ?? string.Empty;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(mode)) return;
|
||||
|
||||
|
||||
var ventilationModeObservation = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = "Ventilation_Mode",
|
||||
Value = mode
|
||||
};
|
||||
|
||||
_ = _observationService.Value.InsertObservation(ventilationModeObservation, mapObs: false);
|
||||
}
|
||||
|
||||
private async Task CalculateOverSedation(BasePatientObservation? obs, ObjectId? patientId = null)
|
||||
{
|
||||
//Mandar observación 'SOBRESEDACIÓN'
|
||||
//cuando:
|
||||
//(RASS =-4 o RASS =-5) y
|
||||
//PSI < 25 y
|
||||
//TS > 5 y
|
||||
//(Propofol > 3 o Midazolam > 0,05 ó Isoflorano > 10)
|
||||
|
||||
try
|
||||
{
|
||||
var pobsName = string.Empty;
|
||||
|
||||
//si patientId viene null viene la observación
|
||||
//Si tiene valor viene de un tratamiento
|
||||
|
||||
if (!patientId.HasValue)
|
||||
{
|
||||
if (obs is not PatientObservation pobs || !int.TryParse(pobs.Value.ToString(), out var pobsValue))
|
||||
return;
|
||||
|
||||
patientId = pobs.PatientId;
|
||||
pobsName = pobs.Name;
|
||||
|
||||
switch (pobsName)
|
||||
{
|
||||
case "RASS" when pobsValue is not (-4 or -5):
|
||||
case "PSI" when pobsValue >= 25:
|
||||
case "TS" when pobsValue <= 5:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var requiredObservations = pobsName switch
|
||||
{
|
||||
"RASS" => ["PSI", "TS"],
|
||||
"PSI" => ["RASS", "TS"],
|
||||
"TS" => ["RASS", "PSI"],
|
||||
_ => new List<string> { "RASS", "PSI", "TS" }
|
||||
};
|
||||
|
||||
var result = await _observationService.Value.FindLastObservations(patientId.Value, 1, requiredObservations);
|
||||
var observations = result.ToDictionary(r => r.Name?.ToString() ?? "null");
|
||||
|
||||
if ((pobsName != "RASS" && (!observations.TryGetValue("RASS", out var rassObs) ||
|
||||
!int.TryParse(rassObs.Value.ToString(), out var rassValue) ||
|
||||
rassValue is not (-4 or -5))) ||
|
||||
(pobsName != "PSI" && (!observations.TryGetValue("PSI", out var psiObs) ||
|
||||
!int.TryParse(psiObs.Value.ToString(), out var psiValue) || psiValue >= 25)) ||
|
||||
(pobsName != "TS" && (!observations.TryGetValue("TS", out var tsObs) ||
|
||||
!int.TryParse(tsObs.Value.ToString(), out var tsValue) || tsValue <= 5)))
|
||||
return;
|
||||
|
||||
var treatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(patientId.Value);
|
||||
if (!treatments.Any(ExceedsSedationThreshold)) return;
|
||||
|
||||
var overSedationObs = new PatientObservation
|
||||
{
|
||||
PatientId = patientId.Value,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = "Over_Sedation",
|
||||
Value = bool.TrueString
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(overSedationObs, mapObs: false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error calculating Over_Sedation. Exception: {ex}", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ExceedsAnalgesiaThreshold(PatientTreatment? treatment)
|
||||
{
|
||||
// Perfusiones de morfina, remifentanilo o fentanilo sostenidas > 24 h
|
||||
|
||||
return treatment is { StartTime: not null } &&
|
||||
treatment.StartTime.Value.AddSeconds(86400) < DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private static bool ExceedsSedationThreshold(PatientTreatment? treatment)
|
||||
{
|
||||
return (treatment != null &&
|
||||
treatment.RequestedGiveCodes.Any(c =>
|
||||
c.Text == "Propofol" && treatment.RequestedGiveAmountMinimum > 3)) ||
|
||||
(treatment != null && treatment.RequestedGiveCodes.Any(c =>
|
||||
c.Text == "Midazolam" && treatment.RequestedGiveAmountMinimum > 0.05)) ||
|
||||
(treatment != null && treatment.RequestedGiveCodes.Any(c =>
|
||||
c.Text == "Isoflorano" && treatment.RequestedGiveAmountMinimum > 10));
|
||||
}
|
||||
|
||||
private async Task<List<PatientTreatment>> CheckExpiredPatientTreatments(PatientTreatment treatment)
|
||||
{
|
||||
//si el tratamiento ha expirado actualizamos el OrderControl a DC y devolvemos las que siguen activas
|
||||
var result = new List<PatientTreatment>();
|
||||
var oldTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(treatment.PatientId);
|
||||
|
||||
foreach (var t in oldTreatments.Where(t => t != null))
|
||||
if (t is { EndTime: not null } && t.EndTime > DateTime.UtcNow)
|
||||
{
|
||||
t.OrderControl = OrderControlType.Dc;
|
||||
_ = _treatmentService.Value.UpdateTreatment(t);
|
||||
}
|
||||
else if (t != null)
|
||||
{
|
||||
result.Add(t);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task CheckTreatmentMedicines(PatientTreatment treatment)
|
||||
{
|
||||
var newMedicines = (await Task.WhenAll(treatment.RequestedGiveCodes
|
||||
.Select(async code => await _medicineService.Value.GetByCode(code.Identifier))))
|
||||
.Where(m => m != null)
|
||||
.ToList();
|
||||
|
||||
if (newMedicines.Count == 0) return;
|
||||
|
||||
var activeTreatments = (await GetActiveTreatmentsByPatient(treatment.PatientId)).ToList();
|
||||
var activeMedicines = (await _medicineService.Value.GetMedicinesOfTreatments(activeTreatments)).ToList();
|
||||
|
||||
// Combina ambas listas y selecciona solo elementos únicos con el mismo nombre
|
||||
var uniqueMedicines = newMedicines
|
||||
.Concat(activeMedicines)
|
||||
.GroupBy(m => m?.Name)
|
||||
.Select(g => g.First())
|
||||
.ToList();
|
||||
|
||||
// uniqueMedicines contiene la lista de medicamentos activos de un paciente
|
||||
CheckMedicationCategories(treatment.PatientId, uniqueMedicines as List<Medicine>);
|
||||
}
|
||||
|
||||
private void CheckMedicationCategories(ObjectId patientId, List<Medicine> uniqueMedicines)
|
||||
{
|
||||
var medicationCategories = new Dictionary<string, List<string>?>
|
||||
{
|
||||
{ "Sedation_Medication_Multivalue", _sedationList },
|
||||
{ "Inotropic_Medication_Multivalue", _inotropicMedicines },
|
||||
{ "Antibiotic_Medication_Multivalue", _antibioticList },
|
||||
{ "Anxiolytic_Medication_Multivalue", _anxiolyticsList },
|
||||
{ "Antipsychotic_Medication_Multivalue", _antipsicoticList },
|
||||
{ "Antidepressants_Medication_Multivalue", _antidepressantsList },
|
||||
{ "Neuro_Medication_Multivalue", _neuroMedicationList },
|
||||
{ "Crystalloid_Serum_Medication_Multivalue", _serumCrystalloidList },
|
||||
{ "Colloid_Serum_Medication_Multivalue", _serumColloidList },
|
||||
{ "Antihypertensives_Medication_Multivalue", _antihypertensivesList }
|
||||
};
|
||||
|
||||
foreach (var category in medicationCategories)
|
||||
{
|
||||
var observations = uniqueMedicines?
|
||||
.Where(m => category.Value != null && !string.IsNullOrEmpty(m.Name) && m.Name != null &&
|
||||
category.Value.Contains(m.Name))
|
||||
.ToList();
|
||||
|
||||
if (observations != null && observations.Any())
|
||||
_ = CreateMedicationMultivalueObservation(observations, patientId, category.Key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task CreateMedicationMultivalueObservation(IEnumerable<Medicine?> medications, ObjectId patientId,
|
||||
string obsName)
|
||||
{
|
||||
var newObs = new PatientObservation
|
||||
{
|
||||
PatientId = patientId,
|
||||
Name = obsName,
|
||||
CodingSystem = CodingSystem,
|
||||
Value = medications.Select(m => m?.Name).ToArray(),
|
||||
Time = DateTime.Now
|
||||
};
|
||||
|
||||
var lastObsList = await _observationService.Value.FindLastObservations(patientId, 1, [obsName]);
|
||||
var lastObs = lastObsList.FirstOrDefault();
|
||||
if (lastObs is { Expired: false })
|
||||
{
|
||||
//expiramos la anterior
|
||||
lastObs.Expired = true;
|
||||
_ = _observationService.Value.UpdateObservation(lastObs);
|
||||
}
|
||||
|
||||
await _observationService.Value.InsertObservation(newObs,
|
||||
mapObs: false); //mapObs:no volvemos a mapear la observación
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,711 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using adas_core.Domain.Utils;
|
||||
using adas_core.Domain.Utils.Interfaces;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace adas_core.Application.Customizations.HUVH.UCIN;
|
||||
|
||||
public class CalculatedObservations : ICalculatedObservations
|
||||
{
|
||||
private const string Spo2PreObservationName = "SpO2";
|
||||
private const string Spo2PostObservationName = "SpO2_Post";
|
||||
|
||||
private const string Spo2PrePostObservationName = "SpO2_Pre_Post";
|
||||
private const string CodingSystem = "ADAS";
|
||||
|
||||
private readonly List<string> _complexityObservations =
|
||||
[
|
||||
"Respiratory_Device_Multivalue", "Intravenous_Routes_Multivalue", "Medication_Multivalue",
|
||||
"System_Multivalue", "Newborn_Weight", "Surgery_Multivalue"
|
||||
];
|
||||
|
||||
private readonly ILogger<CalculatedObservations> _logger;
|
||||
private readonly IMappingUtils _mappingUtils;
|
||||
private readonly Lazy<IMedicineService> _medicineService;
|
||||
private readonly Lazy<IObservationService> _observationService;
|
||||
|
||||
private readonly Lazy<ITreatmentService> _treatmentService;
|
||||
|
||||
|
||||
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||
{
|
||||
_treatmentService = serviceProvider.GetRequiredService<Lazy<ITreatmentService>>();
|
||||
_medicineService = serviceProvider.GetRequiredService<Lazy<IMedicineService>>();
|
||||
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||
|
||||
var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>(); //apiSettings;
|
||||
_mappingUtils = new MappingUtils(apiSettings);
|
||||
}
|
||||
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||
{
|
||||
if (obs.Name is "Intervention_In" or "Intervention_Out") await CalculateInterventionMultiValueObservation(obs);
|
||||
if (obs.Name is "Surgery") await CalculateMultiValueObservation(obs);
|
||||
if (obs.Name != null && _complexityObservations.Contains(obs.Name))
|
||||
{
|
||||
_logger.LogDebug("Mapping observation Complexity {obs}", obs);
|
||||
//TODO ver si hay un máximo de puntuación por grupo de observaciones
|
||||
_ = CalculateComplexity(obs);
|
||||
}
|
||||
|
||||
if (obs.Name is Spo2PreObservationName or Spo2PostObservationName)
|
||||
{
|
||||
_logger.LogDebug("Pre-post saturation observation {obs}", obs);
|
||||
_ = CalculateSaturation_DiffObservation(obs);
|
||||
}
|
||||
|
||||
if (obs.Name is "ALPS" or "NPASS_Sedation" or "NPASS_Analgesia") _ = CalculatePainScale(obs);
|
||||
|
||||
|
||||
if (obs.Name is "Last_Defecation") obs = (T)CalculateLastDefecationValue(obs);
|
||||
|
||||
return obs;
|
||||
}
|
||||
|
||||
|
||||
public async Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
var order = treatment.PlacerOrder?.EntityIdentifier; //aquí almacenamos el número de orden
|
||||
if (string.IsNullOrEmpty(order)) return treatment;
|
||||
|
||||
//comprobamos el estado de los tratamientos anteriores
|
||||
var oldTreatments = await CheckExpiredPatientTreatments(treatment);
|
||||
|
||||
treatment.OrderControl = oldTreatments.Any() ? OrderControlType.Xo : OrderControlType.Nw;
|
||||
|
||||
if (treatment.EndTime != null)
|
||||
//el tratamiento ha expirado
|
||||
treatment.OrderControl = OrderControlType.Dc;
|
||||
|
||||
await CheckTreatmentMedicines(treatment);
|
||||
|
||||
return treatment;
|
||||
}
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
return await Task.FromResult(pumpObservation);
|
||||
|
||||
}
|
||||
|
||||
public async Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
var medicineObs = new PatientObservation
|
||||
{
|
||||
PatientId = patientId,
|
||||
Name = "Medication_Multivalue",
|
||||
CodingSystem = CodingSystem,
|
||||
Value = activeMedicines.Select(m => m.Name ?? string.Empty).Distinct().ToArray(),
|
||||
Time = DateTime.Now
|
||||
};
|
||||
|
||||
var lastMedicationsObs =
|
||||
await _observationService.Value.FindLastObservations(patientId, 1, ["Medication_Multivalue"]);
|
||||
var lastMedicationObs = lastMedicationsObs.FirstOrDefault();
|
||||
if (lastMedicationObs != null)
|
||||
{
|
||||
//expiramos la anterior
|
||||
lastMedicationObs.Expired = true;
|
||||
_ = _observationService.Value.UpdateObservation(lastMedicationObs);
|
||||
}
|
||||
|
||||
await _observationService.Value
|
||||
.InsertObservation(
|
||||
medicineObs); //mapObs:volvemos a mapear la observación para que pase por el cálculo de la complejidad
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(id);
|
||||
return activeTreatments;
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
if (string.IsNullOrEmpty(newObservation.Name))
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error FixTimeInconsistencyWithLast. Observation name is null or empty. Observation: {newObservation}",
|
||||
newObservation);
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
var lastObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||
[newObservation.Name]);
|
||||
var lastObservation = lastObservations.FirstOrDefault();
|
||||
|
||||
if (lastObservation != null && DateTime.Compare(
|
||||
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||
newObservation.Time.Day, newObservation.Time.Hour,
|
||||
newObservation.Time.Minute, newObservation.Time.Second)
|
||||
) >= 0)
|
||||
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||
|
||||
return newObservation;
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||
{
|
||||
return Task.FromResult(listToInsert);
|
||||
}
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private async Task CalculatePainScale(BasePatientObservation obs)
|
||||
{
|
||||
if (obs is not PatientObservation pobs) return;
|
||||
|
||||
|
||||
object valueObs;
|
||||
|
||||
switch (pobs.Name)
|
||||
{
|
||||
case "ALPS":
|
||||
valueObs = pobs.Value;
|
||||
break;
|
||||
case "NPASS_Sedation":
|
||||
{
|
||||
//Buscamos la complementaria "NPASS Analgesia"
|
||||
var analgesiaObs =
|
||||
await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["NPASS_Analgesia"]);
|
||||
var analgesiaValue = analgesiaObs.FirstOrDefault()?.Value.ToString() ?? "0";
|
||||
|
||||
valueObs = $"{pobs.Value}/{analgesiaValue}";
|
||||
}
|
||||
break;
|
||||
case "NPASS_Analgesia":
|
||||
{
|
||||
//Buscamos la complementaria "NPASS Sedation"
|
||||
var sedationObs =
|
||||
await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["NPASS_Sedation"]);
|
||||
var sedationValue = sedationObs.FirstOrDefault()?.Value.ToString() ?? "0";
|
||||
|
||||
valueObs = $"{sedationValue}/{pobs.Value}";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
var painScaleObs = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = "ADAS",
|
||||
Name = "Pain_Scale",
|
||||
Value = valueObs
|
||||
};
|
||||
|
||||
_ = _observationService.Value.InsertObservation(painScaleObs, mapObs: false);
|
||||
}
|
||||
|
||||
private static BasePatientObservation CalculateLastDefecationValue(BasePatientObservation obs)
|
||||
{
|
||||
if (obs is not PatientObservation pobs) return obs;
|
||||
//Assign obs time to value
|
||||
//Convert the UTC DateTime to local time.
|
||||
var localTime = pobs.Time.ToLocalTime();
|
||||
|
||||
//Format the local time into a short date/time string.
|
||||
pobs.Value = localTime.ToString("dd/MM/yyyy HH:mm");
|
||||
|
||||
return pobs;
|
||||
}
|
||||
|
||||
|
||||
private async Task CalculateMultiValueObservation(BasePatientObservation obs)
|
||||
{
|
||||
//El valor de la observación es un array de strings
|
||||
if (obs is not PatientObservation pobs || string.IsNullOrEmpty(obs.Name)) return;
|
||||
|
||||
var newObsName = $"{obs.Name}_Multivalue";
|
||||
var actualObsInBd =
|
||||
await _observationService.Value.FindLastObservations(obs.PatientId, 1, [newObsName]);
|
||||
|
||||
|
||||
var newValue = new List<string>();
|
||||
|
||||
if (pobs.Value is not string stringValueName) return;
|
||||
|
||||
|
||||
if (actualObsInBd.Count > 0)
|
||||
if (actualObsInBd.First().Value is string[] oldValue)
|
||||
{
|
||||
oldValue = oldValue.Where(x => x != stringValueName).ToArray();
|
||||
newValue.AddRange(oldValue);
|
||||
}
|
||||
|
||||
newValue.Add(stringValueName);
|
||||
|
||||
if (newValue.Count == 0) return;
|
||||
|
||||
//Expiramos la anterior
|
||||
var actualObs = actualObsInBd.FirstOrDefault();
|
||||
if (actualObs != null)
|
||||
{
|
||||
actualObs.Expired = true;
|
||||
|
||||
await _observationService.Value.UpdateObservation(actualObs);
|
||||
}
|
||||
|
||||
var newObservation = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = newObsName,
|
||||
Value = newValue.ToArray()
|
||||
};
|
||||
|
||||
_logger.LogDebug(
|
||||
"Calculate {name}_Multivalue {outpatient} Insert Calculated {time} value {value}",
|
||||
newObsName, newObservation.PatientId, newObservation.Time,
|
||||
newObservation.Value.ToJson());
|
||||
|
||||
await _observationService.Value.InsertObservation(newObservation);
|
||||
}
|
||||
|
||||
private async Task CalculateInterventionMultiValueObservation(BasePatientObservation obs)
|
||||
{
|
||||
if (obs is not PatientObservation pobs || string.IsNullOrEmpty(obs.Name) ||
|
||||
pobs.Value is not string valueObs) return;
|
||||
|
||||
if (!GetInterventionValue(valueObs, out var r) || r == null) return;
|
||||
|
||||
var obsType = r.Value.type; //"Intravenous_Routes";
|
||||
var obsGroup = r.Value.Name; // "Vía arterial";
|
||||
var newObsName = $"{obsType}_Multivalue";
|
||||
|
||||
// Obtener la última observación multivalue
|
||||
var result = await _observationService.Value.FindLastObservations(obs.PatientId, 1, [newObsName]);
|
||||
var actualMultiValueObsInDb = result.FirstOrDefault(o => !o.Expired);
|
||||
|
||||
var oldValue = actualMultiValueObsInDb?.Value as string[] ?? [];
|
||||
var newValue = new List<string>(oldValue);
|
||||
|
||||
if (obs.Name.Contains("_In"))
|
||||
{
|
||||
//Por seguridad solo tomamos el último valor que nos llega
|
||||
//Puede ser que no se acuerden de cancelar el anterior antes de añadir un nuevo dispositivo y no puede haber dos dispositivos del mismo tipo activos al mismo tiempo
|
||||
if (obsType == "Respiratory_Device")
|
||||
newValue.Clear();
|
||||
|
||||
// Inserción dispositivo
|
||||
if (!oldValue.Contains(obsGroup))
|
||||
newValue.Add(obsGroup);
|
||||
}
|
||||
else if (obs.Name.Contains("_Out"))
|
||||
{
|
||||
// Retirada del dispositivo
|
||||
//Buscamos la inserción
|
||||
var name = $"{obs.Name.Split('_')[0]}_In";
|
||||
var inObs = await _observationService.Value.FindLastNotExpiredObservatonsByPatient(obs.PatientId, name);
|
||||
|
||||
var sameValueObs = inObs.Where(o => o.Value == pobs.Value).ToList();
|
||||
|
||||
if (sameValueObs.Any())
|
||||
// Si hay más de una observación del mismo tipo, no eliminar del multivalue
|
||||
if (sameValueObs.Count > 1)
|
||||
return;
|
||||
|
||||
// Actualizar valor eliminando el grupo
|
||||
newValue.Remove(obsGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Expiramos la anterior
|
||||
if (actualMultiValueObsInDb is { Expired: false })
|
||||
{
|
||||
actualMultiValueObsInDb.Expired = true;
|
||||
await _observationService.Value.UpdateObservation(actualMultiValueObsInDb);
|
||||
}
|
||||
|
||||
// Si no hay valores nuevos, no se crea una nueva observación
|
||||
if (!newValue.Any())
|
||||
return;
|
||||
|
||||
|
||||
// Crear y registrar nueva observación
|
||||
var newObservation = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = newObsName,
|
||||
Value = newValue.ToArray()
|
||||
};
|
||||
|
||||
_logger.LogDebug(
|
||||
"Calculate {name}_Multivalue {patientid} Insert Calculated {time} value {value}",
|
||||
newObsName, newObservation.PatientId, newObservation.Time,
|
||||
newObservation.Value.ToJson()
|
||||
);
|
||||
|
||||
await _observationService.Value.InsertObservation(newObservation);
|
||||
}
|
||||
|
||||
private bool GetInterventionValue(string valueObs, out (string type, string Name, string Group)? r)
|
||||
{
|
||||
var code = valueObs.Split(" ")[0]; //
|
||||
if (code.EndsWith(".")) // Verifica si termina con un punto
|
||||
code = code.Substring(0, code.Length - 1).Replace('.', ','); // Remueve el último carácter
|
||||
|
||||
if (!double.TryParse(code, out var codeParsed))
|
||||
{
|
||||
r = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
r = _mappingUtils.SearchByCode(codeParsed, "Intervention"); //TODO validar este parámetro con Lola
|
||||
|
||||
return r != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculamos la complejidad basándonos en el valor de Respiratorio/Vías/Medicación/Sistemas/Peso nacimiento/cirugía
|
||||
* cuando entra una nueva observación que afecte a complejidad, se recalcula de 0 para no tener que estar pendiente de qué puntos corresponden a qué observación
|
||||
* Valor máximo 46 Guardamos la observación que nos llega y recalculamos complejidad.
|
||||
*/
|
||||
private async Task CalculateComplexity(BasePatientObservation obs)
|
||||
{
|
||||
var pobs = obs as PatientObservation;
|
||||
if (pobs == null) return;
|
||||
|
||||
var complexity = new PatientObservation
|
||||
{
|
||||
PatientId = obs.PatientId,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem,
|
||||
Name = "Complexity",
|
||||
Value = 0
|
||||
};
|
||||
|
||||
var complexityValue = 0;
|
||||
|
||||
// Diccionario para manejar las operaciones basadas en el nombre de la observación
|
||||
var operations = new Dictionary<string, Func<ObjectId, PatientObservation?, Task<int>>>
|
||||
{
|
||||
{
|
||||
"Respiratory_Device_Multivalue",
|
||||
(patientId, observation) =>
|
||||
CalculateMultivalueObservationComplexityValue(patientId, "Respiratory_Device_Multivalue",
|
||||
observation)
|
||||
},
|
||||
{
|
||||
"Intravenous_Routes_Multivalue",
|
||||
(patientId, observation) =>
|
||||
CalculateMultivalueObservationComplexityValue(patientId, "Intravenous_Routes_Multivalue",
|
||||
observation)
|
||||
},
|
||||
{
|
||||
"Medication_Multivalue",
|
||||
(patientId, observation) =>
|
||||
CalculateMultivalueObservationComplexityValue(patientId, "Medication_Multivalue", observation)
|
||||
},
|
||||
{
|
||||
"System_Multivalue",
|
||||
(patientId, observation) =>
|
||||
CalculateMultivalueObservationComplexityValue(patientId, "System_Multivalue", observation)
|
||||
},
|
||||
{ "Newborn_Weight", CalculateWeightNewBornValue },
|
||||
{
|
||||
"Surgery_Multivalue",
|
||||
(patientId, observation) =>
|
||||
CalculateMultivalueObservationComplexityValue(patientId, "Surgery_Multivalue", observation)
|
||||
}
|
||||
};
|
||||
|
||||
// Realizar cálculos iterando sobre las operaciones
|
||||
foreach (var operation in operations)
|
||||
complexityValue += await operation.Value(pobs.PatientId, operation.Key.Equals(pobs.Name) ? pobs : null);
|
||||
|
||||
complexity.Value = Math.Min(complexityValue, 46); // Limitar el valor máximo a 46
|
||||
|
||||
_logger.LogDebug(
|
||||
"complexity for patient {patientid} => inserting complexity value: {complexityValue} for patient: {complexityPatientid} at time {fixedTimeComplexityTime}",
|
||||
complexity.PatientId, complexity.Value, complexity.PatientId, complexity.Time);
|
||||
|
||||
await _observationService.Value.InsertObservation(complexity, mapObs: false);
|
||||
}
|
||||
|
||||
private async Task<int> CalculateMultivalueObservationComplexityValue(ObjectId patientId, string observationName,
|
||||
PatientObservation? observation = null)
|
||||
{
|
||||
var result =
|
||||
await _observationService.Value.FindLastObservations(patientId, 1, [observationName]);
|
||||
var actualObsInBd = result.FirstOrDefault();
|
||||
|
||||
var valueObj = observation == null ? actualObsInBd?.Value : observation.Value;
|
||||
var valueList = valueObj as string[];
|
||||
|
||||
var valueToReturn = valueList?.Sum(v => _mappingUtils.GetComplexityValue(v)) ?? 0;
|
||||
|
||||
_logger.LogDebug(
|
||||
"complexity for patient {patientid} => observation: {observationName} plus complexity: {Value}", patientId,
|
||||
observationName, valueToReturn);
|
||||
|
||||
return valueToReturn;
|
||||
}
|
||||
|
||||
|
||||
private async Task<int> CalculateWeightNewBornValue(ObjectId patientId, PatientObservation? pobs = null)
|
||||
{
|
||||
var result =
|
||||
await _observationService.Value.FindLastObservations(patientId, 1, ["Newborn_Weight"]);
|
||||
var actualObsInBd = result.FirstOrDefault();
|
||||
|
||||
string? strValue;
|
||||
string? obsName;
|
||||
if (pobs == null)
|
||||
{
|
||||
if (actualObsInBd?.Value == null) return 0;
|
||||
|
||||
strValue = actualObsInBd.Value.ToString();
|
||||
obsName = actualObsInBd.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pobs.Units == "kg") pobs = ParseWeight(pobs);
|
||||
|
||||
strValue = pobs.Value.ToString();
|
||||
obsName = pobs.Name;
|
||||
}
|
||||
|
||||
if (!double.TryParse(strValue, out var valueParsed) || obsName == null)
|
||||
return 0;
|
||||
|
||||
var weightNewBornValue = _mappingUtils.GetComplexityValue(obsName, valueParsed);
|
||||
|
||||
|
||||
_logger.LogDebug(
|
||||
"complexity for patient {patientid} => Weight_Newborn plus complexity: {Weight_NewbornValue}",
|
||||
patientId, weightNewBornValue);
|
||||
|
||||
return weightNewBornValue;
|
||||
}
|
||||
|
||||
private PatientObservation ParseWeight(PatientObservation obs)
|
||||
{
|
||||
if (!double.TryParse(obs.Value.ToString(), out var dValue))
|
||||
{
|
||||
_logger.LogError("Error casting weight Observation {obs}:", obs);
|
||||
return obs;
|
||||
}
|
||||
|
||||
obs.Units = "gr";
|
||||
obs.Value = dValue * 1000;
|
||||
return obs;
|
||||
}
|
||||
|
||||
|
||||
private async Task CalculateSaturation_DiffObservation(BasePatientObservation obs)
|
||||
{
|
||||
var toSearchList = new List<string>();
|
||||
PatientObservation? pre;
|
||||
PatientObservation? post;
|
||||
|
||||
toSearchList.AddRange(new List<string> { Spo2PreObservationName, Spo2PostObservationName });
|
||||
|
||||
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||
var time = obs.Time;
|
||||
|
||||
if (obs.Name == Spo2PreObservationName)
|
||||
{
|
||||
pre = (PatientObservation)obs;
|
||||
post = values.FirstOrDefault(o => o.Name == Spo2PostObservationName);
|
||||
|
||||
if (post?.Time != null && time.CompareTo(post.Time) > 0) time = post.Time;
|
||||
}
|
||||
else
|
||||
{
|
||||
post = (PatientObservation)obs;
|
||||
pre = values.FirstOrDefault(o => o.Name == Spo2PreObservationName);
|
||||
|
||||
if (pre?.Time != null && time.CompareTo(pre.Time) > 0) time = pre.Time;
|
||||
}
|
||||
|
||||
if (pre?.Value != null && post?.Value != null)
|
||||
{
|
||||
var preSuccess = double.TryParse(pre.Value.ToString(), out var preValue);
|
||||
if (!preSuccess) preValue = 0;
|
||||
var postSuccess = double.TryParse(post.Value.ToString(), out var postValue);
|
||||
if (!postSuccess) postValue = 0;
|
||||
|
||||
var saturationDiff = Math.Round(preValue - postValue, 2);
|
||||
|
||||
var saturationDiffObs = new PatientObservation
|
||||
{
|
||||
Name = "SpO2_Diff",
|
||||
CodingSystem = CodingSystem,
|
||||
PatientId = obs.PatientId,
|
||||
Time = time,
|
||||
Value = saturationDiff
|
||||
};
|
||||
var saturationPrePost = new PatientObservation
|
||||
{
|
||||
Name = Spo2PrePostObservationName,
|
||||
CodingSystem = CodingSystem,
|
||||
PatientId = obs.PatientId,
|
||||
Time = time,
|
||||
Value = pre.Value + "/" + post.Value
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(saturationDiffObs);
|
||||
await _observationService.Value.InsertObservation(saturationPrePost);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<PatientTreatment>> CheckExpiredPatientTreatments(PatientTreatment treatment)
|
||||
{
|
||||
//si el tratamiento ha expirado actualizamos el OrderControl a DC y devolvemos las que siguen activas
|
||||
var result = new List<PatientTreatment>();
|
||||
var oldTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(treatment.PatientId);
|
||||
|
||||
foreach (var t in oldTreatments)
|
||||
{
|
||||
if (t == null) continue;
|
||||
|
||||
if (t.PlacerOrder?.EntityIdentifier == treatment.PlacerOrder?.EntityIdentifier)
|
||||
{
|
||||
//Es el mismo tratamiento actualizamos
|
||||
|
||||
if (t.EndTime != null && t.EndTime > DateTime.UtcNow) treatment.OrderControl = OrderControlType.Dc;
|
||||
|
||||
treatment.Id = t.Id; //Asignamos el ID del tratamiento existente para actualizarlo
|
||||
_ = _treatmentService.Value.UpdateTreatment(treatment);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task CheckTreatmentMedicines(PatientTreatment treatment)
|
||||
{
|
||||
var newMedicines = new List<Medicine>();
|
||||
var hasVasoactives = false;
|
||||
foreach (var code in treatment.RequestedGiveCodes)
|
||||
{
|
||||
var m = await _medicineService.Value.GetByCode(code.Identifier);
|
||||
if (m == null) continue;
|
||||
|
||||
//Si el código es de tipo nutrición entonces creamos una observación de ese tipo que tendrá el valor mapeado con el nombre correspondiente
|
||||
//CreateNutritionObservation y NO agregamos a medicamentos
|
||||
var r = _mappingUtils.SearchByCode(m.Codes.First(), "Treatment");
|
||||
if (r is { type: "Nutrition" })
|
||||
{
|
||||
await CreateNutritionObservation(r.Value.group, treatment.PatientId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r is { type: "Medication", group: "Drogas vasoactivas" })
|
||||
hasVasoactives = true;
|
||||
|
||||
newMedicines.Add(m);
|
||||
}
|
||||
|
||||
if (hasVasoactives)
|
||||
{
|
||||
var vObs = new PatientObservation
|
||||
{
|
||||
Name = "HasVasoactive",
|
||||
Value = true,
|
||||
Time = DateTime.UtcNow,
|
||||
CodingSystem = CodingSystem
|
||||
};
|
||||
|
||||
await _observationService.Value.InsertObservation(vObs, mapObs: false);
|
||||
}
|
||||
|
||||
if (newMedicines.Count == 0)
|
||||
return;
|
||||
|
||||
var _ = await GetActiveTreatmentsByPatient(treatment.PatientId);
|
||||
|
||||
var activeTreatments = _.ToList();
|
||||
|
||||
var __ = await _medicineService.Value.GetMedicinesOfTreatments(activeTreatments); //Todo revisar
|
||||
var activeMedicines = __.ToList();
|
||||
|
||||
// Combina ambas listas y selecciona solo elementos únicos con el mismo nombre
|
||||
var uniqueMedicines = newMedicines
|
||||
.Concat(activeMedicines)
|
||||
.GroupBy(m => m.Name)
|
||||
.Select(g => g.First())
|
||||
.ToList();
|
||||
|
||||
await CalculateMedicineObservation(uniqueMedicines, treatment.PatientId);
|
||||
}
|
||||
|
||||
private async Task CreateNutritionObservation(string value, ObjectId patientId)
|
||||
{
|
||||
var nutritionObs = new PatientObservation
|
||||
{
|
||||
PatientId = patientId,
|
||||
Name = "Feeding_Type",
|
||||
CodingSystem = CodingSystem,
|
||||
Value = value,
|
||||
Time = DateTime.Now
|
||||
};
|
||||
|
||||
if (value.ToLower().Contains("parenteral"))
|
||||
{
|
||||
nutritionObs.Name = "Parenteral";
|
||||
nutritionObs.Value = "SI";
|
||||
}
|
||||
|
||||
var lastNutritionObsList =
|
||||
await _observationService.Value.FindLastObservations(patientId, 1, [nutritionObs.Name]);
|
||||
var lastNutritionObs = lastNutritionObsList.FirstOrDefault();
|
||||
if (lastNutritionObs is { Expired: false })
|
||||
{
|
||||
//expiramos la anterior
|
||||
lastNutritionObs.Expired = true;
|
||||
_ = _observationService.Value.UpdateObservation(lastNutritionObs);
|
||||
}
|
||||
|
||||
await _observationService.Value.InsertObservation(nutritionObs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.Pumps;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace adas_core.Application.Customizations.NursePlan;
|
||||
|
||||
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||
{
|
||||
private readonly Lazy<IObservationService> _observationService =
|
||||
new(serviceProvider.GetRequiredService<IObservationService>);
|
||||
|
||||
public Task CalculateActiveBolus(ObjectId patientId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||
{
|
||||
return await Task.FromResult(pumpObservation);
|
||||
|
||||
}
|
||||
|
||||
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||
{
|
||||
return Task.FromResult(obs)!;
|
||||
}
|
||||
|
||||
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||
{
|
||||
return Task.FromResult(treatment);
|
||||
}
|
||||
|
||||
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||
{
|
||||
return Task.FromResult(diagnosis);
|
||||
}
|
||||
|
||||
|
||||
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||
{
|
||||
return Task.FromResult(obs);
|
||||
}
|
||||
|
||||
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||
{
|
||||
return Task.FromResult(listToInsert);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user