Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
+381
@@ -0,0 +1,381 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
Debug/
|
||||||
|
Release/
|
||||||
|
*.tlog
|
||||||
|
packages
|
||||||
|
*.log
|
||||||
|
TestResult.xml
|
||||||
|
*.VisualState.xml
|
||||||
|
Version.cs
|
||||||
|
Version.h
|
||||||
|
Version.cpp
|
||||||
|
.vs
|
||||||
|
/adas-core/Logs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
.idea
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
steps:
|
||||||
|
test:
|
||||||
|
image: mcr.microsoft.com/dotnet/sdk:8.0
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- commit
|
||||||
|
commands:
|
||||||
|
- (dotnet nuget add source $${ADAS_NUGET_URL} -n "ADAS Nugget Server") | 2>/dev/null
|
||||||
|
- dotnet build --configuration Debug /p:Platform=x64 /nowarn:1701,1702,IL2121,CS1591,IL2121,1701,1702,CS1587,CA1416
|
||||||
|
"adas-core/adas-core.csproj"
|
||||||
|
- dotnet test --configuration Debug /p:Platform=x64 /nowarn:1701,1702,IL2121,CS1591,IL2121,1701,1702,CS1587,CA1416
|
||||||
|
"./adas-core.Test/adas-core.Test.csproj"
|
||||||
|
environment:
|
||||||
|
ADAS_NUGET_URL:
|
||||||
|
from_secret: ADAS_NUGET_URL
|
||||||
|
upload:
|
||||||
|
image: docker:dind
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- commit
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
commands:
|
||||||
|
- docker login -u $${CI_REGISTRY_USER} -p $${CI_REGISTRY_PASSWORD} $${CI_REGISTRY}
|
||||||
|
- docker build -t $${CI_REGISTRY}/adas/adas-core/adas-core:latest .
|
||||||
|
- docker push $${CI_REGISTRY}/adas/adas-core/adas-core:latest
|
||||||
|
environment:
|
||||||
|
CI_REGISTRY_USER:
|
||||||
|
from_secret: CI_REGISTRY_USER
|
||||||
|
CI_REGISTRY_PASSWORD:
|
||||||
|
from_secret: CI_REGISTRY_PASSWORD
|
||||||
|
CI_REGISTRY:
|
||||||
|
from_secret: CI_REGISTRY
|
||||||
|
ADAS_HYDE_SSH_KEY:
|
||||||
|
from_secret: ADAS_HYDE_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
|
restart-docker-service:
|
||||||
|
image: alpine
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
commands:
|
||||||
|
- command -v ssh-agent >/dev/null || ( apk add --update openssh )
|
||||||
|
- eval $(ssh-agent -s)
|
||||||
|
- echo "$${ADAS_HYDE_SSH_KEY}" | tr -d '\r' | ssh-add -
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- chmod 700 ~/.ssh
|
||||||
|
- echo "$${SSH_SERVER_HOSTKEYS}" >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
- ssh -o "StrictHostKeyChecking no" gitlabci@10.0.20.67 -p 22 "cd /opt/smartuci;docker-compose
|
||||||
|
stop adas-core;docker-compose rm -f adas-core;docker-compose pull adas-core;docker-compose
|
||||||
|
up -d adas-core" || ssh -o "StrictHostKeyChecking no" gitlabci@red1.epigram.es
|
||||||
|
-p 1522 "cd /opt/adascore;docker-compose stop adas-core;docker-compose rm
|
||||||
|
-f adas-core;docker-compose pull adas-core;docker-compose up -d adas-core"
|
||||||
|
environment:
|
||||||
|
CI_REGISTRY_USER:
|
||||||
|
from_secret: CI_REGISTRY_USER
|
||||||
|
CI_REGISTRY_PASSWORD:
|
||||||
|
from_secret: CI_REGISTRY_PASSWORD
|
||||||
|
CI_REGISTRY:
|
||||||
|
from_secret: CI_REGISTRY
|
||||||
|
ADAS_HYDE_SSH_KEY:
|
||||||
|
from_secret: ADAS_HYDE_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
# --------------------------------------------------------------------------------------
|
||||||
|
# 1. ETAPA DE CONSTRUCCIÓN (BUILD STAGE)
|
||||||
|
# Utiliza la imagen SDK para compilar la aplicación.
|
||||||
|
# --------------------------------------------------------------------------------------
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
COPY NuGet.Config .
|
||||||
|
# Copia los archivos de proyecto (.csproj) de cada subdirectorio y restáuralos.
|
||||||
|
# Esto aprovecha el caché de Docker si solo cambian los paquetes, no el código.
|
||||||
|
COPY ["adas-core/adas-core.csproj", "adas-core/"]
|
||||||
|
COPY ["adas-core.Application/adas-core.Application.csproj", "adas-core.Application/"]
|
||||||
|
COPY ["adas-core.Authentication/adas-core.Authentication.csproj", "adas-core.Authentication/"]
|
||||||
|
COPY ["adas-core.Domain/adas-core.Domain.csproj", "adas-core.Domain/"]
|
||||||
|
COPY ["adas-core.Infrastructure/adas-core.Infrastructure.csproj", "adas-core.Infrastructure/"]
|
||||||
|
COPY ["adas-core.LdapLogin/adas-core.LdapLogin.csproj", "adas-core.LdapLogin/"]
|
||||||
|
COPY ["adas-core.LocalLogin/adas-core.LocalLogin.csproj", "adas-core.LocalLogin/"]
|
||||||
|
COPY ["adas-core.module.LightBeacons/adas-core.module.LightBeacons.csproj", "adas-core.module.LightBeacons/"]
|
||||||
|
COPY ["adas-core.module.ProxyDevices/adas-core.module.ProxyDevices.csproj", "adas-core.module.ProxyDevices/"]
|
||||||
|
COPY ["adas-core.module.Relays/adas-core.module.Relays.csproj", "adas-core.module.Relays/"]
|
||||||
|
COPY ["adas-core.Test/adas-core.Test.csproj", "adas-core.Test/"]
|
||||||
|
# ... (Añade COPY para el resto de proyectos .csproj: LdapLogin, LocalLogin, modules, Test si son dependencias)
|
||||||
|
|
||||||
|
# Copia el archivo de solución (.sln) si existe, si no, usa el siguiente comando con los .csproj
|
||||||
|
# En este caso, asumiremos que se restaura y compila por proyecto principal.
|
||||||
|
# Si tienes un archivo de solución, es mejor copiarlo aquí.
|
||||||
|
|
||||||
|
# Restaura las dependencias (NuGet)
|
||||||
|
RUN dotnet restore "adas-core/adas-core.csproj"
|
||||||
|
|
||||||
|
# Copia el resto de los archivos fuente (todo el código)
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Cambia al directorio del proyecto principal
|
||||||
|
WORKDIR /src/adas-core
|
||||||
|
|
||||||
|
# Publica la aplicación final en modo Release
|
||||||
|
# El argumento -o /app/publish indica dónde se guardará el resultado de la publicación.
|
||||||
|
RUN dotnet publish "adas-core.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------
|
||||||
|
# 2. ETAPA FINAL (RUNTIME STAGE)
|
||||||
|
# Utiliza la imagen de ejecución, que es más pequeña y no contiene herramientas de compilación.
|
||||||
|
# --------------------------------------------------------------------------------------
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copia los archivos publicados desde la etapa 'build'
|
||||||
|
COPY --from=build /app/publish .
|
||||||
|
|
||||||
|
# Define el punto de entrada de la aplicación
|
||||||
|
# Este es el nombre del ensamblado DLL principal
|
||||||
|
ENTRYPOINT ["dotnet", "adas-core.dll"]
|
||||||
|
# El puerto de escucha por defecto de ASP.NET Core en Docker es el 8080 (o 80 en versiones anteriores)
|
||||||
|
ENV ASPNETCORE_URLS=http://+:80
|
||||||
|
EXPOSE 80
|
||||||
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,343 @@
|
|||||||
|
steps:
|
||||||
|
collect_inputs:
|
||||||
|
image: alpine:3.20
|
||||||
|
# Se ejecuta en todas las ramas: features, env/adas/dev, env/adas/pre
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache jq coreutils git findutils
|
||||||
|
- mkdir -p ci-evidence/test-results
|
||||||
|
- SHORT_SHA="$(printf "%s" "${DRONE_COMMIT_SHA}" | cut -c1-12)"
|
||||||
|
- BUILD_TIME="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||||
|
- ENV_NAME="$(printf "%s" "${DRONE_BRANCH}" | sed 's|env/adas/||')"
|
||||||
|
- RELEASE_ID="${RELEASE_ID:-REL-${ENV_NAME}-${DRONE_BUILD_NUMBER}-${SHORT_SHA}}"
|
||||||
|
- echo "$BUILD_TIME" > ci-evidence/build-time.txt
|
||||||
|
- echo "${DRONE_COMMIT_SHA}" > ci-evidence/commit-sha.txt
|
||||||
|
- echo "${SHORT_SHA}" > ci-evidence/commit-short.txt
|
||||||
|
- echo "${DRONE_BRANCH}" > ci-evidence/branch.txt
|
||||||
|
- echo "${ENV_NAME}" > ci-evidence/env-name.txt
|
||||||
|
- echo "${DRONE_BUILD_NUMBER}" > ci-evidence/pipeline-id.txt
|
||||||
|
- echo "${RELEASE_ID}" > ci-evidence/release-id.txt
|
||||||
|
- echo "Teralevel CI" > ci-evidence/ci-tool.txt
|
||||||
|
- git rev-parse --short HEAD > ci-evidence/git-short-head.txt
|
||||||
|
- git rev-parse HEAD > ci-evidence/git-full-head.txt
|
||||||
|
- git status --short > ci-evidence/git-status.txt || true
|
||||||
|
- |
|
||||||
|
find . \
|
||||||
|
-maxdepth 4 \
|
||||||
|
-type f \
|
||||||
|
\( -name 'Dockerfile' -o -name '.teralevel-ci.yml' -o -name '*.sln' -o -name '*.csproj' -o -name 'nuget.config' \) \
|
||||||
|
! -path '*/bin/*' \
|
||||||
|
! -path '*/obj/*' \
|
||||||
|
-exec sha256sum {} \; > ci-evidence/input-checksums.txt || true
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg release_id "$RELEASE_ID" \
|
||||||
|
--arg ur_prd_version "${UR_PRD_VERSION:-PENDIENTE}" \
|
||||||
|
--arg srs_version "${SRS_VERSION:-PENDIENTE}" \
|
||||||
|
--arg rmf_version "${RMF_VERSION:-PENDIENTE}" \
|
||||||
|
--arg trace_version "${TRACE_MATRIX_VERSION:-PENDIENTE}" \
|
||||||
|
--arg sbom_ref "ci-evidence/sbom-cyclonedx.json" \
|
||||||
|
'{
|
||||||
|
release_id: $release_id,
|
||||||
|
ur_prd_version: $ur_prd_version,
|
||||||
|
srs_version: $srs_version,
|
||||||
|
rmf_version: $rmf_version,
|
||||||
|
traceability_matrix_version: $trace_version,
|
||||||
|
sbom_reference: $sbom_ref
|
||||||
|
}' > ci-evidence/release-baseline-ref.json
|
||||||
|
|
||||||
|
test_backend:
|
||||||
|
image: mcr.microsoft.com/dotnet/sdk:8.0
|
||||||
|
# Se ejecuta en todas las ramas: features, env/adas/dev, env/adas/pre
|
||||||
|
environment:
|
||||||
|
ADAS_NUGET_URL:
|
||||||
|
from_secret: ADAS_NUGET_URL
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- mkdir -p ci-evidence/test-results/dotnet
|
||||||
|
- dotnet --info > ci-evidence/dotnet-info.txt
|
||||||
|
- (dotnet nuget add source "${ADAS_NUGET_URL}" -n "ADAS Nugget Server") 2>/dev/null || true
|
||||||
|
- dotnet restore "adas-core/adas-core.csproj"
|
||||||
|
- dotnet restore "./adas-core.Test/adas-core.Test.csproj"
|
||||||
|
- set +e
|
||||||
|
- dotnet build --configuration Debug /p:Platform=x64 /nowarn:1701,1702,IL2121,CS1591,CS1587,CA1416 "adas-core/adas-core.csproj"
|
||||||
|
- BUILD_EXIT=$?
|
||||||
|
- dotnet test --configuration Debug /p:Platform=x64 /nowarn:1701,1702,IL2121,CS1591,CS1587,CA1416 "./adas-core.Test/adas-core.Test.csproj" --results-directory ci-evidence/test-results/dotnet --logger "trx;LogFileName=adas-core-tests.trx"
|
||||||
|
- TEST_EXIT=$?
|
||||||
|
- set -e
|
||||||
|
- |
|
||||||
|
cat > ci-evidence/test-results/dotnet-summary.json <<EOF
|
||||||
|
{
|
||||||
|
"status": "executed",
|
||||||
|
"build_exit_code": ${BUILD_EXIT},
|
||||||
|
"test_exit_code": ${TEST_EXIT},
|
||||||
|
"build_target": "adas-core/adas-core.csproj",
|
||||||
|
"test_target": "./adas-core.Test/adas-core.Test.csproj"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
- test "$BUILD_EXIT" -eq 0
|
||||||
|
- test "$TEST_EXIT" -eq 0
|
||||||
|
|
||||||
|
build_and_push:
|
||||||
|
# Requiere que el runner CI tenga /var/run/docker.sock montado (daemon Docker en CI)
|
||||||
|
image: docker:27-cli
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
CI_REGISTRY_USER:
|
||||||
|
from_secret: CI_REGISTRY_USER
|
||||||
|
CI_REGISTRY_PASSWORD:
|
||||||
|
from_secret: CI_REGISTRY_PASSWORD
|
||||||
|
CI_REGISTRY:
|
||||||
|
from_secret: CI_REGISTRY
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- mkdir -p ci-evidence
|
||||||
|
- docker login "${CI_REGISTRY}" -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}"
|
||||||
|
- SHORT_SHA="$(cat ci-evidence/commit-short.txt)"
|
||||||
|
- PIPELINE_ID="$(cat ci-evidence/pipeline-id.txt)"
|
||||||
|
- ENV_NAME="$(cat ci-evidence/env-name.txt)"
|
||||||
|
- IMAGE_REPO="${CI_REGISTRY}/adas/adas-core/adas-core"
|
||||||
|
- IMAGE_TAG_IMMUTABLE="${ENV_NAME}-${PIPELINE_ID}-${SHORT_SHA}"
|
||||||
|
- IMAGE_REF_IMMUTABLE="${IMAGE_REPO}:${IMAGE_TAG_IMMUTABLE}"
|
||||||
|
- IMAGE_REF_MUTABLE="${IMAGE_REPO}:${ENV_NAME}-latest"
|
||||||
|
- echo "$IMAGE_REF_IMMUTABLE" > ci-evidence/image-ref-immutable.txt
|
||||||
|
- echo "$IMAGE_REF_MUTABLE" > ci-evidence/image-ref-mutable.txt
|
||||||
|
- docker version > ci-evidence/docker-version.txt
|
||||||
|
- |
|
||||||
|
docker build \
|
||||||
|
--label org.opencontainers.image.revision="${DRONE_COMMIT_SHA}" \
|
||||||
|
--label org.opencontainers.image.version="${IMAGE_TAG_IMMUTABLE}" \
|
||||||
|
--label org.opencontainers.image.created="$(cat ci-evidence/build-time.txt)" \
|
||||||
|
-t "${IMAGE_REF_IMMUTABLE}" \
|
||||||
|
-t "${IMAGE_REF_MUTABLE}" \
|
||||||
|
-f Dockerfile \
|
||||||
|
. > ci-evidence/docker-build.log 2>&1 || { cat ci-evidence/docker-build.log; exit 1; }
|
||||||
|
- docker push "${IMAGE_REF_IMMUTABLE}" 2>&1 | tee -a ci-evidence/docker-build.log
|
||||||
|
- docker push "${IMAGE_REF_MUTABLE}" 2>&1 | tee -a ci-evidence/docker-build.log
|
||||||
|
- |
|
||||||
|
docker image inspect "${IMAGE_REF_IMMUTABLE}" \
|
||||||
|
--format '{{index .RepoDigests 0}}' > ci-evidence/image-digest.txt 2>/dev/null \
|
||||||
|
|| docker image inspect "${IMAGE_REF_IMMUTABLE}" \
|
||||||
|
--format '{{.Id}}' > ci-evidence/image-digest.txt
|
||||||
|
- cat ci-evidence/docker-build.log
|
||||||
|
|
||||||
|
generate_sbom:
|
||||||
|
image: anchore/syft:v1.18.1
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
CI_REGISTRY_USER:
|
||||||
|
from_secret: CI_REGISTRY_USER
|
||||||
|
CI_REGISTRY_PASSWORD:
|
||||||
|
from_secret: CI_REGISTRY_PASSWORD
|
||||||
|
CI_REGISTRY:
|
||||||
|
from_secret: CI_REGISTRY
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- mkdir -p /root/.docker ci-evidence
|
||||||
|
- |
|
||||||
|
cat > /root/.docker/config.json <<EOF
|
||||||
|
{
|
||||||
|
"auths": {
|
||||||
|
"${CI_REGISTRY}": {
|
||||||
|
"username": "${CI_REGISTRY_USER}",
|
||||||
|
"password": "${CI_REGISTRY_PASSWORD}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
- IMAGE_REF_IMMUTABLE="$(cat ci-evidence/image-ref-immutable.txt)"
|
||||||
|
- syft version > ci-evidence/syft-version.txt
|
||||||
|
- syft "${IMAGE_REF_IMMUTABLE}" -o cyclonedx-json=ci-evidence/sbom-cyclonedx.json
|
||||||
|
- syft "${IMAGE_REF_IMMUTABLE}" -o spdx-json=ci-evidence/sbom-spdx.json
|
||||||
|
|
||||||
|
assemble_ci_evidence_predeploy:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache jq coreutils
|
||||||
|
- BUILD_TIME="$(cat ci-evidence/build-time.txt)"
|
||||||
|
- COMMIT_SHA="$(cat ci-evidence/commit-sha.txt)"
|
||||||
|
- SHORT_SHA="$(cat ci-evidence/commit-short.txt)"
|
||||||
|
- BRANCH="$(cat ci-evidence/branch.txt)"
|
||||||
|
- ENV_NAME="$(cat ci-evidence/env-name.txt)"
|
||||||
|
- PIPELINE_ID="$(cat ci-evidence/pipeline-id.txt)"
|
||||||
|
- RELEASE_ID="$(cat ci-evidence/release-id.txt)"
|
||||||
|
- IMAGE_REF_IMMUTABLE="$(cat ci-evidence/image-ref-immutable.txt)"
|
||||||
|
- IMAGE_REF_MUTABLE="$(cat ci-evidence/image-ref-mutable.txt)"
|
||||||
|
- IMAGE_DIGEST="$(cat ci-evidence/image-digest.txt)"
|
||||||
|
- DOTNET_SUMMARY="$(cat ci-evidence/test-results/dotnet-summary.json)"
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg project "ADAS" \
|
||||||
|
--arg component "adas-core" \
|
||||||
|
--arg environment "$ENV_NAME" \
|
||||||
|
--arg release_id "$RELEASE_ID" \
|
||||||
|
--arg build_time_utc "$BUILD_TIME" \
|
||||||
|
--arg commit_sha "$COMMIT_SHA" \
|
||||||
|
--arg commit_short "$SHORT_SHA" \
|
||||||
|
--arg branch "$BRANCH" \
|
||||||
|
--arg pipeline_id "$PIPELINE_ID" \
|
||||||
|
--arg ci_tool "Teralevel CI" \
|
||||||
|
--arg image_ref_immutable "$IMAGE_REF_IMMUTABLE" \
|
||||||
|
--arg image_ref_mutable "$IMAGE_REF_MUTABLE" \
|
||||||
|
--arg image_digest "$IMAGE_DIGEST" \
|
||||||
|
--argjson backend_tests "$DOTNET_SUMMARY" \
|
||||||
|
'{
|
||||||
|
project: $project,
|
||||||
|
component: $component,
|
||||||
|
environment: $environment,
|
||||||
|
release_id: $release_id,
|
||||||
|
build_time_utc: $build_time_utc,
|
||||||
|
commit_sha: $commit_sha,
|
||||||
|
commit_short: $commit_short,
|
||||||
|
branch: $branch,
|
||||||
|
pipeline_id: $pipeline_id,
|
||||||
|
ci_tool: $ci_tool,
|
||||||
|
image_ref_immutable: $image_ref_immutable,
|
||||||
|
image_ref_mutable: $image_ref_mutable,
|
||||||
|
image_digest: $image_digest,
|
||||||
|
tests: {
|
||||||
|
backend: $backend_tests
|
||||||
|
}
|
||||||
|
}' > ci-evidence/build-metadata.json
|
||||||
|
- sha256sum ci-evidence/* > ci-evidence/checksums-predeploy.txt || true
|
||||||
|
|
||||||
|
deploy_adas_dev:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
environment:
|
||||||
|
ADAS_SSH_KEY:
|
||||||
|
from_secret: ADAS_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
|
DEPLOY_HOST_DEV:
|
||||||
|
from_secret: DEPLOY_HOST_DEV
|
||||||
|
DEPLOY_USER:
|
||||||
|
from_secret: DEPLOY_USER
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache openssh-client jq
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- echo "$ADAS_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
|
- chmod 600 ~/.ssh/id_ed25519
|
||||||
|
- echo "$SSH_SERVER_HOSTKEYS" >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
- IMAGE_REF_MUTABLE="$(cat ci-evidence/image-ref-mutable.txt)"
|
||||||
|
- |
|
||||||
|
ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_DEV}" \
|
||||||
|
"cd /opt/adas-core-dev && \
|
||||||
|
docker compose stop adas-core && \
|
||||||
|
docker compose rm -f adas-core && \
|
||||||
|
docker compose pull adas-core && \
|
||||||
|
docker compose up -d adas-core"
|
||||||
|
- |
|
||||||
|
REMOTE_DIGEST="$(ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_DEV}" \
|
||||||
|
"docker image inspect ${IMAGE_REF_MUTABLE} --format='{{index .RepoDigests 0}}'")"
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg environment "dev" \
|
||||||
|
--arg host "${DEPLOY_HOST_DEV}" \
|
||||||
|
--arg deployed_ref "$IMAGE_REF_MUTABLE" \
|
||||||
|
--arg deployed_digest "$REMOTE_DIGEST" \
|
||||||
|
'{
|
||||||
|
environment: $environment,
|
||||||
|
host: $host,
|
||||||
|
deployed_ref: $deployed_ref,
|
||||||
|
deployed_digest: $deployed_digest
|
||||||
|
}' > ci-evidence/deploy-info.json
|
||||||
|
|
||||||
|
deploy_adas_pre:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
ADAS_SSH_KEY:
|
||||||
|
from_secret: ADAS_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
|
DEPLOY_HOST_PRE:
|
||||||
|
from_secret: DEPLOY_HOST_PRE
|
||||||
|
DEPLOY_USER:
|
||||||
|
from_secret: DEPLOY_USER
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache openssh-client jq
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- echo "$ADAS_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
|
- chmod 600 ~/.ssh/id_ed25519
|
||||||
|
- echo "$SSH_SERVER_HOSTKEYS" >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
- IMAGE_REF_MUTABLE="$(cat ci-evidence/image-ref-mutable.txt)"
|
||||||
|
- |
|
||||||
|
ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_PRE}" \
|
||||||
|
"cd /opt/adas-core-pre && \
|
||||||
|
docker compose stop adas-core && \
|
||||||
|
docker compose rm -f adas-core && \
|
||||||
|
docker compose pull adas-core && \
|
||||||
|
docker compose up -d adas-core"
|
||||||
|
- |
|
||||||
|
REMOTE_DIGEST="$(ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_PRE}" \
|
||||||
|
"docker image inspect ${IMAGE_REF_MUTABLE} --format='{{index .RepoDigests 0}}'")"
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg environment "pre" \
|
||||||
|
--arg host "${DEPLOY_HOST_PRE}" \
|
||||||
|
--arg deployed_ref "$IMAGE_REF_MUTABLE" \
|
||||||
|
--arg deployed_digest "$REMOTE_DIGEST" \
|
||||||
|
'{
|
||||||
|
environment: $environment,
|
||||||
|
host: $host,
|
||||||
|
deployed_ref: $deployed_ref,
|
||||||
|
deployed_digest: $deployed_digest
|
||||||
|
}' > ci-evidence/deploy-info.json
|
||||||
|
|
||||||
|
finalize_and_publish_ci_evidence:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
ADAS_SSH_KEY:
|
||||||
|
from_secret: ADAS_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
|
DEPLOY_HOST_DEV:
|
||||||
|
from_secret: DEPLOY_HOST_DEV
|
||||||
|
DEPLOY_HOST_PRE:
|
||||||
|
from_secret: DEPLOY_HOST_PRE
|
||||||
|
DEPLOY_USER:
|
||||||
|
from_secret: DEPLOY_USER
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache openssh-client jq coreutils tar gzip
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- echo "$ADAS_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
|
- chmod 600 ~/.ssh/id_ed25519
|
||||||
|
- echo "$SSH_SERVER_HOSTKEYS" >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
- RELEASE_ID="$(cat ci-evidence/release-id.txt)"
|
||||||
|
- ENV_NAME="$(cat ci-evidence/env-name.txt)"
|
||||||
|
- sha256sum ci-evidence/* > ci-evidence/checksums-final.txt || true
|
||||||
|
- tar -czf "ci-evidence-${RELEASE_ID}.tar.gz" ci-evidence
|
||||||
|
- |
|
||||||
|
if [ "${ENV_NAME}" = "dev" ]; then
|
||||||
|
EVIDENCE_HOST="${DEPLOY_HOST_DEV}"
|
||||||
|
else
|
||||||
|
EVIDENCE_HOST="${DEPLOY_HOST_PRE}"
|
||||||
|
fi
|
||||||
|
- ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${EVIDENCE_HOST}" "mkdir -p /opt/adas-ci-evidence/core/${ENV_NAME}"
|
||||||
|
- scp -o "StrictHostKeyChecking yes" "ci-evidence-${RELEASE_ID}.tar.gz" "${DEPLOY_USER}@${EVIDENCE_HOST}:/opt/adas-ci-evidence/core/${ENV_NAME}/"
|
||||||
Binary file not shown.
@@ -0,0 +1,413 @@
|
|||||||
|
steps:
|
||||||
|
collect_inputs:
|
||||||
|
image: alpine:3.20
|
||||||
|
# Se ejecuta en todas las ramas: features, env/adas/dev, env/adas/pre
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache jq coreutils git findutils
|
||||||
|
- mkdir -p ci-evidence/test-results
|
||||||
|
- SHORT_SHA="$(printf "%s" "${DRONE_COMMIT_SHA}" | cut -c1-12)"
|
||||||
|
- BUILD_TIME="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||||
|
- ENV_NAME="$(printf "%s" "${DRONE_BRANCH}" | sed 's|env/adas/||')"
|
||||||
|
- RELEASE_ID="${RELEASE_ID:-REL-${ENV_NAME}-${DRONE_BUILD_NUMBER}-${SHORT_SHA}}"
|
||||||
|
- echo "$BUILD_TIME" > ci-evidence/build-time.txt
|
||||||
|
- echo "${DRONE_COMMIT_SHA}" > ci-evidence/commit-sha.txt
|
||||||
|
- echo "${SHORT_SHA}" > ci-evidence/commit-short.txt
|
||||||
|
- echo "${DRONE_BRANCH}" > ci-evidence/branch.txt
|
||||||
|
- echo "${ENV_NAME}" > ci-evidence/env-name.txt
|
||||||
|
- echo "${DRONE_BUILD_NUMBER}" > ci-evidence/pipeline-id.txt
|
||||||
|
- echo "${RELEASE_ID}" > ci-evidence/release-id.txt
|
||||||
|
- echo "Teralevel CI" > ci-evidence/ci-tool.txt
|
||||||
|
- git rev-parse --short HEAD > ci-evidence/git-short-head.txt
|
||||||
|
- git rev-parse HEAD > ci-evidence/git-full-head.txt
|
||||||
|
- git status --short > ci-evidence/git-status.txt || true
|
||||||
|
- |
|
||||||
|
find . \
|
||||||
|
-maxdepth 4 \
|
||||||
|
-type f \
|
||||||
|
\( -name 'Dockerfile' -o -name '.teralevel-ci.yml' -o -name 'package-lock.json' -o -name 'angular.json' -o -name '*.sln' -o -name '*.csproj' -o -name 'nuget.config' \) \
|
||||||
|
! -path '*/node_modules/*' \
|
||||||
|
! -path '*/bin/*' \
|
||||||
|
! -path '*/obj/*' \
|
||||||
|
-exec sha256sum {} \; > ci-evidence/input-checksums.txt || true
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg release_id "$RELEASE_ID" \
|
||||||
|
--arg ur_prd_version "${UR_PRD_VERSION:-PENDIENTE}" \
|
||||||
|
--arg srs_version "${SRS_VERSION:-PENDIENTE}" \
|
||||||
|
--arg rmf_version "${RMF_VERSION:-PENDIENTE}" \
|
||||||
|
--arg trace_version "${TRACE_MATRIX_VERSION:-PENDIENTE}" \
|
||||||
|
--arg sbom_ref "ci-evidence/sbom-cyclonedx.json" \
|
||||||
|
'{
|
||||||
|
release_id: $release_id,
|
||||||
|
ur_prd_version: $ur_prd_version,
|
||||||
|
srs_version: $srs_version,
|
||||||
|
rmf_version: $rmf_version,
|
||||||
|
traceability_matrix_version: $trace_version,
|
||||||
|
sbom_reference: $sbom_ref
|
||||||
|
}' > ci-evidence/release-baseline-ref.json
|
||||||
|
|
||||||
|
test_backend:
|
||||||
|
image: mcr.microsoft.com/dotnet/sdk:8.0
|
||||||
|
# Se ejecuta en todas las ramas: features, env/adas/dev, env/adas/pre
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- mkdir -p ci-evidence/test-results/dotnet
|
||||||
|
- dotnet --info > ci-evidence/dotnet-info.txt
|
||||||
|
- SOLUTION="$(find . -maxdepth 4 -type f -name '*.sln' ! -path '*/obj/*' ! -path '*/bin/*' | head -n 1 || true)"
|
||||||
|
- |
|
||||||
|
if [ -z "$SOLUTION" ]; then
|
||||||
|
TEST_PROJECTS="$(find . -maxdepth 5 -type f \( -name '*Test*.csproj' -o -name '*Tests*.csproj' \) ! -path '*/obj/*' ! -path '*/bin/*' | tr '\n' ' ' || true)"
|
||||||
|
else
|
||||||
|
TEST_PROJECTS=""
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
if [ -n "$SOLUTION" ]; then
|
||||||
|
dotnet restore "$SOLUTION"
|
||||||
|
set +e
|
||||||
|
dotnet test "$SOLUTION" \
|
||||||
|
--configuration Release \
|
||||||
|
--results-directory ci-evidence/test-results/dotnet \
|
||||||
|
--logger "trx;LogFileName=dotnet-tests.trx"
|
||||||
|
TEST_EXIT=$?
|
||||||
|
set -e
|
||||||
|
elif [ -n "$TEST_PROJECTS" ]; then
|
||||||
|
TEST_EXIT=0
|
||||||
|
for proj in $TEST_PROJECTS; do
|
||||||
|
dotnet restore "$proj"
|
||||||
|
set +e
|
||||||
|
dotnet test "$proj" \
|
||||||
|
--configuration Release \
|
||||||
|
--results-directory ci-evidence/test-results/dotnet \
|
||||||
|
--logger "trx;LogFileName=$(basename "$proj" .csproj)-tests.trx"
|
||||||
|
CUR_EXIT=$?
|
||||||
|
set -e
|
||||||
|
if [ "$CUR_EXIT" -ne 0 ]; then TEST_EXIT=$CUR_EXIT; fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
TEST_EXIT=0
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
if [ -n "$SOLUTION" ] || [ -n "${TEST_PROJECTS:-}" ]; then
|
||||||
|
STATUS="executed"
|
||||||
|
else
|
||||||
|
STATUS="skipped"
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
cat > ci-evidence/test-results/dotnet-summary.json <<EOF
|
||||||
|
{
|
||||||
|
"status": "${STATUS}",
|
||||||
|
"exit_code": ${TEST_EXIT},
|
||||||
|
"target": "$(if [ -n "$SOLUTION" ]; then printf "%s" "$SOLUTION"; else printf "%s" "${TEST_PROJECTS:-none}"; fi)"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
- test "$TEST_EXIT" -eq 0
|
||||||
|
|
||||||
|
test_frontend:
|
||||||
|
# NOTA: Chromium se instala en cada ejecucion (~1-3 min adicionales).
|
||||||
|
# Cuando este disponible, sustituir por una imagen base propia:
|
||||||
|
# git.teralevel.io/adas/node-chrome:20 (node:20-bookworm-slim + chromium pre-instalado)
|
||||||
|
# Eso eliminara el apt-get de este paso y reducira el tiempo total del pipeline.
|
||||||
|
image: node:20-bookworm-slim
|
||||||
|
# Se ejecuta en todas las ramas: features, env/adas/dev, env/adas/pre
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apt-get update
|
||||||
|
- apt-get install -y --no-install-recommends chromium jq ca-certificates
|
||||||
|
- rm -rf /var/lib/apt/lists/*
|
||||||
|
- mkdir -p ci-evidence/test-results/frontend
|
||||||
|
- node --version > ci-evidence/node-version.txt
|
||||||
|
- npm --version > ci-evidence/npm-version.txt
|
||||||
|
- FRONTEND_DIR="$(find . -maxdepth 4 -type f -name 'angular.json' ! -path '*/node_modules/*' -exec dirname {} \; | head -n 1 || true)"
|
||||||
|
- |
|
||||||
|
if [ -z "$FRONTEND_DIR" ]; then
|
||||||
|
FRONTEND_DIR="$(find . -maxdepth 4 -type f -name 'package.json' ! -path '*/node_modules/*' -exec dirname {} \; | head -n 1 || true)"
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
if [ -n "$FRONTEND_DIR" ]; then
|
||||||
|
cd "$FRONTEND_DIR"
|
||||||
|
export CI=true
|
||||||
|
export CHROME_BIN=/usr/bin/chromium
|
||||||
|
npm ci
|
||||||
|
set +e
|
||||||
|
npm test -- --watch=false --browsers=ChromeHeadless --progress=false
|
||||||
|
TEST_EXIT=$?
|
||||||
|
set -e
|
||||||
|
cd -
|
||||||
|
STATUS="executed"
|
||||||
|
else
|
||||||
|
TEST_EXIT=0
|
||||||
|
STATUS="skipped"
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
cat > ci-evidence/test-results/frontend-summary.json <<EOF
|
||||||
|
{
|
||||||
|
"status": "${STATUS}",
|
||||||
|
"exit_code": ${TEST_EXIT},
|
||||||
|
"target": "${FRONTEND_DIR:-none}"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
- test "$TEST_EXIT" -eq 0
|
||||||
|
|
||||||
|
build_and_push:
|
||||||
|
# Requiere que el runner CI tenga /var/run/docker.sock montado (daemon Docker en CI)
|
||||||
|
image: docker:27-cli
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
REGISTRY_USER:
|
||||||
|
from_secret: REGISTRY_USER
|
||||||
|
REGISTRY_PASS:
|
||||||
|
from_secret: REGISTRY_PASS
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- mkdir -p ci-evidence
|
||||||
|
- docker login "git.teralevel.io" -u "${REGISTRY_USER}" -p "${REGISTRY_PASS}"
|
||||||
|
- SHORT_SHA="$(cat ci-evidence/commit-short.txt)"
|
||||||
|
- PIPELINE_ID="$(cat ci-evidence/pipeline-id.txt)"
|
||||||
|
- ENV_NAME="$(cat ci-evidence/env-name.txt)"
|
||||||
|
- IMAGE_REPO="git.teralevel.io/adas/adas-webdisplay"
|
||||||
|
- IMAGE_TAG_IMMUTABLE="${ENV_NAME}-${PIPELINE_ID}-${SHORT_SHA}"
|
||||||
|
- IMAGE_REF_IMMUTABLE="${IMAGE_REPO}:${IMAGE_TAG_IMMUTABLE}"
|
||||||
|
- IMAGE_REF_MUTABLE="${IMAGE_REPO}:${ENV_NAME}-latest"
|
||||||
|
- echo "$IMAGE_REF_IMMUTABLE" > ci-evidence/image-ref-immutable.txt
|
||||||
|
- echo "$IMAGE_REF_MUTABLE" > ci-evidence/image-ref-mutable.txt
|
||||||
|
- docker version > ci-evidence/docker-version.txt
|
||||||
|
- |
|
||||||
|
docker build \
|
||||||
|
--label org.opencontainers.image.revision="${DRONE_COMMIT_SHA}" \
|
||||||
|
--label org.opencontainers.image.version="${IMAGE_TAG_IMMUTABLE}" \
|
||||||
|
--label org.opencontainers.image.created="$(cat ci-evidence/build-time.txt)" \
|
||||||
|
-t "${IMAGE_REF_IMMUTABLE}" \
|
||||||
|
-t "${IMAGE_REF_MUTABLE}" \
|
||||||
|
-f Dockerfile \
|
||||||
|
. > ci-evidence/docker-build.log 2>&1 || { cat ci-evidence/docker-build.log; exit 1; }
|
||||||
|
- docker push "${IMAGE_REF_IMMUTABLE}" 2>&1 | tee -a ci-evidence/docker-build.log
|
||||||
|
- docker push "${IMAGE_REF_MUTABLE}" 2>&1 | tee -a ci-evidence/docker-build.log
|
||||||
|
- |
|
||||||
|
docker image inspect "${IMAGE_REF_IMMUTABLE}" \
|
||||||
|
--format '{{index .RepoDigests 0}}' > ci-evidence/image-digest.txt 2>/dev/null \
|
||||||
|
|| docker image inspect "${IMAGE_REF_IMMUTABLE}" \
|
||||||
|
--format '{{.Id}}' > ci-evidence/image-digest.txt
|
||||||
|
- cat ci-evidence/docker-build.log
|
||||||
|
|
||||||
|
generate_sbom:
|
||||||
|
image: anchore/syft:v1.18.1
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
REGISTRY_USER:
|
||||||
|
from_secret: REGISTRY_USER
|
||||||
|
REGISTRY_PASS:
|
||||||
|
from_secret: REGISTRY_PASS
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- mkdir -p /root/.docker ci-evidence
|
||||||
|
- |
|
||||||
|
cat > /root/.docker/config.json <<EOF
|
||||||
|
{
|
||||||
|
"auths": {
|
||||||
|
"git.teralevel.io": {
|
||||||
|
"username": "$REGISTRY_USER",
|
||||||
|
"password": "$REGISTRY_PASS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
- IMAGE_REF_IMMUTABLE="$(cat ci-evidence/image-ref-immutable.txt)"
|
||||||
|
- syft version > ci-evidence/syft-version.txt
|
||||||
|
- syft "${IMAGE_REF_IMMUTABLE}" -o cyclonedx-json=ci-evidence/sbom-cyclonedx.json
|
||||||
|
- syft "${IMAGE_REF_IMMUTABLE}" -o spdx-json=ci-evidence/sbom-spdx.json
|
||||||
|
|
||||||
|
assemble_ci_evidence_predeploy:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache jq coreutils
|
||||||
|
- BUILD_TIME="$(cat ci-evidence/build-time.txt)"
|
||||||
|
- COMMIT_SHA="$(cat ci-evidence/commit-sha.txt)"
|
||||||
|
- SHORT_SHA="$(cat ci-evidence/commit-short.txt)"
|
||||||
|
- BRANCH="$(cat ci-evidence/branch.txt)"
|
||||||
|
- ENV_NAME="$(cat ci-evidence/env-name.txt)"
|
||||||
|
- PIPELINE_ID="$(cat ci-evidence/pipeline-id.txt)"
|
||||||
|
- RELEASE_ID="$(cat ci-evidence/release-id.txt)"
|
||||||
|
- IMAGE_REF_IMMUTABLE="$(cat ci-evidence/image-ref-immutable.txt)"
|
||||||
|
- IMAGE_REF_MUTABLE="$(cat ci-evidence/image-ref-mutable.txt)"
|
||||||
|
- IMAGE_DIGEST="$(cat ci-evidence/image-digest.txt)"
|
||||||
|
- DOTNET_SUMMARY="$(cat ci-evidence/test-results/dotnet-summary.json)"
|
||||||
|
- FRONTEND_SUMMARY="$(cat ci-evidence/test-results/frontend-summary.json)"
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg project "ADAS" \
|
||||||
|
--arg component "adas-webdisplay" \
|
||||||
|
--arg environment "$ENV_NAME" \
|
||||||
|
--arg release_id "$RELEASE_ID" \
|
||||||
|
--arg build_time_utc "$BUILD_TIME" \
|
||||||
|
--arg commit_sha "$COMMIT_SHA" \
|
||||||
|
--arg commit_short "$SHORT_SHA" \
|
||||||
|
--arg branch "$BRANCH" \
|
||||||
|
--arg pipeline_id "$PIPELINE_ID" \
|
||||||
|
--arg ci_tool "Teralevel CI" \
|
||||||
|
--arg image_ref_immutable "$IMAGE_REF_IMMUTABLE" \
|
||||||
|
--arg image_ref_mutable "$IMAGE_REF_MUTABLE" \
|
||||||
|
--arg image_digest "$IMAGE_DIGEST" \
|
||||||
|
--argjson dotnet_tests "$DOTNET_SUMMARY" \
|
||||||
|
--argjson frontend_tests "$FRONTEND_SUMMARY" \
|
||||||
|
'{
|
||||||
|
project: $project,
|
||||||
|
component: $component,
|
||||||
|
environment: $environment,
|
||||||
|
release_id: $release_id,
|
||||||
|
build_time_utc: $build_time_utc,
|
||||||
|
commit_sha: $commit_sha,
|
||||||
|
commit_short: $commit_short,
|
||||||
|
branch: $branch,
|
||||||
|
pipeline_id: $pipeline_id,
|
||||||
|
ci_tool: $ci_tool,
|
||||||
|
image_ref_immutable: $image_ref_immutable,
|
||||||
|
image_ref_mutable: $image_ref_mutable,
|
||||||
|
image_digest: $image_digest,
|
||||||
|
tests: {
|
||||||
|
backend: $dotnet_tests,
|
||||||
|
frontend: $frontend_tests
|
||||||
|
}
|
||||||
|
}' > ci-evidence/build-metadata.json
|
||||||
|
- sha256sum ci-evidence/* > ci-evidence/checksums-predeploy.txt || true
|
||||||
|
|
||||||
|
deploy_webdisplay_dev:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
environment:
|
||||||
|
ADAS_SSH_KEY:
|
||||||
|
from_secret: ADAS_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
|
DEPLOY_HOST_DEV:
|
||||||
|
from_secret: DEPLOY_HOST_DEV
|
||||||
|
DEPLOY_USER:
|
||||||
|
from_secret: DEPLOY_USER
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache openssh-client jq
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- echo "$ADAS_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
|
- chmod 600 ~/.ssh/id_ed25519
|
||||||
|
- echo "$SSH_SERVER_HOSTKEYS" >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
- IMAGE_REF_MUTABLE="$(cat ci-evidence/image-ref-mutable.txt)"
|
||||||
|
- |
|
||||||
|
ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_DEV}" \
|
||||||
|
"cd /opt/adas-icu-dev && \
|
||||||
|
docker compose stop webdisplay-dev && \
|
||||||
|
docker compose rm -f webdisplay-dev && \
|
||||||
|
docker compose pull webdisplay-dev && \
|
||||||
|
docker compose up -d webdisplay-dev"
|
||||||
|
- |
|
||||||
|
REMOTE_DIGEST="$(ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_DEV}" \
|
||||||
|
"docker image inspect ${IMAGE_REF_MUTABLE} --format='{{index .RepoDigests 0}}'")"
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg environment "dev" \
|
||||||
|
--arg host "${DEPLOY_HOST_DEV}" \
|
||||||
|
--arg deployed_ref "$IMAGE_REF_MUTABLE" \
|
||||||
|
--arg deployed_digest "$REMOTE_DIGEST" \
|
||||||
|
'{
|
||||||
|
environment: $environment,
|
||||||
|
host: $host,
|
||||||
|
deployed_ref: $deployed_ref,
|
||||||
|
deployed_digest: $deployed_digest
|
||||||
|
}' > ci-evidence/deploy-info.json
|
||||||
|
|
||||||
|
deploy_webdisplay_pre:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
ADAS_SSH_KEY:
|
||||||
|
from_secret: ADAS_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
|
DEPLOY_HOST_PRE:
|
||||||
|
from_secret: DEPLOY_HOST_PRE
|
||||||
|
DEPLOY_USER:
|
||||||
|
from_secret: DEPLOY_USER
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache openssh-client jq
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- echo "$ADAS_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
|
- chmod 600 ~/.ssh/id_ed25519
|
||||||
|
- echo "$SSH_SERVER_HOSTKEYS" >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
- IMAGE_REF_MUTABLE="$(cat ci-evidence/image-ref-mutable.txt)"
|
||||||
|
- |
|
||||||
|
ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_PRE}" \
|
||||||
|
"cd /opt/adas-icu-pre && \
|
||||||
|
docker compose stop webdisplay-pre && \
|
||||||
|
docker compose rm -f webdisplay-pre && \
|
||||||
|
docker compose pull webdisplay-pre && \
|
||||||
|
docker compose up -d webdisplay-pre"
|
||||||
|
- |
|
||||||
|
REMOTE_DIGEST="$(ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${DEPLOY_HOST_PRE}" \
|
||||||
|
"docker image inspect ${IMAGE_REF_MUTABLE} --format='{{index .RepoDigests 0}}'")"
|
||||||
|
- |
|
||||||
|
jq -n \
|
||||||
|
--arg environment "pre" \
|
||||||
|
--arg host "${DEPLOY_HOST_PRE}" \
|
||||||
|
--arg deployed_ref "$IMAGE_REF_MUTABLE" \
|
||||||
|
--arg deployed_digest "$REMOTE_DIGEST" \
|
||||||
|
'{
|
||||||
|
environment: $environment,
|
||||||
|
host: $host,
|
||||||
|
deployed_ref: $deployed_ref,
|
||||||
|
deployed_digest: $deployed_digest
|
||||||
|
}' > ci-evidence/deploy-info.json
|
||||||
|
|
||||||
|
finalize_and_publish_ci_evidence:
|
||||||
|
image: alpine:3.20
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- env/adas/dev
|
||||||
|
- env/adas/pre
|
||||||
|
environment:
|
||||||
|
ADAS_SSH_KEY:
|
||||||
|
from_secret: ADAS_SSH_KEY
|
||||||
|
SSH_SERVER_HOSTKEYS:
|
||||||
|
from_secret: SSH_SERVER_HOSTKEYS
|
||||||
|
DEPLOY_HOST_DEV:
|
||||||
|
from_secret: DEPLOY_HOST_DEV
|
||||||
|
DEPLOY_HOST_PRE:
|
||||||
|
from_secret: DEPLOY_HOST_PRE
|
||||||
|
DEPLOY_USER:
|
||||||
|
from_secret: DEPLOY_USER
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache openssh-client jq coreutils tar gzip
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- echo "$ADAS_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
|
- chmod 600 ~/.ssh/id_ed25519
|
||||||
|
- echo "$SSH_SERVER_HOSTKEYS" >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
- RELEASE_ID="$(cat ci-evidence/release-id.txt)"
|
||||||
|
- ENV_NAME="$(cat ci-evidence/env-name.txt)"
|
||||||
|
- sha256sum ci-evidence/* > ci-evidence/checksums-final.txt || true
|
||||||
|
- tar -czf "ci-evidence-${RELEASE_ID}.tar.gz" ci-evidence
|
||||||
|
- |
|
||||||
|
if [ "${ENV_NAME}" = "dev" ]; then
|
||||||
|
EVIDENCE_HOST="${DEPLOY_HOST_DEV}"
|
||||||
|
else
|
||||||
|
EVIDENCE_HOST="${DEPLOY_HOST_PRE}"
|
||||||
|
fi
|
||||||
|
- ssh -o "StrictHostKeyChecking yes" "${DEPLOY_USER}@${EVIDENCE_HOST}" "mkdir -p /opt/adas-ci-evidence/webdisplay/${ENV_NAME}"
|
||||||
|
- scp -o "StrictHostKeyChecking yes" "ci-evidence-${RELEASE_ID}.tar.gz" "${DEPLOY_USER}@${EVIDENCE_HOST}:/opt/adas-ci-evidence/webdisplay/${ENV_NAME}/"
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<add key="smacs" value="https://smacs-nuget.epigramdev.com/v3/index.json" allowInsecureConnections="True" />
|
||||||
|
<add key="nugget" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
using adas_core.Application.Services.Interfaces;
|
||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Customizations.BD;
|
||||||
|
|
||||||
|
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private readonly ILogger<CalculatedObservations> _logger =
|
||||||
|
serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||||
|
|
||||||
|
private readonly Lazy<IObservationService> _observationService =
|
||||||
|
serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||||
|
|
||||||
|
public Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
return Task.FromResult(obs)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
return Task.FromResult(treatment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
return Task.FromResult(diagnosis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
if (pumpObservation.Code == "IHE PCD-04")
|
||||||
|
await CreatePumpAlarmObservation(pumpObservation);
|
||||||
|
return pumpObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(listToInsert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task CreatePumpAlarmObservation(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
PatientObservation patientObservationAlarm = new()
|
||||||
|
{
|
||||||
|
CodingSystem = "ADAS_ALARM",
|
||||||
|
Code = pumpObservation.AlarmState,
|
||||||
|
Name = $"Alarm_Pump_{pumpObservation.AlarmType}",
|
||||||
|
Value = pumpObservation.DeviceId != null
|
||||||
|
? $"Device Id: {pumpObservation.DeviceId}"
|
||||||
|
: $"Infusion Id {pumpObservation.InfusionId}",
|
||||||
|
Time = pumpObservation.Time
|
||||||
|
};
|
||||||
|
|
||||||
|
if (pumpObservation.PatientId.HasValue) patientObservationAlarm.PatientId = pumpObservation.PatientId.Value;
|
||||||
|
|
||||||
|
|
||||||
|
//CheckAlarmConfig(patientObservationAlarm);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = _observationService.Value.InsertObservation(patientObservationAlarm, mapObs: false);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error inserting Pump Observation Alarm. Exception: {e}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using adas_core.Application.Services.Interfaces;
|
||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Customizations.CHUO;
|
||||||
|
|
||||||
|
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private readonly ILogger<CalculatedObservations> _logger =
|
||||||
|
serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(pumpObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Mapping {name} observation {obs}", obs.Name, obs);
|
||||||
|
|
||||||
|
return Task.FromResult<T?>(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//public Task<List<PatientObservation>> MapList(List<PatientObservation> obsToInsert)
|
||||||
|
//{
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
//}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,133 @@
|
|||||||
|
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.HGM;
|
||||||
|
|
||||||
|
//Custom for Hospital Gregorio Marañón
|
||||||
|
public class CalculatedObservations : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private readonly List<string> _highFrequencyVentilation = [];
|
||||||
|
private readonly List<string> _invasiveVentilation = [];
|
||||||
|
private readonly ILogger<CalculatedObservations> _logger;
|
||||||
|
private readonly List<string> _nonInvasiveVentilation = [];
|
||||||
|
private readonly Lazy<IObservationService> _observationService;
|
||||||
|
|
||||||
|
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>().Value;
|
||||||
|
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||||
|
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||||
|
|
||||||
|
var highFrequencyVentilation = apiSettings.HighFrequencyVentilation ?? null;
|
||||||
|
highFrequencyVentilation?.ForEach(x => _highFrequencyVentilation.Add(x.Trim()));
|
||||||
|
|
||||||
|
var invasiveVentilation = apiSettings.InvasiveVentilation ?? null;
|
||||||
|
invasiveVentilation?.ForEach(x => _invasiveVentilation.Add(x.Trim()));
|
||||||
|
|
||||||
|
var nonInvasiveVentilation = apiSettings.NonInvasiveVentilation ?? null;
|
||||||
|
nonInvasiveVentilation?.ForEach(x => _nonInvasiveVentilation.Add(x.Trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(obs.Name)) return obs;
|
||||||
|
|
||||||
|
switch (obs.Name)
|
||||||
|
{
|
||||||
|
case "Resp_Mode":
|
||||||
|
await CalculateVentilationMode(obs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(pumpObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(listToInsert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task 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();
|
||||||
|
if (string.IsNullOrEmpty(strValue))
|
||||||
|
respTypeObs.Value = nameof(RespirationType.None);
|
||||||
|
else
|
||||||
|
respTypeObs.Value = _highFrequencyVentilation.Contains(strValue)
|
||||||
|
? nameof(RespirationType.HighFrequencyVentilation)
|
||||||
|
: _invasiveVentilation.Contains(strValue)
|
||||||
|
? respTypeObs.Value = nameof(RespirationType.Invasive)
|
||||||
|
: _nonInvasiveVentilation.Contains(strValue)
|
||||||
|
? respTypeObs.Value = nameof(RespirationType.NonInvasive)
|
||||||
|
: nameof(RespirationType.None);
|
||||||
|
|
||||||
|
|
||||||
|
var wasInserted = await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
|
||||||
|
if (wasInserted)
|
||||||
|
_logger.LogDebug("Calculated Resp_Type for patientid: {respTypeObsPatientid} value: {respType}",
|
||||||
|
respTypeObs.PatientId, respTypeObs.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,641 @@
|
|||||||
|
using adas_core.Application.Services.Interfaces;
|
||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.AppSettings;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Customizations.HPAZ;
|
||||||
|
|
||||||
|
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private readonly Lazy<IAlarmService> _alarmService = serviceProvider.GetRequiredService<Lazy<IAlarmService>>();
|
||||||
|
|
||||||
|
|
||||||
|
private readonly ApiSettings
|
||||||
|
_apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>().Value; //apiSettings;
|
||||||
|
|
||||||
|
private readonly IConfigObservationService _configObservationService =
|
||||||
|
serviceProvider.GetRequiredService<IConfigObservationService>(); //configObservationService;
|
||||||
|
|
||||||
|
private readonly ILogger<CalculatedObservations> _logger =
|
||||||
|
serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||||
|
|
||||||
|
//Use GroupedObservation to avoid circular dependency with _observationService
|
||||||
|
private readonly Lazy<IObservationService> _observationService =
|
||||||
|
serviceProvider.GetRequiredService<Lazy<IObservationService>>(); //observationService;
|
||||||
|
|
||||||
|
private readonly List<string> _pressBloodArteryMean = ["TAm"];
|
||||||
|
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
return Task.FromResult<IEnumerable<PatientTreatment?>>(new List<PatientTreatment?>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps the obs to an event or alarm depending on its type and inserts it if needed
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type</typeparam>
|
||||||
|
/// <param name="source">Observation</param>
|
||||||
|
/// <param name="onlyByName">True if the observation needs to generate an alert</param>
|
||||||
|
/// <returns>Mapped observation</returns>
|
||||||
|
public async Task<T?> Map<T>(T source, bool onlyByName) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Mapping {obsName} mode observation {obs}", source.Name, source);
|
||||||
|
|
||||||
|
if (source is not BasePatientObservationValue obs) return source;
|
||||||
|
|
||||||
|
var name = obs is PatientObservationAlarm obsAlarm ? obsAlarm.Event : obs.Name;
|
||||||
|
name ??= string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
//No generamos alertas si viene onlyByName
|
||||||
|
if (name == "Resp_Mode")
|
||||||
|
obs = CalculateVentilationMode(obs);
|
||||||
|
|
||||||
|
if (name is "Sattc" or "FiO2") await CalculateSf(obs, name);
|
||||||
|
|
||||||
|
if (name is "FiO2" or "P_VAM" or "PaO2_Tidal") await CalculateOxygenationIndex(obs, name);
|
||||||
|
|
||||||
|
if (name is "FiO2" or "PaO2_Tidal") await CalculatePf(obs, name);
|
||||||
|
|
||||||
|
if (name == "TEST_ALARMA") await _alarmService.Value.CalculateAlarmTest(obs, name);
|
||||||
|
|
||||||
|
obs = await CheckObsWithSameTimeExistsAndIncrementTime(obs);
|
||||||
|
|
||||||
|
if (obs is PatientObservation pobs)
|
||||||
|
{
|
||||||
|
pobs = await CheckAlarmConfig(pobs);
|
||||||
|
return pobs as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obs as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (pumpObservation.Status is PumpEnum.Status.Alarm or PumpEnum.Status.Warning)
|
||||||
|
{
|
||||||
|
PatientObservation? patientObservation = null;
|
||||||
|
string? name = null;
|
||||||
|
|
||||||
|
//La oclusión es para todos los tipos
|
||||||
|
var volumetricAirOcclusionAlarm = _apiSettings.VolumetricAirOcclusionAlarm ?? null;
|
||||||
|
|
||||||
|
if (volumetricAirOcclusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||||
|
volumetricAirOcclusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||||
|
{
|
||||||
|
name = "VolumetricAirOcclusion";
|
||||||
|
//alerta oclusión aire para bombas volumétricas
|
||||||
|
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var listInotropicMedicines = _apiSettings.InotropicMedicines ?? null;
|
||||||
|
|
||||||
|
if (listInotropicMedicines is { Count: > 0 } && pumpObservation.DrugName != null &&
|
||||||
|
listInotropicMedicines.Contains(pumpObservation.DrugName)) //INOTRÓPICOS
|
||||||
|
{
|
||||||
|
var inotropicEndInfusionAlarm = _apiSettings.InotropicEndInfusionAlarm ?? null;
|
||||||
|
|
||||||
|
if (inotropicEndInfusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||||
|
inotropicEndInfusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||||
|
{
|
||||||
|
//Inotrópicos próxima a fin de infusión
|
||||||
|
// Y
|
||||||
|
//proximo fin de infusión, oclusión, y presencia aire….
|
||||||
|
//Solo inotrópicos
|
||||||
|
//Está en la línea 19 del excel y abarca la que hay en la línea 9
|
||||||
|
// TODO: revisar en los logs que nombre de type (Buscar por crud xmlns)
|
||||||
|
name = "InotropicEndInfusion";
|
||||||
|
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pumPressureAlarm = _apiSettings.PumPressureAlarm ?? null;
|
||||||
|
|
||||||
|
if (pumPressureAlarm != null && pumpObservation.AlarmType != null &&
|
||||||
|
pumPressureAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||||
|
{
|
||||||
|
name = "Pressure";
|
||||||
|
//alerta de presión(la alerta de la bomba se programa + -30mmHg por encima de la presión de la línea).
|
||||||
|
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
var endContinuousInfusionAlarm = _apiSettings.EndContinuousInfusionAlarm ?? null;
|
||||||
|
|
||||||
|
if (endContinuousInfusionAlarm != null && pumpObservation.AlarmType != null &&
|
||||||
|
endContinuousInfusionAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||||
|
{
|
||||||
|
name = "EndContinuousInfusion";
|
||||||
|
//próximo a fin de infusión /fin de infusión
|
||||||
|
//información de bombas solo perfusión continua
|
||||||
|
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
var volumetricAirInLineAlarm = _apiSettings.VolumetricAirInLineAlarm ?? null;
|
||||||
|
|
||||||
|
if (volumetricAirInLineAlarm != null && pumpObservation.AlarmType != null &&
|
||||||
|
volumetricAirInLineAlarm.Contains(pumpObservation.AlarmType.ToString() ?? string.Empty))
|
||||||
|
{
|
||||||
|
name = "VolumetricAirInLine";
|
||||||
|
//alerta aire para bombas volumétricas (burbujas de aire para la bomba)
|
||||||
|
patientObservation = await CreatePumpAlarmObservation(name, pumpObservation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (patientObservation != null && name != null)
|
||||||
|
{
|
||||||
|
_ = _observationService.Value.InsertObservation(patientObservation);
|
||||||
|
_ = _alarmService.Value.SendAlarm(patientObservation, name, AlarmEnum.Name.Pump,
|
||||||
|
AlarmEnum.Severity.None, AlarmEnum.Type.Auto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error mapping alarm pump observation. Exception: {exMessage}", ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pumpObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newObservation.Name))
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
"Error FixTimeInconsistencyWithLast new observation name is null or empty: {newObservation}.",
|
||||||
|
newObservation);
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lasObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||||
|
[newObservation.Name]);
|
||||||
|
var lastObservation = lasObservations.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastObservation != null && DateTime.Compare(
|
||||||
|
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||||
|
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||||
|
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||||
|
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||||
|
newObservation.Time.Day, newObservation.Time.Hour,
|
||||||
|
newObservation.Time.Minute, newObservation.Time.Second)
|
||||||
|
) >= 0)
|
||||||
|
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||||
|
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToMap)
|
||||||
|
{
|
||||||
|
var mappedObsList = listToMap
|
||||||
|
.Select(obs => obs.DeepCopy())
|
||||||
|
.Select(obs => _configObservationService.Map(obs).Result)
|
||||||
|
.Where(obs => obs != null)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// mappedObsList contains observation mapped
|
||||||
|
// Check blue code
|
||||||
|
|
||||||
|
_ = CalculateBlueCodeList(mappedObsList);
|
||||||
|
|
||||||
|
|
||||||
|
return Task.FromResult(listToMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(alarmToInsert.EventId))
|
||||||
|
obs.Code = alarmToInsert.EventId;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(alarmToInsert.Event))
|
||||||
|
obs.Name = alarmToInsert.Event;
|
||||||
|
|
||||||
|
obs.Value = alarmToInsert.Value;
|
||||||
|
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task ICalculatedObservations.SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code, AlarmEnum.Type type)
|
||||||
|
{
|
||||||
|
await _alarmService.Value.SendAlarm(obs, name, code, AlarmEnum.Severity.None, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initial check to ignore old observations generating blue codes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obs">Observation</param>
|
||||||
|
/// <returns>True if it needs to be ignored</returns>
|
||||||
|
private bool CheckIfObservationIsOlderAndShouldBeIgnored(PatientObservation obs)
|
||||||
|
{
|
||||||
|
if (obs.Time.ToUniversalTime().AddMinutes(_apiSettings.IgnoreCalcObservationsOlderInMinutesThan) <
|
||||||
|
DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
Log.Debug(
|
||||||
|
"ignoring calc old observation: name:{obsName} obs_time:{obsTime} system_time {DateTimeNow} id:{obsId}",
|
||||||
|
obs.Name ?? "null", obs.Time, DateTime.Now, obs.Id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<PatientObservation> CheckAlarmConfig(PatientObservation pobs)
|
||||||
|
{
|
||||||
|
var configObs = await _configObservationService.Get(new PatientObservation
|
||||||
|
{
|
||||||
|
Name = pobs.Name,
|
||||||
|
PatientId = pobs.PatientId
|
||||||
|
});
|
||||||
|
|
||||||
|
pobs.Alarm = configObs?.Alarm ?? null;
|
||||||
|
|
||||||
|
return pobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PatientObservation CreateAlarmObservation(string name, PatientObservation pobs)
|
||||||
|
{
|
||||||
|
return new PatientObservation
|
||||||
|
{
|
||||||
|
CodingSystem = "ADAS_ALARM",
|
||||||
|
Code = name,
|
||||||
|
Name = $"Alarm_{name}",
|
||||||
|
Value = pobs.Value,
|
||||||
|
PatientId = pobs.PatientId,
|
||||||
|
Time = pobs.Time,
|
||||||
|
Alarm = pobs.Alarm
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a blue code observation Lists needs to be generated and inserts it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obsList"></param>
|
||||||
|
public async Task CalculateBlueCodeList(List<PatientObservation?>? obsList)
|
||||||
|
{
|
||||||
|
//Las 3 observaciones vienen siempre juntas en el mismo mensaje
|
||||||
|
//Solo se comprueba si se cumplen 2 de las 3 condiciones
|
||||||
|
|
||||||
|
var condition = 0;
|
||||||
|
var patientId = obsList?.FirstOrDefault()?.PatientId;
|
||||||
|
if (patientId == null) return;
|
||||||
|
|
||||||
|
var fcObs = obsList?.FirstOrDefault(o => o is { Name: "FC" });
|
||||||
|
var sattcObs = obsList?.FirstOrDefault(o => o is { Name: "Sattc" });
|
||||||
|
var tamObs = obsList?.FirstOrDefault(o => o is { Name: "TAm" });
|
||||||
|
|
||||||
|
// FC < 60
|
||||||
|
if (fcObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(fcObs) &&
|
||||||
|
double.TryParse(fcObs.Value.ToString(), out var cardiacBeatRate) && cardiacBeatRate < 60)
|
||||||
|
{
|
||||||
|
Log.Debug("BlueCode condition: FC {fc} for patient: {obsPatientid} fc increase limit", cardiacBeatRate,
|
||||||
|
fcObs.PatientId);
|
||||||
|
condition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpO2 < 80 (Sattc)
|
||||||
|
if (sattcObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(sattcObs) &&
|
||||||
|
double.TryParse(sattcObs.Value.ToString(), out var spO2Value) && spO2Value < 80)
|
||||||
|
{
|
||||||
|
Log.Debug("Blue code condition: SpO2 {sp} for patient: {obsPatientid} Sattc increase limit", spO2Value,
|
||||||
|
sattcObs.PatientId);
|
||||||
|
condition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition == 0) return;
|
||||||
|
|
||||||
|
// Early exit if 2 conditions are met
|
||||||
|
if (condition == 2)
|
||||||
|
{
|
||||||
|
_ = SendBlueCode(fcObs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TAm actual es un 50% por debajo de la medición de 30 seg antes
|
||||||
|
if (tamObs != null && !CheckIfObservationIsOlderAndShouldBeIgnored(tamObs) &&
|
||||||
|
double.TryParse(tamObs.Value.ToString(), out var tamObsValue))
|
||||||
|
{
|
||||||
|
// Buscamos el anterior
|
||||||
|
var lastPressBloodObsList =
|
||||||
|
await _observationService.Value.FindLastObservations(tamObs.PatientId, 1, _pressBloodArteryMean);
|
||||||
|
var lastPressBloodObs = lastPressBloodObsList.FirstOrDefault();
|
||||||
|
|
||||||
|
// Diferencia entre la última observación es < 30 s
|
||||||
|
if (lastPressBloodObs != null &&
|
||||||
|
double.TryParse(lastPressBloodObs.Value.ToString(), out var lastPressBloodValue) &&
|
||||||
|
(tamObs.Time - lastPressBloodObs.Time).TotalSeconds <= 35 &&
|
||||||
|
tamObsValue <= lastPressBloodValue / 2)
|
||||||
|
{
|
||||||
|
Log.Debug("Blue code condition: TAm decrease limit over 30s for patient: {obsPatientid}",
|
||||||
|
tamObs.PatientId);
|
||||||
|
condition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition >= 2) _ = SendBlueCode(tamObs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task SendBlueCode(PatientObservation? pobs)
|
||||||
|
{
|
||||||
|
if (pobs == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log.Debug("Blue code Alarm for patient: {obsPatientid}", pobs.PatientId);
|
||||||
|
|
||||||
|
var blueCodeObservation = CreateAlarmObservation("BlueCode", pobs);
|
||||||
|
|
||||||
|
blueCodeObservation = await CheckAlarmConfig(blueCodeObservation);
|
||||||
|
|
||||||
|
_ = _observationService.Value.InsertObservation(blueCodeObservation);
|
||||||
|
|
||||||
|
_ = SendAlarm(blueCodeObservation, "BlueCode", AlarmEnum.Name.Blue, AlarmEnum.Type.Auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//PRVC : donde aparezca cambiar y mostrar en su lugar: VCRP
|
||||||
|
//FLUJO ALTO: poner OAF en su lugar
|
||||||
|
private BasePatientObservationValue CalculateVentilationMode(BasePatientObservationValue obs)
|
||||||
|
{
|
||||||
|
var value = obs is PatientObservationAlarm oAlarm ? oAlarm.Value
|
||||||
|
: obs is PatientObservation o ? o.Value : null;
|
||||||
|
|
||||||
|
|
||||||
|
if (value != null && value.ToString()!.Contains("PRVC"))
|
||||||
|
obs.Value = value.ToString()!.Replace("PRVC", "VCRP");
|
||||||
|
else if (value != null && value.ToString()!.Contains("FLUJ.ALTO")) obs.Value = "OAF";
|
||||||
|
|
||||||
|
_logger.LogDebug("Calculating patient id: {id} ventilation mode: {obsName}, value : {obsValue}", obs.PatientId,
|
||||||
|
obs.Name, obs.Value);
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO duplicado con el calculated del 12o, sacar a un utils
|
||||||
|
private async Task<BasePatientObservationValue> CheckObsWithSameTimeExistsAndIncrementTime(
|
||||||
|
BasePatientObservationValue obs)
|
||||||
|
{
|
||||||
|
if (obs is not PatientObservation pobs) return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//S/F Calc ( craneal saturation / FiO2
|
||||||
|
private async Task CalculateSf(BasePatientObservationValue obs, string name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PatientObservation? saturation = null;
|
||||||
|
PatientObservation? fio2 = null;
|
||||||
|
|
||||||
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["FiO2", "Sattc"]);
|
||||||
|
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "FiO2":
|
||||||
|
fio2 = (PatientObservation)obs;
|
||||||
|
saturation = values.FirstOrDefault(o => o.Name == "Sattc");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Sattc":
|
||||||
|
saturation = (PatientObservation)obs;
|
||||||
|
fio2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fio2 != null && saturation != null && !fio2.Expired &&
|
||||||
|
double.TryParse(fio2.Value.ToString(), out var fio) && !saturation.Expired &&
|
||||||
|
double.TryParse(saturation.Value.ToString(), out var sat) && sat <= 97)
|
||||||
|
{
|
||||||
|
if (fio == 0)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error calculating SF. FiO2: {fio}", fio);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sfValue = sat / fio;
|
||||||
|
|
||||||
|
sfValue = Math.Round(sfValue, 4);
|
||||||
|
|
||||||
|
var sfObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Name = "Sattc_FiO2",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
Value = sfValue,
|
||||||
|
Time = obs.Time
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(sfObs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error calculate S/F observation. Exception: {exMessage}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Oxygenation index is calculated => P_VAM x FiO2 x 100 / PaO2_Tidal
|
||||||
|
/// the method is called when it receives P_VAM or FiO2 or PaO2_Tidal 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(BasePatientObservationValue obs, string name)
|
||||||
|
{
|
||||||
|
var toSearchList = new List<string>();
|
||||||
|
PatientObservation? pVam = null;
|
||||||
|
PatientObservation? fiO2 = null;
|
||||||
|
PatientObservation? paO2 = null;
|
||||||
|
|
||||||
|
toSearchList.AddRange(new List<string> { "P_VAM", "FiO2", "PaO2_Tidal" });
|
||||||
|
|
||||||
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "P_VAM":
|
||||||
|
pVam = (PatientObservation)obs;
|
||||||
|
fiO2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||||
|
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "FiO2":
|
||||||
|
fiO2 = (PatientObservation)obs;
|
||||||
|
pVam = values.FirstOrDefault(o => o.Name == "P_VAM");
|
||||||
|
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PaO2_Tidal":
|
||||||
|
paO2 = (PatientObservation)obs;
|
||||||
|
fiO2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||||
|
pVam = values.FirstOrDefault(o => o.Name == "P_VAM");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Controlar que FiO2 no haya expirada al recogerla
|
||||||
|
if (fiO2 != null && paO2 != null && pVam != null &&
|
||||||
|
int.TryParse(pVam.Value.ToString(), out var pvam) &&
|
||||||
|
int.TryParse(fiO2.Value.ToString(), out var fio2) &&
|
||||||
|
int.TryParse(paO2.Value.ToString(), out var pao2))
|
||||||
|
{
|
||||||
|
if (pao2 == 0)
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
"Error calculate Oxygenation Index observation. PaO2: {pao2}, observation: {obsName}", pao2,
|
||||||
|
name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var oxygenationIndexValue = pvam * fio2 * 100 / pao2;
|
||||||
|
|
||||||
|
var oxygenationIndexObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Name = "Oxygenation_Index",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
Value = oxygenationIndexValue,
|
||||||
|
Time = obs.Time
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(oxygenationIndexObs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error calculate Oxygenation Index observation. Exception: {exMessage}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//P/F Calc ( PaO2_Tidal / FiO2
|
||||||
|
private async Task CalculatePf(BasePatientObservationValue obs, string name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PatientObservation? paO2 = null;
|
||||||
|
PatientObservation? fio2 = null;
|
||||||
|
|
||||||
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||||
|
["FiO2", "PaO2_Tidal"]);
|
||||||
|
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case "FiO2":
|
||||||
|
fio2 = (PatientObservation)obs;
|
||||||
|
paO2 = values.FirstOrDefault(o => o.Name == "PaO2_Tidal");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PaO2_Tidal":
|
||||||
|
paO2 = (PatientObservation)obs;
|
||||||
|
fio2 = values.FirstOrDefault(o => o.Name == "FiO2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fio2 != null && paO2 != null && !fio2.Expired && !paO2.Expired &&
|
||||||
|
double.TryParse(paO2.Value.ToString(), out var pa) &&
|
||||||
|
double.TryParse(fio2.Value.ToString(), out var fi))
|
||||||
|
{
|
||||||
|
if (fi == 0)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error Calculating PF. FiO2 value is 0. Observation:{obs}", obs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sfValue = pa / fi;
|
||||||
|
|
||||||
|
sfValue = Math.Round(sfValue, 4);
|
||||||
|
|
||||||
|
var sfObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Name = "PaO2_FiO2",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
Value = sfValue,
|
||||||
|
Time = obs.Time
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(sfObs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error calculate P/F observation. Exception: {exMessage}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<PatientObservation?> CreatePumpAlarmObservation(string name,
|
||||||
|
PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
var positionPump = pumpObservation.IsAux != null && !pumpObservation.IsAux.Value
|
||||||
|
? $"Rack {pumpObservation.GatewayNumber} Bomba {pumpObservation.Number}"
|
||||||
|
: $"Rack Aux {pumpObservation.GatewayNumber} Bomba {pumpObservation.Number}";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PatientObservation patientObservation = new()
|
||||||
|
{
|
||||||
|
CodingSystem = "ADAS_ALARM",
|
||||||
|
Code = $"Pump_{name}",
|
||||||
|
Name = $"Alarm_Pump_{name}",
|
||||||
|
Value = pumpObservation.DrugName ?? positionPump,
|
||||||
|
Time = pumpObservation.Time
|
||||||
|
};
|
||||||
|
|
||||||
|
if (pumpObservation.PatientId != null)
|
||||||
|
patientObservation.PatientId = pumpObservation.PatientId.Value;
|
||||||
|
|
||||||
|
return await CheckAlarmConfig(patientObservation);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,883 @@
|
|||||||
|
using adas_core.Application.Services.Interfaces;
|
||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.AppSettings;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Customizations.HRYC;
|
||||||
|
|
||||||
|
public class CalculatedObservations : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private readonly IOptions<ApiSettings> _apiSettings;
|
||||||
|
private readonly List<string> _codesForInvasiveVentilation = [];
|
||||||
|
|
||||||
|
private readonly IConfigObservationService _configObservationService;
|
||||||
|
|
||||||
|
//private readonly Lazy<IBoxService> _boxService;
|
||||||
|
private readonly List<string> _highFrequencyVentilation = [];
|
||||||
|
private readonly Lazy<ILightBeaconService> _lightBeaconService;
|
||||||
|
private readonly ILogger<CalculatedObservations> _logger;
|
||||||
|
private readonly List<string> _nonInvasiveVentilation = [];
|
||||||
|
private readonly Lazy<IObservationService> _observationService;
|
||||||
|
private readonly Lazy<IPatientService> _patientService;
|
||||||
|
|
||||||
|
|
||||||
|
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>(); //observationService;
|
||||||
|
_patientService = serviceProvider.GetRequiredService<Lazy<IPatientService>>();
|
||||||
|
_apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>(); //apiSettings;
|
||||||
|
//_boxService = serviceProvider.GetRequiredService<Lazy<IBoxService>>();
|
||||||
|
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||||
|
_lightBeaconService = serviceProvider.GetRequiredService<Lazy<ILightBeaconService>>();
|
||||||
|
_configObservationService =
|
||||||
|
serviceProvider.GetRequiredService<IConfigObservationService>(); //configObservationService;
|
||||||
|
|
||||||
|
|
||||||
|
var highFrenquencyVentilation = _apiSettings.Value.HighFrequencyVentilation ?? null;
|
||||||
|
highFrenquencyVentilation?.ForEach(x => _highFrequencyVentilation.Add(x.Trim()));
|
||||||
|
|
||||||
|
|
||||||
|
var nonInvasiveVentilation = _apiSettings.Value.NonInvasiveVentilation ?? null;
|
||||||
|
nonInvasiveVentilation?.ForEach(x => _nonInvasiveVentilation.Add(x.Trim()));
|
||||||
|
|
||||||
|
var codesForInvasiveVentilation = //TODO comprobar si se refiere a InvasiveVentilation
|
||||||
|
_apiSettings.Value.InvasiveVentilation ?? null;
|
||||||
|
codesForInvasiveVentilation?.ForEach(x => _codesForInvasiveVentilation.Add(x.Trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<T?> Map<T>(T obs, bool onlyByName) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Mapping {name} observation {obs}", obs.Name, obs);
|
||||||
|
|
||||||
|
switch (obs.Name)
|
||||||
|
{
|
||||||
|
case "Resp_Mode":
|
||||||
|
_logger.LogTrace("Mapping Resp mode observation {obs}", obs);
|
||||||
|
await CalculateVentilationMode(obs);
|
||||||
|
break;
|
||||||
|
case "Diuresis":
|
||||||
|
case "Weight_Current":
|
||||||
|
if (obs.Name == "Weight_Current") await CalculateWeight_DiffObservation(obs);
|
||||||
|
await CalculateDiureis_WeightObservation(obs);
|
||||||
|
break;
|
||||||
|
case "AllergiesObs":
|
||||||
|
await CalculateAllergiesObservation(obs);
|
||||||
|
break;
|
||||||
|
case "DrainagesObs":
|
||||||
|
await CalculateDrainagesObservation(obs);
|
||||||
|
break;
|
||||||
|
case "PEEP":
|
||||||
|
case "Pleateu_Pressure":
|
||||||
|
await CalculateDelta_PressureObservation(obs);
|
||||||
|
break;
|
||||||
|
case "Daily_Balance":
|
||||||
|
await CalculateDaily_BalanceObservation(obs);
|
||||||
|
break;
|
||||||
|
case "Hydric_Balance":
|
||||||
|
await CalculateHydricBalanceCalculated(obs);
|
||||||
|
obs = (T)await CalculateHydricBalance(obs);
|
||||||
|
break;
|
||||||
|
case "Hour_Balance":
|
||||||
|
obs = (T)await CalculateHourBalance(obs);
|
||||||
|
break;
|
||||||
|
case "FR":
|
||||||
|
await CalculateRespRate(obs);
|
||||||
|
await CalculateIrox(obs);
|
||||||
|
break;
|
||||||
|
case "Vent_Rate":
|
||||||
|
await CalculateRespRate(obs);
|
||||||
|
break;
|
||||||
|
case "SpO2":
|
||||||
|
case "FiO2":
|
||||||
|
await CalculateIrox(obs);
|
||||||
|
break;
|
||||||
|
case "NEWS":
|
||||||
|
await CalculateNews(obs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(pumpObservation);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
return Task.FromResult(new List<PatientTreatment?>().AsEnumerable());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
return Task.FromResult(diagnosis);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newObservation.Name))
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
"Error FixTimeInconsistencyWithLast newObservation name ia null or empty. Observation: {newObservation}",
|
||||||
|
newObservation);
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||||
|
[newObservation.Name]);
|
||||||
|
var lastObservation = lastObservations.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastObservation != null && DateTime.Compare(
|
||||||
|
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||||
|
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||||
|
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||||
|
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||||
|
newObservation.Time.Day, newObservation.Time.Hour,
|
||||||
|
newObservation.Time.Minute, newObservation.Time.Second)
|
||||||
|
) >= 0)
|
||||||
|
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||||
|
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||||
|
{
|
||||||
|
var ventRate = listToInsert.FirstOrDefault(obs => obs.Name == "MDC_VENT_RESP_RATE");
|
||||||
|
var respRate = listToInsert.FirstOrDefault(obs => obs.Name == "MDC_RESP_RATE");
|
||||||
|
|
||||||
|
// Check if obs for Vent_Rate and FR is on the list to insert
|
||||||
|
if (ventRate == null || respRate == null) return listToInsert;
|
||||||
|
|
||||||
|
var ventRateValue = double.TryParse(ventRate.Value.ToString(), out var v1) ? v1 : 0;
|
||||||
|
// ventRate is on the list to insert but its value is 0
|
||||||
|
if (ventRateValue == 0)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Find ventRate on PreMap request not processed because its value is 0");
|
||||||
|
return listToInsert;
|
||||||
|
}
|
||||||
|
|
||||||
|
var respRateValue = double.TryParse(ventRate.Value.ToString(), out var v2) ? v2 : 0;
|
||||||
|
// respRate is on the list to insert but its value is 0
|
||||||
|
if (respRateValue == 0)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Find respRate on PreMap request not processed because its value is 0");
|
||||||
|
return listToInsert;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Exists both obs and have value != 0
|
||||||
|
// In that case we need to calculate Resp_Rate_Calculated just with the value of Vent_Rate
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"Find on PreMap Vent_Rate and FR in the same request process Vent_Rate first to calculate Resp_Rate_Calculated");
|
||||||
|
await _observationService.Value.InsertObservation(ventRate);
|
||||||
|
listToInsert.Remove(ventRate);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error while PreMap on insert obs: {ventRate} exception: {e}", ventRate, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return listToInsert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IF news greater or equal than 5 and less than 7 is warning beacon and if greater or equal than 7 alert
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obs"></param>
|
||||||
|
private async Task CalculateNews(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
var parsed = int.TryParse(pobs.Value.ToString(), out var valueParsed);
|
||||||
|
var patient = await _patientService.Value.FindById(obs.PatientId);
|
||||||
|
if (patient == null) return;
|
||||||
|
//var beaconConfig = await _boxService.Value.GetBeaconConfig(new PatientLocation(patient.PointOfCare, patient.Bed));
|
||||||
|
|
||||||
|
//power off beacon
|
||||||
|
|
||||||
|
//recuperar la beacon del paciente y encenderla apagarla si el valor es > 5&6 o 7 alert
|
||||||
|
|
||||||
|
if ((parsed && valueParsed < 5) || !parsed)
|
||||||
|
//await _balizaService.Value.PowerOffLed(beaconCnf);
|
||||||
|
//await _observationService.Value.SendObsBroadcast(obs);
|
||||||
|
await SendAlarm(obs, AlarmEnum.Name.NewsOff);
|
||||||
|
else
|
||||||
|
switch (valueParsed)
|
||||||
|
{
|
||||||
|
case >= 5 and < 7:
|
||||||
|
_logger.LogDebug("beacon yellow alert by NEWS for patient: {patientid}", obs.PatientId);
|
||||||
|
await SendAlarm(obs, AlarmEnum.Name.NewsWarning);
|
||||||
|
//await _balizaService.Value.SendBeaconColor(patient, LightBeaconColor.YELLOW);
|
||||||
|
break;
|
||||||
|
case >= 7:
|
||||||
|
_logger.LogDebug("beacon red alert by NEWS for patient: {patientid}", obs.PatientId);
|
||||||
|
await SendAlarm(obs, AlarmEnum.Name.NewsAlert);
|
||||||
|
//await _balizaService.Value.SendBeaconColor(patient, LightBeaconColor.RED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (obsAlarm == null) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SendAlarm(BasePatientObservation obs, AlarmEnum.Name name)
|
||||||
|
{
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
PatientObservation nObs = new()
|
||||||
|
{
|
||||||
|
CodingSystem = "ADAS_ALARM",
|
||||||
|
Code = name.ToString(),
|
||||||
|
Name = $"Alarm_{name}",
|
||||||
|
PatientId = pobs.PatientId,
|
||||||
|
Time = pobs.Time
|
||||||
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//ConfigObservations
|
||||||
|
var configObs = await _configObservationService.Get(new PatientObservation
|
||||||
|
{
|
||||||
|
Name = nObs.Name,
|
||||||
|
PatientId = obs.PatientId
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (configObs == null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Config observation is null on send alarm NEWS for {nObs}", nObs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configObs is { Alarm.Enabled: true })
|
||||||
|
{
|
||||||
|
nObs.Alarm = configObs.Alarm;
|
||||||
|
|
||||||
|
if (configObs.Alarm.Beacon is { Enabled: true })
|
||||||
|
{
|
||||||
|
var patient = await _patientService.Value.FindById(obs.PatientId);
|
||||||
|
if (patient != null)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"PatientId: {nObsPatientId}. Send Beacon alarmName {configObsAlarmBeaconBeaconColorValue}",
|
||||||
|
nObs.PatientId, configObs.Alarm.Beacon.BeaconColor);
|
||||||
|
nObs.Value = configObs.Alarm.Beacon.BeaconColor.ToString();
|
||||||
|
SendBeaconCode(configObs.Alarm.Beacon.BeaconColor, patient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug(
|
||||||
|
"Insert obs alarm for news at: {DateTimeNow} patientId: {nObsPatientId} color value: {nObsValue}",
|
||||||
|
DateTime.Now, nObs.PatientId, nObs.Value);
|
||||||
|
await _observationService.Value.InsertObservation(nObs);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("Exception sending alarm: {exMessage}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendBeaconCode(AlarmEnum.BeaconColor color, Patient patient)
|
||||||
|
{
|
||||||
|
if (!patient.PointOfCareId.HasValue)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error sending beacon color on calculateObservations poc id on patient is null {Patient}",
|
||||||
|
patient.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (color)
|
||||||
|
{
|
||||||
|
case AlarmEnum.BeaconColor.Blue:
|
||||||
|
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Blue);
|
||||||
|
break;
|
||||||
|
case AlarmEnum.BeaconColor.Yellow:
|
||||||
|
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Yellow);
|
||||||
|
break;
|
||||||
|
case AlarmEnum.BeaconColor.Red:
|
||||||
|
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Red);
|
||||||
|
break;
|
||||||
|
case AlarmEnum.BeaconColor.None:
|
||||||
|
_lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Off);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SpO2/FiO2)/FR IROX formula. Only calculate when all observations are in last 10 minutes.
|
||||||
|
private async Task CalculateIrox(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pob = (PatientObservation)obs;
|
||||||
|
var obsToCalc = new List<PatientObservation> { pob };
|
||||||
|
switch (pob.Name)
|
||||||
|
{
|
||||||
|
case "SpO2":
|
||||||
|
|
||||||
|
var fio2Frvalues = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||||
|
["FiO2", "FR"]);
|
||||||
|
if (fio2Frvalues.Count > 0) obsToCalc.AddRange(fio2Frvalues);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "FiO2":
|
||||||
|
var spo2Frvalues = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||||
|
["SpO2", "FR"]);
|
||||||
|
if (spo2Frvalues.Count > 0) obsToCalc.AddRange(spo2Frvalues);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "FR":
|
||||||
|
var fio2Spo2Values = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||||
|
["FiO2", "SpO2"]);
|
||||||
|
|
||||||
|
if (fio2Spo2Values.Count > 0) obsToCalc.AddRange(fio2Spo2Values);
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obsToCalc.All(o => o.Time.CompareTo(DateTime.UtcNow.AddMinutes(10)) <= 0)) return;
|
||||||
|
|
||||||
|
var fio2 = obsToCalc.FirstOrDefault(o => o.Name == "FiO2");
|
||||||
|
var fr = obsToCalc.FirstOrDefault(o => o.Name == "FR");
|
||||||
|
var spo2 = obsToCalc.FirstOrDefault(o => o.Name == "SpO2");
|
||||||
|
if (fio2 == null || fr == null || spo2 == null) return;
|
||||||
|
|
||||||
|
|
||||||
|
if (!double.TryParse(spo2.Value.ToString(), out var nSpo2) ||
|
||||||
|
!double.TryParse(fio2.Value.ToString(), out var nFio2) ||
|
||||||
|
!double.TryParse(fr.Value.ToString(), out var nFr))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Error parsing values. fio2: {fio2}, fr: {fr}, spo2: {spo2}", fio2, fr, spo2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var spo2Value = nSpo2;
|
||||||
|
var fio2Value = nFio2;
|
||||||
|
var frValue = nFr;
|
||||||
|
|
||||||
|
if (spo2Value == 0 || fio2Value == 0 || frValue == 0) return;
|
||||||
|
|
||||||
|
|
||||||
|
var value = nSpo2 / nFio2 / nFr;
|
||||||
|
|
||||||
|
var irox = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "IROX",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time,
|
||||||
|
Value = value
|
||||||
|
};
|
||||||
|
await _observationService.Value.InsertObservation(irox);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError("Exception calculating IROX, error: {eMessage}", e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
RespRate solo se tiene que poner cuando no hay ningún ventRate en los últimos min y veinte segundos y el último no es un 0.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
//static readonly SemaphoreSlim semaphoreCalculateRespRate = new(1, 1);
|
||||||
|
private async Task CalculateRespRate(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
_logger.LogDebug("CalculateRespRate {obsPatientid} wait {obsName} {obsTime} {pobsValue}", obs.PatientId,
|
||||||
|
obs.Name, obs.Time, pobs.Value);
|
||||||
|
if (Convert.ToDouble(pobs.Value) == 0) return;
|
||||||
|
|
||||||
|
if (Convert.ToDouble(pobs.Value) == 0) return;
|
||||||
|
|
||||||
|
var insert = true;
|
||||||
|
if (obs.Name == "FR")
|
||||||
|
{
|
||||||
|
// Insertamos si no existe una obs Vent_Rate o si es existe tiene más de X" y su valor es > 0
|
||||||
|
var lastVentRate =
|
||||||
|
(await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["Vent_Rate"]))
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (lastVentRate == null || (double.TryParse(lastVentRate.Value.ToString(), out var v) ? v : 0) == 0)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("CalculateRespRate {id} lastVentRate: null", obs.PatientId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var diff = DateTime.UtcNow.Subtract(lastVentRate.Time.ToUniversalTime());
|
||||||
|
insert =
|
||||||
|
lastVentRate.Time.ToUniversalTime().AddMinutes(_apiSettings.Value.CalculateRespRateVentExpires) <
|
||||||
|
DateTime.UtcNow;
|
||||||
|
_logger.LogDebug(
|
||||||
|
"CalculateRespRate {patientid} lastVentRate: {value} - {time} passed {diff} {insert}",
|
||||||
|
obs.PatientId, lastVentRate.Value, lastVentRate.Time, diff, insert ? "Inserted" : "Not inserted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insert)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"CalculateRespRate {patientid} Insert Resp_Rate_Calculated with {name} - {time} value {value}",
|
||||||
|
obs.PatientId, obs.Name, obs.Time, pobs.Value);
|
||||||
|
var calculatedRespRate = new PatientObservation
|
||||||
|
{
|
||||||
|
Id = new ObjectId(),
|
||||||
|
Name = "Resp_Rate_Calculated",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Name == "FR" ? obs.Time : obs.Time.AddSeconds(1),
|
||||||
|
Value = pobs.Value,
|
||||||
|
ParentData = new ParentDataClass { Name = obs.Name }
|
||||||
|
};
|
||||||
|
await _observationService.Value.InsertObservation(calculatedRespRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"CalculateRespRate {patientid} Insert Resp_Rate_Calculated with {name} - {time} value {value}",
|
||||||
|
obs.PatientId, obs.Name, obs.Time, pobs.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug("CalculateRespRate {patientid} release {name} {time} {value}", obs.PatientId,
|
||||||
|
obs.Name, obs.Time, pobs.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<BasePatientObservation> CalculateHydricBalance(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
|
||||||
|
var lastHydricBalanceFromHour =
|
||||||
|
await _observationService.Value.FindLastBeforeDate(pobs.PatientId, pobs.Time.AddMinutes(59),
|
||||||
|
"Hydric_Balance");
|
||||||
|
|
||||||
|
if (lastHydricBalanceFromHour != null &&
|
||||||
|
DateTime.Compare(new DateTime(lastHydricBalanceFromHour.Time.Year, lastHydricBalanceFromHour.Time.Month,
|
||||||
|
lastHydricBalanceFromHour.Time.Day, lastHydricBalanceFromHour.Time.Hour, 0, 0)
|
||||||
|
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0)
|
||||||
|
pobs.Time = lastHydricBalanceFromHour.Time.AddSeconds(1);
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<BasePatientObservation> CalculateHourBalance(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
|
||||||
|
var lastHourBalanceFromHour =
|
||||||
|
await _observationService.Value.FindLastBeforeDate(pobs.PatientId, pobs.Time.AddMinutes(59),
|
||||||
|
"Hour_Balance");
|
||||||
|
|
||||||
|
if (lastHourBalanceFromHour != null &&
|
||||||
|
DateTime.Compare(new DateTime(lastHourBalanceFromHour.Time.Year, lastHourBalanceFromHour.Time.Month,
|
||||||
|
lastHourBalanceFromHour.Time.Day, lastHourBalanceFromHour.Time.Hour, 0, 0)
|
||||||
|
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0)
|
||||||
|
pobs.Time = lastHourBalanceFromHour.Time.AddSeconds(1);
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateHydricBalanceCalculated(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
//Hydric_Balance_Calculated
|
||||||
|
//No guardamos como calculadas nunca horas futuras. En el obx siempre vienen con la hora y los minutos a 00
|
||||||
|
|
||||||
|
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
var nowUniversalTime = DateTime.Now.ToUniversalTime();
|
||||||
|
//La hora de la observación es mayor que la actual. No generamos la calculada
|
||||||
|
if (DateTime.Compare(new DateTime(obs.Time.Year, obs.Time.Month, obs.Time.Day, obs.Time.Hour, 0, 0),
|
||||||
|
new DateTime(nowUniversalTime.Year, nowUniversalTime.Month, nowUniversalTime.Day, nowUniversalTime.Hour,
|
||||||
|
0, 0)) > 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"HYDRIC BALANCE: La hora de la observación es mayor que la actual. No generamos la calculada {obs}",
|
||||||
|
obs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Para la calculada. Si la última que tenemos es de la hora actual y lo que viene es de una hora anterior no entra como calculada.
|
||||||
|
var lastHydricBalanceList = await _observationService.Value.FindLastObservations(obs.PatientId, 1,
|
||||||
|
["Hydric_Balance_Calculated"]);
|
||||||
|
var lastHydricBalance = lastHydricBalanceList.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastHydricBalance != null && lastHydricBalance.Time.Hour == DateTime.UtcNow.Hour &&
|
||||||
|
obs.Time.Hour != DateTime.UtcNow.Hour)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"HYDRIC BALANCE: ultima que tenemos es de la hora actual y lo que viene es de una hora anterior no entra como calculada {obs}",
|
||||||
|
obs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Si el último hydric balance es de una hora posterior a la observación que acaba de llegar no entra como calculada.
|
||||||
|
if (lastHydricBalance != null &&
|
||||||
|
DateTime.Compare(new DateTime(lastHydricBalance.Time.Year, lastHydricBalance.Time.Month,
|
||||||
|
lastHydricBalance.Time.Day, lastHydricBalance.Time.Hour, 0, 0)
|
||||||
|
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 1
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"HYDRIC BALANCE: Si el ultimo hydric balance es de una hora posterior a la observación que acaba de llegar no entra como calculada. {obs}",
|
||||||
|
obs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var calculatedHydricBalance = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Hydric_Balance_Calculated",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time.AddSeconds(1), //To discriminate updates.
|
||||||
|
Value = pobs.Value,
|
||||||
|
Units = obs.Units
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (lastHydricBalance != null && DateTime.Compare(
|
||||||
|
new DateTime(lastHydricBalance.Time.Year, lastHydricBalance.Time.Month, lastHydricBalance.Time.Day,
|
||||||
|
lastHydricBalance.Time.Hour, 0, 0)
|
||||||
|
, new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0)
|
||||||
|
calculatedHydricBalance.Time = lastHydricBalance.Time.AddSeconds(1);
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(calculatedHydricBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateVentilationMode(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("CalculateVentilationMode {obs}", obs);
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
|
||||||
|
var respTypeObs = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Resp_Type",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time
|
||||||
|
};
|
||||||
|
//https://epigram.teamwork.com/#/tasks/34765750
|
||||||
|
if (obs.Code != null && _codesForInvasiveVentilation.Contains(obs.Code))
|
||||||
|
{
|
||||||
|
//añadir que sea solo cuando el valor es invasiva
|
||||||
|
respTypeObs.Value = nameof(RespirationType.Invasive);
|
||||||
|
respTypeObs.Time = obs.Time.AddSeconds(1);
|
||||||
|
await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var strValue = pobs.Value.ToString();
|
||||||
|
if (strValue == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//si es en espera tendrá que insertar que es en espera
|
||||||
|
if (!"EnESPERA".Equals(strValue))
|
||||||
|
{
|
||||||
|
respTypeObs.Value = _highFrequencyVentilation.Contains(strValue)
|
||||||
|
? nameof(RespirationType.HighFrequencyVentilation)
|
||||||
|
: _nonInvasiveVentilation.Contains(strValue)
|
||||||
|
? respTypeObs.Value = nameof(RespirationType.NonInvasive)
|
||||||
|
: nameof(RespirationType.Invasive);
|
||||||
|
|
||||||
|
await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateWeight_DiffObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var toSearchList = new List<string>();
|
||||||
|
|
||||||
|
toSearchList.AddRange(new List<string> { "Weight_Current" });
|
||||||
|
|
||||||
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||||
|
|
||||||
|
var pWeight = values.FirstOrDefault(o => o.Name == "Weight_Current");
|
||||||
|
|
||||||
|
var newWeightObs = (PatientObservation)obs;
|
||||||
|
|
||||||
|
if (pWeight?.Value != null && double.TryParse(pWeight.Value.ToString(), out var weight) &&
|
||||||
|
double.TryParse(newWeightObs.Value.ToString(), out var newWeight))
|
||||||
|
{
|
||||||
|
var weightDiffValue = Math.Round(newWeight - weight, 2);
|
||||||
|
|
||||||
|
var weightDiff = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Weight_Diff",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time,
|
||||||
|
Value = weightDiffValue,
|
||||||
|
Units = obs.Units
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(weightDiff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateDiureis_WeightObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var toSearchList = new List<string>();
|
||||||
|
|
||||||
|
PatientObservation? diuresisObs;
|
||||||
|
PatientObservation? weightObs;
|
||||||
|
|
||||||
|
toSearchList.AddRange(new List<string> { "Diuresis", "Weight_Current" });
|
||||||
|
|
||||||
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||||
|
|
||||||
|
if (obs.Name == "Diuresis")
|
||||||
|
{
|
||||||
|
diuresisObs = (PatientObservation)obs;
|
||||||
|
weightObs = values.FirstOrDefault(o => o.Name == "Weight_Current");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
weightObs = (PatientObservation)obs;
|
||||||
|
diuresisObs = values.FirstOrDefault(o => o.Name == "Diuresis");
|
||||||
|
|
||||||
|
if (diuresisObs == null || CheckExpired(diuresisObs)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weightObs?.Value != null)
|
||||||
|
if (double.TryParse(weightObs.Value.ToString(), out var nWeight) && nWeight != 0 &&
|
||||||
|
double.TryParse(diuresisObs.Value.ToString(), out var diuresis))
|
||||||
|
{
|
||||||
|
var diruesisWeightValue = Math.Round(diuresis / nWeight, 2);
|
||||||
|
|
||||||
|
var diruesisWeight = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Diuresis_Weight",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time,
|
||||||
|
Value = diruesisWeightValue,
|
||||||
|
Units = "ml/kg"
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(diruesisWeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateAllergiesObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
|
||||||
|
var allergiesObs = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Allergies",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time,
|
||||||
|
MessageTime = pobs.MessageTime
|
||||||
|
};
|
||||||
|
|
||||||
|
var patientAllergiesValues =
|
||||||
|
new List<PatientAllergiesValue>((IEnumerable<PatientAllergiesValue>)pobs.Value);
|
||||||
|
|
||||||
|
var allergiesValues = patientAllergiesValues.GroupBy(o => o.Type)
|
||||||
|
.Select(x =>
|
||||||
|
new PatientAllergiesValue
|
||||||
|
{
|
||||||
|
Type = x.Key,
|
||||||
|
Value = string.Join(", ", x.Select(v => v.Value)),
|
||||||
|
Notes = string.Join(", ", x.Select(n => n.Notes))
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
var farmacosType = false;
|
||||||
|
var farmacosValues = new List<string>();
|
||||||
|
var values = new List<string>();
|
||||||
|
|
||||||
|
foreach (var allergies in allergiesValues)
|
||||||
|
{
|
||||||
|
if (allergies.Value == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var type = allergies.Type?.Replace("Alergia a ", "").Replace("Alergia ", "").ToUpper();
|
||||||
|
|
||||||
|
if (type != null)
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "FÁRMACOS":
|
||||||
|
farmacosType = true;
|
||||||
|
farmacosValues.Add(allergies.Value.ToUpper());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
values.Add(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (farmacosType)
|
||||||
|
{
|
||||||
|
values.Add($"FÁRMACOS ({string.Join(", ", farmacosValues)})");
|
||||||
|
allergiesObs.Status = StatusEnum.Type.Alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
allergiesObs.Value = string.Join(", ", values);
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(allergiesObs);
|
||||||
|
}
|
||||||
|
catch (InvalidCastException)
|
||||||
|
{
|
||||||
|
_logger.LogError("CalculateAllergiesObservation {obs}", obs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateDrainagesObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var pobs = (PatientObservation)obs;
|
||||||
|
|
||||||
|
var patientDraingesValue = (PatientDrainagesValue)pobs.Value;
|
||||||
|
|
||||||
|
if (patientDraingesValue.Type == "Drenaje ventricular")
|
||||||
|
{
|
||||||
|
var dve = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "DVE",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time,
|
||||||
|
Units = obs.Units
|
||||||
|
};
|
||||||
|
|
||||||
|
var drainageHeight = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Drainage_Height",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = obs.Time
|
||||||
|
};
|
||||||
|
|
||||||
|
if (patientDraingesValue.Volume != null)
|
||||||
|
{
|
||||||
|
dve.Value = patientDraingesValue.Volume;
|
||||||
|
await _observationService.Value.InsertObservation(dve);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patientDraingesValue.Height != null)
|
||||||
|
{
|
||||||
|
drainageHeight.Value = patientDraingesValue.Height;
|
||||||
|
await _observationService.Value.InsertObservation(drainageHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateDelta_PressureObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var toSearchList = new List<string>();
|
||||||
|
|
||||||
|
PatientObservation? peep;
|
||||||
|
PatientObservation? pleateuPressure;
|
||||||
|
|
||||||
|
toSearchList.AddRange(new List<string> { "PEEP", "Pleateu_Pressure" });
|
||||||
|
|
||||||
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||||
|
var time = obs.Time;
|
||||||
|
double pleateuPressureValue = 0;
|
||||||
|
|
||||||
|
if (obs.Name == "PEEP")
|
||||||
|
{
|
||||||
|
peep = (PatientObservation)obs;
|
||||||
|
pleateuPressure = values.FirstOrDefault(o => o.Name == "Pleateu_Pressure");
|
||||||
|
|
||||||
|
if (pleateuPressure?.Time != null && time.CompareTo(pleateuPressure.Time) > 0) time = pleateuPressure.Time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pleateuPressure = (PatientObservation)obs;
|
||||||
|
peep = values.FirstOrDefault(o => o.Name == "PEEP");
|
||||||
|
|
||||||
|
if (peep?.Time != null && time.CompareTo(peep.Time) > 0) time = peep.Time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peep?.Value != null && pleateuPressure?.Value != null)
|
||||||
|
{
|
||||||
|
var peepSuccess = double.TryParse(peep.Value.ToString(), out var peepValue);
|
||||||
|
if (!peepSuccess) peepValue = 0;
|
||||||
|
|
||||||
|
if (!peepSuccess) pleateuPressureValue = 0;
|
||||||
|
|
||||||
|
var deltaPressure = Math.Round(pleateuPressureValue - peepValue, 2);
|
||||||
|
|
||||||
|
|
||||||
|
var deltaPressureObs = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Delta_Pressure",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = time,
|
||||||
|
Value = deltaPressure
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(deltaPressureObs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateDaily_BalanceObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
if (obs.Time.ToLocalTime().Hour == 8)
|
||||||
|
{
|
||||||
|
var dailyBalanceCalculated = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "Daily_Balance_Calculated",
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = DateTime.Now,
|
||||||
|
Units = obs.Units,
|
||||||
|
Value = ((PatientObservation)obs).Value
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(dailyBalanceCalculated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CheckExpired(PatientObservation obs)
|
||||||
|
{
|
||||||
|
if (obs.Expires == null) return false;
|
||||||
|
|
||||||
|
var timeExpire = obs.Time.ToLocalTime().AddSeconds(Convert.ToDouble(obs.Expires));
|
||||||
|
|
||||||
|
return DateTime.Now.CompareTo(timeExpire) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,695 @@
|
|||||||
|
using adas_core.Application.Services.Interfaces;
|
||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.AppSettings;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Customizations.HUVH.UCIA;
|
||||||
|
|
||||||
|
public class CalculatedObservations : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private const string CodingSystem = "ADAS";
|
||||||
|
private readonly List<string>? _antibioticList;
|
||||||
|
private readonly List<string>? _antidepressantsList;
|
||||||
|
private readonly List<string>? _antihypertensivesList;
|
||||||
|
private readonly List<string>? _antipsicoticList;
|
||||||
|
private readonly List<string>? _anxiolyticsList;
|
||||||
|
private readonly List<string>? _inotropicMedicines;
|
||||||
|
private readonly ILogger<CalculatedObservations> _logger;
|
||||||
|
private readonly Lazy<IMedicineService> _medicineService;
|
||||||
|
private readonly List<string>? _neuroMedicationList;
|
||||||
|
private readonly Lazy<IObservationService> _observationService;
|
||||||
|
|
||||||
|
private readonly List<string>? _sedationList;
|
||||||
|
private readonly List<string>? _serumColloidList;
|
||||||
|
private readonly List<string>? _serumCrystalloidList;
|
||||||
|
|
||||||
|
private readonly Lazy<ITreatmentService> _treatmentService;
|
||||||
|
|
||||||
|
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_treatmentService = serviceProvider.GetRequiredService<Lazy<ITreatmentService>>();
|
||||||
|
_medicineService = serviceProvider.GetRequiredService<Lazy<IMedicineService>>();
|
||||||
|
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||||
|
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||||
|
|
||||||
|
var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>(); //apiSettings;
|
||||||
|
|
||||||
|
_sedationList = apiSettings.Value.Sedation;
|
||||||
|
_inotropicMedicines = apiSettings.Value.InotropicMedicines;
|
||||||
|
_antibioticList = apiSettings.Value.AntibioticList;
|
||||||
|
_anxiolyticsList = apiSettings.Value.AnxiolyticList;
|
||||||
|
_antipsicoticList = apiSettings.Value.AntipsicoticList;
|
||||||
|
_antidepressantsList = apiSettings.Value.AntidepressantsList;
|
||||||
|
_neuroMedicationList = apiSettings.Value.NeuroMedicationList;
|
||||||
|
_serumCrystalloidList = apiSettings.Value.SerumCrystalloidList;
|
||||||
|
_serumColloidList = apiSettings.Value.SerumColloidList;
|
||||||
|
_antihypertensivesList = apiSettings.Value.AntihypertensivesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
if (obs.Name is "PSI" or "RASS" or "TS") _ = CalculateOverSedation(obs);
|
||||||
|
|
||||||
|
if (obs.Name is "Inspiratory_Pressure" or "Compliancia" or "Air_Flow") _ = CalculateVentilationMode(obs);
|
||||||
|
|
||||||
|
if (obs.Name is "ECMO_Location" or "Location_Drainage_Cannula" or "Location_Return_Cannula")
|
||||||
|
obs = (T)await CalculateEcmoLocation(obs);
|
||||||
|
|
||||||
|
if (obs.Name is "EVN" or "ANI" or "ESCID") _ = CalculateOverAnalgesia(obs);
|
||||||
|
|
||||||
|
if (obs.Name is "Pmeset" or "PEEP") _ = CalculateDrivingPressure(obs);
|
||||||
|
|
||||||
|
if (obs.Name is "SpO2_FiO2_Ratio" or "FR") _ = CalculateRoxIndex(obs);
|
||||||
|
|
||||||
|
if (obs.Name is "Diuresis") _ = CalculateDiuresis(obs);
|
||||||
|
|
||||||
|
if (obs.Name is "Rehabilitation") obs = (T)await CalculateRehabilitationAlarm(obs);
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
var order = treatment.PlacerOrder?.EntityIdentifier; //aquí almacenamos el número de orden
|
||||||
|
if (string.IsNullOrEmpty(order)) return treatment;
|
||||||
|
|
||||||
|
//comprobamos el estado de los tratamientos anteriores
|
||||||
|
var oldTreatments = await CheckExpiredPatientTreatments(treatment);
|
||||||
|
|
||||||
|
treatment.OrderControl = oldTreatments.Any() ? OrderControlType.Xo : OrderControlType.Nw;
|
||||||
|
|
||||||
|
if (treatment.EndTime != null)
|
||||||
|
//el tratamiento ha expirado
|
||||||
|
treatment.OrderControl = OrderControlType.Dc;
|
||||||
|
|
||||||
|
await CheckTreatmentMedicines(treatment);
|
||||||
|
|
||||||
|
return treatment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(pumpObservation);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
//Esto viene del schedulerService para chequear los medicamentos activos
|
||||||
|
CheckMedicationCategories(patientId, activeMedicines);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(id);
|
||||||
|
return activeTreatments;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newObservation.Name))
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
"Error FixTimeInconsistencyWithLast. Observation name is null or empty. Observation: {newObservation}",
|
||||||
|
newObservation);
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||||
|
[newObservation.Name]);
|
||||||
|
var lastObservation = lastObservations.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastObservation != null && DateTime.Compare(
|
||||||
|
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||||
|
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||||
|
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||||
|
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||||
|
newObservation.Time.Day, newObservation.Time.Hour,
|
||||||
|
newObservation.Time.Minute, newObservation.Time.Second)
|
||||||
|
) >= 0)
|
||||||
|
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||||
|
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(listToInsert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<BasePatientObservation> CalculateRehabilitationAlarm(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
//En rojo si el grado es de 0 a 2 incluidos, por más de 7 días
|
||||||
|
|
||||||
|
if (obs is not PatientObservation pobs || !int.TryParse(pobs.Value.ToString(), out var pobsValue) ||
|
||||||
|
pobsValue > 2) return obs;
|
||||||
|
|
||||||
|
var result = await _observationService.Value.FindLastObservations(obs.PatientId, 6, ["Rehabilitation"]);
|
||||||
|
|
||||||
|
var obsInAlert = result.Count(o =>
|
||||||
|
int.TryParse(o.Value.ToString(), out var oValue) && oValue is >= 0 and <= 2);
|
||||||
|
if (obsInAlert == 6) pobs.Status = StatusEnum.Type.Alert;
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateDiuresis(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
// Calculado como el sumatorio de la Diuresis de las últimas 6h
|
||||||
|
// entre el último peso medido del paciente y entre 6. Medido en ml/kg/h
|
||||||
|
// Valor = sum(Diuresis últimas 6 horas) / Weight / 6
|
||||||
|
|
||||||
|
if (obs is not PatientObservation pobs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double weightValue = 0;
|
||||||
|
var numValues = pobs.Name switch
|
||||||
|
{
|
||||||
|
"Diuresis" => 2, // Si la observación entrante es "Diuresis", necesitamos las 2 últimas para completar 6h.
|
||||||
|
"Weight" => 3, // Si la observación entrante es "Weight", necesitamos las 3 últimas de "Diuresis".
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (numValues == 0)
|
||||||
|
return; // Si no es ni Diuresis ni Weight, no aplicamos cálculo.
|
||||||
|
|
||||||
|
// Obtener las observaciones de diuresis necesarias
|
||||||
|
var diuresisObservations =
|
||||||
|
await _observationService.Value.FindLastObservations(pobs.PatientId, numValues, ["Diuresis"]);
|
||||||
|
var diuresisValues = diuresisObservations
|
||||||
|
.Select(o => double.TryParse(o.Value.ToString(), out var value) ? value : 0)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (pobs.Name == "Diuresis")
|
||||||
|
{
|
||||||
|
// Si la observación entrante es Diuresis, la agregamos
|
||||||
|
if (double.TryParse(pobs.Value.ToString(), out var currentDiuresis))
|
||||||
|
diuresisValues.Insert(0, currentDiuresis);
|
||||||
|
|
||||||
|
// Buscar el último peso registrado
|
||||||
|
var weightObservations =
|
||||||
|
await _observationService.Value.FindLastObservations(pobs.PatientId, 1, ["Weight"]);
|
||||||
|
var weightObs = weightObservations.FirstOrDefault();
|
||||||
|
if (weightObs != null && double.TryParse(weightObs.Value.ToString(), out var wObsValue))
|
||||||
|
weightValue = wObsValue;
|
||||||
|
}
|
||||||
|
else if (pobs.Name == "Weight" && double.TryParse(pobs.Value.ToString(), out var wValue))
|
||||||
|
{
|
||||||
|
// Si la observación entrante es Weight, asignamos su valor directamente.
|
||||||
|
weightValue = wValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validaciones antes de calcular
|
||||||
|
if (diuresisValues.Count < 3)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Calculated Diuresis lacks sufficient values. Required: 3, Found: {count}",
|
||||||
|
diuresisValues.Count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weightValue <= 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Calculated Diuresis aborted due to invalid weight value: {weight}", weightValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cálculo del índice de diuresis
|
||||||
|
var diuresisIndex = diuresisValues.Sum() / weightValue / 6;
|
||||||
|
|
||||||
|
var diuresisObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = pobs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = "Calculated_Diuresis",
|
||||||
|
Value = diuresisIndex
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(diuresisObs, mapObs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task CalculateRoxIndex(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
// Cálculo dividiendo el ratio SpO2/FiO2 entre la FR
|
||||||
|
// Valor = (SpO2_FiO2_Ratio) / FR
|
||||||
|
|
||||||
|
if (obs is not PatientObservation pobs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<string>? requiredObservations = pobs.Name switch
|
||||||
|
{
|
||||||
|
"SpO2_FiO2_Ratio" => ["FR"], // Si la observación actual es SpO2_FiO2_Ratio, necesitamos FR
|
||||||
|
"FR" => ["SpO2_FiO2_Ratio"], // Si la observación actual es FR, necesitamos SpO2_FiO2_Ratio
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (requiredObservations is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var result = await _observationService.Value.FindLastObservations(pobs.PatientId, 1, requiredObservations);
|
||||||
|
var targetObs = result.FirstOrDefault();
|
||||||
|
|
||||||
|
if (targetObs == null || !double.TryParse(targetObs.Value.ToString(), out var targetValue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Determinar los valores necesarios para el cálculo
|
||||||
|
var spo2FiO2Ratio = pobs.Name == "SpO2_FiO2_Ratio"
|
||||||
|
? double.TryParse(pobs.Value.ToString(), out var ratio) ? ratio : 0
|
||||||
|
: targetValue;
|
||||||
|
|
||||||
|
var fr = pobs.Name == "FR"
|
||||||
|
? double.TryParse(pobs.Value.ToString(), out var frValue) ? frValue : 0
|
||||||
|
: targetValue;
|
||||||
|
|
||||||
|
if (fr == 0) // Evita división por cero
|
||||||
|
return;
|
||||||
|
|
||||||
|
var roxIndexObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = pobs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = "Rox_Index",
|
||||||
|
Value = spo2FiO2Ratio / fr
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(roxIndexObs, mapObs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateDrivingPressure(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
//Diferencia entre la Pmeset y la PEEP
|
||||||
|
//Calculo Valor = Pmeset - PEEP
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (obs is not PatientObservation pobs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var targetObservation = pobs.Name switch
|
||||||
|
{
|
||||||
|
"Pmeset" => "PEEP",
|
||||||
|
"PEEP" => "Pmeset",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (targetObservation is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var resultList =
|
||||||
|
await _observationService.Value.FindLastObservations(obs.PatientId, 1, [targetObservation]);
|
||||||
|
var targetObs = resultList.FirstOrDefault();
|
||||||
|
if (targetObs == null || !int.TryParse(targetObs.Value.ToString(), out var targetValue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var peepValue = pobs.Name == "PEEP"
|
||||||
|
? int.TryParse(pobs.Value.ToString(), out var peep) ? peep : 0
|
||||||
|
: targetValue;
|
||||||
|
var pmesetValue = pobs.Name == "Pmeset"
|
||||||
|
? int.TryParse(pobs.Value.ToString(), out var pmeset) ? pmeset : 0
|
||||||
|
: targetValue;
|
||||||
|
|
||||||
|
var drivingPressureObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = "Driving_Pressure",
|
||||||
|
Value = pmesetValue - peepValue
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(drivingPressureObs, mapObs: false);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateOverAnalgesia(BasePatientObservation? obs, ObjectId? patientId = null)
|
||||||
|
{
|
||||||
|
// Mandar observación 'SOBREANALGESIA'
|
||||||
|
// 0 <= EVN <= 3 o ESCID = 3 o ANI > 70
|
||||||
|
// y
|
||||||
|
// Perfusiones de morfina, remifentanilo y fentanilo sostenidas > 24h.
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<string> requiredObservations = ["EVN", "ESCID", "ANI"];
|
||||||
|
|
||||||
|
// Si patientId es null, la información proviene de una observación.
|
||||||
|
// Si tiene valor, proviene de un tratamiento.
|
||||||
|
if (!patientId.HasValue)
|
||||||
|
{
|
||||||
|
if (obs is not PatientObservation pobs || !int.TryParse(pobs.Value.ToString(), out _))
|
||||||
|
return;
|
||||||
|
|
||||||
|
patientId = pobs.PatientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
var observations =
|
||||||
|
await _observationService.Value.FindLastObservations(patientId.Value, 1, requiredObservations);
|
||||||
|
|
||||||
|
// Verificar si alguna observación cumple la condición
|
||||||
|
var condition1 = observations.Any(observation =>
|
||||||
|
int.TryParse(observation.Value.ToString(), out var obsValue) && observation.Name switch
|
||||||
|
{
|
||||||
|
"EVN" when obsValue is >= 0 and <= 3 => true,
|
||||||
|
"ESCID" when obsValue == 3 => true,
|
||||||
|
"ANI" when obsValue > 70 => true,
|
||||||
|
_ => false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!condition1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Verificar tratamientos activos y umbral de analgesia
|
||||||
|
var treatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(patientId.Value);
|
||||||
|
var patientTreatments = treatments.ToList();
|
||||||
|
if (!patientTreatments.Any()) return;
|
||||||
|
|
||||||
|
var morfina =
|
||||||
|
patientTreatments.FirstOrDefault(t => t != null && t.RequestedGiveCodes.Any(c => c.Text is "Morfina"));
|
||||||
|
var remifentanilo = patientTreatments.FirstOrDefault(t =>
|
||||||
|
t != null && t.RequestedGiveCodes.Any(c => c.Text is "Remifentanilo"));
|
||||||
|
var fentanilo =
|
||||||
|
patientTreatments.FirstOrDefault(t =>
|
||||||
|
t != null && t.RequestedGiveCodes.Any(c => c.Text is "Fentanilo"));
|
||||||
|
|
||||||
|
if (morfina != null && !ExceedsAnalgesiaThreshold(morfina) &&
|
||||||
|
remifentanilo != null && !ExceedsAnalgesiaThreshold(remifentanilo) &&
|
||||||
|
fentanilo != null && !ExceedsAnalgesiaThreshold(fentanilo))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
var overAnalgesiaObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patientId.Value,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = "Over_Analgesia",
|
||||||
|
Value = bool.TrueString
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(overAnalgesiaObs, mapObs: false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error calculating Over_Analgesia. Exception: {ex}", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<BasePatientObservation> CalculateEcmoLocation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
//Las opciones pueden ser VV, VA o ECMO.
|
||||||
|
//Cuando llegue VV se muestra VV.
|
||||||
|
//Cuando llegue VA se muestra VA.
|
||||||
|
//Cuando llegue los siguientes parámetros, se debe mostrar ECMO: ECCO2r, VVDL, VA+V, VVDL+V, VV+V, VVA
|
||||||
|
if (obs is not PatientObservation pobs)
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
|
||||||
|
var ecmoValues = new List<string> { "ECCO2r", "VVDL", "VA+V", "VVDL+V", "VV+V", "VVA" };
|
||||||
|
|
||||||
|
var obsValue = pobs.Value.ToString();
|
||||||
|
|
||||||
|
if (obsValue != null && ecmoValues.Contains(obsValue)) pobs.Value = "ECMO";
|
||||||
|
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateVentilationMode(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
//- Si llega valor de PI pero NO COMPL, el tipo de ventilación es VMNI
|
||||||
|
//- Si llega valor de PS pero no llega COMPL, el tipo de ventilación es VMNI
|
||||||
|
//- Si llega COMPL, el tipo de ventilación es VMI
|
||||||
|
//- Si llega Flujo, leer el tipo de ventilación de CCC(CNAF o CTAF)
|
||||||
|
|
||||||
|
var mode = string.Empty;
|
||||||
|
|
||||||
|
switch (obs.Name)
|
||||||
|
{
|
||||||
|
case "Inspiratory_Pressure":
|
||||||
|
var complObs = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["Compliancia"]);
|
||||||
|
if (!complObs.Any())
|
||||||
|
mode = "VMNI";
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Compliancia":
|
||||||
|
mode = "VMI";
|
||||||
|
break;
|
||||||
|
case "Air_Flow":
|
||||||
|
var cccVentMode =
|
||||||
|
await _observationService.Value.FindByPatientIdAndCodingSystemAsync(obs.PatientId, "CCC",
|
||||||
|
"Ventilation_Mode");
|
||||||
|
|
||||||
|
if (!await cccVentMode.AnyAsync())
|
||||||
|
return;
|
||||||
|
mode = cccVentMode.First().Value.ToString() ?? string.Empty;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(mode)) return;
|
||||||
|
|
||||||
|
|
||||||
|
var ventilationModeObservation = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = "Ventilation_Mode",
|
||||||
|
Value = mode
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = _observationService.Value.InsertObservation(ventilationModeObservation, mapObs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateOverSedation(BasePatientObservation? obs, ObjectId? patientId = null)
|
||||||
|
{
|
||||||
|
//Mandar observación 'SOBRESEDACIÓN'
|
||||||
|
//cuando:
|
||||||
|
//(RASS =-4 o RASS =-5) y
|
||||||
|
//PSI < 25 y
|
||||||
|
//TS > 5 y
|
||||||
|
//(Propofol > 3 o Midazolam > 0,05 ó Isoflorano > 10)
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pobsName = string.Empty;
|
||||||
|
|
||||||
|
//si patientId viene null viene la observación
|
||||||
|
//Si tiene valor viene de un tratamiento
|
||||||
|
|
||||||
|
if (!patientId.HasValue)
|
||||||
|
{
|
||||||
|
if (obs is not PatientObservation pobs || !int.TryParse(pobs.Value.ToString(), out var pobsValue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
patientId = pobs.PatientId;
|
||||||
|
pobsName = pobs.Name;
|
||||||
|
|
||||||
|
switch (pobsName)
|
||||||
|
{
|
||||||
|
case "RASS" when pobsValue is not (-4 or -5):
|
||||||
|
case "PSI" when pobsValue >= 25:
|
||||||
|
case "TS" when pobsValue <= 5:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var requiredObservations = pobsName switch
|
||||||
|
{
|
||||||
|
"RASS" => ["PSI", "TS"],
|
||||||
|
"PSI" => ["RASS", "TS"],
|
||||||
|
"TS" => ["RASS", "PSI"],
|
||||||
|
_ => new List<string> { "RASS", "PSI", "TS" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await _observationService.Value.FindLastObservations(patientId.Value, 1, requiredObservations);
|
||||||
|
var observations = result.ToDictionary(r => r.Name?.ToString() ?? "null");
|
||||||
|
|
||||||
|
if ((pobsName != "RASS" && (!observations.TryGetValue("RASS", out var rassObs) ||
|
||||||
|
!int.TryParse(rassObs.Value.ToString(), out var rassValue) ||
|
||||||
|
rassValue is not (-4 or -5))) ||
|
||||||
|
(pobsName != "PSI" && (!observations.TryGetValue("PSI", out var psiObs) ||
|
||||||
|
!int.TryParse(psiObs.Value.ToString(), out var psiValue) || psiValue >= 25)) ||
|
||||||
|
(pobsName != "TS" && (!observations.TryGetValue("TS", out var tsObs) ||
|
||||||
|
!int.TryParse(tsObs.Value.ToString(), out var tsValue) || tsValue <= 5)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var treatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(patientId.Value);
|
||||||
|
if (!treatments.Any(ExceedsSedationThreshold)) return;
|
||||||
|
|
||||||
|
var overSedationObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patientId.Value,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = "Over_Sedation",
|
||||||
|
Value = bool.TrueString
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(overSedationObs, mapObs: false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("Error calculating Over_Sedation. Exception: {ex}", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ExceedsAnalgesiaThreshold(PatientTreatment? treatment)
|
||||||
|
{
|
||||||
|
// Perfusiones de morfina, remifentanilo o fentanilo sostenidas > 24 h
|
||||||
|
|
||||||
|
return treatment is { StartTime: not null } &&
|
||||||
|
treatment.StartTime.Value.AddSeconds(86400) < DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ExceedsSedationThreshold(PatientTreatment? treatment)
|
||||||
|
{
|
||||||
|
return (treatment != null &&
|
||||||
|
treatment.RequestedGiveCodes.Any(c =>
|
||||||
|
c.Text == "Propofol" && treatment.RequestedGiveAmountMinimum > 3)) ||
|
||||||
|
(treatment != null && treatment.RequestedGiveCodes.Any(c =>
|
||||||
|
c.Text == "Midazolam" && treatment.RequestedGiveAmountMinimum > 0.05)) ||
|
||||||
|
(treatment != null && treatment.RequestedGiveCodes.Any(c =>
|
||||||
|
c.Text == "Isoflorano" && treatment.RequestedGiveAmountMinimum > 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<PatientTreatment>> CheckExpiredPatientTreatments(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
//si el tratamiento ha expirado actualizamos el OrderControl a DC y devolvemos las que siguen activas
|
||||||
|
var result = new List<PatientTreatment>();
|
||||||
|
var oldTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(treatment.PatientId);
|
||||||
|
|
||||||
|
foreach (var t in oldTreatments.Where(t => t != null))
|
||||||
|
if (t is { EndTime: not null } && t.EndTime > DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
t.OrderControl = OrderControlType.Dc;
|
||||||
|
_ = _treatmentService.Value.UpdateTreatment(t);
|
||||||
|
}
|
||||||
|
else if (t != null)
|
||||||
|
{
|
||||||
|
result.Add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CheckTreatmentMedicines(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
var newMedicines = (await Task.WhenAll(treatment.RequestedGiveCodes
|
||||||
|
.Select(async code => await _medicineService.Value.GetByCode(code.Identifier))))
|
||||||
|
.Where(m => m != null)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (newMedicines.Count == 0) return;
|
||||||
|
|
||||||
|
var activeTreatments = (await GetActiveTreatmentsByPatient(treatment.PatientId)).ToList();
|
||||||
|
var activeMedicines = (await _medicineService.Value.GetMedicinesOfTreatments(activeTreatments)).ToList();
|
||||||
|
|
||||||
|
// Combina ambas listas y selecciona solo elementos únicos con el mismo nombre
|
||||||
|
var uniqueMedicines = newMedicines
|
||||||
|
.Concat(activeMedicines)
|
||||||
|
.GroupBy(m => m?.Name)
|
||||||
|
.Select(g => g.First())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// uniqueMedicines contiene la lista de medicamentos activos de un paciente
|
||||||
|
CheckMedicationCategories(treatment.PatientId, uniqueMedicines as List<Medicine>);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckMedicationCategories(ObjectId patientId, List<Medicine> uniqueMedicines)
|
||||||
|
{
|
||||||
|
var medicationCategories = new Dictionary<string, List<string>?>
|
||||||
|
{
|
||||||
|
{ "Sedation_Medication_Multivalue", _sedationList },
|
||||||
|
{ "Inotropic_Medication_Multivalue", _inotropicMedicines },
|
||||||
|
{ "Antibiotic_Medication_Multivalue", _antibioticList },
|
||||||
|
{ "Anxiolytic_Medication_Multivalue", _anxiolyticsList },
|
||||||
|
{ "Antipsychotic_Medication_Multivalue", _antipsicoticList },
|
||||||
|
{ "Antidepressants_Medication_Multivalue", _antidepressantsList },
|
||||||
|
{ "Neuro_Medication_Multivalue", _neuroMedicationList },
|
||||||
|
{ "Crystalloid_Serum_Medication_Multivalue", _serumCrystalloidList },
|
||||||
|
{ "Colloid_Serum_Medication_Multivalue", _serumColloidList },
|
||||||
|
{ "Antihypertensives_Medication_Multivalue", _antihypertensivesList }
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var category in medicationCategories)
|
||||||
|
{
|
||||||
|
var observations = uniqueMedicines?
|
||||||
|
.Where(m => category.Value != null && !string.IsNullOrEmpty(m.Name) && m.Name != null &&
|
||||||
|
category.Value.Contains(m.Name))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (observations != null && observations.Any())
|
||||||
|
_ = CreateMedicationMultivalueObservation(observations, patientId, category.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task CreateMedicationMultivalueObservation(IEnumerable<Medicine?> medications, ObjectId patientId,
|
||||||
|
string obsName)
|
||||||
|
{
|
||||||
|
var newObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patientId,
|
||||||
|
Name = obsName,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Value = medications.Select(m => m?.Name).ToArray(),
|
||||||
|
Time = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
var lastObsList = await _observationService.Value.FindLastObservations(patientId, 1, [obsName]);
|
||||||
|
var lastObs = lastObsList.FirstOrDefault();
|
||||||
|
if (lastObs is { Expired: false })
|
||||||
|
{
|
||||||
|
//expiramos la anterior
|
||||||
|
lastObs.Expired = true;
|
||||||
|
_ = _observationService.Value.UpdateObservation(lastObs);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(newObs,
|
||||||
|
mapObs: false); //mapObs:no volvemos a mapear la observación
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,711 @@
|
|||||||
|
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 adas_core.Domain.Utils;
|
||||||
|
using adas_core.Domain.Utils.Interfaces;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Customizations.HUVH.UCIN;
|
||||||
|
|
||||||
|
public class CalculatedObservations : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private const string Spo2PreObservationName = "SpO2";
|
||||||
|
private const string Spo2PostObservationName = "SpO2_Post";
|
||||||
|
|
||||||
|
private const string Spo2PrePostObservationName = "SpO2_Pre_Post";
|
||||||
|
private const string CodingSystem = "ADAS";
|
||||||
|
|
||||||
|
private readonly List<string> _complexityObservations =
|
||||||
|
[
|
||||||
|
"Respiratory_Device_Multivalue", "Intravenous_Routes_Multivalue", "Medication_Multivalue",
|
||||||
|
"System_Multivalue", "Newborn_Weight", "Surgery_Multivalue"
|
||||||
|
];
|
||||||
|
|
||||||
|
private readonly ILogger<CalculatedObservations> _logger;
|
||||||
|
private readonly IMappingUtils _mappingUtils;
|
||||||
|
private readonly Lazy<IMedicineService> _medicineService;
|
||||||
|
private readonly Lazy<IObservationService> _observationService;
|
||||||
|
|
||||||
|
private readonly Lazy<ITreatmentService> _treatmentService;
|
||||||
|
|
||||||
|
|
||||||
|
public CalculatedObservations(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_treatmentService = serviceProvider.GetRequiredService<Lazy<ITreatmentService>>();
|
||||||
|
_medicineService = serviceProvider.GetRequiredService<Lazy<IMedicineService>>();
|
||||||
|
_observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>();
|
||||||
|
_logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
|
||||||
|
|
||||||
|
var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>(); //apiSettings;
|
||||||
|
_mappingUtils = new MappingUtils(apiSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
if (obs.Name is "Intervention_In" or "Intervention_Out") await CalculateInterventionMultiValueObservation(obs);
|
||||||
|
if (obs.Name is "Surgery") await CalculateMultiValueObservation(obs);
|
||||||
|
if (obs.Name != null && _complexityObservations.Contains(obs.Name))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Mapping observation Complexity {obs}", obs);
|
||||||
|
//TODO ver si hay un máximo de puntuación por grupo de observaciones
|
||||||
|
_ = CalculateComplexity(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obs.Name is Spo2PreObservationName or Spo2PostObservationName)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Pre-post saturation observation {obs}", obs);
|
||||||
|
_ = CalculateSaturation_DiffObservation(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obs.Name is "ALPS" or "NPASS_Sedation" or "NPASS_Analgesia") _ = CalculatePainScale(obs);
|
||||||
|
|
||||||
|
|
||||||
|
if (obs.Name is "Last_Defecation") obs = (T)CalculateLastDefecationValue(obs);
|
||||||
|
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
var order = treatment.PlacerOrder?.EntityIdentifier; //aquí almacenamos el número de orden
|
||||||
|
if (string.IsNullOrEmpty(order)) return treatment;
|
||||||
|
|
||||||
|
//comprobamos el estado de los tratamientos anteriores
|
||||||
|
var oldTreatments = await CheckExpiredPatientTreatments(treatment);
|
||||||
|
|
||||||
|
treatment.OrderControl = oldTreatments.Any() ? OrderControlType.Xo : OrderControlType.Nw;
|
||||||
|
|
||||||
|
if (treatment.EndTime != null)
|
||||||
|
//el tratamiento ha expirado
|
||||||
|
treatment.OrderControl = OrderControlType.Dc;
|
||||||
|
|
||||||
|
await CheckTreatmentMedicines(treatment);
|
||||||
|
|
||||||
|
return treatment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(pumpObservation);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
var medicineObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patientId,
|
||||||
|
Name = "Medication_Multivalue",
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Value = activeMedicines.Select(m => m.Name ?? string.Empty).Distinct().ToArray(),
|
||||||
|
Time = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
var lastMedicationsObs =
|
||||||
|
await _observationService.Value.FindLastObservations(patientId, 1, ["Medication_Multivalue"]);
|
||||||
|
var lastMedicationObs = lastMedicationsObs.FirstOrDefault();
|
||||||
|
if (lastMedicationObs != null)
|
||||||
|
{
|
||||||
|
//expiramos la anterior
|
||||||
|
lastMedicationObs.Expired = true;
|
||||||
|
_ = _observationService.Value.UpdateObservation(lastMedicationObs);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _observationService.Value
|
||||||
|
.InsertObservation(
|
||||||
|
medicineObs); //mapObs:volvemos a mapear la observación para que pase por el cálculo de la complejidad
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
var activeTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(id);
|
||||||
|
return activeTreatments;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newObservation.Name))
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
"Error FixTimeInconsistencyWithLast. Observation name is null or empty. Observation: {newObservation}",
|
||||||
|
newObservation);
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1,
|
||||||
|
[newObservation.Name]);
|
||||||
|
var lastObservation = lastObservations.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastObservation != null && DateTime.Compare(
|
||||||
|
new DateTime(lastObservation.Time.Year, lastObservation.Time.Month,
|
||||||
|
lastObservation.Time.Day, lastObservation.Time.Hour,
|
||||||
|
lastObservation.Time.Minute, lastObservation.Time.Second),
|
||||||
|
new DateTime(newObservation.Time.Year, newObservation.Time.Month,
|
||||||
|
newObservation.Time.Day, newObservation.Time.Hour,
|
||||||
|
newObservation.Time.Minute, newObservation.Time.Second)
|
||||||
|
) >= 0)
|
||||||
|
newObservation.Time = lastObservation.Time.AddSeconds(1);
|
||||||
|
|
||||||
|
return newObservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(listToInsert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculatePainScale(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
if (obs is not PatientObservation pobs) return;
|
||||||
|
|
||||||
|
|
||||||
|
object valueObs;
|
||||||
|
|
||||||
|
switch (pobs.Name)
|
||||||
|
{
|
||||||
|
case "ALPS":
|
||||||
|
valueObs = pobs.Value;
|
||||||
|
break;
|
||||||
|
case "NPASS_Sedation":
|
||||||
|
{
|
||||||
|
//Buscamos la complementaria "NPASS Analgesia"
|
||||||
|
var analgesiaObs =
|
||||||
|
await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["NPASS_Analgesia"]);
|
||||||
|
var analgesiaValue = analgesiaObs.FirstOrDefault()?.Value.ToString() ?? "0";
|
||||||
|
|
||||||
|
valueObs = $"{pobs.Value}/{analgesiaValue}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "NPASS_Analgesia":
|
||||||
|
{
|
||||||
|
//Buscamos la complementaria "NPASS Sedation"
|
||||||
|
var sedationObs =
|
||||||
|
await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["NPASS_Sedation"]);
|
||||||
|
var sedationValue = sedationObs.FirstOrDefault()?.Value.ToString() ?? "0";
|
||||||
|
|
||||||
|
valueObs = $"{sedationValue}/{pobs.Value}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var painScaleObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
Name = "Pain_Scale",
|
||||||
|
Value = valueObs
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = _observationService.Value.InsertObservation(painScaleObs, mapObs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BasePatientObservation CalculateLastDefecationValue(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
if (obs is not PatientObservation pobs) return obs;
|
||||||
|
//Assign obs time to value
|
||||||
|
//Convert the UTC DateTime to local time.
|
||||||
|
var localTime = pobs.Time.ToLocalTime();
|
||||||
|
|
||||||
|
//Format the local time into a short date/time string.
|
||||||
|
pobs.Value = localTime.ToString("dd/MM/yyyy HH:mm");
|
||||||
|
|
||||||
|
return pobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task CalculateMultiValueObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
//El valor de la observación es un array de strings
|
||||||
|
if (obs is not PatientObservation pobs || string.IsNullOrEmpty(obs.Name)) return;
|
||||||
|
|
||||||
|
var newObsName = $"{obs.Name}_Multivalue";
|
||||||
|
var actualObsInBd =
|
||||||
|
await _observationService.Value.FindLastObservations(obs.PatientId, 1, [newObsName]);
|
||||||
|
|
||||||
|
|
||||||
|
var newValue = new List<string>();
|
||||||
|
|
||||||
|
if (pobs.Value is not string stringValueName) return;
|
||||||
|
|
||||||
|
|
||||||
|
if (actualObsInBd.Count > 0)
|
||||||
|
if (actualObsInBd.First().Value is string[] oldValue)
|
||||||
|
{
|
||||||
|
oldValue = oldValue.Where(x => x != stringValueName).ToArray();
|
||||||
|
newValue.AddRange(oldValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
newValue.Add(stringValueName);
|
||||||
|
|
||||||
|
if (newValue.Count == 0) return;
|
||||||
|
|
||||||
|
//Expiramos la anterior
|
||||||
|
var actualObs = actualObsInBd.FirstOrDefault();
|
||||||
|
if (actualObs != null)
|
||||||
|
{
|
||||||
|
actualObs.Expired = true;
|
||||||
|
|
||||||
|
await _observationService.Value.UpdateObservation(actualObs);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newObservation = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = newObsName,
|
||||||
|
Value = newValue.ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogDebug(
|
||||||
|
"Calculate {name}_Multivalue {outpatient} Insert Calculated {time} value {value}",
|
||||||
|
newObsName, newObservation.PatientId, newObservation.Time,
|
||||||
|
newObservation.Value.ToJson());
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(newObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CalculateInterventionMultiValueObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
if (obs is not PatientObservation pobs || string.IsNullOrEmpty(obs.Name) ||
|
||||||
|
pobs.Value is not string valueObs) return;
|
||||||
|
|
||||||
|
if (!GetInterventionValue(valueObs, out var r) || r == null) return;
|
||||||
|
|
||||||
|
var obsType = r.Value.type; //"Intravenous_Routes";
|
||||||
|
var obsGroup = r.Value.Name; // "Vía arterial";
|
||||||
|
var newObsName = $"{obsType}_Multivalue";
|
||||||
|
|
||||||
|
// Obtener la última observación multivalue
|
||||||
|
var result = await _observationService.Value.FindLastObservations(obs.PatientId, 1, [newObsName]);
|
||||||
|
var actualMultiValueObsInDb = result.FirstOrDefault(o => !o.Expired);
|
||||||
|
|
||||||
|
var oldValue = actualMultiValueObsInDb?.Value as string[] ?? [];
|
||||||
|
var newValue = new List<string>(oldValue);
|
||||||
|
|
||||||
|
if (obs.Name.Contains("_In"))
|
||||||
|
{
|
||||||
|
//Por seguridad solo tomamos el último valor que nos llega
|
||||||
|
//Puede ser que no se acuerden de cancelar el anterior antes de añadir un nuevo dispositivo y no puede haber dos dispositivos del mismo tipo activos al mismo tiempo
|
||||||
|
if (obsType == "Respiratory_Device")
|
||||||
|
newValue.Clear();
|
||||||
|
|
||||||
|
// Inserción dispositivo
|
||||||
|
if (!oldValue.Contains(obsGroup))
|
||||||
|
newValue.Add(obsGroup);
|
||||||
|
}
|
||||||
|
else if (obs.Name.Contains("_Out"))
|
||||||
|
{
|
||||||
|
// Retirada del dispositivo
|
||||||
|
//Buscamos la inserción
|
||||||
|
var name = $"{obs.Name.Split('_')[0]}_In";
|
||||||
|
var inObs = await _observationService.Value.FindLastNotExpiredObservatonsByPatient(obs.PatientId, name);
|
||||||
|
|
||||||
|
var sameValueObs = inObs.Where(o => o.Value == pobs.Value).ToList();
|
||||||
|
|
||||||
|
if (sameValueObs.Any())
|
||||||
|
// Si hay más de una observación del mismo tipo, no eliminar del multivalue
|
||||||
|
if (sameValueObs.Count > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Actualizar valor eliminando el grupo
|
||||||
|
newValue.Remove(obsGroup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Expiramos la anterior
|
||||||
|
if (actualMultiValueObsInDb is { Expired: false })
|
||||||
|
{
|
||||||
|
actualMultiValueObsInDb.Expired = true;
|
||||||
|
await _observationService.Value.UpdateObservation(actualMultiValueObsInDb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no hay valores nuevos, no se crea una nueva observación
|
||||||
|
if (!newValue.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
// Crear y registrar nueva observación
|
||||||
|
var newObservation = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = newObsName,
|
||||||
|
Value = newValue.ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogDebug(
|
||||||
|
"Calculate {name}_Multivalue {patientid} Insert Calculated {time} value {value}",
|
||||||
|
newObsName, newObservation.PatientId, newObservation.Time,
|
||||||
|
newObservation.Value.ToJson()
|
||||||
|
);
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(newObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GetInterventionValue(string valueObs, out (string type, string Name, string Group)? r)
|
||||||
|
{
|
||||||
|
var code = valueObs.Split(" ")[0]; //
|
||||||
|
if (code.EndsWith(".")) // Verifica si termina con un punto
|
||||||
|
code = code.Substring(0, code.Length - 1).Replace('.', ','); // Remueve el último carácter
|
||||||
|
|
||||||
|
if (!double.TryParse(code, out var codeParsed))
|
||||||
|
{
|
||||||
|
r = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
r = _mappingUtils.SearchByCode(codeParsed, "Intervention"); //TODO validar este parámetro con Lola
|
||||||
|
|
||||||
|
return r != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculamos la complejidad basándonos en el valor de Respiratorio/Vías/Medicación/Sistemas/Peso nacimiento/cirugía
|
||||||
|
* 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
|
||||||
|
* Valor máximo 46 Guardamos la observación que nos llega y recalculamos complejidad.
|
||||||
|
*/
|
||||||
|
private async Task CalculateComplexity(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var pobs = obs as PatientObservation;
|
||||||
|
if (pobs == null) return;
|
||||||
|
|
||||||
|
var complexity = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Name = "Complexity",
|
||||||
|
Value = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
var complexityValue = 0;
|
||||||
|
|
||||||
|
// Diccionario para manejar las operaciones basadas en el nombre de la observación
|
||||||
|
var operations = new Dictionary<string, Func<ObjectId, PatientObservation?, Task<int>>>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"Respiratory_Device_Multivalue",
|
||||||
|
(patientId, observation) =>
|
||||||
|
CalculateMultivalueObservationComplexityValue(patientId, "Respiratory_Device_Multivalue",
|
||||||
|
observation)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Intravenous_Routes_Multivalue",
|
||||||
|
(patientId, observation) =>
|
||||||
|
CalculateMultivalueObservationComplexityValue(patientId, "Intravenous_Routes_Multivalue",
|
||||||
|
observation)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Medication_Multivalue",
|
||||||
|
(patientId, observation) =>
|
||||||
|
CalculateMultivalueObservationComplexityValue(patientId, "Medication_Multivalue", observation)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"System_Multivalue",
|
||||||
|
(patientId, observation) =>
|
||||||
|
CalculateMultivalueObservationComplexityValue(patientId, "System_Multivalue", observation)
|
||||||
|
},
|
||||||
|
{ "Newborn_Weight", CalculateWeightNewBornValue },
|
||||||
|
{
|
||||||
|
"Surgery_Multivalue",
|
||||||
|
(patientId, observation) =>
|
||||||
|
CalculateMultivalueObservationComplexityValue(patientId, "Surgery_Multivalue", observation)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Realizar cálculos iterando sobre las operaciones
|
||||||
|
foreach (var operation in operations)
|
||||||
|
complexityValue += await operation.Value(pobs.PatientId, operation.Key.Equals(pobs.Name) ? pobs : null);
|
||||||
|
|
||||||
|
complexity.Value = Math.Min(complexityValue, 46); // Limitar el valor máximo a 46
|
||||||
|
|
||||||
|
_logger.LogDebug(
|
||||||
|
"complexity for patient {patientid} => inserting complexity value: {complexityValue} for patient: {complexityPatientid} at time {fixedTimeComplexityTime}",
|
||||||
|
complexity.PatientId, complexity.Value, complexity.PatientId, complexity.Time);
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(complexity, mapObs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<int> CalculateMultivalueObservationComplexityValue(ObjectId patientId, string observationName,
|
||||||
|
PatientObservation? observation = null)
|
||||||
|
{
|
||||||
|
var result =
|
||||||
|
await _observationService.Value.FindLastObservations(patientId, 1, [observationName]);
|
||||||
|
var actualObsInBd = result.FirstOrDefault();
|
||||||
|
|
||||||
|
var valueObj = observation == null ? actualObsInBd?.Value : observation.Value;
|
||||||
|
var valueList = valueObj as string[];
|
||||||
|
|
||||||
|
var valueToReturn = valueList?.Sum(v => _mappingUtils.GetComplexityValue(v)) ?? 0;
|
||||||
|
|
||||||
|
_logger.LogDebug(
|
||||||
|
"complexity for patient {patientid} => observation: {observationName} plus complexity: {Value}", patientId,
|
||||||
|
observationName, valueToReturn);
|
||||||
|
|
||||||
|
return valueToReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<int> CalculateWeightNewBornValue(ObjectId patientId, PatientObservation? pobs = null)
|
||||||
|
{
|
||||||
|
var result =
|
||||||
|
await _observationService.Value.FindLastObservations(patientId, 1, ["Newborn_Weight"]);
|
||||||
|
var actualObsInBd = result.FirstOrDefault();
|
||||||
|
|
||||||
|
string? strValue;
|
||||||
|
string? obsName;
|
||||||
|
if (pobs == null)
|
||||||
|
{
|
||||||
|
if (actualObsInBd?.Value == null) return 0;
|
||||||
|
|
||||||
|
strValue = actualObsInBd.Value.ToString();
|
||||||
|
obsName = actualObsInBd.Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pobs.Units == "kg") pobs = ParseWeight(pobs);
|
||||||
|
|
||||||
|
strValue = pobs.Value.ToString();
|
||||||
|
obsName = pobs.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.TryParse(strValue, out var valueParsed) || obsName == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var weightNewBornValue = _mappingUtils.GetComplexityValue(obsName, valueParsed);
|
||||||
|
|
||||||
|
|
||||||
|
_logger.LogDebug(
|
||||||
|
"complexity for patient {patientid} => Weight_Newborn plus complexity: {Weight_NewbornValue}",
|
||||||
|
patientId, weightNewBornValue);
|
||||||
|
|
||||||
|
return weightNewBornValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PatientObservation ParseWeight(PatientObservation obs)
|
||||||
|
{
|
||||||
|
if (!double.TryParse(obs.Value.ToString(), out var dValue))
|
||||||
|
{
|
||||||
|
_logger.LogError("Error casting weight Observation {obs}:", obs);
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs.Units = "gr";
|
||||||
|
obs.Value = dValue * 1000;
|
||||||
|
return obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task CalculateSaturation_DiffObservation(BasePatientObservation obs)
|
||||||
|
{
|
||||||
|
var toSearchList = new List<string>();
|
||||||
|
PatientObservation? pre;
|
||||||
|
PatientObservation? post;
|
||||||
|
|
||||||
|
toSearchList.AddRange(new List<string> { Spo2PreObservationName, Spo2PostObservationName });
|
||||||
|
|
||||||
|
var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList);
|
||||||
|
var time = obs.Time;
|
||||||
|
|
||||||
|
if (obs.Name == Spo2PreObservationName)
|
||||||
|
{
|
||||||
|
pre = (PatientObservation)obs;
|
||||||
|
post = values.FirstOrDefault(o => o.Name == Spo2PostObservationName);
|
||||||
|
|
||||||
|
if (post?.Time != null && time.CompareTo(post.Time) > 0) time = post.Time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
post = (PatientObservation)obs;
|
||||||
|
pre = values.FirstOrDefault(o => o.Name == Spo2PreObservationName);
|
||||||
|
|
||||||
|
if (pre?.Time != null && time.CompareTo(pre.Time) > 0) time = pre.Time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pre?.Value != null && post?.Value != null)
|
||||||
|
{
|
||||||
|
var preSuccess = double.TryParse(pre.Value.ToString(), out var preValue);
|
||||||
|
if (!preSuccess) preValue = 0;
|
||||||
|
var postSuccess = double.TryParse(post.Value.ToString(), out var postValue);
|
||||||
|
if (!postSuccess) postValue = 0;
|
||||||
|
|
||||||
|
var saturationDiff = Math.Round(preValue - postValue, 2);
|
||||||
|
|
||||||
|
var saturationDiffObs = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "SpO2_Diff",
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = time,
|
||||||
|
Value = saturationDiff
|
||||||
|
};
|
||||||
|
var saturationPrePost = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = Spo2PrePostObservationName,
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
PatientId = obs.PatientId,
|
||||||
|
Time = time,
|
||||||
|
Value = pre.Value + "/" + post.Value
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(saturationDiffObs);
|
||||||
|
await _observationService.Value.InsertObservation(saturationPrePost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<PatientTreatment>> CheckExpiredPatientTreatments(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
//si el tratamiento ha expirado actualizamos el OrderControl a DC y devolvemos las que siguen activas
|
||||||
|
var result = new List<PatientTreatment>();
|
||||||
|
var oldTreatments = await _treatmentService.Value.GetActiveTreatmentsByPatient(treatment.PatientId);
|
||||||
|
|
||||||
|
foreach (var t in oldTreatments)
|
||||||
|
{
|
||||||
|
if (t == null) continue;
|
||||||
|
|
||||||
|
if (t.PlacerOrder?.EntityIdentifier == treatment.PlacerOrder?.EntityIdentifier)
|
||||||
|
{
|
||||||
|
//Es el mismo tratamiento actualizamos
|
||||||
|
|
||||||
|
if (t.EndTime != null && t.EndTime > DateTime.UtcNow) treatment.OrderControl = OrderControlType.Dc;
|
||||||
|
|
||||||
|
treatment.Id = t.Id; //Asignamos el ID del tratamiento existente para actualizarlo
|
||||||
|
_ = _treatmentService.Value.UpdateTreatment(treatment);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CheckTreatmentMedicines(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
var newMedicines = new List<Medicine>();
|
||||||
|
var hasVasoactives = false;
|
||||||
|
foreach (var code in treatment.RequestedGiveCodes)
|
||||||
|
{
|
||||||
|
var m = await _medicineService.Value.GetByCode(code.Identifier);
|
||||||
|
if (m == null) continue;
|
||||||
|
|
||||||
|
//Si el código es de tipo nutrición entonces creamos una observación de ese tipo que tendrá el valor mapeado con el nombre correspondiente
|
||||||
|
//CreateNutritionObservation y NO agregamos a medicamentos
|
||||||
|
var r = _mappingUtils.SearchByCode(m.Codes.First(), "Treatment");
|
||||||
|
if (r is { type: "Nutrition" })
|
||||||
|
{
|
||||||
|
await CreateNutritionObservation(r.Value.group, treatment.PatientId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r is { type: "Medication", group: "Drogas vasoactivas" })
|
||||||
|
hasVasoactives = true;
|
||||||
|
|
||||||
|
newMedicines.Add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasVasoactives)
|
||||||
|
{
|
||||||
|
var vObs = new PatientObservation
|
||||||
|
{
|
||||||
|
Name = "HasVasoactive",
|
||||||
|
Value = true,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
CodingSystem = CodingSystem
|
||||||
|
};
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(vObs, mapObs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newMedicines.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var _ = await GetActiveTreatmentsByPatient(treatment.PatientId);
|
||||||
|
|
||||||
|
var activeTreatments = _.ToList();
|
||||||
|
|
||||||
|
var __ = await _medicineService.Value.GetMedicinesOfTreatments(activeTreatments); //Todo revisar
|
||||||
|
var activeMedicines = __.ToList();
|
||||||
|
|
||||||
|
// Combina ambas listas y selecciona solo elementos únicos con el mismo nombre
|
||||||
|
var uniqueMedicines = newMedicines
|
||||||
|
.Concat(activeMedicines)
|
||||||
|
.GroupBy(m => m.Name)
|
||||||
|
.Select(g => g.First())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
await CalculateMedicineObservation(uniqueMedicines, treatment.PatientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CreateNutritionObservation(string value, ObjectId patientId)
|
||||||
|
{
|
||||||
|
var nutritionObs = new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patientId,
|
||||||
|
Name = "Feeding_Type",
|
||||||
|
CodingSystem = CodingSystem,
|
||||||
|
Value = value,
|
||||||
|
Time = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
if (value.ToLower().Contains("parenteral"))
|
||||||
|
{
|
||||||
|
nutritionObs.Name = "Parenteral";
|
||||||
|
nutritionObs.Value = "SI";
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastNutritionObsList =
|
||||||
|
await _observationService.Value.FindLastObservations(patientId, 1, [nutritionObs.Name]);
|
||||||
|
var lastNutritionObs = lastNutritionObsList.FirstOrDefault();
|
||||||
|
if (lastNutritionObs is { Expired: false })
|
||||||
|
{
|
||||||
|
//expiramos la anterior
|
||||||
|
lastNutritionObs.Expired = true;
|
||||||
|
_ = _observationService.Value.UpdateObservation(lastNutritionObs);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _observationService.Value.InsertObservation(nutritionObs);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using adas_core.Application.Services.Interfaces;
|
||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Customizations.NursePlan;
|
||||||
|
|
||||||
|
public class CalculatedObservations(IServiceProvider serviceProvider) : ICalculatedObservations
|
||||||
|
{
|
||||||
|
private readonly Lazy<IObservationService> _observationService =
|
||||||
|
new(serviceProvider.GetRequiredService<IObservationService>);
|
||||||
|
|
||||||
|
public Task CalculateActiveBolus(ObjectId patientId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PumpObservation> Map(PumpObservation pumpObservation)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(pumpObservation);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
|
||||||
|
{
|
||||||
|
return Task.FromResult(obs)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientTreatment> Map(PatientTreatment treatment)
|
||||||
|
{
|
||||||
|
return Task.FromResult(treatment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
|
||||||
|
{
|
||||||
|
return Task.FromResult(diagnosis);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
|
||||||
|
{
|
||||||
|
return Task.FromResult(listToInsert);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class ApiRequestException(string message) : Exception($"Api request exception: {message}");
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class BadRequestException : Exception
|
||||||
|
{
|
||||||
|
public BadRequestException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadRequestException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class ConflictException : Exception
|
||||||
|
{
|
||||||
|
public ConflictException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConflictException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class CustomArgumentException : Exception
|
||||||
|
{
|
||||||
|
public CustomArgumentException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomArgumentException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class ForbbidenException : Exception
|
||||||
|
{
|
||||||
|
public ForbbidenException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForbbidenException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class InvalidFormatException : Exception
|
||||||
|
{
|
||||||
|
public InvalidFormatException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidFormatException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class NotFoundException : Exception
|
||||||
|
{
|
||||||
|
public NotFoundException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotFoundException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotFoundException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class TokenException(string message) : Exception(message);
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class UnauthorizedException : Exception
|
||||||
|
{
|
||||||
|
public UnauthorizedException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnauthorizedException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Exceptions;
|
||||||
|
|
||||||
|
public class UnprocessableEntityException : Exception
|
||||||
|
{
|
||||||
|
public UnprocessableEntityException(HttpEnum.ErrorMessage message) : base(((int)message).ToString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnprocessableEntityException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using adas_core.Domain.Models.Providers;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Providers;
|
||||||
|
|
||||||
|
public class AdasProvider(IOptions<ProvidersSettings> providerSettings, IHttpClientFactory httpClientFactory)
|
||||||
|
: BaseProvider(providerSettings, httpClientFactory)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Get observations of:
|
||||||
|
* Predict of UCI stay duration
|
||||||
|
* Predict of medications for patients
|
||||||
|
*/
|
||||||
|
public override async Task<List<PatientObservation>> GetObservations(Patient patient)
|
||||||
|
{
|
||||||
|
var calculatedObservations = new List<PatientObservation>();
|
||||||
|
|
||||||
|
//get data from two endpoints one from UCI stay another for medication
|
||||||
|
var predictOfStay = await GetPredictOfStay(patient.PatientNumber);
|
||||||
|
|
||||||
|
if (predictOfStay == null || predictOfStay.Result.ToLower().Contains("error"))
|
||||||
|
Log.Error("Error retrieving predict of stay in ADAS result, message: {predictOfStay}", predictOfStay);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var durationPredicted1 = predictOfStay.Payload.MaxBy(i => i.PercentageMin)!.Duration;
|
||||||
|
var durationPredicted2 = predictOfStay.Payload.MinBy(i => i.PercentageMin)!.Duration;
|
||||||
|
|
||||||
|
calculatedObservations.Add(
|
||||||
|
new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patient.Id,
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
Name = "Stay_Predict_Days_Most_Confident",
|
||||||
|
//get the most confident interval to show the most probable scenario
|
||||||
|
Value = durationPredicted1,
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
|
||||||
|
calculatedObservations.Add(new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patient.Id,
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
Name = "Stay_Predict_Days_Less_Confident",
|
||||||
|
//get the less confident interval to show the less probable scenario
|
||||||
|
Value = durationPredicted2,
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var predictMedication = await GetPredictMedications(patient.PatientNumber);
|
||||||
|
|
||||||
|
|
||||||
|
if (predictMedication != null && predictMedication.Any())
|
||||||
|
calculatedObservations.Add(new PatientObservation
|
||||||
|
{
|
||||||
|
PatientId = patient.Id,
|
||||||
|
CodingSystem = "ADAS",
|
||||||
|
Name = "Medication_Predict",
|
||||||
|
Value = ParseAdasMedicationsToMedicationObservation(predictMedication),
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return calculatedObservations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ParseAdasMedicationsToMedicationObservation(
|
||||||
|
List<ResultModelPredictMedicationAdas> medicationPredict)
|
||||||
|
{
|
||||||
|
return string.Join("^", medicationPredict.Take(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ResultModelPredictOfStayAdas?> GetPredictOfStay(string? patientNumber)
|
||||||
|
{
|
||||||
|
if (patientNumber == null)
|
||||||
|
{
|
||||||
|
Log.Error("Error retrieving ADAS predict of stay patient number is null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var client = GetClient();
|
||||||
|
var response = await client.GetAsync($"predictStay?patientNumber={patientNumber}");
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonConvert.DeserializeObject<ResultModelPredictOfStayAdas>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Error(
|
||||||
|
"Error retrieving calculated ADAS observation length of stay for patient: {patientNumber}, status code: {response.StatusCode} ",
|
||||||
|
patientNumber, response.StatusCode);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Exception retrieving ADAS predict of stay for patient: {patientNumber} exception: {e}",
|
||||||
|
patientNumber, e.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<ResultModelPredictMedicationAdas>?> GetPredictMedications(string? patientNumber)
|
||||||
|
{
|
||||||
|
if (patientNumber == null)
|
||||||
|
{
|
||||||
|
Log.Error("Error retrieving ADAS predict of stay for patient number is null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var client = GetClient();
|
||||||
|
|
||||||
|
var response = await client.GetAsync($"predictMedicationNeedsPharmacy?patientNumber={patientNumber}");
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonConvert.DeserializeObject<List<ResultModelPredictMedicationAdas>>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Error(
|
||||||
|
"Error retrieving calculated ADAS medicines for patient: {patientNumber}, status code: {response.StatusCode}",
|
||||||
|
patientNumber, response.StatusCode);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Exception retrieving ADAS predict medicines for patient: {patientNumber} exception: {e}",
|
||||||
|
patientNumber, e.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpClient GetClient()
|
||||||
|
{
|
||||||
|
var client = HttpClientFactory.CreateClient();
|
||||||
|
client.BaseAddress = new Uri(Url);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using adas_core.Domain.Models.Providers;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Providers;
|
||||||
|
|
||||||
|
public abstract class BaseProvider(
|
||||||
|
IOptions<ProvidersSettings> providerSettings,
|
||||||
|
IHttpClientFactory httpClientFactory)
|
||||||
|
{
|
||||||
|
protected IHttpClientFactory HttpClientFactory = httpClientFactory;
|
||||||
|
protected string Url { get; set; } = providerSettings.Value.Url;
|
||||||
|
|
||||||
|
public abstract Task<List<PatientObservation>> GetObservations(Patient patient);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.DTO;
|
||||||
|
using adas_core.Domain.Models.Masters;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IAdmissionRepository : IMongoRepository<Admission>
|
||||||
|
{
|
||||||
|
Task Delete(ObjectId id);
|
||||||
|
|
||||||
|
Task Update(Admission admission);
|
||||||
|
|
||||||
|
Task UpdateLocation(ObjectId id, ObjectId newLocation);
|
||||||
|
|
||||||
|
Task UpdatePatient(ObjectId id, Person patient);
|
||||||
|
|
||||||
|
Task<IEnumerable<Admission>> FindAll();
|
||||||
|
|
||||||
|
Task<Admission?> FindById(ObjectId id);
|
||||||
|
|
||||||
|
Task<Admission?> FindByNhc(string nhc);
|
||||||
|
|
||||||
|
//Task<IEnumerable<Admission>?> FindByUnit(string unit);
|
||||||
|
|
||||||
|
Task<List<Admission>> FindByLocation(PatientLocation location);
|
||||||
|
|
||||||
|
Task<IEnumerable<Admission>?> FindByOrigin(string origin);
|
||||||
|
Task<Admission?> InsertOneAsyncAndReturn(Admission origin);
|
||||||
|
Task<Admission?> SearchByPatientNumberAndDistinctUnit(string patientNumber, ObjectId unitId);
|
||||||
|
Task<List<Admission>> GetAdmissionByUnitIdWithOutPoC(ObjectId unitId);
|
||||||
|
Task<List<Admission>> FindByPointOfCareId(ObjectId pocId);
|
||||||
|
Task<List<Admission>> FindByUnitIds(List<ObjectId> unitIds);
|
||||||
|
Task<long> CountByUnitId(ObjectId unitId);
|
||||||
|
|
||||||
|
Task<IEnumerable<Admission>> UpdateMasterListOption(List<ObjectId> unitIds, UpdateOptionMasterListDto opt,
|
||||||
|
string typeName);
|
||||||
|
|
||||||
|
Task<IEnumerable<Admission>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt, string typeName);
|
||||||
|
Task<bool> DeleteAdmissionsByUnitId(ObjectId unitId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.GroupedObservations;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IAlarmRepository : IMongoRepository<PatientObservationAlarm>
|
||||||
|
{
|
||||||
|
Task<List<PatientObservationAlarm>> AggregatedPatientLastObservationsByField(ObjectId patientId,
|
||||||
|
List<Field>? filterObservations = null);
|
||||||
|
|
||||||
|
Task<List<PatientObservationAlarm>> AggregatedPatientNotExpiredObservationsByField(ObjectId patientId,
|
||||||
|
List<Field>? filterObservations, List<ConfigObservation> configAlarm);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IAppointmentArchiveRepository
|
||||||
|
{
|
||||||
|
Task InsertOneAsync(PatientAppointment patientAppointment);
|
||||||
|
Task DeleteBeforeDate(DateTime date);
|
||||||
|
Task<long> InsertBatch(IEnumerable<PatientAppointment> appointment);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IAppointmentRepository : IMongoRepository<PatientAppointment>
|
||||||
|
{
|
||||||
|
Task<List<PatientAppointment>> GetByPatient(ObjectId patientId);
|
||||||
|
|
||||||
|
new Task InsertOneAsync(PatientAppointment appointment);
|
||||||
|
Task Update(PatientAppointment appointment);
|
||||||
|
Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId);
|
||||||
|
new Task DeleteAsync(ObjectId id);
|
||||||
|
Task<IAsyncCursor<PatientAppointment>> FindByPatientIdAsync(ObjectId patientId);
|
||||||
|
Task DeleteByPatientId(ObjectId patientId);
|
||||||
|
Task<PatientAppointment?> FindByPatientAndVisitNumber(ObjectId patientId, string visitNumber);
|
||||||
|
Task<PatientAppointment?> FindByPatientAndReason(ObjectId patientId, string? appointmentReason);
|
||||||
|
Task<List<PatientAppointment>> FindByLocation(PatientLocation location);
|
||||||
|
Task<List<PatientAppointment>> FindByPoC(PointOfCare poc);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IArchivePatientCarePlanRepository : IMongoRepository<PatientCarePlan>
|
||||||
|
{
|
||||||
|
Task<List<PatientCarePlan>?> FindByPatientId(ObjectId patientId);
|
||||||
|
Task<List<PatientCarePlan>?> FindByPatientId(string patientId);
|
||||||
|
Task<List<PatientCarePlan>?> FindByPatientNumber(string patientId);
|
||||||
|
Task<List<PatientCarePlan>> FindAll();
|
||||||
|
|
||||||
|
Task<List<PatientCarePlan>?> FindByIds(ObjectId oldPatientId, string? oldPatientPatientId,
|
||||||
|
string? oldPatientPatientNumber);
|
||||||
|
|
||||||
|
Task InsertManyAsync(List<PatientCarePlan> patientCarePla);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IAuthorityRepository : IMongoRepository<Authorization>
|
||||||
|
{
|
||||||
|
public Task<Authorization> GetById(ObjectId authId);
|
||||||
|
void CreateNewAuthority(string roleName, ObjectId userId);
|
||||||
|
public Task<List<Authorization>> GetUserAuthorities(ObjectId userId);
|
||||||
|
public Task<List<Authorization>> GetAllAuthorities();
|
||||||
|
public Task<bool> DeleteAllAuthoritiesByUser(ObjectId userId);
|
||||||
|
Task<bool> DeleteAllAuthoritiesByUnit(ObjectId unitId);
|
||||||
|
Task<bool> DeleteAllAuthoritiesByDisplay(ObjectId displayId);
|
||||||
|
Task<List<Authorization>> GetByUnitId(ObjectId unitId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface ICameraRepository : IMongoRepository<Camera>
|
||||||
|
{
|
||||||
|
Task<Camera?> GetById(ObjectId cameraId);
|
||||||
|
Task<Camera?> GetByName(string name);
|
||||||
|
List<Camera> GetCameraInList(List<ObjectId> configurationRelayList);
|
||||||
|
IFindFluent<Camera, Camera> GetPaginatedCameras(PaginationFilter request);
|
||||||
|
Task<Camera?> InsertOneCamera(Camera camera);
|
||||||
|
Task<Camera?> UpdateCameraAsync(ObjectId objectId, Camera camera);
|
||||||
|
Task<List<Camera>> GetSearchByNameCameras(string textToSearch);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IConfigObservationRepository : IMongoRepository<ConfigObservation>
|
||||||
|
{
|
||||||
|
Task<ConfigObservation?> FindById(ObjectId id);
|
||||||
|
|
||||||
|
Task<ConfigObservation?> Update(ConfigObservation configObservation);
|
||||||
|
|
||||||
|
Task<ConfigObservation?> Delete(ObjectId id);
|
||||||
|
|
||||||
|
Task<List<ObjectId>> FindAllIds();
|
||||||
|
|
||||||
|
Task<ICollection<ConfigObservation>> FindAll();
|
||||||
|
|
||||||
|
Task<List<string>> GetConfigNames(string id);
|
||||||
|
Task<List<string>> GetConfigNames();
|
||||||
|
Task<long> Count();
|
||||||
|
Task<ICollection<ConfigObservation>> GetPaginatedItems(PaginationFilter filter);
|
||||||
|
Task<ConfigObservation?> FindByName(string name);
|
||||||
|
Task<ConfigObservation?> GetByCodeSysAndCode(string? codingSystem, string? code);
|
||||||
|
Task<ConfigObservation> InsertOneAsyncAndReturn(ConfigObservation configObservationItem);
|
||||||
|
Task<List<ConfigObservation>> FindAllByName(string name);
|
||||||
|
|
||||||
|
Task<ConfigObservation?> GetSingleConfigObservationItem(string? code, string? codingSystem, string? name,
|
||||||
|
string? originalName);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IConfigPumpsRepository : IMongoRepository<ConfigPumps>
|
||||||
|
{
|
||||||
|
Task<ConfigPumps?> FindById(string id);
|
||||||
|
Task<List<ConfigPumps>?> GetAllConfigs();
|
||||||
|
|
||||||
|
Task<ConfigPumps?> UpdateConfig(ConfigPumps config);
|
||||||
|
Task<bool> DeleteConfig(ConfigPumps config);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IConfigUnitsRepository : IMongoRepository<ConfigUnits>
|
||||||
|
{
|
||||||
|
Task<ConfigUnits?> FindById(string id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Models.DTO;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDeviceRepository : IMongoRepository<Device>
|
||||||
|
{
|
||||||
|
Task<Device?> FindByMacAddr(string deviceDtoMacAddr);
|
||||||
|
Task<Device?> FindBySerialNumber(string deviceDtoSerialNumber);
|
||||||
|
Task<Device?> FindByUuid(string deviceDtoUuid);
|
||||||
|
Task<Device?> FindByKey(string deviceDtoKey);
|
||||||
|
Task UpdateDeviceStats(ObjectId id,DeviceDto deviceExist);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDiagnosisArchiveRepository
|
||||||
|
{
|
||||||
|
Task InsertOneAsync(PatientDiagnosis patientDiagnosis);
|
||||||
|
Task DeleteBeforeDate(DateTime date);
|
||||||
|
Task<long> InsertBatch(IEnumerable<PatientDiagnosis> diagnosis);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDiagnosisRepository : IMongoRepository<PatientDiagnosis>
|
||||||
|
{
|
||||||
|
Task<List<PatientDiagnosis>> GetByPatient(ObjectId patientId);
|
||||||
|
|
||||||
|
new Task InsertOneAsync(PatientDiagnosis diagnosis);
|
||||||
|
new Task DeleteAsync(ObjectId id);
|
||||||
|
Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId);
|
||||||
|
Task<IAsyncCursor<PatientDiagnosis>> FindByPatientIdAsync(ObjectId patientId);
|
||||||
|
Task DeleteByPatientId(ObjectId patientId);
|
||||||
|
Task<PatientDiagnosis?> FindByPatientIdAndCode(ObjectId patientId, string? diagnosisCode, string? codingSystem);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.DTO;
|
||||||
|
using adas_core.Domain.Models.Masters;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDischargeRepository : IMongoRepository<Discharge>
|
||||||
|
{
|
||||||
|
Task Delete(ObjectId id);
|
||||||
|
|
||||||
|
Task Update(Discharge discharge);
|
||||||
|
|
||||||
|
Task UpdateUnit(ObjectId id, string unit);
|
||||||
|
|
||||||
|
Task UpdatePatient(ObjectId id, Patient patient);
|
||||||
|
|
||||||
|
Task<IEnumerable<Discharge>> FindAll();
|
||||||
|
|
||||||
|
Task<Discharge?> FindById(ObjectId id);
|
||||||
|
|
||||||
|
Task<IEnumerable<Discharge>?> FindByUnit(string unit);
|
||||||
|
|
||||||
|
Task<long> CountByUnitId(ObjectId unitId);
|
||||||
|
|
||||||
|
Task<IEnumerable<Discharge>?> FindByDestination(string destination);
|
||||||
|
|
||||||
|
Task<IEnumerable<Discharge>?> FindByService(string service);
|
||||||
|
Task<IEnumerable<Discharge>?> GetDischargesByUnitIds(IEnumerable<ObjectId>? unitIds);
|
||||||
|
|
||||||
|
|
||||||
|
Task<Discharge?> GetDischargeByLocation(PatientLocation location);
|
||||||
|
Task<Discharge?> GetByPatientId(ObjectId patientId);
|
||||||
|
|
||||||
|
Task<IEnumerable<Discharge>?> FindByPoCId(ObjectId pocId);
|
||||||
|
Task<Discharge?> GetDischargeByPointOfCareId(ObjectId poc);
|
||||||
|
|
||||||
|
Task<IEnumerable<Discharge>> UpdateMasterListOption(List<ObjectId> unitIds, UpdateOptionMasterListDto opt,
|
||||||
|
string typeName);
|
||||||
|
|
||||||
|
Task<IEnumerable<Discharge>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt, string typeName);
|
||||||
|
Task<bool> DeleteByUnitId(ObjectId unitId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using adas_core.Domain.Models.Responses;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDisplayCardConfigRepository : IMongoRepository<CardConfig>
|
||||||
|
{
|
||||||
|
Task<List<CardConfig>> GetAll();
|
||||||
|
Task<CardConfig?> GetById(ObjectId configId);
|
||||||
|
Task<CardConfig?> InsertOneAsyncAndReturn(CardConfig config);
|
||||||
|
Task<UpdateResponse<CardConfig?>> UpdateOne(CardConfig? config);
|
||||||
|
Task<CardConfig?> DeleteOne(ObjectId configId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using adas_core.Domain.Models.Responses;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDisplayChartConfigRepository : IMongoRepository<ChartConfig>
|
||||||
|
{
|
||||||
|
Task<List<ChartConfig>> GetAll();
|
||||||
|
Task<ChartConfig?> GetById(ObjectId configId);
|
||||||
|
Task<ChartConfig?> InsertOneAsyncAndReturn(ChartConfig config);
|
||||||
|
Task<UpdateResponse<ChartConfig?>> UpdateOne(ChartConfig? config);
|
||||||
|
Task<ChartConfig?> DeleteOne(ObjectId configId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models.DTO.Display;
|
||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.GroupedObservations;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using adas_core.Domain.Models.Responses;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDisplayConfigRepository : IMongoRepository<DisplayConfig>
|
||||||
|
{
|
||||||
|
Task<List<DisplayConfig>> GetAll();
|
||||||
|
IFindFluent<DisplayConfig, DisplayConfigSummary> GetAllPaginated(PaginationFilter request);
|
||||||
|
Task<List<DisplayConfig>> GetByType(DisplayConfigEnums.DisplayType type);
|
||||||
|
Task<DisplayConfig?> GetById(ObjectId id);
|
||||||
|
Task<DisplayConfig?> GetDefault(DisplayConfigEnums.DisplayType type);
|
||||||
|
Task<DisplayConfig?> InsertOneAsyncAndReturn(DisplayConfig config);
|
||||||
|
Task<SmartDisplay?> UpdateSmartDisplay(ObjectId displayConfigId, SmartDisplay? newDisplayConfig);
|
||||||
|
|
||||||
|
Task<DisplayNurse?> UpdateDisplayNurse(ObjectId displayConfigId, DisplayNurseDto? newDisplayConfig,
|
||||||
|
List<string> nurseObs);
|
||||||
|
|
||||||
|
Task<DisplayConfig?> GetDefaultByUnitIdAndType(ObjectId unitId, DisplayConfigEnums.DisplayType displayType);
|
||||||
|
Task<bool> UpdateConfigColor(ObjectId objectIdConfigDisplay, ColorConfig colorConfig);
|
||||||
|
Task<bool> UpdateSetHomeBanner(ObjectId objectIdConfigDisplay, List<BannerItem> bannerItems);
|
||||||
|
Task<bool> UpdateBaseConfig(ObjectId objectIdConfigDisplay, DisplayConfig baseConfig);
|
||||||
|
Task<bool> UpdateHeaderConfig(ObjectId objectIdConfigDisplay, HeaderConfig headerConfig);
|
||||||
|
Task<bool> UpdateDisplayConfigHospitalName(ObjectId objectIdConfigDisplay, string name);
|
||||||
|
Task<bool> UpdateFieldList(ObjectId objectIdConfigDisplay, List<Field> fields);
|
||||||
|
Task<DisplayConfig?> DeleteDisplayConfig(ObjectId objectIdConfigDisplay);
|
||||||
|
Task<List<DisplayConfigMinimalResponse>> GetAllCompact();
|
||||||
|
Task<List<ObjectId>> GetAllByCardConfigId(ObjectId cardConfigId);
|
||||||
|
Task<List<ObjectId>> GetAllByCardConfigIdAndRotating(ObjectId cardConfigId);
|
||||||
|
Task<bool> UpdateCardConfigId(ObjectId? displayConfigId, ObjectId? resultId);
|
||||||
|
Task<bool> AddChartId(ObjectId? displayConfigId, ObjectId newChartIdToAdd);
|
||||||
|
Task<UpdateResult> UpdateDeletedChartConfig(ObjectId deletedId);
|
||||||
|
Task<ChartConfig> GetChartConfig(ObjectId objectIdConfigChart);
|
||||||
|
Task<bool> UpdateDetailConfigId(ObjectId? displayConfigId, ObjectId? resultId);
|
||||||
|
Task<List<ObjectId>> GetAllByCardDetailConfigId(ObjectId baseConfigId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using adas_core.Domain.Models.Responses;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDisplayDetailConfigRepository : IMongoRepository<CardDetailsConfig>
|
||||||
|
{
|
||||||
|
Task<List<CardDetailsConfig>> GetAll();
|
||||||
|
Task<CardDetailsConfig?> GetById(ObjectId configId);
|
||||||
|
Task<CardDetailsConfig?> InsertOneAsyncAndReturn(CardDetailsConfig config);
|
||||||
|
Task<UpdateResponse<CardDetailsConfig?>> UpdateOne(CardDetailsConfig? config);
|
||||||
|
Task<CardDetailsConfig?> DeleteOne(ObjectId configId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IDisplayRepository : IMongoRepository<Display>
|
||||||
|
{
|
||||||
|
Task<List<Display>> GetAll();
|
||||||
|
|
||||||
|
// ¿FilterByAuthorities / FindByUser
|
||||||
|
// Delete
|
||||||
|
// FindByUnit
|
||||||
|
// UpdateConfig -> algo en específico? ¿Toda la colección?
|
||||||
|
Task<List<Display>> GetByPointOfCare(PointOfCare pointOfCare);
|
||||||
|
|
||||||
|
// Task<List<Display>> GetByUser();
|
||||||
|
Task<Display?> GetByName(string name);
|
||||||
|
Task<Display?> GetById(ObjectId id);
|
||||||
|
Task<Display?> GetByIdWithConfigDisplay(ObjectId id);
|
||||||
|
Task<List<Display>> GetByUnitId(ObjectId id);
|
||||||
|
Task<List<Display>> GetByConfigId(ObjectId id);
|
||||||
|
|
||||||
|
Task<Display?> UpdatePointOfCareList(ObjectId objectId, List<ObjectId> listPocObId);
|
||||||
|
Task<Display?> UpdateConfig(ObjectId oldDisplayId, DisplayConfig newDisplayConfigCast);
|
||||||
|
Task<Display?> UpdateConfigPreset(ObjectId objectIdDisplay, ObjectId objectIdConfigDisplay);
|
||||||
|
Task<Display> UpdateName(Display display, string name);
|
||||||
|
IFindFluent<Display, Display> GetPaginatedDisplays(PaginationFilter filter);
|
||||||
|
Task<long> IsDisplayConfigInUse(ObjectId displayConfigId);
|
||||||
|
Task<Display?> UpdateConfigId(ObjectId objectId, ObjectId displayConfigId);
|
||||||
|
Task<long> CountByUnitId(ObjectId unitId);
|
||||||
|
Task<bool> DeleteManyByUnitId(ObjectId unitId);
|
||||||
|
Task<List<Display>> GetByCardConfigId(ObjectId configId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IHistoricalConfigChangesRepository : IMongoRepository<HistoricalConfigChanges>
|
||||||
|
{
|
||||||
|
Task<HistoricalConfigChanges?> FindById(ObjectId id);
|
||||||
|
|
||||||
|
Task<HistoricalConfigChanges?> Update(HistoricalConfigChanges historicalConfigChange);
|
||||||
|
|
||||||
|
Task<HistoricalConfigChanges?> Delete(ObjectId id);
|
||||||
|
|
||||||
|
Task<List<ObjectId>> FindAllIds();
|
||||||
|
|
||||||
|
Task<ICollection<HistoricalConfigChanges>> FindAll();
|
||||||
|
new Task<HistoricalConfigChanges?> InsertOneAsync(HistoricalConfigChanges patientObservation);
|
||||||
|
|
||||||
|
Task<ICollection<HistoricalConfigChanges>> FindLastHistoricalConfigChangesByType(
|
||||||
|
DisplayConfigEnums.ConfigTypes cfgType, int num = 10);
|
||||||
|
|
||||||
|
Task<ICollection<HistoricalConfigChanges>> FindLastHistoricalConfigChangesByUser(string user,
|
||||||
|
DisplayConfigEnums.ConfigTypes? cfgType = null, int num = 10);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface ILightBeaconRepository : IMongoRepository<LightBeacon>
|
||||||
|
{
|
||||||
|
List<LightBeacon> GetLightBeaconInList(List<ObjectId> configurationRelayList);
|
||||||
|
Task<LightBeacon?> GetById(ObjectId relayId);
|
||||||
|
Task<LightBeacon?> GetByName(string name);
|
||||||
|
Task<LightBeacon?> InsertOneAsyncAndReturn(LightBeacon beacon);
|
||||||
|
IFindFluent<LightBeacon, LightBeacon> GetPaginatedRelays(PaginationFilter filter);
|
||||||
|
Task<List<LightBeacon>> GetSearchByName(string textToSearch);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using adas_core.Domain.Models.DTO;
|
||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.Masters;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IMasterListRepository<T> : IMongoRepository<T> where T : MasterList
|
||||||
|
{
|
||||||
|
Task Delete(ObjectId id);
|
||||||
|
Task Update(T list);
|
||||||
|
Task<T?> FindById(ObjectId id, LocaleEnum? locale);
|
||||||
|
Task<T?> FindById(ObjectId id);
|
||||||
|
Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId, LocaleEnum locale);
|
||||||
|
Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId);
|
||||||
|
Task<IEnumerable<T>> GetAll();
|
||||||
|
Task<IEnumerable<MasterListDto>> GetAllWithoutOptions();
|
||||||
|
Task<T?> FindByName(string name);
|
||||||
|
Task<List<OptionList>> GetMasterListByIdAndTextSearchContaining(ObjectId id, string? textSearch);
|
||||||
|
Task<OptionList?> AddOptionToMasterList(ObjectId id, FilterOptionListElement opt);
|
||||||
|
Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt, LocaleEnum locale);
|
||||||
|
Task<OptionList?> UpdateFullMasterListOption(ObjectId id, OptionList newOpt);
|
||||||
|
Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt);
|
||||||
|
Task<bool> DeleteMasterListOption(ObjectId id, ObjectId deleteOptId);
|
||||||
|
Task<UpdateMasterListDetailsDto?> UpdateOptionDetailsToMasterList(ObjectId id, UpdateMasterListDetailsDto opt);
|
||||||
|
Task<bool> UpdateMasterListName(ObjectId id, string name);
|
||||||
|
Task<bool> UpdateMasterListDescription(ObjectId id, string description);
|
||||||
|
Task<bool> RemoveMasterListOption(ObjectId id, OptionList oldOpt);
|
||||||
|
IFindFluent<T, T> GetPaginatedMasterList(PaginationFilter filter);
|
||||||
|
Task<List<OptionList>> GetPaginatedOptions(PaginationFilter filter, ObjectId listId);
|
||||||
|
Task<int> Count();
|
||||||
|
Task<List<OptionList>> GetMasterListByIdAndSearchOptions(ObjectId id, FilterOptionListElement? filterOption);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IMedicineRepository : IMongoRepository<Medicine>
|
||||||
|
{
|
||||||
|
Task<Medicine?> GetMedicine(string code);
|
||||||
|
|
||||||
|
Task<List<Medicine>> GetMedicineByCodeOrNote(List<string> codeNotes);
|
||||||
|
Task<Medicine?> GetMedicineByName(string name);
|
||||||
|
Task<List<Medicine>> GetAll();
|
||||||
|
Task<Medicine?> GetMedicineById(ObjectId medicineId);
|
||||||
|
Task<Medicine?> PostMedicine(Medicine medicine);
|
||||||
|
Task<Medicine?> UpdateMedicine(Medicine medicine);
|
||||||
|
Task DeleteMedicineById(ObjectId medicineId);
|
||||||
|
IAggregateFluent<BsonDocument> GetDistinctFieldDataQuery(string field);
|
||||||
|
|
||||||
|
IFindFluent<Medicine, Medicine> GetPaginatedMedicines(PaginationFilter filter);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IMongoRepository<T>
|
||||||
|
{
|
||||||
|
IMongoCollection<T> Collection { get; }
|
||||||
|
|
||||||
|
string GetCollectionName();
|
||||||
|
Task InsertOneAsync(T obj);
|
||||||
|
Task<T?> DeleteAsync(ObjectId id);
|
||||||
|
Task UpdateOneAsync(ObjectId id, T obj);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface INoticeRepository : IMongoRepository<Notice>
|
||||||
|
{
|
||||||
|
Task Delete(ObjectId id);
|
||||||
|
Task Update(Notice notice);
|
||||||
|
Task<IEnumerable<Notice>> FindAll();
|
||||||
|
Task<Notice?> FindById(ObjectId id);
|
||||||
|
Task<IEnumerable<Notice>?> FindByDate(DateTime date);
|
||||||
|
Task<IEnumerable<Notice>?> FindByType(string type);
|
||||||
|
Task<IEnumerable<Notice>?> FindByDisplayId(ObjectId displayId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IObservationArchiveRepository : IMongoRepository<PatientObservation>
|
||||||
|
{
|
||||||
|
new Task InsertOneAsync(PatientObservation patientObservation);
|
||||||
|
Task DeleteBeforeDate(DateTime date);
|
||||||
|
Task<long> InsertBatch(IEnumerable<PatientObservation> observations);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>> AggregatedPatientLastObservations(ObjectId patientId, int num, DateTime lastDate,
|
||||||
|
List<string> filterObservations);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>> FindAllFromPatient(ObjectId patientId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.GroupedObservations;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IObservationRepository : IMongoRepository<PatientObservation>
|
||||||
|
{
|
||||||
|
Task<List<BsonDocument>> AggregatedPatientGroupedObservations(ObjectId patientId, GroupedField groupedField);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>> AggregatedPatientLastObservations(ObjectId patientId, int num,
|
||||||
|
List<string>? filterObservations = null);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>> AggregatedPatientLastObservationsByLastDate(ObjectId patientId, int num,
|
||||||
|
DateTime lastDate, List<string>? filterObservations = null);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>> AggregatedPatientLastObservationsByField(ObjectId patientId,
|
||||||
|
List<Field>? filterObservations = null);
|
||||||
|
|
||||||
|
Task<IEnumerable<PatientObservation>> FindLastObservations(ObjectId patientId, string codingSystem, string code,
|
||||||
|
int num = 2);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>> FindLastObservationsByCodingSystem(ObjectId patientId, string codingSystem,
|
||||||
|
int num = 10);
|
||||||
|
|
||||||
|
Task<PatientObservation?> FindLastObservationBeforeDate(ObjectId patientId, string? name, DateTime date);
|
||||||
|
|
||||||
|
Task UpdateExpiredObservations(List<PatientObservation> expiredObservations);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>?> FindAnyWithSameDate(ObjectId patientId, string? name, DateTime date);
|
||||||
|
Task<List<PatientObservation>> FindAnyBeforeDate(ObjectId patientId, DateTime date);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>> FindLatestUniqueValuesByName(ObjectId patientId, string name, int? expires);
|
||||||
|
|
||||||
|
new Task InsertOneAsync(PatientObservation patientObservation);
|
||||||
|
Task DeleteByPatientId(ObjectId id);
|
||||||
|
Task<IAsyncCursor<PatientObservation>> FindByPatientIdAsync(ObjectId patientId);
|
||||||
|
|
||||||
|
Task<IAsyncCursor<PatientObservation>> FindByPatientIdAndCodingSystemAsync(ObjectId patientId, string codingSystem,
|
||||||
|
string name);
|
||||||
|
|
||||||
|
new Task DeleteAsync(ObjectId id);
|
||||||
|
Task<List<PatientObservation>> DeleteOlderDaysAsync(string name, int retentionPolicyValue);
|
||||||
|
Task<List<PatientObservation>> DeleteOlderNumberAsync(string name, int retentionPolicyValue);
|
||||||
|
Task<bool> ExistBySystemId(ObjectId patientid, string systemId);
|
||||||
|
Task<List<PatientObservation>> DeleteOlderSecondsAsync(string name, int value);
|
||||||
|
Task<List<PatientObservation?>> AggregatedPatientActiveIntravenousLinesObservations(ObjectId patientId);
|
||||||
|
Task<Dictionary<ObjectId, DateTime>> FindAllLastPatientObservationTime();
|
||||||
|
|
||||||
|
Task<PatientObservation?> FindById(ObjectId id);
|
||||||
|
|
||||||
|
Task<List<PatientObservation>?> FindByPatientId(ObjectId id);
|
||||||
|
Task Update(PatientObservation observation);
|
||||||
|
Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId);
|
||||||
|
|
||||||
|
Task<IEnumerable<PatientObservation>> FindNotExpired(List<string?>? filterObservations);
|
||||||
|
|
||||||
|
Task<IEnumerable<PatientObservation>> FindByName(string name, DateTime? date);
|
||||||
|
|
||||||
|
Task UpdateMany(IEnumerable<PatientObservation> patientObservations, UpdateDefinition<PatientObservation> update);
|
||||||
|
|
||||||
|
Task<IEnumerable<PatientObservation>> FindAll();
|
||||||
|
|
||||||
|
Task ExpireExpiredObservations(List<ConfigObservation> configObservationsToExpire);
|
||||||
|
//Task<PaginationResponse<PatientObservation>> GetPaginatedObservations(PaginationFilter filter);
|
||||||
|
|
||||||
|
IFindFluent<PatientObservation, PatientObservation> GetPaginatedObservations(PaginationFilter filter);
|
||||||
|
|
||||||
|
Task<IEnumerable<PatientObservation>> FindLastNotExpiredObservatonsByPatient(ObjectId patientId, string name,
|
||||||
|
int? endAfter = null, int? num = null);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPatientArchiveRepository : IMongoRepository<Patient>
|
||||||
|
{
|
||||||
|
Task<Patient?> FindByPatientNumber(string patientNumber);
|
||||||
|
|
||||||
|
Task<List<Patient>> FindAll();
|
||||||
|
Task<Patient?> SearchByPatientNumberAndDistinctUnit(string patientNumber, ObjectId unitId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPatientCarePlanRepository : IMongoRepository<PatientCarePlan>
|
||||||
|
{
|
||||||
|
Task<List<PatientCarePlan>> FindByPatientId(ObjectId patientId);
|
||||||
|
Task<List<PatientCarePlan>> FindByUserId(ObjectId userId);
|
||||||
|
Task<List<PatientCarePlan>> FindAll();
|
||||||
|
Task UpdateManyObjectId(string patientid, ObjectId patientId, ObjectId oldId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.DTO;
|
||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.Masters;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPatientRepository : IMongoRepository<Patient>
|
||||||
|
{
|
||||||
|
Task Delete(ObjectId id);
|
||||||
|
Task<Patient?> FindByLocation(PatientLocation location);
|
||||||
|
Task<Patient?> FindById(ObjectId id);
|
||||||
|
Task UpdateLocation(ObjectId id, PatientLocation location);
|
||||||
|
Task UpdateLocation(ObjectId id, ObjectId location);
|
||||||
|
Task UpdateAttendingDoctor(ObjectId id, Person attendingDoctor);
|
||||||
|
Task UpdatePatientData(ObjectId id, string patientNumber, Person data, bool updatePatientNumber = true);
|
||||||
|
Task Update(Patient patient);
|
||||||
|
Task<Patient?> FindByPatientNumber(string patientNumber);
|
||||||
|
Task<Patient?> FindByPatientId(string patientId);
|
||||||
|
Task<List<Patient>> FindAll();
|
||||||
|
Task<List<Patient>> FindByPointOfCare(string pointOfCare);
|
||||||
|
Task<List<Patient>> FindByPointOfCare(ObjectId pointOfCare);
|
||||||
|
Task<Patient?> FindByPointOfCareId(ObjectId pointOfCare);
|
||||||
|
Task<List<Patient>> FindDischargedPatients();
|
||||||
|
Task<Patient?> UpdateOne(Patient updatedPatient);
|
||||||
|
Task<List<Patient>> FindInActivePoC();
|
||||||
|
Task<List<Patient>> FindInInactivePoC();
|
||||||
|
Task<List<Patient>> FindPatientsNotUpdatedSince(DateTime date);
|
||||||
|
Task<Patient?> FindByPatientId(ObjectId patientId);
|
||||||
|
Task<Patient?> UpdatePatientIncomingData(ObjectId patientId, Patient person);
|
||||||
|
Task<Patient?> UpdatePatientDemographicData(ObjectId patientId, Patient person);
|
||||||
|
Task<Patient> FindByUnitAndPocId(ObjectId unit, ObjectId pointOfCare);
|
||||||
|
Task<long> CountByUnitId(ObjectId unitId);
|
||||||
|
Task<Patient?> SearchByPatientNumberAndDistinctUnit(string patientNumber, ObjectId unitId);
|
||||||
|
IFindFluent<Patient, Patient> GetPaginatedPatients(PaginationFilter filter);
|
||||||
|
Task<List<Patient>> FindAllPatientWithFinishedProcedures(int archiveProcedureEndDateAfterMinutes);
|
||||||
|
Task<List<Patient>> FindAllPatientWithFinishedTests(int archiveTestEndDateAfterMinutes);
|
||||||
|
Task<List<Patient>> FindAllPatientWithFinishedTreatment(int archiveTreatmentEndDateAfterMinutes);
|
||||||
|
Task<List<Patient>> UpdateMasterListOption(List<ObjectId> unitIds, UpdateOptionMasterListDto opt, string typeName);
|
||||||
|
Task<List<Patient>> GetPatientsByUnitIds(List<ObjectId> unitIds, string typeName);
|
||||||
|
Task<IEnumerable<Patient>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt, string typeName);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPoCMappingRepository
|
||||||
|
{
|
||||||
|
Task<PoCMapping?> FindByKey(string key);
|
||||||
|
string GetCollectionName();
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPoCSettingsRepository : IMongoRepository<PoCSettings>
|
||||||
|
{
|
||||||
|
Task Delete(ObjectId id);
|
||||||
|
|
||||||
|
Task<PoCSettings?> FindByLocation(PatientLocation location);
|
||||||
|
|
||||||
|
Task<PoCSettings?> FindById(ObjectId id);
|
||||||
|
|
||||||
|
Task Update(PoCSettings pocSettings);
|
||||||
|
|
||||||
|
Task<List<PoCSettings>> FindAll();
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models;
|
||||||
|
using adas_core.Domain.Models.DTO;
|
||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPointOfCareRepository : IMongoRepository<PointOfCare>
|
||||||
|
{
|
||||||
|
Task Delete(ObjectId id);
|
||||||
|
|
||||||
|
Task Update(PointOfCare pointOfCare);
|
||||||
|
|
||||||
|
Task UpdateUnitId(ObjectId id, Unit unit);
|
||||||
|
|
||||||
|
Task UpdateConfiguration(ObjectId id, PointOfCareConfiguration configuration);
|
||||||
|
|
||||||
|
Task<PointOfCare?> FindById(ObjectId id);
|
||||||
|
|
||||||
|
Task<IEnumerable<PointOfCare>?> FindAllByUnitId(ObjectId unit);
|
||||||
|
|
||||||
|
Task<IEnumerable<PointOfCare>?> FindByRoom(string room);
|
||||||
|
|
||||||
|
Task<List<PointOfCare>> FindByFilter(FilterDefinition<PointOfCare> filter,
|
||||||
|
ProjectionDefinition<PointOfCare>? projection = null);
|
||||||
|
|
||||||
|
Task<IEnumerable<PointOfCare>?> FindByBed(string bed);
|
||||||
|
Task<List<PointOfCare>?> GetAll();
|
||||||
|
Task<List<PointOfCare>?> GetAllConfigs();
|
||||||
|
|
||||||
|
Task<List<PointOfCare>?> GetAllLocationInfo();
|
||||||
|
|
||||||
|
Task<PointOfCare?> GetPoCConfiguration(ObjectId pocId);
|
||||||
|
|
||||||
|
|
||||||
|
Task<PointOfCare?> FindByBedAndUnitId(string? bed, ObjectId unitId);
|
||||||
|
|
||||||
|
Task<PointOfCare?> FindByPatientLocation(PatientLocation patientLocation);
|
||||||
|
|
||||||
|
Task<IEnumerable<PointOfCare>> FindByUnitAndStatus(ObjectId unitId, StatusEnum.PointOfCare status,
|
||||||
|
bool excludeVirtual = false);
|
||||||
|
|
||||||
|
Task UpdateRelayConfig(ObjectId pocId, List<Relay> relayConfig);
|
||||||
|
Task UpdateRelayConfig(ObjectId pocId, List<ObjectId> relayConfig);
|
||||||
|
|
||||||
|
IFindFluent<PointOfCare, PointOfCare> GetPaginatedPoCs(PaginationFilter filter);
|
||||||
|
Task<long> CountByUnitId(ObjectId unitId);
|
||||||
|
Task<long> CountVirtualsByUnitId(ObjectId unitId);
|
||||||
|
Task<bool> DeleteManyByUnitId(ObjectId unitId);
|
||||||
|
Task<PointOfCare?> FindByIdAllConfig(ObjectId id);
|
||||||
|
Task<HashSet<ObjectId>> FindAllIdCamerasInUse();
|
||||||
|
Task<HashSet<ObjectId>> FindAllIdRelaysInUse();
|
||||||
|
Task<HashSet<ObjectId>> FindAllIdBeaconsInUse();
|
||||||
|
Task<IEnumerable<PointOfCare>?> FindAllByUnitIdWithDevices(ObjectId unitId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPumpAlarmEventRepository
|
||||||
|
{
|
||||||
|
Task InsertAsync(PumpAlarmEvent alarmEvent);
|
||||||
|
|
||||||
|
Task<IEnumerable<PumpAlarmEvent>> FindByDeviceIdAsync(
|
||||||
|
string deviceId,
|
||||||
|
DateTime? from = null,
|
||||||
|
DateTime? to = null,
|
||||||
|
int? limit = null);
|
||||||
|
|
||||||
|
Task<PumpAlarmEvent?> FindLastByDeviceIdAsync(string deviceId);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
Task DeleteByPatientId(ObjectId patientId);
|
||||||
|
|
||||||
|
Task<long> UpdateManyObjectIdByFiledNameAsync(string fieldName, ObjectId newId, ObjectId oldId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPumpAlarmStateRepository
|
||||||
|
{
|
||||||
|
Task<PumpAlarmState?> FindActiveAsync(
|
||||||
|
string deviceId,
|
||||||
|
PumpEnum.AlarmType? alarmType,
|
||||||
|
string? alarmCodeMdc = null);
|
||||||
|
|
||||||
|
Task<IEnumerable<PumpAlarmState>> FindAllActiveByDeviceAsync(string deviceId);
|
||||||
|
|
||||||
|
Task UpsertActiveAsync(PumpAlarmState state);
|
||||||
|
|
||||||
|
Task RemoveAsync(
|
||||||
|
string deviceId,
|
||||||
|
PumpEnum.AlarmType? alarmType,
|
||||||
|
string? alarmCodeMdc = null);
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
Task DeleteByPatientId(ObjectId patientId);
|
||||||
|
|
||||||
|
Task<long> UpdateManyObjectIdByFieldNameAsync(string fieldName, ObjectId newId, ObjectId oldId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces
|
||||||
|
{
|
||||||
|
public interface IPumpArchiveRepository
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Devuelve la colección subyacente
|
||||||
|
/// </summary>
|
||||||
|
IMongoCollection<PumpObservation> Collection { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserta una observación de bomba en la colección de archivo.
|
||||||
|
/// </summary>
|
||||||
|
Task InsertAsync(PumpObservation obs);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserta múltiples observaciones en la colección de archivo.
|
||||||
|
/// </summary>
|
||||||
|
Task InsertManyAsync(IEnumerable<PumpObservation> observations);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Búsqueda por paciente para auditoría o restauración.
|
||||||
|
/// </summary>
|
||||||
|
Task<IEnumerable<PumpObservation>> FindByPatientIdAsync(ObjectId patientId,
|
||||||
|
DateTime? from = null, DateTime? to = null, int? limit = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPumpObservationRepository
|
||||||
|
{
|
||||||
|
Task InsertAsync(PumpObservation obs);
|
||||||
|
Task InsertManyAsync(IEnumerable<PumpObservation> observations);
|
||||||
|
|
||||||
|
Task<IEnumerable<PumpObservation>> FindByDeviceIdAsync(
|
||||||
|
string deviceId,
|
||||||
|
DateTime? from = null,
|
||||||
|
DateTime? to = null,
|
||||||
|
int? limit = null);
|
||||||
|
|
||||||
|
Task<PumpObservation?> FindLastByDeviceIdAsync(string deviceId);
|
||||||
|
Task<Dictionary<ObjectId, DateTime>> FindAllLastPatientObservationTimeAsync();
|
||||||
|
|
||||||
|
Task<IEnumerable<PumpObservation>> FindByPatientId(ObjectId? patientId);
|
||||||
|
|
||||||
|
Task<List<PumpObservation>> AggregatedPatientLastObservations(ObjectId patientId, int num = 100);
|
||||||
|
Task DeleteByPatientId(ObjectId? patientId);
|
||||||
|
Task<long> DeleteOlderThanDaysAsync(int days, string? name = null);
|
||||||
|
Task<long> DeleteKeepLastNAsync(int maxCount);
|
||||||
|
|
||||||
|
Task<long> UpdateManyObjectIdByFieldAsync(string fieldName, ObjectId newId, ObjectId? oldId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using adas_core.Domain.Models.Pumps;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IPumpStateRepository
|
||||||
|
{
|
||||||
|
Task<PumpState?> FindByDeviceIdAsync(string deviceId);
|
||||||
|
|
||||||
|
Task UpsertAsync(PumpState state);
|
||||||
|
|
||||||
|
Task<IEnumerable<PumpState>> GetAllAsync();
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IRecordingAlertArchiveRepository : IMongoRepository<PatientRecordingAlert>
|
||||||
|
{
|
||||||
|
new Task InsertOneAsync(PatientRecordingAlert recordingAlert);
|
||||||
|
Task DeleteBeforeDate(DateTime date);
|
||||||
|
Task<long> InsertBatch(IEnumerable<PatientRecordingAlert> recordingAlerts);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using adas_core.Domain.Models;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IRecordingAlertRepository : IMongoRepository<PatientRecordingAlert>
|
||||||
|
{
|
||||||
|
Task<List<PatientRecordingAlert>> AggregatedPatientLastObservations(ObjectId patientId, int num);
|
||||||
|
|
||||||
|
Task<List<PatientRecordingAlert>> FindLastObservations(ObjectId patientId, string name, int num = 2);
|
||||||
|
new Task InsertOneAsync(PatientRecordingAlert patientRecordingAlert);
|
||||||
|
Task DeleteOlderDaysAsync(string name, int value);
|
||||||
|
Task DeleteOlderNumberAsync(string name, int value);
|
||||||
|
Task DeleteByPatientId(ObjectId patientId);
|
||||||
|
Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId);
|
||||||
|
Task<IAsyncCursor<PatientRecordingAlert>> FindByPatientIdAsync(ObjectId patientId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using adas_core.Domain.Enums;
|
||||||
|
using adas_core.Domain.Models.Filter;
|
||||||
|
using adas_core.Domain.Models.MongoModels;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace adas_core.Application.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IRelayRepository : IMongoRepository<Relay>
|
||||||
|
{
|
||||||
|
Task<Relay?> GetById(ObjectId relayId);
|
||||||
|
List<Relay> GetRelayByTypeInList(List<ObjectId> configurationRelayList, RelayEnum.Type type);
|
||||||
|
List<Relay> GetRelayInList(List<ObjectId> configurationRelayList);
|
||||||
|
IFindFluent<Relay, Relay> GetPaginatedRelays(PaginationFilter filter);
|
||||||
|
Task<Relay?> InsertOneRelayAsync(Relay request);
|
||||||
|
Task<Relay?> UpdateRelayAsync(ObjectId objectId, Relay relay);
|
||||||
|
Task<Relay?> GetByName(string? requestRelayName);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user