695 lines
27 KiB
C#
695 lines
27 KiB
C#
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
|
|
}
|
|
} |