=== 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
@@ -17,6 +17,7 @@ namespace adas_core.Application.Customizations.H12O.UCIN;
/// raw observations and active <see cref="PatientTreatment"/> entries, using the catalogue of
/// codes, groups, and types configured in <see cref="ApiSettings"/>.
/// </summary>
/// <!-- aidoc:v1 sig=1b16cfc -->
public class CalculatedObservations : ICalculatedObservations
{
private readonly List<string> _complexityObservations =
@@ -87,6 +88,8 @@ public class CalculatedObservations : ICalculatedObservations
/// ONi, ventilation modes, ECMO, and notes indicating medication) from <see cref="ApiSettings"/>.
/// </summary>
/// <param name="serviceProvider">The application's service provider used to resolve the required dependencies and configuration.</param>
/// <!-- aidoc-review:v1 severity=low kind=stale_summary
/// "The summary lists the configured catalogues loaded from ApiSettings but omits SurgeryText, which is also loaded in the constructor." -->
public CalculatedObservations(IServiceProvider serviceProvider)
{
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>(); //observationService;
@@ -159,6 +162,8 @@ public class CalculatedObservations : ICalculatedObservations
/// A <see cref="Task{T}"/> that resolves to the (possibly transformed) observation, or
/// <see langword="null"/> when the input observation has no name.
/// </returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "The documentation states the method resolves to null 'when the input observation has no name', but the early-exit branch returns the original `obs`, not null." -->
public async Task<T?> Map<T>(T obs, bool onlyByName) where T : BasePatientObservation
{
// Early exit: if the observation has no name, there's nothing to map
@@ -244,6 +249,8 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="treatment">The <see cref="PatientTreatment"/> to be mapped.</param>
/// <returns>A task that represents the asynchronous mapping operation. The task result contains the processed <see cref="PatientTreatment"/>.</returns>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="treatment"/> parameter is <c>null</c>.</exception>
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "ArgumentNullException is documented but the method body never throws it; no null check exists for the treatment parameter, so a null argument would result in a NullReferenceException, not ArgumentNullException." -->
public async Task<PatientTreatment> Map(PatientTreatment treatment)
{
if (treatment.SingleDose)
@@ -316,6 +323,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="pumpObservation">The pump observation to map.</param>
/// <returns>A task containing the same <see cref="PumpObservation"/> instance that was passed in.</returns>
/// <!-- aidoc:v1 sig=50be4c1 body=e481734 -->
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
{
return await Task.FromResult(pumpObservation);
@@ -330,6 +338,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="activeMedicines">The list of active <see cref="Medicine"/> instances currently associated with the patient.</param>
/// <param name="patientId">The unique identifier of the patient.</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=299c0fe body=f6867d8 -->
public async Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
{
await CalculateMedicineObservation(activeMedicines, [], new PatientTreatment { PatientId = patientId });
@@ -342,6 +351,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="patientId">The unique identifier of the patient.</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=2aadb2d body=f1796c6 -->
public async Task CalculateActiveBolus(ObjectId patientId)
{
// SIN RXA
@@ -395,6 +405,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="id">The unique identifier of the patient.</param>
/// <returns>A collection of active <see cref="PatientTreatment"/> objects for the patient.</returns>
/// <!-- aidoc:v1 sig=1c9e799 body=2a62eb7 -->
public async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
{
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(id);
@@ -409,6 +420,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="diagnosis">The <see cref="PatientDiagnosis"/> to map.</param>
/// <returns>A task containing the same <see cref="PatientDiagnosis"/> instance that was passed in.</returns>
/// <!-- aidoc:v1 sig=8ddf601 body=ad326e6 -->
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
{
return Task.FromResult(diagnosis);
@@ -425,6 +437,8 @@ public class CalculatedObservations : ICalculatedObservations
/// A task that represents the asynchronous operation. The task result contains the fixed
/// <see cref="PatientObservation"/> if the input had a valid name; otherwise, <see langword="null"/>.
/// </returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "The summary states the trigger is when the new observation arrives with the 'same (down-to-the-second) timestamp', but the code's DateTime.Compare >= 0 condition also triggers the shift when the new observation's truncated time is strictly earlier than the last observation's." -->
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
{
if (string.IsNullOrEmpty(newObservation.Name))
@@ -460,6 +474,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="listToInsert">The list of patient observations to be pre-mapped.</param>
/// <returns>A task containing the original list of patient observations.</returns>
/// <!-- aidoc:v1 sig=5a37e9b body=0791af0 -->
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
{
return Task.FromResult(listToInsert);
@@ -473,6 +488,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="obs">The patient observation that triggered the alarm.</param>
/// <param name="alarmToInsert">The alarm metadata to be inserted alongside the observation.</param>
/// <returns>A task containing the same <see cref="PatientObservation"/> instance that was passed in.</returns>
/// <!-- aidoc:v1 sig=405db8e body=ea790e4 -->
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
{
return Task.FromResult(obs);
@@ -487,6 +503,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="code">The optional alarm code from <see cref="AlarmEnum.Name"/>.</param>
/// <returns>Never returns a result.</returns>
/// <exception cref="NotImplementedException">Always thrown because alarm dispatch is not implemented in the UCIN customization.</exception>
/// <!-- aidoc:v1 sig=90426a4 body=bfa6f2f -->
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
{
throw new NotImplementedException();
@@ -501,6 +518,8 @@ public class CalculatedObservations : ICalculatedObservations
/// <returns>A task that represents the asynchronous insert operation.</returns>
/// <exception cref="InvalidCastException">Thrown when <paramref name="obs"/> cannot be cast to <see cref="PatientObservation"/>.</exception>
/// <exception cref="Exception">Rethrown after the underlying exception is written to the console for diagnostics.</exception>
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "Summary states 'Errors are logged' but the code uses Console.WriteLine for exception output, not the _logger. The companion <exception> tag correctly describes console output, so the summary is mildly inconsistent with the actual behavior." -->
public async Task CheckSurgeryExpired(BasePatientObservation obs)
{
try
@@ -536,6 +555,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation expected to be a <see cref="PatientObservation"/>.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the (possibly time-shifted) base patient observation.</returns>
/// <!-- aidoc:v1 sig=02a8359 body=9a6b741 -->
public async Task<BasePatientObservation> CheckObsExistsAndIncrementTime(BasePatientObservation obs)
{
var pobs = (PatientObservation)obs;
@@ -559,6 +579,8 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation expected to be a <see cref="PatientObservation"/>.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the (possibly time-shifted) base patient observation.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary claims the method is for 'temperature observations', but the code contains no temperature-specific logic — it works for any observation type passed in, using whatever Name is on the observation." -->
public async Task<BasePatientObservation> CheckObsWithSameTimeExistsAndIncrementTime(BasePatientObservation obs)
{
var pobs = (PatientObservation)obs;
@@ -579,6 +601,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The observation that triggered the calculation (one of <c>AirPressure_Mean</c>, <c>FiO2</c>, or <c>PaO2</c>).</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=3429ff2 body=103e384 -->
public async Task CalculateOxygenationIndex(BasePatientObservation obs)
{
var toSearchList = new List<string>();
@@ -655,6 +678,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The single-dose treatment whose end time is to be calculated.</param>
/// <returns>The same <see cref="PatientTreatment"/> instance with its <c>EndTime</c> updated.</returns>
/// <!-- aidoc:v1 sig=271263e body=4ddb3f4 -->
private static PatientTreatment CalculateSingleDoseEndDate(PatientTreatment treatment)
{
/* Deprecated calc finish treatment date on shift end. Now every treatment single dose is last 8 Hours
@@ -690,6 +714,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The treatment whose medicines should be checked.</param>
/// <returns>A task that represents the asynchronous check operation.</returns>
/// <!-- aidoc:v1 sig=26b9617 body=0b5d20b -->
public async Task CheckTreatmentMedicines(PatientTreatment treatment)
{
//sI TIENE UNA NOTA CON NPT SON DE TIPO NUTRICIÓN PARENTERAL Y SUMAN 1
@@ -784,6 +809,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The treatment to inspect for NPT indicators, or <see langword="null"/>.</param>
/// <returns>A task that resolves to a <see cref="Medicine"/> instance describing the parenteral nutrition, or an unnamed, untyped instance when no NPT notes are present.</returns>
/// <!-- aidoc:v1 sig=d078407 body=3e76d41 -->
private static Task<Medicine> CalculateParentalNutritionMedicine(PatientTreatment? treatment)
{
List<string> medicineType = [];
@@ -818,6 +844,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="medicines">The medicines to add or remove depending on <c>OrderControl</c>.</param>
/// <param name="treatment">The treatment that triggered the recalculation.</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=0ed4852 body=363a6db -->
public async Task CalculateMedicineObservation(List<Medicine> activeMedicines, List<Medicine> medicines,
PatientTreatment treatment)
{
@@ -876,6 +903,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="activeMedicines">The list of active medicines used to derive the risk level.</param>
/// <param name="treatment">The treatment that triggered the recalculation.</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=b13c549 body=24f69f5 -->
private async Task CalculateErMedication(List<Medicine> activeMedicines, PatientTreatment treatment)
{
//var activeTreatments = treatmentService.Value.GetActiveTreatmentsByPatient(treatment.patientid);
@@ -908,6 +936,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="activeMedicines">The list of active medicines to evaluate.</param>
/// <returns>A task that resolves to the integer risk level (05).</returns>
/// <!-- aidoc:v1 sig=3c6a3b1 body=606ffd9 -->
private static Task<int> CalculateErMedicineLevels(List<Medicine> activeMedicines)
{
var ironVitaminDCodes = new List<string> { "374424002", "175041000140104" };
@@ -964,6 +993,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The respiratory-mode observation expected to be a <see cref="PatientObservation"/>.</param>
/// <returns>A task that represents the asynchronous insert operation.</returns>
/// <!-- aidoc:v1 sig=a32f888 body=5994877 -->
public async Task CalculateVentilationMode(BasePatientObservation obs)
{
var pobs = (PatientObservation)obs;
@@ -998,6 +1028,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation that triggered the calculation (expected to be a <see cref="PatientObservation"/>).</param>
/// <returns>A task that resolves to the same base patient observation that was passed in.</returns>
/// <!-- aidoc:v1 sig=dbb815a body=5ae4249 -->
public async Task<BasePatientObservation> CalculateAsistResp(BasePatientObservation obs)
{
//Comprobar si hay un resp_type más nuevo y si no lo hay ignorar
@@ -1057,6 +1088,8 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The treatment whose ECMO state is being applied.</param>
/// <returns>A task that represents the asynchronous recalculation operation.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Documentation states 'In every case the change is followed by a complexity recalculation via CalculateComplexity', but the default case returns early without calling CalculateComplexity." -->
private async Task CalculateComplexityOnEcmo(PatientTreatment treatment)
{
var ecmoObs = new PatientObservation
@@ -1102,6 +1135,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="obs">The base patient observation that triggered the recalculation.</param>
/// <param name="ignoreObs">When <see langword="true"/>, the supplied <paramref name="obs"/> is not added to the calculation inputs (useful for synthetic observations like ECMO).</param>
/// <returns>A task that resolves to the same base patient observation that was passed in.</returns>
/// <!-- aidoc:v1 sig=b7809c7 body=cf3438b -->
public async Task<BasePatientObservation> CalculateComplexity(BasePatientObservation obs, bool ignoreObs = false)
{
try
@@ -1278,6 +1312,7 @@ public class CalculatedObservations : ICalculatedObservations
/// early because the incoming observation is a duplicate insert (in which case the caller should
/// not overwrite the stored observation).
/// </returns>
/// <!-- aidoc:v1 sig=09f61b3 body=4d3947c -->
public async Task<BasePatientObservation?> CalculateIntravenousLineObservation(BasePatientObservation obs)
{
try
@@ -1413,6 +1448,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation whose value represents the patient's weight.</param>
/// <returns>A task that resolves to the integer complexity contribution (07).</returns>
/// <!-- aidoc:v1 sig=a79c349 body=4c9b390 -->
private async Task<int> CalculateWeight(BasePatientObservation obs)
{
var complexityValueOfWeight = 0;
@@ -1445,6 +1481,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation expected to be a <see cref="PatientObservation"/> with a numeric value.</param>
/// <returns>A task that resolves to the (possibly converted) base patient observation.</returns>
/// <!-- aidoc:v1 sig=18ad5f6 body=5d01118 -->
public Task<BasePatientObservation> ParseWeight(BasePatientObservation obs)
{
if (obs is not PatientObservation pobs || !double.TryParse(pobs.Value.ToString(), out var dValue))
@@ -1471,6 +1508,7 @@ public class CalculatedObservations : ICalculatedObservations
/// derived from whichever type is supplied.
/// </param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=9488dd5 body=f704b41 -->
public async Task CalculateMonitor(object monitorObservation)
{
var monitorValue = 0;
@@ -1545,6 +1583,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The treatment that triggered the recalculation.</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=a3bb931 body=d219f09 -->
private async Task CalculateSurgery(PatientTreatment treatment)
{
var surgeryScore = 0;
@@ -1596,6 +1635,7 @@ public class CalculatedObservations : ICalculatedObservations
/// <param name="patientId">The unique identifier of the patient.</param>
/// <param name="newTreatment">The optional new treatment to be included in the active-bolus set.</param>
/// <returns>A task that resolves to the list of treatments currently counted as active boluses.</returns>
/// <!-- aidoc:v1 sig=401adb8 body=c80c23f -->
private async Task<List<PatientTreatment>> GetActiveBolus(ObjectId patientId, PatientTreatment? newTreatment)
{
var treatmentsProcessed = new List<PatientTreatment>();
@@ -1660,6 +1700,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="treatment">The treatment that triggered the recalculation and should be included in the active-bolus set.</param>
/// <returns>A task that represents the asynchronous insert operation.</returns>
/// <!-- aidoc:v1 sig=493996c body=3ef85e3 -->
private async Task CalculateBolus(PatientTreatment treatment)
{
var activeBolus = await GetActiveBolus(treatment.PatientId, treatment);
@@ -1686,6 +1727,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation that triggered the alert evaluation (<c>TAm</c>, <c>Age_Gestational</c>, or <c>Age_Gestational_Fixed</c>).</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=857f5e0 body=0bf2cd4 -->
public async Task CalculateTAmAlert(BasePatientObservation obs)
{
var pobs = (PatientObservation)obs;
@@ -1749,6 +1791,7 @@ public class CalculatedObservations : ICalculatedObservations
/// </summary>
/// <param name="obs">The base patient observation that triggered the calculation (<c>Temp_Patient</c> or <c>Temp_Incubator</c>).</param>
/// <returns>A task that represents the asynchronous calculation operation.</returns>
/// <!-- aidoc:v1 sig=f3ac5ae body=4120ebf -->
public async Task CalculateTempGradient(BasePatientObservation obs)
{
List<PatientObservation> tempRetrievedesFromBd;