=== Summary: 675 files | 7 generated | 484 fresh | 4605 untracked | 4268 adopted | 355 marked | 466 validated-ok | 2+0 stale (sig+body) | 0 skipped | 0 failed | elapsed 11:08:11.442 (40091.44s) ===

This commit is contained in:
julian
2026-06-28 02:50:05 -07:00
parent a19fb90902
commit 586f02a2ca
654 changed files with 5260 additions and 0 deletions
@@ -15,6 +15,7 @@ namespace adas_core.Application.Customizations.HUVH.UCIA;
/// Represents a concrete implementation of the <see cref="ICalculatedObservations"/> interface,
/// providing functionality to manage a collection of calculated observations.
/// </summary>
/// <!-- aidoc:v1 sig=1b16cfc -->
public class CalculatedObservations : ICalculatedObservations
{
private const string CodingSystem = "ADAS";
@@ -67,6 +68,8 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="patientId">The identifier of the patient whose active bolus should be calculated.</param>
/// <exception cref="NotImplementedException">Thrown when the method is invoked, as the calculation logic has not yet been implemented.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=stale_summary
/// "The summary states that the method 'calculates the active bolus', but the body only throws NotImplementedException and performs no calculation; the <exception> tag mitigates this by noting the logic is not yet implemented." -->
public Task CalculateActiveBolus(ObjectId patientId)
{
throw new NotImplementedException();
@@ -79,6 +82,8 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="obs">The patient observation to map; may be replaced with the result of the matched asynchronous calculation when applicable.</param>
/// <param name="onlyByName">Indicates whether the mapping should be performed using only the observation's name.</param>
/// <returns>The processed patient observation, potentially updated by the applicable calculation.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=mentions_removed_behavior
/// "The <param name=\"onlyByName\"> describes behavior ('Indicates whether the mapping should be performed using only the observation's name'), but the parameter is never referenced anywhere in the method body; the dispatching always relies solely on the observation's name regardless of this flag." -->
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);
@@ -106,6 +111,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The patient treatment to map and update.</param>
/// <returns>The patient treatment with its order control set according to the evaluated business rules.</returns>
/// <!-- aidoc:v1 sig=442a6e8 body=e1bed22 -->
public async Task<PatientTreatment> Map(PatientTreatment treatment)
{
var order = treatment.PlacerOrder?.EntityIdentifier; //aquí almacenamos el número de orden
@@ -130,6 +136,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="pumpObservation">The pump observation to map.</param>
/// <returns>A completed task containing the provided <see cref="PumpObservation"/>.</returns>
/// <!-- aidoc:v1 sig=50be4c1 body=e481734 -->
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
{
return await Task.FromResult(pumpObservation);
@@ -141,6 +148,8 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="activeMedicines">The list of currently active medicines assigned to the patient.</param>
/// <param name="patientId">The unique identifier of the patient whose medication categories will be checked.</param>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary claims the method 'calculates medicine observations', but the implementation only invokes CheckMedicationCategories and returns Task.CompletedTask; no observation calculation is performed." -->
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
{
//Esto viene del schedulerService para chequear los medicamentos activos
@@ -154,6 +163,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="id">The unique identifier of the patient whose active treatments should be retrieved.</param>
/// <returns>A collection of <see cref="PatientTreatment"/> objects representing the patient's active treatments.</returns>
/// <!-- aidoc:v1 sig=1c9e799 body=2a62eb7 -->
public async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
{
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(id);
@@ -167,6 +177,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="diagnosis">The <see cref="PatientDiagnosis"/> to be mapped.</param>
/// <returns>A task that represents the asynchronous mapping operation, containing the resulting <see cref="PatientDiagnosis"/>.</returns>
/// <exception cref="NotImplementedException">Thrown when the method is invoked, as the mapping logic has not yet been implemented.</exception>
/// <!-- aidoc:v1 sig=8ddf601 body=bfa6f2f -->
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
{
throw new NotImplementedException();
@@ -179,6 +190,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="newObservation">The new patient observation whose timestamp should be adjusted to avoid time inconsistencies with prior observations.</param>
/// <returns>The patient observation, with its <c>Time</c> adjusted when a time collision is detected, or the original observation when its name is null or empty.</returns>
/// <!-- aidoc:v1 sig=2b42b30 body=04118be -->
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
{
if (string.IsNullOrEmpty(newObservation.Name))
@@ -211,6 +223,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="listToInsert">The list of patient observations to pre-map before insertion.</param>
/// <returns>A completed task containing the provided list of patient observations.</returns>
/// <!-- aidoc:v1 sig=5a37e9b body=0791af0 -->
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
{
return Task.FromResult(listToInsert);
@@ -222,6 +235,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="obs">The patient observation to be returned as the mapping result.</param>
/// <param name="alarmToInsert">The patient observation alarm intended to be associated with the observation.</param>
/// <returns>A task containing the patient observation.</returns>
/// <!-- aidoc:v1 sig=405db8e body=ea790e4 -->
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
{
return Task.FromResult(obs);
@@ -235,6 +249,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="code">The optional alarm code categorizing the alarm, or null if no code is specified.</param>
/// <returns>A task that represents the asynchronous alarm sending operation.</returns>
/// <exception cref="NotImplementedException">Thrown to indicate that the method has not yet been implemented.</exception>
/// <!-- aidoc:v1 sig=90426a4 body=bfa6f2f -->
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
{
throw new NotImplementedException();
@@ -246,6 +261,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation to evaluate for the rehabilitation alarm condition.</param>
/// <returns>The observation with its status set to Alert when the six previous rehabilitation observations also fall within the 0-2 range; otherwise the observation is returned as-is.</returns>
/// <!-- aidoc:v1 sig=4d51d03 body=02faf98 -->
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
@@ -270,6 +286,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The incoming base patient observation; only <see cref="PatientObservation"/> instances whose
/// <c>Name</c> is "Diuresis" or "Weight" are processed, otherwise the method returns without changes.</param>
/// <!-- aidoc:v1 sig=a9e1f01 body=35f930e -->
private async Task CalculateDiuresis(BasePatientObservation obs)
{
// Calculado como el sumatorio de la Diuresis de las últimas 6h
@@ -350,6 +367,7 @@ public class CalculatedObservations : ICalculatedObservations
/// Calculates the ROX Index by dividing the SpO2/FiO2 ratio by the respiratory rate (FR) and persists the result as a new <c>Rox_Index</c> observation. The method supports both directions of the calculation: when the incoming observation is the SpO2/FiO2 ratio, it retrieves the latest FR, and vice versa. It silently returns if the observation is not a <c>PatientObservation</c>, if the observation name is not recognized, if the required paired observation cannot be found, if its value cannot be parsed, or if the FR value is zero (to avoid division by zero).
/// </summary>
/// <param name="obs">The base patient observation that triggers the ROX index calculation. Only observations named <c>SpO2_FiO2_Ratio</c> or <c>FR</c> are processed; any other type or name is ignored.</param>
/// <!-- aidoc:v1 sig=b303a48 body=1e098ad -->
private async Task CalculateRoxIndex(BasePatientObservation obs)
{
// Cálculo dividiendo el ratio SpO2/FiO2 entre la FR
@@ -402,6 +420,7 @@ public class CalculatedObservations : ICalculatedObservations
/// Calculates the driving pressure for a patient as the difference between Pmeset and PEEP when a new Pmeset or PEEP observation is provided. Looks up the complementary observation to obtain the missing value, then creates and persists a "Driving_Pressure" observation. Returns early if the input is not a PatientObservation, the observation name is neither Pmeset nor PEEP, the complementary observation cannot be found, or its value cannot be parsed as an integer.
/// </summary>
/// <param name="obs">The base patient observation that triggered the calculation; expected to represent a Pmeset or PEEP measurement.</param>
/// <!-- aidoc:v1 sig=b3a7d66 body=19b29eb -->
private async Task CalculateDrivingPressure(BasePatientObservation obs)
{
//Diferencia entre la Pmeset y la PEEP
@@ -458,6 +477,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The observation that triggered the evaluation; its value must be numeric and it is ignored if <paramref name="patientId"/> is provided (e.g., when invoked from a treatment context).</param>
/// <param name="patientId">The patient identifier when the evaluation is triggered by a treatment event; when null, it is derived from <paramref name="obs"/>.</param>
/// <!-- aidoc:v1 sig=28b0d06 body=65c1f9b -->
private async Task CalculateOverAnalgesia(BasePatientObservation? obs, ObjectId? patientId = null)
{
// Mandar observación 'SOBREANALGESIA'
@@ -537,6 +557,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation to evaluate and potentially transform.</param>
/// <returns>A task that yields the observation, with its value normalized to "ECMO" when the original value is one of the recognized ECMO variants.</returns>
/// <!-- aidoc:v1 sig=5673ebb body=65604a9 -->
private Task<BasePatientObservation> CalculateEcmoLocation(BasePatientObservation obs)
{
//Las opciones pueden ser VV, VA o ECMO.
@@ -564,6 +585,7 @@ public class CalculatedObservations : ICalculatedObservations
/// anything.
/// </summary>
/// <param name="obs">The incoming patient observation whose name drives the ventilation mode calculation.</param>
/// <!-- aidoc:v1 sig=dd5b490 body=76605b5 -->
private async Task CalculateVentilationMode(BasePatientObservation obs)
{
//- Si llega valor de PI pero NO COMPL, el tipo de ventilación es VMNI
@@ -619,6 +641,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The triggering patient observation used to evaluate the sedation state. When provided, its name and value drive the initial validation; when null, the method relies on the <paramref name="patientId"/> parameter (typically from a treatment update).</param>
/// <param name="patientId">Optional identifier of the patient to evaluate. If null, it is derived from <paramref name="obs"/>; otherwise, the method performs a full evaluation using the patient's recent observations.</param>
/// <!-- aidoc:v1 sig=0a9014e body=8a7e50f -->
private async Task CalculateOverSedation(BasePatientObservation? obs, ObjectId? patientId = null)
{
//Mandar observación 'SOBRESEDACIÓN'
@@ -700,6 +723,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The patient treatment to evaluate; may be null.</param>
/// <returns><c>true</c> if the treatment has a start time and was started more than 24 hours ago; otherwise, <c>false</c>.</returns>
/// <!-- aidoc:v1 sig=ee619c2 body=c94e0d4 -->
private static bool ExceedsAnalgesiaThreshold(PatientTreatment? treatment)
{
// Perfusiones de morfina, remifentanilo o fentanilo sostenidas > 24 h
@@ -713,6 +737,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The patient treatment to evaluate, or <c>null</c>.</param>
/// <returns><c>true</c> if the treatment is not <c>null</c> and any requested medication exceeds its defined sedation threshold; otherwise, <c>false</c>.</returns>
/// <!-- aidoc:v1 sig=5aa55d0 body=d2a9955 -->
private static bool ExceedsSedationThreshold(PatientTreatment? treatment)
{
return (treatment != null &&
@@ -729,6 +754,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The patient treatment whose patient is used to look up the list of active treatments to evaluate.</param>
/// <returns>A task that returns the list of active patient treatments that were not discontinued.</returns>
/// <!-- aidoc:v1 sig=4f3a796 body=a702644 -->
private async Task<List<PatientTreatment>> CheckExpiredPatientTreatments(PatientTreatment treatment)
{
//si el tratamiento ha expirado actualizamos el OrderControl a DC y devolvemos las que siguen activas
@@ -757,6 +783,7 @@ public class CalculatedObservations : ICalculatedObservations
/// further validation.
/// </summary>
/// <param name="treatment">The patient treatment whose requested medicines will be checked against the patient's active medicines.</param>
/// <!-- aidoc:v1 sig=e762e81 body=63b9252 -->
private async Task CheckTreatmentMedicines(PatientTreatment treatment)
{
var newMedicines = (await Task.WhenAll(treatment.RequestedGiveCodes
@@ -785,6 +812,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="patientId">The identifier of the patient whose medication categories are being evaluated and linked to the created observations.</param>
/// <param name="uniqueMedicines">The distinct list of medicines to be checked against the predefined category reference lists.</param>
/// <!-- aidoc:v1 sig=ef6fae4 body=be6580c -->
private void CheckMedicationCategories(ObjectId patientId, List<Medicine> uniqueMedicines)
{
var medicationCategories = new Dictionary<string, List<string>?>
@@ -821,6 +849,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="medications">The collection of medications whose names will be stored as the observation values.</param>
/// <param name="patientId">The identifier of the patient the observation belongs to.</param>
/// <param name="obsName">The name used to group and look up the previous observation for the same concept.</param>
/// <!-- aidoc:v1 sig=c1a952c body=987bc59 -->
private async Task CreateMedicationMultivalueObservation(IEnumerable<Medicine?> medications, ObjectId patientId,
string obsName)
{