1547 lines
66 KiB
C#
1547 lines
66 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;
|
|
|
|
namespace adas_core.Application.Customizations.H12O.UCIN;
|
|
|
|
public class CalculatedObservations : ICalculatedObservations
|
|
{
|
|
private readonly List<string> _complexityObservations =
|
|
["Respiratory", "IntravenousLines", "Medication", "Surgery", "Weight_Newborn", "Weight_Current", "Monitor"];
|
|
|
|
private readonly List<string> _ecmo = [];
|
|
private readonly List<string> _electroencephalogram = [];
|
|
|
|
private readonly List<string> _highFrequencyVentilation = [];
|
|
//private readonly List<string> _shift = [];
|
|
|
|
|
|
private readonly Tuple<IntraVenousLineTypes, int, List<string>>[] _intraVenousLinesTypeValue =
|
|
[
|
|
Tuple.Create(IntraVenousLineTypes.Artery, 5,
|
|
new List<string> { "Catéter arterial", "Catéter UMBILICAL arteria" }),
|
|
Tuple.Create(IntraVenousLineTypes.CentralVein, 4,
|
|
new List<string> { "Catéter venoso CENTRAL", "Catéter UMBILICAL vena" }),
|
|
Tuple.Create(IntraVenousLineTypes.Picc, 3, new List<string> { "Catéter PICC" }),
|
|
Tuple.Create(IntraVenousLineTypes.MiddleLine, 2,
|
|
new List<string> { "Catéter línea media", "Catéter EPICUTÁNEO PERIFÉRICO" }),
|
|
Tuple.Create(IntraVenousLineTypes.Peripheral, 1, new List<string> { "Catéter Venoso PERIFÉRICO" })
|
|
];
|
|
|
|
private readonly List<string> _invasiveVentilation = [];
|
|
private readonly ILogger<CalculatedObservations> _logger;
|
|
|
|
|
|
private readonly List<string> _medicationBolus = [];
|
|
|
|
//private readonly Lazy<IMedicineService> medicineService;
|
|
private readonly IMedicineService _medicineService;
|
|
|
|
private readonly List<string> _nonInvasiveVentilation = [];
|
|
|
|
//private readonly List<string> Oni = new List<string>();
|
|
private readonly List<string> _notesIndicatingMedication = [];
|
|
|
|
|
|
private readonly Lazy<IObservationService> _observationService;
|
|
private readonly List<string> _oniCodes = [];
|
|
private readonly List<string> _regionalBrainSaturation = [];
|
|
private readonly List<string> _respiratory = [];
|
|
|
|
|
|
private readonly Tuple<RespiratoryTypes, int, List<string>>[] _respiratoryTypeValue =
|
|
[
|
|
// Tuple.Create(RespiratoryTypes.INO, 10, new List<string>{ ""}),
|
|
Tuple.Create(RespiratoryTypes.Vafo, 5, new List<string> { "V.A.F.O." }),
|
|
Tuple.Create(RespiratoryTypes.Vmc, 3, new List<string> { "V.M.C." }),
|
|
Tuple.Create(RespiratoryTypes.Vmni, 2, new List<string> { "V.N.I. Ciclada", "CPAP" }),
|
|
Tuple.Create(RespiratoryTypes.NasalCannulas, 1, new List<string> { "Alto Flujo", "Bajo Flujo" }),
|
|
Tuple.Create(RespiratoryTypes.None, 0, new List<string> { "Sin assistance respiratoria" })
|
|
];
|
|
|
|
private readonly List<string> _rxaStatus = ["Concluido"];
|
|
private readonly List<string> _surgery = [];
|
|
private readonly List<string> _surgeryText = [];
|
|
private readonly List<string> _transcutanous = [];
|
|
private readonly Lazy<ITreatmentService> _treatmentService;
|
|
|
|
|
|
public CalculatedObservations(IServiceProvider serviceProvider)
|
|
{
|
|
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>(); //observationService;
|
|
_medicineService = serviceProvider.GetRequiredService<IMedicineService>(); //medicineService;
|
|
_treatmentService = serviceProvider.GetRequiredService<Lazy<ITreatmentService>>(); //treatmentService;
|
|
|
|
var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>(); //apiSettings;
|
|
|
|
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
|
|
|
var electroencephalogram = apiSettings.Value.Electroencephalogram ?? null;
|
|
electroencephalogram?.ForEach(x => _electroencephalogram.Add(x.Trim()));
|
|
|
|
var medicationBolus = apiSettings.Value.MedicationBolus ?? null;
|
|
medicationBolus?.ForEach(x => _medicationBolus.Add(x.Trim()));
|
|
|
|
var transcutaneous = apiSettings.Value.Transcutaneous ?? null;
|
|
transcutaneous?.ForEach(x => _transcutanous.Add(x.Trim()));
|
|
|
|
var regionalBrainSaturation = apiSettings.Value.RegionalBrainSaturation ?? null;
|
|
regionalBrainSaturation?.ForEach(x => _regionalBrainSaturation.Add(x.Trim()));
|
|
|
|
var surgery = apiSettings.Value.Surgery ?? null;
|
|
surgery?.ForEach(x => _surgery.Add(x.Trim()));
|
|
|
|
var surgeryText = apiSettings.Value.SurgeryText ?? null;
|
|
surgeryText?.ForEach(x => _surgeryText.Add(x.Trim()));
|
|
|
|
var respiratory = apiSettings.Value.Respiratory ?? null;
|
|
respiratory?.ForEach(x => _respiratory.Add(x.Trim()));
|
|
//inoCode = Respiratory.LastOrDefault();
|
|
|
|
var oni = apiSettings.Value.Oni ?? null;
|
|
oni?.ForEach(x => _oniCodes.Add(x.Trim()));
|
|
|
|
var highFrequencyVentilation = apiSettings.Value.HighFrequencyVentilation ?? null;
|
|
highFrequencyVentilation?.ForEach(x => _highFrequencyVentilation.Add(x.Trim()));
|
|
|
|
var invasiveVentilation = apiSettings.Value.InvasiveVentilation ?? null;
|
|
invasiveVentilation?.ForEach(x => _invasiveVentilation.Add(x.Trim()));
|
|
|
|
var nonInvasiveVentilation = apiSettings.Value.NonInvasiveVentilation ?? null;
|
|
nonInvasiveVentilation?.ForEach(x => _nonInvasiveVentilation.Add(x.Trim()));
|
|
|
|
//var shift = apiSettings.Value.Shift ?? null;
|
|
//shift?.ForEach(x => _shift.Add(x.Trim()));
|
|
|
|
var notesIndicatingMedication =
|
|
apiSettings.Value.NotesIndicatingMedication ?? null;
|
|
notesIndicatingMedication?.ForEach(x => _notesIndicatingMedication.Add(x.Trim()));
|
|
|
|
var ecmo = apiSettings.Value.Ecmo ?? null;
|
|
ecmo?.ForEach(x => _ecmo.Add(x.Trim()));
|
|
}
|
|
|
|
|
|
public async Task<T?> Map<T>(T obs, bool onlyByName) where T : BasePatientObservation
|
|
{
|
|
if (string.IsNullOrEmpty(obs.Name)) return obs;
|
|
//Llega Vías o algo en Vías dictionary
|
|
//Solo tenemos en cuenta las observaciones de ICA
|
|
if (!string.IsNullOrEmpty(obs.Code) && _respiratory.Contains(obs.Code) && obs.CodingSystem == "SNM")
|
|
{
|
|
_logger.LogDebug("Mapping observation Respiratorio {obs}", obs);
|
|
await CalculateAsistResp(obs);
|
|
}
|
|
|
|
if (obs.Name is "AirPressure_Mean" or "FiO2" or "PaO2") await CalculateOxygenationIndex(obs);
|
|
|
|
//Solo tenemos en cuenta las observaciones de Central
|
|
if (obs.Name == "Resp_Mode")
|
|
{
|
|
_logger.LogDebug("Mapping Resp mode observation {obs}", obs);
|
|
await CalculateVentilationMode(obs);
|
|
}
|
|
|
|
|
|
if (obs.Name is "TAm" or "Age_Gestational_Fixed" or "Age_Gestational") await CalculateTAmAlert(obs);
|
|
|
|
if (obs.Name is "Weight_Newborn" or "Weight_Current")
|
|
if (obs is PatientObservation { Expired: false })
|
|
obs = (T)await ParseWeight(obs);
|
|
|
|
if (obs is { Name: "Temp_Incubator" } or { Name: "Temp_Patient" }) await CalculateTempGradient(obs);
|
|
|
|
|
|
if (obs is { Name: "IntravenousLinesObs" })
|
|
{
|
|
var intraObs = await CalculateIntravenousLineObservation(obs);
|
|
|
|
if (intraObs != null)
|
|
obs = (T)intraObs;
|
|
}
|
|
|
|
if (obs.Name is "pCO2tc" or "Transcutaneous_O2")
|
|
if (obs.Code != null && _regionalBrainSaturation.Contains(obs.Code))
|
|
await CalculateMonitor(obs);
|
|
|
|
if (obs.Name == "Surgery") await CheckSurgeryExpired(obs);
|
|
|
|
|
|
if (obs.Name != null && _complexityObservations.Contains(obs.Name))
|
|
{
|
|
_logger.LogDebug("Mapping observation Complexity {obs}", obs);
|
|
await CalculateComplexity(obs);
|
|
}
|
|
|
|
if (obs.Name != null && (obs.Name.Equals("Diuresis_Hour") ||
|
|
obs.Name.Equals("Drainages_Hour") ||
|
|
obs.Name.Equals("Hydric_Balance") ||
|
|
obs.Name.Equals("IV_Entries_Hour") ||
|
|
obs.Name.Equals("Enteral_Entries_Hour")))
|
|
obs = (T)await CheckObsExistsAndIncrementTime(obs);
|
|
|
|
if (obs.Name != null && (obs.Name.Equals("Temp_Patient") ||
|
|
obs.Name.Equals("Temp_Incubator")
|
|
))
|
|
obs = (T)await CheckObsWithSameTimeExistsAndIncrementTime(obs);
|
|
return obs;
|
|
}
|
|
|
|
public async Task<PatientTreatment> Map(PatientTreatment treatment)
|
|
{
|
|
if (treatment.SingleDose)
|
|
treatment = CalculateSingleDoseEndDate(treatment);
|
|
|
|
var tempTreatment = treatment;
|
|
|
|
await CheckTreatmentMedicines(tempTreatment);
|
|
|
|
|
|
if (tempTreatment.RequestedGiveCodes.Any())
|
|
{
|
|
if (tempTreatment.RequestedGiveCodes.Any(t =>
|
|
_medicationBolus.Contains(t.Identifier))) //remove && t.codingSystem == "FTPCS" not match always
|
|
{
|
|
_logger.LogDebug("Medication Bolus detected. Creating calculated observation");
|
|
await CalculateBolus(tempTreatment);
|
|
}
|
|
|
|
if (tempTreatment.RequestedGiveCodes.Any(t => _electroencephalogram.Contains(t.Identifier)))
|
|
await CalculateMonitor(tempTreatment);
|
|
|
|
if (tempTreatment.RequestedGiveCodes.Any(t =>
|
|
_surgery.Contains(t.Identifier) && _surgeryText.Contains(t.Text)))
|
|
await CalculateSurgery(tempTreatment);
|
|
|
|
|
|
if (treatment.RequestedGiveCodes.Any(t => _ecmo.Contains(t.Identifier)))
|
|
//If ecmo treatment is NW recalculate complexity to show ECMO if is DC recalculate complexity
|
|
await CalculateComplexityOnEcmo(treatment);
|
|
|
|
if (tempTreatment.RequestedGiveCodes.Any(t => _oniCodes.Contains(t.Identifier)))
|
|
{
|
|
if (tempTreatment.OrderControl == OrderControlType.Nw)
|
|
{
|
|
var oniObservation = new PatientObservation
|
|
{
|
|
PatientId = treatment.PatientId,
|
|
Code = "84481000140102",
|
|
Name = "ONi",
|
|
CodingSystem = "MDC",
|
|
Value = tempTreatment.RequestedGiveAmountMinimum ?? '-',
|
|
Time = tempTreatment.OrderTime ?? DateTime.Now,
|
|
Units = "ppm"
|
|
};
|
|
await _observationService.Value.InsertObservation(oniObservation, mapObs: false);
|
|
}
|
|
|
|
if (treatment.OrderControl == OrderControlType.Dc)
|
|
{
|
|
var lastOnis = await _observationService.Value.FindLastObservations(treatment.PatientId, 1,
|
|
["ONi"]);
|
|
var lastOni = lastOnis.FirstOrDefault();
|
|
if (lastOni == null) return treatment;
|
|
lastOni.Expired = true;
|
|
await _observationService.Value.UpdateObservation(lastOni);
|
|
await _observationService.Value.InsertObservation(lastOni, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return treatment;
|
|
}
|
|
|
|
|
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
|
{
|
|
return await Task.FromResult(pumpObservation);
|
|
|
|
}
|
|
|
|
public async Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
|
{
|
|
await CalculateMedicineObservation(activeMedicines, [], new PatientTreatment { PatientId = patientId });
|
|
}
|
|
|
|
public async Task CalculateActiveBolus(ObjectId patientId)
|
|
{
|
|
// SIN RXA
|
|
/*
|
|
* var activeBolus = treatmentService.Value.GetActiveTreatmentsByPatient(patientId)
|
|
.FindAll(p => p.requestedGiveCodes.Any(r => MedicationBolus.Contains(r.identifier)) && p.orderTime > DateTime.Now.AddHours(-12) && p.boloPom);
|
|
|
|
var bolusObs = new PatientObservation()
|
|
{
|
|
patientid = patientId,
|
|
time = DateTime.Now,
|
|
//code = "MedicationBolus", //treatment.requestedGiveCode.identifier,
|
|
//codingSystem = "ADAS", //treatment.requestedGiveCode.codingSystem,
|
|
name = "OpiateBoluses",
|
|
codingSystem = "ADAS",
|
|
value = activeBolus.Count
|
|
};
|
|
|
|
var lastBolus = observationService.Value.FindLastObservations(patientId, 1, new List<string> { "OpiateBoluses" }).FirstOrDefault();
|
|
if (lastBolus != null && int.Parse(lastBolus.value.ToString()) == int.Parse(bolusObs.value.ToString()))
|
|
{
|
|
return;
|
|
}
|
|
observationService.Value.InsertObservation(bolusObs);
|
|
*/
|
|
//Por RXA
|
|
|
|
var activeBolus = await GetActiveBolus(patientId, null);
|
|
var bolusObs = new PatientObservation
|
|
{
|
|
PatientId = patientId,
|
|
Time = DateTime.Now,
|
|
//code = "MedicationBolus", //treatment.requestedGiveCode.identifier,
|
|
//codingSystem = "ADAS", //treatment.requestedGiveCode.codingSystem,
|
|
Name = "OpiateBoluses",
|
|
CodingSystem = "ADAS",
|
|
Value = activeBolus.Count
|
|
};
|
|
|
|
|
|
var lastsBolus = await _observationService.Value.FindLastObservations(patientId, 1, ["OpiateBoluses"]);
|
|
var lastBolus = lastsBolus.FirstOrDefault();
|
|
if (lastBolus != null && int.TryParse(lastBolus.Value.ToString(), out var lastbolus) &&
|
|
int.TryParse(bolusObs.Value.ToString(), out var bolusobs) && lastbolus == bolusobs) return;
|
|
await _observationService.Value.InsertObservation(bolusObs, mapObs: false);
|
|
}
|
|
|
|
public async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
|
{
|
|
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(id);
|
|
|
|
return activeTreatments;
|
|
}
|
|
|
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
|
{
|
|
return Task.FromResult(diagnosis);
|
|
}
|
|
|
|
/*
|
|
* Designed to fix observations like intravenous with the possibility to receive multiple intravenous observations in the same hl7 message.
|
|
* Sometimes ADAS calculates many in the same second. causing inconsistencies when retrieving last observation.
|
|
*/
|
|
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
|
{
|
|
if (string.IsNullOrEmpty(newObservation.Name))
|
|
{
|
|
_logger.LogError("Observation name is null or empty: {newObservation}", newObservation);
|
|
return null;
|
|
}
|
|
|
|
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);
|
|
|
|
newObservation.Id = ObjectId.GenerateNewId();
|
|
|
|
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();
|
|
}
|
|
|
|
public async Task CheckSurgeryExpired(BasePatientObservation obs)
|
|
{
|
|
try
|
|
{
|
|
var pobs = (PatientObservation)obs;
|
|
if (!pobs.Expired) return;
|
|
var surgeryObs = new PatientObservation
|
|
{
|
|
PatientId = obs.PatientId,
|
|
Name = "Surgery",
|
|
Min = 0,
|
|
Max = 5,
|
|
CodingSystem = "ADAS",
|
|
Time = obs.Time.AddSeconds(1),
|
|
Value = 0,
|
|
Expires = pobs.Expires
|
|
};
|
|
_logger.LogDebug("CheckSurgeryExpired. Inserting: {obs}", surgeryObs.ToString());
|
|
|
|
await _observationService.Value.InsertObservation(surgeryObs, mapObs: false);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*Used for observations that can come with the same time, the last which enter is the newest. So increment time so that the system can identify which is the last.
|
|
*/
|
|
public async Task<BasePatientObservation> CheckObsExistsAndIncrementTime(BasePatientObservation obs)
|
|
{
|
|
var pobs = (PatientObservation)obs;
|
|
|
|
var lastObsFromHour =
|
|
await _observationService.Value.FindLastBeforeDate(pobs.PatientId, pobs.Time.AddMinutes(59), obs.Name);
|
|
|
|
if (lastObsFromHour != null &&
|
|
DateTime.Compare(new DateTime(lastObsFromHour.Time.Year, lastObsFromHour.Time.Month,
|
|
lastObsFromHour.Time.Day, lastObsFromHour.Time.Hour, 0, 0)
|
|
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0)
|
|
pobs.Time = lastObsFromHour.Time.AddSeconds(1);
|
|
|
|
return pobs;
|
|
}
|
|
|
|
|
|
public async Task<BasePatientObservation> CheckObsWithSameTimeExistsAndIncrementTime(BasePatientObservation obs)
|
|
{
|
|
var pobs = (PatientObservation)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;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Oxygenation index is calculated => PMAP x FiO2 x 100 / PaO2
|
|
/// the method is called when it receives pmap or fio or pao2 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(BasePatientObservation obs)
|
|
{
|
|
var toSearchList = new List<string>();
|
|
PatientObservation? airPressMeanObs = null;
|
|
PatientObservation? fiO2Obs = null;
|
|
PatientObservation? paO2Obs = null;
|
|
|
|
try
|
|
{
|
|
toSearchList.AddRange(new List<string> { "AirPressure_Mean", "FiO2", "PaO2" });
|
|
|
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
|
|
|
switch (obs.Name)
|
|
{
|
|
case "AirPressure_Mean":
|
|
airPressMeanObs = (PatientObservation)obs;
|
|
fiO2Obs = values.FirstOrDefault(o => o.Name == "FiO2");
|
|
paO2Obs = values.FirstOrDefault(o => o.Name == "PaO2");
|
|
break;
|
|
|
|
case "FiO2":
|
|
fiO2Obs = (PatientObservation)obs;
|
|
airPressMeanObs = values.FirstOrDefault(o => o.Name == "AirPressure_Mean");
|
|
paO2Obs = values.FirstOrDefault(o => o.Name == "PaO2");
|
|
break;
|
|
|
|
case "PaO2":
|
|
paO2Obs = (PatientObservation)obs;
|
|
fiO2Obs = values.FirstOrDefault(p => p.Name == "FiO2");
|
|
airPressMeanObs = values.FirstOrDefault(o => o.Name == "AirPressure_Mean");
|
|
break;
|
|
}
|
|
|
|
|
|
//Controlar que fio2 no haya expirada al recogerla
|
|
if (fiO2Obs != null && paO2Obs != null && airPressMeanObs != null)
|
|
if (int.TryParse(airPressMeanObs.Value.ToString(), out var airPressureMean) &&
|
|
int.TryParse(fiO2Obs.Value.ToString(), out var fio2) &&
|
|
int.TryParse(paO2Obs.Value.ToString(), out var pao2))
|
|
{
|
|
if (pao2 == 0)
|
|
{
|
|
_logger.LogWarning(
|
|
"Calculate Oxygenation Index observation. PaO2: {pao2}, observation: {obsName}", pao2,
|
|
obs.Name);
|
|
return;
|
|
}
|
|
|
|
var oxygenationIndexValue = airPressureMean * fio2 * 100 / pao2;
|
|
|
|
var oxygenationIndexObs = new PatientObservation
|
|
{
|
|
PatientId = obs.PatientId,
|
|
Name = "Oxygenation_Index",
|
|
CodingSystem = "ADAS",
|
|
Value = oxygenationIndexValue,
|
|
Time = DateTime.Now,
|
|
Expires = 10 //Expires in 10 seg because its FiO2 expire time.
|
|
};
|
|
|
|
await _observationService.Value.InsertObservation(oxygenationIndexObs, mapObs: false);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError("Error calculate Oxygenation Index observation. Exception: {exMessage}", ex.Message);
|
|
}
|
|
}
|
|
|
|
|
|
private static PatientTreatment CalculateSingleDoseEndDate(PatientTreatment treatment)
|
|
{
|
|
/* Deprecated calc finish treatment date on shift end. Now every treatment single dose is last 8 Hours
|
|
DateTime now = DateTime.UtcNow;
|
|
//Turno actual, tenemos que poner como fecha fin la fecha de inicio del turno siguiente
|
|
var shiftNow = Shift.Where(
|
|
i => DateTime.ParseExact(i, "HH:mm", CultureInfo.InvariantCulture).Ticks < DateTime.Now.Ticks
|
|
).LastOrDefault();
|
|
|
|
var index = Shift.IndexOf(shiftNow);
|
|
|
|
string endDateShift;
|
|
|
|
if (Shift.Count <= index + 1) endDateShift = Shift[0];
|
|
else endDateShift = Shift[index + 1];
|
|
|
|
var HourMinutes = endDateShift.Split(':');
|
|
|
|
if (now.Hour.CompareTo(int.Parse(HourMinutes[0])) > 0)
|
|
now = now.AddDays(1);
|
|
|
|
DateTime finisTreatmentDate = new DateTime(now.Year, now.Month, now.Day, int.Parse(HourMinutes[0]), int.Parse(HourMinutes[1]), 0);
|
|
*/
|
|
treatment.EndTime = treatment.OrderTime?.AddHours(8) ?? DateTime.Now.AddHours(8);
|
|
return treatment;
|
|
}
|
|
|
|
public async Task CheckTreatmentMedicines(PatientTreatment treatment)
|
|
{
|
|
//sI TIENE UNA NOTA CON NPT SON DE TIPO NUTRICIÓN PARENTERAL Y SUMAN 1
|
|
var listNotesCode = treatment.Notes.Select(note => note.Comment).ToList();
|
|
|
|
if (treatment.RequestedGiveCodes.Any())
|
|
listNotesCode.AddRange(treatment.RequestedGiveCodes.Select(treatmentCodes => treatmentCodes.Identifier));
|
|
|
|
//var medicines = medicineService.Value.GetByCodeOrNote(listNotesCode);
|
|
var medicines = await _medicineService.GetByCodeOrNote(listNotesCode);
|
|
var parentalNutritionMedicine = await CalculateParentalNutritionMedicine(treatment);
|
|
medicines.Add(parentalNutritionMedicine);
|
|
|
|
//If not detect any medicine in medicine table, check if contáis NTE with, if it's true, it's a medicine.
|
|
/*
|
|
NTE|||Medicación|^OrderDefinition\r
|
|
|
|
NTE|||Perfusiones|^OrderDefinition\r
|
|
|
|
NTE|||SUEROS Y HEMODER|^OrderDefinition\r
|
|
*/
|
|
if (medicines is { Count: 0 })
|
|
{
|
|
var isMedicine = treatment.Notes.Any(n => _notesIndicatingMedication.Contains(n.Comment));
|
|
|
|
if (isMedicine && treatment.RequestedGiveCodes is { Count: > 0 })
|
|
treatment.RequestedGiveCodes.ForEach(c =>
|
|
{
|
|
if (!string.IsNullOrEmpty(c.Identifier))
|
|
medicines.Add(new Medicine
|
|
{
|
|
Codes = [c.Identifier],
|
|
Name = c.Text
|
|
});
|
|
});
|
|
}
|
|
|
|
if (medicines.Any())
|
|
{
|
|
if (!string.IsNullOrEmpty(treatment.RequestedGiveTreatment))
|
|
try
|
|
{
|
|
medicines =
|
|
[
|
|
new Medicine
|
|
{
|
|
Name = treatment.RequestedGiveTreatment,
|
|
Type = medicines.FindAll(t => t.Type.Any())
|
|
.Select(m => m.Type.Aggregate((x, y) => x + "," + y)).Distinct().ToList(),
|
|
Codes = medicines.FindAll(t => t.Codes.Any())
|
|
.Select(m => m.Codes.Aggregate((x, y) => x + "," + y)).Distinct().ToList(),
|
|
Group = medicines.FindAll(t => t.Group.Any())
|
|
.Select(m => m.Group.Aggregate((x, y) => x + "," + y)).Distinct().ToList(),
|
|
Notes = medicines.FindAll(t => t.Notes.Any())
|
|
.Select(m => m.Notes.Aggregate((x, y) => x + "," + y)).Distinct().ToList()
|
|
}
|
|
];
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError("Error Checking Treatment Medicines. {medicines} . Exception {ex}",
|
|
string.Join(",", medicines), ex);
|
|
}
|
|
|
|
var _ = await GetActiveTreatmentsByPatient(treatment.PatientId);
|
|
var activeTreatments = _.ToList();
|
|
//var activeMedicines = medicineService.Value.GetMedicinesOfTreatments(activeTreatments);
|
|
var __ = await _medicineService.GetMedicinesOfTreatments(activeTreatments);
|
|
var activeMedicines = __.ToList();
|
|
|
|
var activeNptTreatments =
|
|
activeTreatments.FindAll(t => t?.Notes.FirstOrDefault(n => n.Comment == "NPT") != null);
|
|
if (activeNptTreatments.Count > 0)
|
|
{
|
|
//activeMedicines.AddRange((IEnumerable<Medicine>)activeNPTTreatments.Select(async s => await CalculateParentalNutritionMedicine(s)).Where(parentalMedicine => parentalMedicine != null));
|
|
//activeMedicines.AddRange(await Task.WhenAll(activeNPTTreatments.Select(async s => await CalculateParentalNutritionMedicine(s))).Where(parentalMedicine => parentalMedicine != null));
|
|
|
|
var tasks = activeNptTreatments.Select(async s => await CalculateParentalNutritionMedicine(s));
|
|
var taskResults = await Task.WhenAll(tasks);
|
|
var filteredMedicines = taskResults.ToList();
|
|
if (filteredMedicines.Any()) filteredMedicines.ForEach(m => { activeMedicines.Add(m); });
|
|
}
|
|
|
|
await CalculateMedicineObservation(activeMedicines, medicines, treatment);
|
|
}
|
|
}
|
|
|
|
private static Task<Medicine> CalculateParentalNutritionMedicine(PatientTreatment? treatment)
|
|
{
|
|
List<string> medicineType = [];
|
|
Note? commentType = null;
|
|
if (treatment?.Notes.FirstOrDefault(n => n.Comment == "NPT") != null)
|
|
{
|
|
commentType = treatment.Notes.FirstOrDefault(n => n.CommentType == "formularybaseformulation");
|
|
|
|
|
|
if (treatment.Notes.FirstOrDefault(n =>
|
|
n.Comment is "LÍPIDOS NEONATALES AL 20%" or "LÍPIDOS NEONATALES AL 20% CON...") != null)
|
|
medicineType = [nameof(MedicineEnum.Types.ParenteralNutritionLipids)];
|
|
else
|
|
medicineType = [nameof(MedicineEnum.Types.ParenteralNutrition)];
|
|
}
|
|
|
|
var medicine = new Medicine
|
|
{
|
|
Type = medicineType,
|
|
Name = commentType != null ? commentType.Comment : "UnNamed"
|
|
};
|
|
return Task.FromResult(medicine);
|
|
}
|
|
|
|
/*
|
|
* Cada vez que entra un tratamiento recalcular medicación y riesgo de medicación: recuperamos todos los tratamientos activos del paciente,
|
|
* siendo activos: todos aquellos que no han sido cancelados DC Y SIENDO NW NUEVO,
|
|
* Medicación: Si treatment.orderControl = NW entra nuevo sumamos 1 si no hay ninguno de ese tipo ya activo
|
|
* si entra treatment.orderControl = DC restamos 1 si no hay ninguno de ese tipo medición.type
|
|
* y
|
|
*/
|
|
public async Task CalculateMedicineObservation(List<Medicine> activeMedicines, List<Medicine> medicines,
|
|
PatientTreatment treatment)
|
|
{
|
|
var medicinesWithType = activeMedicines.FindAll(m => m.Type.Any());
|
|
|
|
foreach (var medicine in medicines)
|
|
if (treatment.OrderControl is OrderControlType.Nw or OrderControlType.Xo)
|
|
{
|
|
if (treatment.StartTime != null && DateTime.UtcNow.CompareTo(treatment.StartTime) < 0) return;
|
|
|
|
if (treatment.OrderControl == OrderControlType.Nw)
|
|
activeMedicines.Add(medicine);
|
|
|
|
if (treatment.OrderControl == OrderControlType.Xo
|
|
&& activeMedicines.All(m => m.Name != medicine.Name)) activeMedicines.Add(medicine);
|
|
|
|
if (medicinesWithType != null &&
|
|
medicinesWithType.All(m => m.Type != medicine.Type))
|
|
medicinesWithType.Add(medicine);
|
|
}
|
|
else if (treatment.OrderControl == OrderControlType.Dc)
|
|
{
|
|
if (medicinesWithType != null)
|
|
{
|
|
medicinesWithType.Remove(medicine);
|
|
activeMedicines.RemoveAll(m => m.Name == medicine.Name);
|
|
}
|
|
}
|
|
|
|
var medicineTypes = medicinesWithType!.SelectMany(m => m.Type.Select(t => new { type = t }))
|
|
.GroupBy(x => x.type).Count();
|
|
|
|
var medicineObs = new PatientObservation
|
|
{
|
|
PatientId = treatment.PatientId,
|
|
Name = "Medication",
|
|
CodingSystem = "ADAS",
|
|
Value = medicineTypes,
|
|
Time = DateTime.Now
|
|
};
|
|
|
|
var lastMedicationsObs = await _observationService.Value.FindLastObservations(treatment.PatientId, 1,
|
|
["Medication"]);
|
|
var lastMedicationObs = lastMedicationsObs.FirstOrDefault();
|
|
if (lastMedicationObs == null || !lastMedicationObs.Value.Equals(medicineObs.Value))
|
|
await _observationService.Value.InsertObservation(medicineObs, mapObs: false);
|
|
|
|
await CalculateErMedication(activeMedicines, treatment);
|
|
}
|
|
|
|
|
|
private async Task CalculateErMedication(List<Medicine> activeMedicines, PatientTreatment treatment)
|
|
{
|
|
//var activeTreatments = treatmentService.Value.GetActiveTreatmentsByPatient(treatment.patientid);
|
|
var result = await CalculateErMedicineLevels(activeMedicines);
|
|
|
|
|
|
var erMedicationObs = new PatientObservation
|
|
{
|
|
Name = "ERMedication",
|
|
CodingSystem = "ADAS",
|
|
PatientId = treatment.PatientId,
|
|
Time = DateTime.Now,
|
|
Min = 0,
|
|
Max = 5,
|
|
Value = result
|
|
};
|
|
|
|
var lastErMedicationsObsList = await _observationService.Value.FindLastObservations(treatment.PatientId, 1,
|
|
["ERMedication"]);
|
|
var lastErMedicationObs = lastErMedicationsObsList.FirstOrDefault();
|
|
if (lastErMedicationObs == null || !lastErMedicationObs.Value.Equals(erMedicationObs.Value))
|
|
await _observationService.Value.InsertObservation(erMedicationObs, mapObs: false);
|
|
}
|
|
|
|
|
|
private static Task<int> CalculateErMedicineLevels(List<Medicine> activeMedicines)
|
|
{
|
|
var ironVitaminDCodes = new List<string> { "374424002", "175041000140104" };
|
|
|
|
//Aquí a cambiar que la nutrición parenteral siempre sume 4 no 5 quitar de medicinas de 5 solo suma 5 en caso de ser
|
|
//Los lípidos son dos órdenes de NP con el segmento RXO6.2 (NPT: 1 ml LÍPIDOS NEONATALES AL 20% CON MEDICAMENTOS 1 o
|
|
//NPT: 1 ml LÍPIDOS NEONATALES AL 20% 1)
|
|
|
|
var medicines5Points = activeMedicines.Where(m =>
|
|
m.Type.Contains(nameof(MedicineEnum.Types.Pge1)) ||
|
|
m.Type.Contains(nameof(MedicineEnum.Types.Insulin)) ||
|
|
m.Group.Contains(nameof(MedicineEnum.Group.DoubleSignature)) ||
|
|
m.Group.Contains(nameof(MedicineEnum.Group.Vasoactive)) ||
|
|
m.Type.Contains(nameof(MedicineEnum.Types.ParenteralNutritionLipids))
|
|
)
|
|
.ToList();
|
|
|
|
if (medicines5Points.Count > 2 ||
|
|
activeMedicines.FirstOrDefault(m =>
|
|
m.Type.Contains(nameof(MedicineEnum.Types.ParenteralNutritionLipids))) !=
|
|
null) return Task.FromResult(5);
|
|
|
|
if (medicines5Points.Count is > 0 and <= 2 ||
|
|
activeMedicines.FirstOrDefault(m => m.Type.Contains(nameof(MedicineEnum.Types.ParenteralNutrition))) !=
|
|
null
|
|
) return Task.FromResult(4);
|
|
|
|
var medicines2Points = activeMedicines.Where(m =>
|
|
m.Group.Contains(nameof(MedicineEnum.Group.Metabolic))
|
|
).ToList();
|
|
|
|
if (medicines2Points.Count > 0) return Task.FromResult(2);
|
|
|
|
//All medicines without type/group and not vitamin D or Iron
|
|
|
|
var medicines1Point = activeMedicines.FindAll(m => !m.Codes.Any(c => ironVitaminDCodes.Contains(c)));
|
|
|
|
if (medicines1Point.Count > 0) return Task.FromResult(1);
|
|
|
|
|
|
var ironVitaminDMedicines = activeMedicines.Where(m =>
|
|
m.Codes.Any(c => ironVitaminDCodes.Contains(c))
|
|
).ToList();
|
|
|
|
if (ironVitaminDMedicines.Count == activeMedicines.Count || activeMedicines.Count == 0)
|
|
return Task.FromResult(0);
|
|
|
|
return Task.FromResult(1);
|
|
}
|
|
|
|
|
|
//TODO revisar con los valores reales cuando se sepan
|
|
public 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();
|
|
|
|
|
|
respTypeObs.Value = _highFrequencyVentilation.Contains(strValue ?? string.Empty)
|
|
? nameof(RespirationType.HighFrequencyVentilation)
|
|
: _invasiveVentilation.Contains(strValue ?? string.Empty)
|
|
? respTypeObs.Value = nameof(RespirationType.Invasive)
|
|
: _nonInvasiveVentilation.Contains(strValue ?? string.Empty)
|
|
? respTypeObs.Value = nameof(RespirationType.NonInvasive)
|
|
: nameof(RespirationType.None);
|
|
|
|
await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
|
|
}
|
|
|
|
public async Task<BasePatientObservation> CalculateAsistResp(BasePatientObservation obs)
|
|
{
|
|
//Comprobar si hay un resp_type más nuevo y si no lo hay ignorar
|
|
|
|
var pobs = (PatientObservation)obs;
|
|
var lastsAsistResp = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["Resp_Mode"]);
|
|
var lastAsistResp = lastsAsistResp.FirstOrDefault();
|
|
if (lastAsistResp != null && lastAsistResp.Time.CompareTo(obs.Time) > 0 &&
|
|
lastAsistResp.Name != "ONi") return obs;
|
|
|
|
var calculatedRespiratory = new PatientObservation
|
|
{
|
|
PatientId = obs.PatientId,
|
|
Time = DateTime.Now,
|
|
CodingSystem = "ADAS",
|
|
Name = "Respiratory",
|
|
Value = 0
|
|
};
|
|
|
|
if (obs.Name == "ONi")
|
|
{
|
|
//find last assist resp obs
|
|
if (lastAsistResp != null)
|
|
{
|
|
var respiratoryValue = _respiratoryTypeValue.FirstOrDefault(r => r.Item3.Contains(lastAsistResp.Value));
|
|
if (respiratoryValue != null) calculatedRespiratory.Value = respiratoryValue.Item2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var respiratoryValue = _respiratoryTypeValue.FirstOrDefault(r => r.Item3.Contains(pobs.Value));
|
|
|
|
if (respiratoryValue != null) calculatedRespiratory.Value = respiratoryValue.Item2;
|
|
}
|
|
|
|
|
|
var isIno = !string.IsNullOrEmpty(obs.Code) && _oniCodes.Contains(obs.Code);
|
|
|
|
if (isIno && !pobs.Expired) calculatedRespiratory.Value = 10;
|
|
|
|
|
|
//Check if last ino exist and is not expired
|
|
var lastsIno = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["ONi"]);
|
|
var lastIno = lastsIno.FirstOrDefault();
|
|
if (lastIno is { Expired: false }) calculatedRespiratory.Value = 10;
|
|
|
|
await _observationService.Value.InsertObservation(calculatedRespiratory, mapObs: false);
|
|
|
|
return obs;
|
|
}
|
|
|
|
|
|
private async Task CalculateComplexityOnEcmo(PatientTreatment treatment)
|
|
{
|
|
var ecmoObs = new PatientObservation
|
|
{
|
|
PatientId = treatment.PatientId,
|
|
Name = "ECMO"
|
|
};
|
|
|
|
switch (treatment.OrderControl)
|
|
{
|
|
case OrderControlType.Nw:
|
|
ecmoObs.Value = OrderControlType.Nw;
|
|
|
|
break;
|
|
case OrderControlType.Dc:
|
|
var haveEcmo = await _treatmentService.Value.GetActiveTreatmentsByPatient(treatment.PatientId);
|
|
|
|
|
|
ecmoObs.Value = haveEcmo.Any(t => t != null && t.RequestedGiveCodes.Any(r =>
|
|
_ecmo.Contains(r.Identifier) &&
|
|
t.PlacerOrder?.EntityIdentifier != treatment.PlacerOrder?.EntityIdentifier))
|
|
? OrderControlType.Xo
|
|
: OrderControlType.Dc;
|
|
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
await CalculateComplexity(ecmoObs);
|
|
}
|
|
|
|
|
|
/**
|
|
* Calculamos la complejidad basándonos en el valor de PESO/VÍAS/ASSIST.RESP/MONIT./CIRUGÍA/MEDICACIÓN
|
|
* 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
|
|
* La complejidad va de 0 a 5. Guardamos la observación que nos llega y recalculamos complejidad.
|
|
*/
|
|
public async Task<BasePatientObservation> CalculateComplexity(BasePatientObservation obs, bool ignoreObs = false)
|
|
{
|
|
try
|
|
{
|
|
var logUid = Guid.NewGuid();
|
|
var complexity = new PatientObservation
|
|
{
|
|
PatientId = obs.PatientId, Time = DateTime.UtcNow, CodingSystem = "ADAS", Name = "Complexity", Value = 0
|
|
};
|
|
var complexityValue = 0;
|
|
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(obs.PatientId);
|
|
var haveEcmo = activeTreatments.Any(t =>
|
|
t != null && t.RequestedGiveCodes.Any(r => _ecmo.Contains(r.Identifier)));
|
|
var pobs = obs as PatientObservation;
|
|
|
|
var complexityObservations =
|
|
await _observationService.Value.FindLastObservations(obs.PatientId, 1, _complexityObservations);
|
|
|
|
//Nos acaba de entrar, la usamos por delante de la última de base de datos
|
|
//21-02-22 No es correcto, solo remover si el tiempo de esa observación que entra es más nuevo que la de bd
|
|
var actualObsInBd = complexityObservations.FirstOrDefault(o => o.Name == obs.Name);
|
|
if (actualObsInBd != null && obs.Time > actualObsInBd.Time)
|
|
complexityObservations.RemoveAll(it =>
|
|
it.Name == obs.Name);
|
|
|
|
if (!ignoreObs && pobs is { Expired: false }) complexityObservations.Add(pobs);
|
|
|
|
foreach (var observation in complexityObservations)
|
|
switch (observation.Name)
|
|
{
|
|
case "Weight_Current":
|
|
// if(observation.expired) break; A este no le importa que esté expirado, lo tiene que hacer siempre.
|
|
var weightCurrentValue = await CalculateWeight(observation);
|
|
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => Weight_Current plus complexity: {WeightCurrentValue}",
|
|
observation.PatientId, logUid, weightCurrentValue);
|
|
complexityValue += weightCurrentValue;
|
|
break;
|
|
|
|
case "Weight_Newborn": //Only count newborn weight when weight current don't exist.
|
|
if (complexityObservations.FirstOrDefault(o => o.Name == "Weight_Current") == null)
|
|
{
|
|
var weightNewbornValue = await CalculateWeight(observation);
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => Weight_Newborn plus complexity: {Weight_NewbornValue}",
|
|
observation.PatientId, logUid, weightNewbornValue);
|
|
complexityValue += weightNewbornValue;
|
|
}
|
|
|
|
break;
|
|
|
|
case "Medication":
|
|
if (observation.Expired) break;
|
|
var value = observation.Value.ToString();
|
|
|
|
if (!int.TryParse(value, out var valueParsed))
|
|
valueParsed = 0;
|
|
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => Medication plus complexity: {valueParsed}",
|
|
observation.PatientId, logUid, valueParsed);
|
|
complexityValue += valueParsed;
|
|
break;
|
|
|
|
case "Surgery":
|
|
if (observation.Expired) break;
|
|
var surgeryValue = Convert.ToInt32(observation.Value);
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => Surgery plus complexity: {surgeryValue}",
|
|
observation.PatientId, logUid, surgeryValue);
|
|
complexityValue += surgeryValue;
|
|
break;
|
|
|
|
case "IntravenousLines":
|
|
if (observation.Expired) break;
|
|
var intravenousLinesValue = Convert.ToInt32(observation.Value);
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => IntravenousLines plus complexity: {IntravenousLinesValue}",
|
|
observation.PatientId, logUid, intravenousLinesValue);
|
|
complexityValue += intravenousLinesValue;
|
|
break;
|
|
|
|
case "Monitor":
|
|
if (observation.Expired) continue;
|
|
var monitorValue = Convert.ToInt32(observation.Value);
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => monitor plus complexity: {monitorValue}",
|
|
observation.PatientId, logUid, monitorValue);
|
|
complexityValue += monitorValue;
|
|
break;
|
|
|
|
case "Respiratory":
|
|
if (observation.Expired) break;
|
|
var respiratoryValue = Convert.ToInt32(observation.Value);
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => respiratory plus complexity: {respiratoryValue}",
|
|
observation.PatientId, logUid, respiratoryValue);
|
|
complexityValue += respiratoryValue;
|
|
break;
|
|
}
|
|
|
|
complexity.Value = complexityValue;
|
|
|
|
if (haveEcmo && obs.Name != "ECMO")
|
|
//complexity.value = $"ECMO ({complexityValue})";
|
|
complexity.Value = $"{complexityValue} ECMO";
|
|
|
|
if (complexityObservations.Any(o => o.Name == "ECMO"))
|
|
{
|
|
var ecmoObs = complexityObservations.FirstOrDefault(o => o.Name == "ECMO");
|
|
|
|
if (Enum.TryParse(typeof(OrderControlType), ecmoObs?.Value.ToString(), out var treatmentControl))
|
|
switch (treatmentControl)
|
|
{
|
|
case OrderControlType.Dc:
|
|
break;
|
|
//case OrderControlType.XO:
|
|
//case OrderControlType.NW:
|
|
default:
|
|
//complexity.value = $"ECMO ({complexityValue})";
|
|
complexity.Value = $"{complexityValue} ECMO";
|
|
//var pObs = await FixTimeInconsistencyWithLast(complexity);
|
|
if (pobs != null)
|
|
await _observationService.Value.InsertObservation(pobs);
|
|
break;
|
|
}
|
|
}
|
|
|
|
var lastsObsComplexity =
|
|
await _observationService.Value.FindLastObservations(obs.PatientId, 1, [complexity.Name]);
|
|
var lastObsComplexity = lastsObsComplexity.FirstOrDefault();
|
|
if (lastObsComplexity is not null)
|
|
{
|
|
var lastObsParsed = int.TryParse(lastObsComplexity.Value.ToString(), out var lastObsValue);
|
|
|
|
if (lastObsParsed && int.TryParse(complexity.Value.ToString(), out var intValue) &&
|
|
lastObsValue == intValue) return obs;
|
|
}
|
|
|
|
var fixedTimeComplexity = await FixTimeInconsistencyWithLast(complexity);
|
|
_logger.LogDebug(
|
|
"complexity for patient {patientid} id log{logUID} => inserting complexity value: {complexityValue} for patient: {complexityPatientid} at time {fixedTimeComplexityTime}",
|
|
complexity.PatientId, logUid, complexity.Value, complexity.PatientId, fixedTimeComplexity?.Time);
|
|
|
|
if (fixedTimeComplexity != null)
|
|
await _observationService.Value.InsertObservation(fixedTimeComplexity, mapObs: false);
|
|
|
|
return obs;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError("Error calculating complexity. Exception: {ex}", ex);
|
|
return obs;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Calculate intravenous line when new intravenous observation enters. Get all intravenous obs and filtering actives.
|
|
/// Si existe ya un catéter del mismo tipo, apuntando a la misma localización con una fecha que ya existe y no la ha
|
|
/// sido retirada y vuelve a venir
|
|
/// una inserción, no hacemos caso porque es una actualización.
|
|
/// </summary>
|
|
/// <param name="obs"></param>
|
|
/// <returns></returns>
|
|
public async Task<BasePatientObservation?> CalculateIntravenousLineObservation(BasePatientObservation obs)
|
|
{
|
|
try
|
|
{
|
|
var pobs = (PatientObservation)obs;
|
|
var intravenousLineValue = (PatientIntravenousLinesValue)pobs.Value;
|
|
|
|
//Check for doctor miss click on ICCA. sometimes they put insert with remove time
|
|
//when it has a remove time always is remove, never insert
|
|
if (intravenousLineValue is { Action: "Insertado", RemoveTime: not null })
|
|
intravenousLineValue.Action = "Retirado";
|
|
|
|
|
|
//GetByCodeSysAndCode active Intravenous observations
|
|
//var intraVenousLineObservations = observationService.Value.FindLastObservations(obs.patientid, 1, new List<string> { obs.name });
|
|
List<PatientObservation?> activeIntraVenousLineObservations = [];
|
|
try
|
|
{
|
|
activeIntraVenousLineObservations =
|
|
await _observationService.Value.FindLastIntravenousLinesObservationByLocation(obs.PatientId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(
|
|
"Cannot transform to PatientObservation value to PatientIntravenousLinesValue {exMessage}",
|
|
ex.Message);
|
|
}
|
|
|
|
if (activeIntraVenousLineObservations.Any())
|
|
activeIntraVenousLineObservations = activeIntraVenousLineObservations.FindAll(v =>
|
|
v != null && ((PatientIntravenousLinesValue)v.Value).Action == "Insertado");
|
|
/*
|
|
var activeIntravenousLineObservations = intraVenousLineObservations.GroupBy(obs => (((PatientIntravenousLinesValue)obs.value).type,
|
|
((PatientIntravenousLinesValue)obs.value).insertTime,
|
|
((PatientIntravenousLinesValue)obs.value).location))
|
|
.Where(grp => grp.All(o => ((PatientIntravenousLinesValue)o.value).RemoveTime == null))
|
|
.SelectMany(group => group).ToList();
|
|
*/
|
|
//If intravenous obs have remove time, remove it from activeIntravenousLines before calculating.
|
|
|
|
if (intravenousLineValue.RemoveTime != null)
|
|
{
|
|
activeIntraVenousLineObservations.RemoveAll(o =>
|
|
o != null && ((PatientIntravenousLinesValue)o.Value).Location == intravenousLineValue.Location);
|
|
}
|
|
else
|
|
{
|
|
//If insert come with same data than other insert and same insertTime is update. Don't need to register it again as insert.is updated
|
|
var intravenousLineBeforeUpdate = activeIntraVenousLineObservations.FirstOrDefault(o => o != null &&
|
|
((PatientIntravenousLinesValue)o.Value).Location == intravenousLineValue.Location &&
|
|
Equals(((PatientIntravenousLinesValue)o.Value).InsertTime, intravenousLineValue.InsertTime) &&
|
|
((PatientIntravenousLinesValue)o.Value).Type == intravenousLineValue.Type &&
|
|
intravenousLineValue.RemoveTime == null);
|
|
|
|
if (intravenousLineBeforeUpdate != null)
|
|
{
|
|
//If duration changed Update register
|
|
|
|
if (((PatientIntravenousLinesValue)intravenousLineBeforeUpdate.Value).Duration ==
|
|
intravenousLineValue.Duration)
|
|
return null;
|
|
|
|
((PatientIntravenousLinesValue)intravenousLineBeforeUpdate.Value).Duration =
|
|
intravenousLineValue.Duration ?? string.Empty;
|
|
|
|
await _observationService.Value.UpdateObservation(intravenousLineBeforeUpdate);
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
if (!activeIntraVenousLineObservations.Any(o =>
|
|
o != null &&
|
|
((PatientIntravenousLinesValue)o.Value).Location == intravenousLineValue.Location &&
|
|
((PatientIntravenousLinesValue)o.Value).Type == intravenousLineValue.Type))
|
|
activeIntraVenousLineObservations.Add(pobs);
|
|
}
|
|
|
|
//Generate calculad intravenousLine obs
|
|
|
|
//var intraVenousLineScore2 = activeIntraVenousLineObservations.Select(activeObservation => IntraVenousLinesTypeValue.Where(i => i.Item3.Contains(((PatientIntravenousLinesValue)activeObservation.value).type))).Select(typeValue => typeValue.FirstOrDefault()?.Item2??0).Sum();
|
|
|
|
// Step 1: Select active observations and cast to PatientIntravenousLinesValue
|
|
var activeObservations = activeIntraVenousLineObservations.Select(activeObservation =>
|
|
(PatientIntravenousLinesValue?)activeObservation?.Value);
|
|
|
|
// Step 2: Match active observations with type-value mappings
|
|
// We use .Replace("\u00A0", " ") on type to avoid special codification for spaces between characters
|
|
var matchedValues = activeObservations.Select(activeObservation => _intraVenousLinesTypeValue.Where(i =>
|
|
activeObservation is { Type: not null } &&
|
|
i.Item3.Contains(activeObservation.Type.Replace("\u00A0", " "))))
|
|
.ToList();
|
|
|
|
// Step 3: Extract the values from matched tuples
|
|
var values = 0;
|
|
matchedValues.ForEach(typeValue => values += typeValue.FirstOrDefault()?.Item2 ?? 0);
|
|
|
|
// Step 4: Calculate the sum
|
|
var intraVenousLineScore = values;
|
|
|
|
if (intraVenousLineScore > 10) intraVenousLineScore = 10;
|
|
|
|
|
|
var intravenousObs = new PatientObservation
|
|
{
|
|
PatientId = obs.PatientId,
|
|
Name = "IntravenousLines",
|
|
Min = 0,
|
|
CodingSystem = "ADAS",
|
|
Max = 10,
|
|
Time = DateTime.UtcNow,
|
|
Value = intraVenousLineScore
|
|
};
|
|
|
|
var ob = await FixTimeInconsistencyWithLast(intravenousObs);
|
|
if (ob != null)
|
|
await _observationService.Value.InsertObservation(ob, mapObs: false);
|
|
}
|
|
catch (InvalidCastException ex)
|
|
{
|
|
_logger.LogError("CalculateIntravenousLineObservation {obs}: {exMessage}", obs, ex.Message);
|
|
}
|
|
|
|
return obs;
|
|
}
|
|
|
|
|
|
private async Task<int> CalculateWeight(BasePatientObservation obs)
|
|
{
|
|
var complexityValueOfWeight = 0;
|
|
if (obs.Units == "kg") obs = await ParseWeight(obs);
|
|
|
|
var pobs = (PatientObservation)obs;
|
|
|
|
|
|
if (!double.TryParse(pobs.Value.ToString(), out var valueParsed))
|
|
return complexityValueOfWeight;
|
|
|
|
complexityValueOfWeight = valueParsed switch
|
|
{
|
|
< 750 => 7,
|
|
>= 750 and <= 999 => 5,
|
|
>= 1000 and <= 1249 => 2,
|
|
>= 1250 and <= 1999 => 1,
|
|
>= 2000 => 0,
|
|
_ => complexityValueOfWeight
|
|
};
|
|
|
|
return complexityValueOfWeight;
|
|
}
|
|
|
|
|
|
public Task<BasePatientObservation> ParseWeight(BasePatientObservation obs)
|
|
{
|
|
if (obs is not PatientObservation pobs || !double.TryParse(pobs.Value.ToString(), out var dValue))
|
|
{
|
|
_logger.LogError("Error casting weight Observation {obs}:", obs);
|
|
return Task.FromResult(obs);
|
|
}
|
|
|
|
pobs.Units = "gr";
|
|
pobs.Value = dValue * 1000;
|
|
return Task.FromResult(obs);
|
|
}
|
|
|
|
|
|
//Monitor observation can be a observation or treatment
|
|
//TODO como saber si tiene fecha de fin o frecuencia
|
|
public async Task CalculateMonitor(object monitorObservation)
|
|
{
|
|
var monitorValue = 0;
|
|
BasePatientObservation? pobs = null;
|
|
ObjectId patientId = new();
|
|
PatientTreatment? tobs = null;
|
|
|
|
if (monitorObservation.GetType() == typeof(PatientObservation))
|
|
{
|
|
pobs = (BasePatientObservation)monitorObservation;
|
|
patientId = pobs.PatientId;
|
|
}
|
|
else if (monitorObservation.GetType() == typeof(PatientTreatment))
|
|
{
|
|
tobs = (PatientTreatment)monitorObservation;
|
|
patientId = tobs.PatientId;
|
|
}
|
|
|
|
|
|
//Observations in last 30 min are active
|
|
var activeMonitorObservationsList = await _observationService.Value.FindLastObservations(patientId, 1,
|
|
["Saturation_RegBrain", "Saturation_RegSomatic", "Transcutaneous_O2"]);
|
|
if (!activeMonitorObservationsList.Any())
|
|
{
|
|
_logger.LogWarning("Active Monitor Observation List is null or empty for patientId: {patientId}",
|
|
patientId);
|
|
return;
|
|
}
|
|
|
|
var activeMonitorObservations = activeMonitorObservationsList.FindAll(o => !o.Expired);
|
|
|
|
|
|
if (pobs != null && !((PatientObservation)pobs).Expired)
|
|
activeMonitorObservations.Add((PatientObservation)pobs);
|
|
|
|
if (activeMonitorObservations.Any(o => o.Code != null && _transcutanous.Contains(o.Code))) monitorValue += 1;
|
|
if (activeMonitorObservations.Any(o => o.Code != null && _regionalBrainSaturation.Contains(o.Code)))
|
|
monitorValue += 1;
|
|
|
|
|
|
//Patient treatment
|
|
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(patientId);
|
|
|
|
activeTreatments = activeTreatments.ToList().FindAll(p =>
|
|
p != null && p.RequestedGiveCodes.Any(r =>
|
|
_electroencephalogram.Contains(r.Identifier) && r.Text.Contains("Monitor EEGa")));
|
|
|
|
if (tobs != null && tobs.OrderControl != OrderControlType.Dc && activeTreatments.Any()) monitorValue += 1;
|
|
else if (tobs is { OrderControl: OrderControlType.Nw }) monitorValue += 1;
|
|
|
|
|
|
//Generate calculad monitor obs
|
|
var monitorObs = new PatientObservation
|
|
{
|
|
PatientId = patientId,
|
|
Name = "Monitor",
|
|
CodingSystem = "ADAS",
|
|
Min = 0,
|
|
Max = 3,
|
|
Time = DateTime.Now,
|
|
Value = monitorValue
|
|
};
|
|
|
|
await _observationService.Value.InsertObservation(monitorObs, mapObs: false);
|
|
}
|
|
|
|
|
|
private async Task CalculateSurgery(PatientTreatment treatment)
|
|
{
|
|
var surgeryScore = 0;
|
|
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(treatment.PatientId);
|
|
//Filter only surgery treatments
|
|
var activeSurgeryTreatments = activeTreatments.ToList().FindAll(t =>
|
|
t != null && t.RequestedGiveCodes.Any(code =>
|
|
_surgery.Contains(code.Identifier) && _surgeryText.Contains(code.Text)));
|
|
|
|
switch (treatment.OrderControl)
|
|
{
|
|
//Refactor solo con los tratamientos activos de cirugía, un DC cancela a su entityIdentifier correspondiente.
|
|
|
|
case OrderControlType.Nw:
|
|
activeSurgeryTreatments.Add(treatment);
|
|
break;
|
|
case OrderControlType.Dc:
|
|
activeSurgeryTreatments.RemoveAll(t =>
|
|
t != null && t.PlacerOrder?.EntityIdentifier == treatment.PlacerOrder?.EntityIdentifier);
|
|
break;
|
|
}
|
|
|
|
|
|
if (activeSurgeryTreatments.Count > 0) surgeryScore = 5;
|
|
|
|
var surgeryObs = new PatientObservation
|
|
{
|
|
PatientId = treatment.PatientId,
|
|
Name = "Surgery",
|
|
Min = 0,
|
|
Max = 5,
|
|
CodingSystem = "ADAS",
|
|
Time = DateTime.Now,
|
|
Value = surgeryScore
|
|
};
|
|
|
|
await _observationService.Value.InsertObservation(surgeryObs, mapObs: false);
|
|
}
|
|
|
|
|
|
private async Task<List<PatientTreatment>> GetActiveBolus(ObjectId patientId, PatientTreatment? newTreatment)
|
|
{
|
|
var treatmentsProcessed = new List<PatientTreatment>();
|
|
var activeTreatments = await _treatmentService.Value.GetBolusTreatments(patientId);
|
|
|
|
|
|
if (newTreatment != null) activeTreatments.Add(newTreatment);
|
|
|
|
//Agrupar por namespaceID y quedarme con el último message time que será el último que han reecho.
|
|
//Si ese último es concluido suma 1.
|
|
|
|
var treatmentsGroupedByNamespaceId = activeTreatments
|
|
.GroupBy(t => t.PlacerOrder?.NamespaceId)
|
|
//.Select(group => group.OrderByDescending(t => t.messageTime)).ToList();
|
|
.Select(grp => grp.ToList())
|
|
.ToList();
|
|
//.Select(g => g.FirstOrDefault()).ToList();
|
|
|
|
foreach (var treatmentGroup in treatmentsGroupedByNamespaceId)
|
|
{
|
|
var modificatedBolus = treatmentGroup.FindAll(t =>
|
|
t.RequestedGiveCodesStatus.Any(r => r.EndAdministrationTime != DateTime.MinValue));
|
|
//Eliminamos todos aquellos que han sido modificados con posterioridad, esto nos lo indica cuando tiene endAdministrationTime != null
|
|
treatmentGroup.RemoveAll(t =>
|
|
modificatedBolus.Any(m => m.RequestedGiveCodesStatus.FirstOrDefault()?.EndAdministrationTime
|
|
== t.RequestedGiveCodesStatus.FirstOrDefault()?.AdministrationTime));
|
|
/* treatmentGroup.RemoveAll(t => t.requestedGiveCodesStatus
|
|
.Any(r => r.endAdministrationTime == null && modificatedBolus.FirstOrDefault(m =>
|
|
m.requestedGiveCodesStatus.Any(code => code.endAdministrationTime == r.administrationTime))
|
|
!= null));
|
|
*/
|
|
//modificatedBolus.Any(b =>
|
|
// b.requestedGiveCodesStatus.Any(code => code.endAdministrationTime == r.administrationTime))));
|
|
|
|
|
|
//Opción B a veces se cancelan sin endTime. Simplemente, agrupar por administrationTime y quedarme con el último por time del mensaje.
|
|
treatmentGroup.RemoveAll(t => !t.RequestedGiveCodesStatus.Any());
|
|
|
|
var groupByAdmTime = treatmentGroup.GroupBy(t =>
|
|
t.RequestedGiveCodesStatus.FirstOrDefault()!.AdministrationTime)
|
|
.Select(grp => grp.OrderByDescending(t => t.MessageTime).First());
|
|
|
|
|
|
treatmentsProcessed.AddRange(groupByAdmTime);
|
|
//todos los que tengan startOfAdministration y no tenga esa fecha ninguno de modificatedBolus en endOfTreatment
|
|
}
|
|
|
|
|
|
return treatmentsProcessed
|
|
.FindAll(p =>
|
|
p.RequestedGiveCodes.Any(r => _medicationBolus.Contains(r.Identifier)) &&
|
|
p.RequestedGiveCodesStatus.FirstOrDefault() != null &&
|
|
p.RequestedGiveCodesStatus.FirstOrDefault()!.AdministrationTime?.ToUniversalTime() >
|
|
DateTime.UtcNow.AddHours(-12) &&
|
|
p.RequestedGiveCodesStatus.FirstOrDefault()!.AdministrationTime?.ToUniversalTime() <= DateTime.UtcNow &&
|
|
p.RequestedGiveCodesStatus.Any(rxa => rxa.Status != null && _rxaStatus.Contains(rxa.Status)));
|
|
}
|
|
|
|
|
|
private async Task CalculateBolus(PatientTreatment treatment)
|
|
{
|
|
var activeBolus = await GetActiveBolus(treatment.PatientId, treatment);
|
|
|
|
var bolusObs = new PatientObservation
|
|
{
|
|
PatientId = treatment.PatientId,
|
|
Time = DateTime.Now,
|
|
Name = "OpiateBoluses",
|
|
CodingSystem = "ADAS",
|
|
Value = activeBolus.Count
|
|
};
|
|
await _observationService.Value.InsertObservation(bolusObs);
|
|
}
|
|
|
|
/*
|
|
* En rojo si TAm < Edad Gestacional en semanas en la primera semana y luego edad corregida
|
|
*/
|
|
public async Task CalculateTAmAlert(BasePatientObservation obs)
|
|
{
|
|
var pobs = (PatientObservation)obs;
|
|
var tamStatus = StatusEnum.Type.Ok;
|
|
var groupedObservations = new List<PatientObservation> { pobs };
|
|
|
|
var gestationalWeeksToCheck = 0;
|
|
|
|
if (obs.Name == "Age_Gestational")
|
|
groupedObservations = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
|
["Age_Gestational_Fixed", "TAm"]);
|
|
if (obs.Name == "Age_Gestational_Fixed")
|
|
groupedObservations = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
|
["Age_Gestational", "TAm"]);
|
|
|
|
if (obs.Name == "TAm")
|
|
groupedObservations = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
|
["Age_Gestational", "Age_Gestational_Fixed"]);
|
|
|
|
var ageGestational = groupedObservations.FirstOrDefault(o => o.Name == "Age_Gestational");
|
|
if (ageGestational != null && int.TryParse(ageGestational.Value.ToString(), out var ageParsed) && ageParsed < 2)
|
|
{
|
|
gestationalWeeksToCheck = Convert.ToInt32(ageGestational.Value);
|
|
}
|
|
else
|
|
{
|
|
var ageGestationalFixed = groupedObservations.FirstOrDefault(o => o.Name == "Age_Gestational_Fixed");
|
|
if (ageGestationalFixed != null) gestationalWeeksToCheck = Convert.ToInt32(ageGestationalFixed.Value);
|
|
//var gestationalWeeks = int.Parse(ageGestationalFixed.value.ToString());
|
|
//if (Convert.ToInt32(pobs.value) < gestationalWeeks) TAmStatus = ObservationStatus.Alert;
|
|
}
|
|
|
|
var tamObs = groupedObservations.FirstOrDefault(o => o.Name == "TAm");
|
|
if (tamObs != null)
|
|
if (Convert.ToInt32(tamObs.Value) < gestationalWeeksToCheck)
|
|
tamStatus = StatusEnum.Type.Alert;
|
|
|
|
if (pobs.Name == "TAm")
|
|
{
|
|
pobs.Status = tamStatus;
|
|
}
|
|
else
|
|
{
|
|
if (tamObs != null)
|
|
{
|
|
tamObs.Id = ObjectId.GenerateNewId();
|
|
tamObs.Time = DateTime.Now;
|
|
tamObs.Status = tamStatus;
|
|
await _observationService.Value.InsertObservation(tamObs, mapObs: false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*Entra temp axilar o incubadora. Restamos la axilar a la incubadora. Solo se calcula si están los dos valores. */
|
|
public async Task CalculateTempGradient(BasePatientObservation obs)
|
|
{
|
|
List<PatientObservation> tempRetrievedesFromBd;
|
|
PatientObservation? tempRetrievedFromBd = null;
|
|
var pobs = (PatientObservation)obs;
|
|
if ("Temp_Patient".Equals(pobs.Name))
|
|
{
|
|
tempRetrievedesFromBd =
|
|
await _observationService.Value.FindLastObservations(pobs.PatientId, 1, ["Temp_Incubator"]);
|
|
tempRetrievedFromBd = tempRetrievedesFromBd.FirstOrDefault();
|
|
}
|
|
|
|
if ("Temp_Incubator".Equals(pobs.Name))
|
|
{
|
|
tempRetrievedesFromBd =
|
|
await _observationService.Value.FindLastObservations(pobs.PatientId, 1, ["Temp_Patient"]);
|
|
tempRetrievedFromBd = tempRetrievedesFromBd.FirstOrDefault();
|
|
}
|
|
|
|
|
|
//Now Temp Gradient is only calculated when temp_Patient and Temp_Incubator come in last 10 min.
|
|
//if (tempRetrievedFromBd != null && DateTime.UtcNow.CompareTo(tempRetrievedFromBd.time.ToUniversalTime().AddMinutes(10)) <= 0)
|
|
if (tempRetrievedFromBd == null) return;
|
|
var difFechas = pobs.Time.ToUniversalTime() - tempRetrievedFromBd.Time.ToUniversalTime();
|
|
//if (tempRetrievedFromBd != null && pobs.time.ToUniversalTime().CompareTo(tempRetrievedFromBd.time.ToUniversalTime().AddMinutes(10)) <= 0)
|
|
if (Math.Abs(difFechas.TotalMinutes) <= 10 &&
|
|
double.TryParse(tempRetrievedFromBd.Value.ToString(), out var tempRetrievedFromBdParsed) &&
|
|
double.TryParse(pobs.Value.ToString(), out var pobsParsed))
|
|
{
|
|
double tempGradientValue;
|
|
if ("Temp_Patient".Equals(pobs.Name))
|
|
tempGradientValue = tempRetrievedFromBdParsed - pobsParsed;
|
|
else
|
|
tempGradientValue = pobsParsed - tempRetrievedFromBdParsed;
|
|
var tempGradientObs = new PatientObservation
|
|
{
|
|
PatientId = obs.PatientId,
|
|
Name = "Temp_Gradient",
|
|
CodingSystem = "ADAS",
|
|
Time = obs.Time,
|
|
Value = tempGradientValue
|
|
};
|
|
|
|
var obsToInsert = (PatientObservation)await CheckObsWithSameTimeExistsAndIncrementTime(tempGradientObs);
|
|
|
|
obsToInsert.Id = ObjectId.GenerateNewId();
|
|
|
|
await _observationService.Value.InsertObservation(obsToInsert, mapObs: false);
|
|
}
|
|
}
|
|
|
|
private enum IntraVenousLineTypes
|
|
{
|
|
Artery,
|
|
CentralVein,
|
|
Picc,
|
|
MiddleLine,
|
|
Peripheral
|
|
}
|
|
|
|
// ReSharper disable once UnusedMember.Local
|
|
private enum RespiratoryTypes
|
|
{
|
|
Ino,
|
|
Vafo,
|
|
Vmc,
|
|
Vmni,
|
|
NasalCannulas,
|
|
None
|
|
}
|
|
} |