Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user