paperclip-plugin-autopilot-ops 0.1.33 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/manifest.js +9 -4
- package/dist/ui/index.js +9 -4
- package/dist/worker.js +216 -61
- package/package.json +1 -1
package/dist/manifest.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/manifest.ts
|
|
2
2
|
var PLUGIN_ID = "alephoo.autopilot-ops";
|
|
3
|
-
var PLUGIN_VERSION = "0.1.
|
|
3
|
+
var PLUGIN_VERSION = "0.1.34";
|
|
4
4
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
5
5
|
var PAGE_ROUTE = "autopilot";
|
|
6
6
|
var TOOL_NAMES = {
|
|
@@ -68,13 +68,18 @@ var manifest = {
|
|
|
68
68
|
{
|
|
69
69
|
name: TOOL_NAMES.listarCasos,
|
|
70
70
|
displayName: "Listar casos",
|
|
71
|
-
description:
|
|
71
|
+
description: 'Lista casos del registro de negocio de la instituci\xF3n, abiertos y cerrados, del m\xE1s recientemente actualizado al m\xE1s viejo. Filtros opcionales: workflow (si el plugin no tiene esa funci\xF3n responde el error `workflow_desconocido`); estado (uno) o estados (varios, en un arreglo); referencia (todos los casos de ese objeto real, por ejemplo `rentabilidad:<prestacion_id>:<financiador_id>`, para saber si ya tiene caso sin recorrer el listado); limit (por defecto 50, m\xE1x. 500). Para recorrer todos sin perder ninguno aunque cambien mientras tanto: `orden: "id"` y, en cada p\xE1gina siguiente, `despues_de` con el id que indica la respuesta (\xABPuede haber m\xE1s casos\u2026\xBB); si vuelven menos casos que el limit, no hay m\xE1s. `offset` pagina el orden por actualizaci\xF3n (se corre si los casos cambian entre una p\xE1gina y otra). Solo lectura.',
|
|
72
72
|
parametersSchema: {
|
|
73
73
|
type: "object",
|
|
74
74
|
properties: {
|
|
75
75
|
workflow: { type: "string" },
|
|
76
76
|
estado: { type: "string" },
|
|
77
|
-
|
|
77
|
+
estados: { type: "array", items: { type: "string" }, description: "Varios estados a la vez (se ignora si viene estado)." },
|
|
78
|
+
referencia: { type: "string", description: "Solo los casos con esta referencia exacta." },
|
|
79
|
+
limit: { type: "number" },
|
|
80
|
+
orden: { type: "string", enum: ["actualizacion", "id"], description: '"id": orden estable para recorrer todo con despues_de. Por defecto, por \xFAltima actualizaci\xF3n.' },
|
|
81
|
+
despues_de: { type: "string", description: 'Id del \xFAltimo caso de la p\xE1gina anterior (con orden "id"): trae los que siguen.' },
|
|
82
|
+
offset: { type: "number" }
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
},
|
|
@@ -128,7 +133,7 @@ var manifest = {
|
|
|
128
133
|
{
|
|
129
134
|
name: TOOL_NAMES.abrirCaso,
|
|
130
135
|
displayName: "Abrir caso",
|
|
131
|
-
description: 'Abre un caso nuevo en un workflow, en su estado inicial. Workflows: `internacion_al_dia` (una internaci\xF3n abierta; referencia obligatoria `internacion:<id>`; datos: internacion_id), `honorario_en_cero` (referencia `honorarios:<profesional_id>`; datos: profesional_id, profesional), `debito_profesional` (referencia `debito:<profesional_id>:<nota_credito_id>`; datos: profesional_id, profesional, nota_credito_id, obra_social), `liquidacion_profesional` (referencia `liquidacion:<profesional_id>:<AAAA-MM-DD>`; datos: profesional_id, profesional, liquidado_el, institucion, mail_his), `cobranza_financiador` (un caso abierto por financiador; referencia obligatoria `cobranza:<obra_social_id>`; datos: obra_social (nombre como en el HIS), obra_social_id, institucion (nombre de la instituci\xF3n para el reclamo)), `circular_aranceles` (una circular de aranceles entera; referencia obligatoria `circular:<obra social>:<hash corto del archivo>`; datos: obra_social, convenio (nombre en el HIS), archivo {nombre, hash, paginas}, vigencia_desde AAAA-MM-DD, porcentaje_declarado y filas_declaradas si la circular los dice), `demanda_pendiente` (referencia obligatoria `orden:<id>`, `solicitud:<id>` o `control:<persona_id>:<regla_id>`; datos: regla_id (regla activa) y candidato tal cual lo devuelve buscar-demanda.mjs; el plugin verifica la regla con el candidato (si no la cumple, no abre) y fija regla_version, canal, intentos, vence_el; nunca nombre, documento ni tel\xE9fono del paciente),`actualizacion_arancel`, `tarea_operativa`, `recupero_turno` (datos: fecha AAAA-MM-DD, hora HH:MM, profesional, especialidad del turno libre; referencia "AAAA-MM-DD HH:MM \xB7 Profesional"), `cuenta_completa` (una prestaci\xF3n pendiente de facturar con faltantes; referencia obligatoria "bono:<n\xFAmero>", datos: bono_id, bono_numero, obra_social, plan, prestacion, fecha_prestacion AAAA-MM-DD, monto_pesos, internacion_id opcional; en faltantes, `responsable` {tipo profesional, id, nombre} opcional para que el plugin avise a quien resuelve), `facturacion_pendiente` (una prestaci\xF3n sin facturar; misma referencia `bono:<n\xFAmero>` y mismos datos; el plugin calcula plazo_dias, vence_el y plazo_confirmado con los plazos por obra social de la instituci\xF3n), `credencial_profesional` (un profesional con agenda; referencia obligatoria `profesional:<id>`; datos: profesional_id, profesional (apellido y nombre, es personal de la instituci\xF3n), matricula_nacional, matricula_provincial, codigo_provincia, especialidades). `referencia` identifica el objeto real (convenio, cuenta, turno) y evita duplicados: si ya existe un caso abierto con la misma referencia, se devuelve ese. Pasar `idempotencyKey` para reintentos seguros.',
|
|
136
|
+
description: 'Abre un caso nuevo en un workflow, en su estado inicial. Workflows: `internacion_al_dia` (una internaci\xF3n abierta; referencia obligatoria `internacion:<id>`; datos: internacion_id), `honorario_en_cero` (referencia `honorarios:<profesional_id>`; datos: profesional_id, profesional), `debito_profesional` (referencia `debito:<profesional_id>:<nota_credito_id>`; datos: profesional_id, profesional, nota_credito_id, obra_social), `liquidacion_profesional` (referencia `liquidacion:<profesional_id>:<AAAA-MM-DD>`; datos: profesional_id, profesional, liquidado_el, institucion, mail_his), `cobranza_financiador` (un caso abierto por financiador; referencia obligatoria `cobranza:<obra_social_id>`; datos: obra_social (nombre como en el HIS), obra_social_id, institucion (nombre de la instituci\xF3n para el reclamo)), `circular_aranceles` (una circular de aranceles entera; referencia obligatoria `circular:<obra social>:<hash corto del archivo>`; datos: obra_social, convenio (nombre en el HIS), archivo {nombre, hash, paginas}, vigencia_desde AAAA-MM-DD, porcentaje_declarado y filas_declaradas si la circular los dice), `demanda_pendiente` (referencia obligatoria `orden:<id>`, `solicitud:<id>` o `control:<persona_id>:<regla_id>`; datos: regla_id (regla activa) y candidato tal cual lo devuelve buscar-demanda.mjs; el plugin verifica la regla con el candidato (si no la cumple, no abre) y fija regla_version, canal, intentos, vence_el; nunca nombre, documento ni tel\xE9fono del paciente),`actualizacion_arancel`, `tarea_operativa`, `recupero_turno` (datos: fecha AAAA-MM-DD, hora HH:MM, profesional, especialidad del turno libre; referencia "AAAA-MM-DD HH:MM \xB7 Profesional"), `cuenta_completa` (una prestaci\xF3n pendiente de facturar con faltantes; referencia obligatoria "bono:<n\xFAmero>", datos: bono_id, bono_numero, obra_social, plan, prestacion, fecha_prestacion AAAA-MM-DD, monto_pesos, internacion_id opcional; en faltantes, `responsable` {tipo profesional, id, nombre} opcional para que el plugin avise a quien resuelve), `facturacion_pendiente` (una prestaci\xF3n sin facturar; misma referencia `bono:<n\xFAmero>` y mismos datos; el plugin calcula plazo_dias, vence_el y plazo_confirmado con los plazos por obra social de la instituci\xF3n), `credencial_profesional` (un profesional con agenda; referencia obligatoria `profesional:<id>`; datos: profesional_id, profesional (apellido y nombre, es personal de la instituci\xF3n), matricula_nacional, matricula_provincial, codigo_provincia, especialidades), `rentabilidad_practica` (referencia obligatoria `rentabilidad:<prestacion_id>:<financiador_id>`; datos: prestacion_id, financiador_id, codigo, practica, financiador), `rentabilidad_internacion` (una internaci\xF3n egresada; referencia obligatoria `rentabilidad_internacion:<internacion_id>`; datos: internacion_id, financiador_id, financiador). `referencia` identifica el objeto real (convenio, cuenta, turno) y evita duplicados: si ya existe un caso abierto con la misma referencia, se devuelve ese (creado: false). En `rentabilidad_internacion` se devuelve el caso existente aunque est\xE9 cerrado: una internaci\xF3n se mide una sola vez. Pasar `idempotencyKey` para reintentos seguros.',
|
|
132
137
|
parametersSchema: {
|
|
133
138
|
type: "object",
|
|
134
139
|
properties: {
|
package/dist/ui/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
|
|
9
9
|
// src/manifest.ts
|
|
10
10
|
var PLUGIN_ID = "alephoo.autopilot-ops";
|
|
11
|
-
var PLUGIN_VERSION = "0.1.
|
|
11
|
+
var PLUGIN_VERSION = "0.1.34";
|
|
12
12
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
13
13
|
var PAGE_ROUTE = "autopilot";
|
|
14
14
|
var TOOL_NAMES = {
|
|
@@ -76,13 +76,18 @@ var manifest = {
|
|
|
76
76
|
{
|
|
77
77
|
name: TOOL_NAMES.listarCasos,
|
|
78
78
|
displayName: "Listar casos",
|
|
79
|
-
description:
|
|
79
|
+
description: 'Lista casos del registro de negocio de la instituci\xF3n, abiertos y cerrados, del m\xE1s recientemente actualizado al m\xE1s viejo. Filtros opcionales: workflow (si el plugin no tiene esa funci\xF3n responde el error `workflow_desconocido`); estado (uno) o estados (varios, en un arreglo); referencia (todos los casos de ese objeto real, por ejemplo `rentabilidad:<prestacion_id>:<financiador_id>`, para saber si ya tiene caso sin recorrer el listado); limit (por defecto 50, m\xE1x. 500). Para recorrer todos sin perder ninguno aunque cambien mientras tanto: `orden: "id"` y, en cada p\xE1gina siguiente, `despues_de` con el id que indica la respuesta (\xABPuede haber m\xE1s casos\u2026\xBB); si vuelven menos casos que el limit, no hay m\xE1s. `offset` pagina el orden por actualizaci\xF3n (se corre si los casos cambian entre una p\xE1gina y otra). Solo lectura.',
|
|
80
80
|
parametersSchema: {
|
|
81
81
|
type: "object",
|
|
82
82
|
properties: {
|
|
83
83
|
workflow: { type: "string" },
|
|
84
84
|
estado: { type: "string" },
|
|
85
|
-
|
|
85
|
+
estados: { type: "array", items: { type: "string" }, description: "Varios estados a la vez (se ignora si viene estado)." },
|
|
86
|
+
referencia: { type: "string", description: "Solo los casos con esta referencia exacta." },
|
|
87
|
+
limit: { type: "number" },
|
|
88
|
+
orden: { type: "string", enum: ["actualizacion", "id"], description: '"id": orden estable para recorrer todo con despues_de. Por defecto, por \xFAltima actualizaci\xF3n.' },
|
|
89
|
+
despues_de: { type: "string", description: 'Id del \xFAltimo caso de la p\xE1gina anterior (con orden "id"): trae los que siguen.' },
|
|
90
|
+
offset: { type: "number" }
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
93
|
},
|
|
@@ -136,7 +141,7 @@ var manifest = {
|
|
|
136
141
|
{
|
|
137
142
|
name: TOOL_NAMES.abrirCaso,
|
|
138
143
|
displayName: "Abrir caso",
|
|
139
|
-
description: 'Abre un caso nuevo en un workflow, en su estado inicial. Workflows: `internacion_al_dia` (una internaci\xF3n abierta; referencia obligatoria `internacion:<id>`; datos: internacion_id), `honorario_en_cero` (referencia `honorarios:<profesional_id>`; datos: profesional_id, profesional), `debito_profesional` (referencia `debito:<profesional_id>:<nota_credito_id>`; datos: profesional_id, profesional, nota_credito_id, obra_social), `liquidacion_profesional` (referencia `liquidacion:<profesional_id>:<AAAA-MM-DD>`; datos: profesional_id, profesional, liquidado_el, institucion, mail_his), `cobranza_financiador` (un caso abierto por financiador; referencia obligatoria `cobranza:<obra_social_id>`; datos: obra_social (nombre como en el HIS), obra_social_id, institucion (nombre de la instituci\xF3n para el reclamo)), `circular_aranceles` (una circular de aranceles entera; referencia obligatoria `circular:<obra social>:<hash corto del archivo>`; datos: obra_social, convenio (nombre en el HIS), archivo {nombre, hash, paginas}, vigencia_desde AAAA-MM-DD, porcentaje_declarado y filas_declaradas si la circular los dice), `demanda_pendiente` (referencia obligatoria `orden:<id>`, `solicitud:<id>` o `control:<persona_id>:<regla_id>`; datos: regla_id (regla activa) y candidato tal cual lo devuelve buscar-demanda.mjs; el plugin verifica la regla con el candidato (si no la cumple, no abre) y fija regla_version, canal, intentos, vence_el; nunca nombre, documento ni tel\xE9fono del paciente),`actualizacion_arancel`, `tarea_operativa`, `recupero_turno` (datos: fecha AAAA-MM-DD, hora HH:MM, profesional, especialidad del turno libre; referencia "AAAA-MM-DD HH:MM \xB7 Profesional"), `cuenta_completa` (una prestaci\xF3n pendiente de facturar con faltantes; referencia obligatoria "bono:<n\xFAmero>", datos: bono_id, bono_numero, obra_social, plan, prestacion, fecha_prestacion AAAA-MM-DD, monto_pesos, internacion_id opcional; en faltantes, `responsable` {tipo profesional, id, nombre} opcional para que el plugin avise a quien resuelve), `facturacion_pendiente` (una prestaci\xF3n sin facturar; misma referencia `bono:<n\xFAmero>` y mismos datos; el plugin calcula plazo_dias, vence_el y plazo_confirmado con los plazos por obra social de la instituci\xF3n), `credencial_profesional` (un profesional con agenda; referencia obligatoria `profesional:<id>`; datos: profesional_id, profesional (apellido y nombre, es personal de la instituci\xF3n), matricula_nacional, matricula_provincial, codigo_provincia, especialidades). `referencia` identifica el objeto real (convenio, cuenta, turno) y evita duplicados: si ya existe un caso abierto con la misma referencia, se devuelve ese. Pasar `idempotencyKey` para reintentos seguros.',
|
|
144
|
+
description: 'Abre un caso nuevo en un workflow, en su estado inicial. Workflows: `internacion_al_dia` (una internaci\xF3n abierta; referencia obligatoria `internacion:<id>`; datos: internacion_id), `honorario_en_cero` (referencia `honorarios:<profesional_id>`; datos: profesional_id, profesional), `debito_profesional` (referencia `debito:<profesional_id>:<nota_credito_id>`; datos: profesional_id, profesional, nota_credito_id, obra_social), `liquidacion_profesional` (referencia `liquidacion:<profesional_id>:<AAAA-MM-DD>`; datos: profesional_id, profesional, liquidado_el, institucion, mail_his), `cobranza_financiador` (un caso abierto por financiador; referencia obligatoria `cobranza:<obra_social_id>`; datos: obra_social (nombre como en el HIS), obra_social_id, institucion (nombre de la instituci\xF3n para el reclamo)), `circular_aranceles` (una circular de aranceles entera; referencia obligatoria `circular:<obra social>:<hash corto del archivo>`; datos: obra_social, convenio (nombre en el HIS), archivo {nombre, hash, paginas}, vigencia_desde AAAA-MM-DD, porcentaje_declarado y filas_declaradas si la circular los dice), `demanda_pendiente` (referencia obligatoria `orden:<id>`, `solicitud:<id>` o `control:<persona_id>:<regla_id>`; datos: regla_id (regla activa) y candidato tal cual lo devuelve buscar-demanda.mjs; el plugin verifica la regla con el candidato (si no la cumple, no abre) y fija regla_version, canal, intentos, vence_el; nunca nombre, documento ni tel\xE9fono del paciente),`actualizacion_arancel`, `tarea_operativa`, `recupero_turno` (datos: fecha AAAA-MM-DD, hora HH:MM, profesional, especialidad del turno libre; referencia "AAAA-MM-DD HH:MM \xB7 Profesional"), `cuenta_completa` (una prestaci\xF3n pendiente de facturar con faltantes; referencia obligatoria "bono:<n\xFAmero>", datos: bono_id, bono_numero, obra_social, plan, prestacion, fecha_prestacion AAAA-MM-DD, monto_pesos, internacion_id opcional; en faltantes, `responsable` {tipo profesional, id, nombre} opcional para que el plugin avise a quien resuelve), `facturacion_pendiente` (una prestaci\xF3n sin facturar; misma referencia `bono:<n\xFAmero>` y mismos datos; el plugin calcula plazo_dias, vence_el y plazo_confirmado con los plazos por obra social de la instituci\xF3n), `credencial_profesional` (un profesional con agenda; referencia obligatoria `profesional:<id>`; datos: profesional_id, profesional (apellido y nombre, es personal de la instituci\xF3n), matricula_nacional, matricula_provincial, codigo_provincia, especialidades), `rentabilidad_practica` (referencia obligatoria `rentabilidad:<prestacion_id>:<financiador_id>`; datos: prestacion_id, financiador_id, codigo, practica, financiador), `rentabilidad_internacion` (una internaci\xF3n egresada; referencia obligatoria `rentabilidad_internacion:<internacion_id>`; datos: internacion_id, financiador_id, financiador). `referencia` identifica el objeto real (convenio, cuenta, turno) y evita duplicados: si ya existe un caso abierto con la misma referencia, se devuelve ese (creado: false). En `rentabilidad_internacion` se devuelve el caso existente aunque est\xE9 cerrado: una internaci\xF3n se mide una sola vez. Pasar `idempotencyKey` para reintentos seguros.',
|
|
140
145
|
parametersSchema: {
|
|
141
146
|
type: "object",
|
|
142
147
|
properties: {
|
package/dist/worker.js
CHANGED
|
@@ -39932,7 +39932,7 @@ function startWorkerRpcHost(options) {
|
|
|
39932
39932
|
|
|
39933
39933
|
// src/manifest.ts
|
|
39934
39934
|
var PLUGIN_ID = "alephoo.autopilot-ops";
|
|
39935
|
-
var PLUGIN_VERSION = "0.1.
|
|
39935
|
+
var PLUGIN_VERSION = "0.1.34";
|
|
39936
39936
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
39937
39937
|
var PAGE_ROUTE = "autopilot";
|
|
39938
39938
|
var TOOL_NAMES = {
|
|
@@ -40000,13 +40000,18 @@ var manifest = {
|
|
|
40000
40000
|
{
|
|
40001
40001
|
name: TOOL_NAMES.listarCasos,
|
|
40002
40002
|
displayName: "Listar casos",
|
|
40003
|
-
description:
|
|
40003
|
+
description: 'Lista casos del registro de negocio de la instituci\xF3n, abiertos y cerrados, del m\xE1s recientemente actualizado al m\xE1s viejo. Filtros opcionales: workflow (si el plugin no tiene esa funci\xF3n responde el error `workflow_desconocido`); estado (uno) o estados (varios, en un arreglo); referencia (todos los casos de ese objeto real, por ejemplo `rentabilidad:<prestacion_id>:<financiador_id>`, para saber si ya tiene caso sin recorrer el listado); limit (por defecto 50, m\xE1x. 500). Para recorrer todos sin perder ninguno aunque cambien mientras tanto: `orden: "id"` y, en cada p\xE1gina siguiente, `despues_de` con el id que indica la respuesta (\xABPuede haber m\xE1s casos\u2026\xBB); si vuelven menos casos que el limit, no hay m\xE1s. `offset` pagina el orden por actualizaci\xF3n (se corre si los casos cambian entre una p\xE1gina y otra). Solo lectura.',
|
|
40004
40004
|
parametersSchema: {
|
|
40005
40005
|
type: "object",
|
|
40006
40006
|
properties: {
|
|
40007
40007
|
workflow: { type: "string" },
|
|
40008
40008
|
estado: { type: "string" },
|
|
40009
|
-
|
|
40009
|
+
estados: { type: "array", items: { type: "string" }, description: "Varios estados a la vez (se ignora si viene estado)." },
|
|
40010
|
+
referencia: { type: "string", description: "Solo los casos con esta referencia exacta." },
|
|
40011
|
+
limit: { type: "number" },
|
|
40012
|
+
orden: { type: "string", enum: ["actualizacion", "id"], description: '"id": orden estable para recorrer todo con despues_de. Por defecto, por \xFAltima actualizaci\xF3n.' },
|
|
40013
|
+
despues_de: { type: "string", description: 'Id del \xFAltimo caso de la p\xE1gina anterior (con orden "id"): trae los que siguen.' },
|
|
40014
|
+
offset: { type: "number" }
|
|
40010
40015
|
}
|
|
40011
40016
|
}
|
|
40012
40017
|
},
|
|
@@ -40060,7 +40065,7 @@ var manifest = {
|
|
|
40060
40065
|
{
|
|
40061
40066
|
name: TOOL_NAMES.abrirCaso,
|
|
40062
40067
|
displayName: "Abrir caso",
|
|
40063
|
-
description: 'Abre un caso nuevo en un workflow, en su estado inicial. Workflows: `internacion_al_dia` (una internaci\xF3n abierta; referencia obligatoria `internacion:<id>`; datos: internacion_id), `honorario_en_cero` (referencia `honorarios:<profesional_id>`; datos: profesional_id, profesional), `debito_profesional` (referencia `debito:<profesional_id>:<nota_credito_id>`; datos: profesional_id, profesional, nota_credito_id, obra_social), `liquidacion_profesional` (referencia `liquidacion:<profesional_id>:<AAAA-MM-DD>`; datos: profesional_id, profesional, liquidado_el, institucion, mail_his), `cobranza_financiador` (un caso abierto por financiador; referencia obligatoria `cobranza:<obra_social_id>`; datos: obra_social (nombre como en el HIS), obra_social_id, institucion (nombre de la instituci\xF3n para el reclamo)), `circular_aranceles` (una circular de aranceles entera; referencia obligatoria `circular:<obra social>:<hash corto del archivo>`; datos: obra_social, convenio (nombre en el HIS), archivo {nombre, hash, paginas}, vigencia_desde AAAA-MM-DD, porcentaje_declarado y filas_declaradas si la circular los dice), `demanda_pendiente` (referencia obligatoria `orden:<id>`, `solicitud:<id>` o `control:<persona_id>:<regla_id>`; datos: regla_id (regla activa) y candidato tal cual lo devuelve buscar-demanda.mjs; el plugin verifica la regla con el candidato (si no la cumple, no abre) y fija regla_version, canal, intentos, vence_el; nunca nombre, documento ni tel\xE9fono del paciente),`actualizacion_arancel`, `tarea_operativa`, `recupero_turno` (datos: fecha AAAA-MM-DD, hora HH:MM, profesional, especialidad del turno libre; referencia "AAAA-MM-DD HH:MM \xB7 Profesional"), `cuenta_completa` (una prestaci\xF3n pendiente de facturar con faltantes; referencia obligatoria "bono:<n\xFAmero>", datos: bono_id, bono_numero, obra_social, plan, prestacion, fecha_prestacion AAAA-MM-DD, monto_pesos, internacion_id opcional; en faltantes, `responsable` {tipo profesional, id, nombre} opcional para que el plugin avise a quien resuelve), `facturacion_pendiente` (una prestaci\xF3n sin facturar; misma referencia `bono:<n\xFAmero>` y mismos datos; el plugin calcula plazo_dias, vence_el y plazo_confirmado con los plazos por obra social de la instituci\xF3n), `credencial_profesional` (un profesional con agenda; referencia obligatoria `profesional:<id>`; datos: profesional_id, profesional (apellido y nombre, es personal de la instituci\xF3n), matricula_nacional, matricula_provincial, codigo_provincia, especialidades). `referencia` identifica el objeto real (convenio, cuenta, turno) y evita duplicados: si ya existe un caso abierto con la misma referencia, se devuelve ese. Pasar `idempotencyKey` para reintentos seguros.',
|
|
40068
|
+
description: 'Abre un caso nuevo en un workflow, en su estado inicial. Workflows: `internacion_al_dia` (una internaci\xF3n abierta; referencia obligatoria `internacion:<id>`; datos: internacion_id), `honorario_en_cero` (referencia `honorarios:<profesional_id>`; datos: profesional_id, profesional), `debito_profesional` (referencia `debito:<profesional_id>:<nota_credito_id>`; datos: profesional_id, profesional, nota_credito_id, obra_social), `liquidacion_profesional` (referencia `liquidacion:<profesional_id>:<AAAA-MM-DD>`; datos: profesional_id, profesional, liquidado_el, institucion, mail_his), `cobranza_financiador` (un caso abierto por financiador; referencia obligatoria `cobranza:<obra_social_id>`; datos: obra_social (nombre como en el HIS), obra_social_id, institucion (nombre de la instituci\xF3n para el reclamo)), `circular_aranceles` (una circular de aranceles entera; referencia obligatoria `circular:<obra social>:<hash corto del archivo>`; datos: obra_social, convenio (nombre en el HIS), archivo {nombre, hash, paginas}, vigencia_desde AAAA-MM-DD, porcentaje_declarado y filas_declaradas si la circular los dice), `demanda_pendiente` (referencia obligatoria `orden:<id>`, `solicitud:<id>` o `control:<persona_id>:<regla_id>`; datos: regla_id (regla activa) y candidato tal cual lo devuelve buscar-demanda.mjs; el plugin verifica la regla con el candidato (si no la cumple, no abre) y fija regla_version, canal, intentos, vence_el; nunca nombre, documento ni tel\xE9fono del paciente),`actualizacion_arancel`, `tarea_operativa`, `recupero_turno` (datos: fecha AAAA-MM-DD, hora HH:MM, profesional, especialidad del turno libre; referencia "AAAA-MM-DD HH:MM \xB7 Profesional"), `cuenta_completa` (una prestaci\xF3n pendiente de facturar con faltantes; referencia obligatoria "bono:<n\xFAmero>", datos: bono_id, bono_numero, obra_social, plan, prestacion, fecha_prestacion AAAA-MM-DD, monto_pesos, internacion_id opcional; en faltantes, `responsable` {tipo profesional, id, nombre} opcional para que el plugin avise a quien resuelve), `facturacion_pendiente` (una prestaci\xF3n sin facturar; misma referencia `bono:<n\xFAmero>` y mismos datos; el plugin calcula plazo_dias, vence_el y plazo_confirmado con los plazos por obra social de la instituci\xF3n), `credencial_profesional` (un profesional con agenda; referencia obligatoria `profesional:<id>`; datos: profesional_id, profesional (apellido y nombre, es personal de la instituci\xF3n), matricula_nacional, matricula_provincial, codigo_provincia, especialidades), `rentabilidad_practica` (referencia obligatoria `rentabilidad:<prestacion_id>:<financiador_id>`; datos: prestacion_id, financiador_id, codigo, practica, financiador), `rentabilidad_internacion` (una internaci\xF3n egresada; referencia obligatoria `rentabilidad_internacion:<internacion_id>`; datos: internacion_id, financiador_id, financiador). `referencia` identifica el objeto real (convenio, cuenta, turno) y evita duplicados: si ya existe un caso abierto con la misma referencia, se devuelve ese (creado: false). En `rentabilidad_internacion` se devuelve el caso existente aunque est\xE9 cerrado: una internaci\xF3n se mide una sola vez. Pasar `idempotencyKey` para reintentos seguros.',
|
|
40064
40069
|
parametersSchema: {
|
|
40065
40070
|
type: "object",
|
|
40066
40071
|
properties: {
|
|
@@ -43114,8 +43119,8 @@ var rentabilidadPractica = {
|
|
|
43114
43119
|
descripcion: "Calcula, para cada pr\xE1ctica y cada financiador, lo que deja: lo que paga el convenio menos el honorario del profesional (con la regla del HIS) y los insumos. Marca las que dan p\xE9rdida o quedan debajo del umbral de la instituci\xF3n, y las que no se pueden calcular porque faltan datos en el HIS. Decide la direcci\xF3n: renegociar con el financiador o aceptarla. El puesto no escribe en el sistema.",
|
|
43115
43120
|
inicial: "detectado",
|
|
43116
43121
|
estados: ["detectado", "pendiente_aprobacion", "datos_incompletos", "completado", "en_renegociacion", "resuelta", "aceptada", "rentable", "descartado"],
|
|
43117
|
-
finalesOk: ["resuelta"],
|
|
43118
|
-
finalesNoOk: ["
|
|
43122
|
+
finalesOk: ["resuelta", "rentable", "aceptada"],
|
|
43123
|
+
finalesNoOk: ["descartado"],
|
|
43119
43124
|
minutosAbsorbidos: 15,
|
|
43120
43125
|
transiciones: [
|
|
43121
43126
|
{
|
|
@@ -43174,13 +43179,54 @@ function validarLecturaCostoInternacion(caso, datos, contexto) {
|
|
|
43174
43179
|
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "hace falta lectura_id: la lectura de la base registrada con ops_registrar_accion")
|
|
43175
43180
|
];
|
|
43176
43181
|
}
|
|
43182
|
+
var DIAS_REVISION_CUENTA = 14;
|
|
43183
|
+
var centavos = (v) => typeof v === "number" && Number.isFinite(v) ? Math.round(v * 100) : null;
|
|
43184
|
+
var fechaCortaISO = (v) => {
|
|
43185
|
+
const iso5 = fechaAISO(v);
|
|
43186
|
+
return iso5 ? `${iso5.slice(8, 10)}/${iso5.slice(5, 7)}/${iso5.slice(0, 4)}` : null;
|
|
43187
|
+
};
|
|
43188
|
+
function baseRevisionCuenta(d) {
|
|
43189
|
+
const e = d.evaluacion && typeof d.evaluacion === "object" ? d.evaluacion : {};
|
|
43190
|
+
return {
|
|
43191
|
+
facturado: typeof d.revision_facturado === "number" ? d.revision_facturado : typeof e.facturado === "number" ? e.facturado : null,
|
|
43192
|
+
costo: typeof d.revision_costo === "number" ? d.revision_costo : typeof e.costo === "number" ? e.costo : null
|
|
43193
|
+
};
|
|
43194
|
+
}
|
|
43195
|
+
function resultadoRevisionCuenta(datosCaso, e, hoy) {
|
|
43196
|
+
const base = baseRevisionCuenta(datosCaso);
|
|
43197
|
+
const cambio2 = (antes, ahora) => antes !== null && centavos(antes) !== centavos(ahora);
|
|
43198
|
+
if (cambio2(base.facturado, e.facturado) || cambio2(base.costo, e.costo)) return "con_cambios";
|
|
43199
|
+
const vence = fechaAISO(datosCaso.revision_vence_el);
|
|
43200
|
+
return !vence || !hoy || hoy >= vence ? "sin_cambios" : null;
|
|
43201
|
+
}
|
|
43202
|
+
function notaRevisionCuenta(d, estado, e, hoy) {
|
|
43203
|
+
const pedida = fechaCortaISO(d.revision_pedida_el);
|
|
43204
|
+
const desde = pedida ? `Se pidi\xF3 revisar la cuenta el ${pedida}` : "Se pidi\xF3 revisar la cuenta";
|
|
43205
|
+
if (estado === "en_revision") {
|
|
43206
|
+
const vence = fechaCortaISO(d.revision_vence_el);
|
|
43207
|
+
return `${desde}: si no cambia, vuelve a la direcci\xF3n${vence ? ` el ${vence}` : ""}.`;
|
|
43208
|
+
}
|
|
43209
|
+
if (estado !== "pendiente_aprobacion" || typeof d.revisada_sin_cambios !== "boolean") return "";
|
|
43210
|
+
if (d.revisada_sin_cambios) {
|
|
43211
|
+
const dias = hoy ? diasEntre3(d.revision_pedida_el, hoy) : null;
|
|
43212
|
+
return `${desde} y${dias !== null && dias > 0 ? ` en ${dias} ${dias === 1 ? "d\xEDa" : "d\xEDas"}` : ""} no cambi\xF3.`;
|
|
43213
|
+
}
|
|
43214
|
+
const base = baseRevisionCuenta(d);
|
|
43215
|
+
const cambios = [
|
|
43216
|
+
base.facturado !== null && centavos(base.facturado) !== centavos(e.facturado) ? `lo facturado pas\xF3 de ${pesos2(base.facturado)} a ${pesos2(e.facturado)}` : null,
|
|
43217
|
+
base.costo !== null && centavos(base.costo) !== centavos(e.costo) ? `el costo pas\xF3 de ${pesos2(base.costo)} a ${pesos2(e.costo)}` : null
|
|
43218
|
+
].filter((x) => x !== null);
|
|
43219
|
+
const sigue = e.clase === "perdida" ? "sigue con p\xE9rdida" : "sigue debajo del margen m\xEDnimo";
|
|
43220
|
+
return `${desde}: ${cambios.length ? cambios.join(" y ") : "la cuenta cambi\xF3 desde entonces"}, y ${sigue}.`;
|
|
43221
|
+
}
|
|
43177
43222
|
var destinoCostoInternacion = (caso, _datos, contexto) => {
|
|
43178
43223
|
const r = contexto.costoInternacion;
|
|
43179
43224
|
if (!r || "error" in r) return caso.estado;
|
|
43180
43225
|
const clase2 = r.evaluacion.clase;
|
|
43181
43226
|
if (clase2 === "datos_incompletos") return "datos_incompletos";
|
|
43182
43227
|
if (clase2 === "rentable") return caso.estado === "detectado" ? "rentable" : "resuelta";
|
|
43183
|
-
|
|
43228
|
+
if (caso.estado === "en_revision") return resultadoRevisionCuenta(caso.datos, r.evaluacion, contexto.hoy) ? "pendiente_aprobacion" : "en_revision";
|
|
43229
|
+
return "pendiente_aprobacion";
|
|
43184
43230
|
};
|
|
43185
43231
|
var rentabilidadInternacion = {
|
|
43186
43232
|
clave: "rentabilidad_internacion",
|
|
@@ -43189,8 +43235,8 @@ var rentabilidadInternacion = {
|
|
|
43189
43235
|
descripcion: "Calcula, para cada internaci\xF3n egresada, lo que dej\xF3: lo facturado contra lo que cost\xF3 (honorarios con la regla del HIS, insumos que farmacia le entreg\xF3 al paciente a costo de compra, d\xEDas cama y quir\xF3fano con los costos que fija la instituci\xF3n). Las que dan p\xE9rdida o quedan debajo del umbral van a la direcci\xF3n: revisar la cuenta (consumos sin facturar, renegociar el m\xF3dulo con el financiador) o aceptarla as\xED. El puesto no escribe en el sistema.",
|
|
43190
43236
|
inicial: "detectado",
|
|
43191
43237
|
estados: ["detectado", "pendiente_aprobacion", "datos_incompletos", "completado", "en_revision", "resuelta", "aceptada", "rentable", "descartado"],
|
|
43192
|
-
finalesOk: ["resuelta"],
|
|
43193
|
-
finalesNoOk: ["
|
|
43238
|
+
finalesOk: ["resuelta", "rentable", "aceptada"],
|
|
43239
|
+
finalesNoOk: ["descartado"],
|
|
43194
43240
|
minutosAbsorbidos: 20,
|
|
43195
43241
|
transiciones: [
|
|
43196
43242
|
{
|
|
@@ -43202,7 +43248,7 @@ var rentabilidadInternacion = {
|
|
|
43202
43248
|
descripcion: "Primera lectura de la internaci\xF3n. El plugin calcula el resultado y decide: pendiente de aprobaci\xF3n (p\xE9rdida o margen bajo), datos incompletos o rentable.",
|
|
43203
43249
|
validar: validarLecturaCostoInternacion
|
|
43204
43250
|
},
|
|
43205
|
-
{ via: "aprobar", de: ["pendiente_aprobacion"], a: "en_revision", actor: ["humano"], descripcion:
|
|
43251
|
+
{ via: "aprobar", de: ["pendiente_aprobacion"], a: "en_revision", actor: ["humano"], descripcion: `La direcci\xF3n pide revisar la cuenta: consumos que no se facturaron o el m\xF3dulo con el financiador. El puesto vuelve a medir: si la cuenta cambia y sigue con p\xE9rdida o margen bajo, o si pasan ${DIAS_REVISION_CUENTA} d\xEDas sin cambios, vuelve a la direcci\xF3n.` },
|
|
43206
43252
|
{
|
|
43207
43253
|
via: "rechazar",
|
|
43208
43254
|
de: ["pendiente_aprobacion", "en_revision"],
|
|
@@ -43226,7 +43272,7 @@ var rentabilidadInternacion = {
|
|
|
43226
43272
|
a: destinoCostoInternacion,
|
|
43227
43273
|
actor: ["agente", "humano", "sistema"],
|
|
43228
43274
|
nivelRequerido: "observa",
|
|
43229
|
-
descripcion:
|
|
43275
|
+
descripcion: `Volver a leer la internaci\xF3n. El plugin decide: resuelta (ya deja margen, por ejemplo porque se factur\xF3 lo que faltaba), pendiente de aprobaci\xF3n (sigue con p\xE9rdida o margen bajo; desde la revisi\xF3n, solo si la cuenta cambi\xF3 o pasaron ${DIAS_REVISION_CUENTA} d\xEDas sin cambios), sigue en revisi\xF3n o datos incompletos.`,
|
|
43230
43276
|
validar: validarLecturaCostoInternacion
|
|
43231
43277
|
},
|
|
43232
43278
|
{
|
|
@@ -43843,7 +43889,7 @@ function evaluarRentabilidad(input2) {
|
|
|
43843
43889
|
if (l.insumos.length === 0) avisos.push("sin_insumos");
|
|
43844
43890
|
const debajo = [];
|
|
43845
43891
|
const honorarios = [];
|
|
43846
|
-
if (l.honorarios.length === 0) faltas.push("
|
|
43892
|
+
if (l.honorarios.length === 0) faltas.push("sin_profesional");
|
|
43847
43893
|
for (const h of l.honorarios) {
|
|
43848
43894
|
const nombre = h.profesional ?? h.profesional_id;
|
|
43849
43895
|
if (!h.regla) {
|
|
@@ -43893,6 +43939,7 @@ var NOMBRE_FALTA = {
|
|
|
43893
43939
|
sin_valor_convenio: "el convenio no tiene valor para esta pr\xE1ctica",
|
|
43894
43940
|
insumo_sin_precio: "hay insumos sin precio",
|
|
43895
43941
|
sin_regla_honorario: "hay profesionales sin regla de honorarios",
|
|
43942
|
+
sin_profesional: "se factur\xF3 sin un profesional (si es un medicamento o un descartable, no corresponde medirla como pr\xE1ctica)",
|
|
43896
43943
|
regla_sin_valor: "hay reglas de honorarios sin valor"
|
|
43897
43944
|
};
|
|
43898
43945
|
var porcentaje = (n) => `${n.toLocaleString("es-AR", { maximumFractionDigits: 1 })} %`;
|
|
@@ -44033,7 +44080,8 @@ function leerLecturaCostoInternacion(v) {
|
|
|
44033
44080
|
const monto = num7(f.monto);
|
|
44034
44081
|
if (cantidad2 === null || cantidad2 < 0 || monto === null || monto < 0) return { error: `lectura.facturado[${i}]: cantidad y monto tienen que ser n\xFAmeros \u2265 0` };
|
|
44035
44082
|
if (f.regla !== null && f.regla !== void 0 && !leerRegla(f.regla)) return { error: `lectura.facturado[${i}].regla: tiene que ser {id, prof, inst} o null` };
|
|
44036
|
-
|
|
44083
|
+
const noLiquidable = f.liquidable === false || f.liquidable === 0 || f.liquidable === "0" || f.liquidable === "false";
|
|
44084
|
+
facturado.push({ prestacion_id: texto7(f.prestacion_id) ?? String(i), nombre: texto7(f.nombre) ?? "", cantidad: cantidad2, monto: redondear5(monto), profesional_id: texto7(f.profesional_id), regla: leerRegla(f.regla), ...noLiquidable ? { liquidable: false } : {} });
|
|
44037
44085
|
}
|
|
44038
44086
|
const consumos = [];
|
|
44039
44087
|
for (const [i, x] of r.consumos.entries()) {
|
|
@@ -44054,28 +44102,65 @@ function leerLecturaCostoInternacion(v) {
|
|
|
44054
44102
|
var DIA_MS = 864e5;
|
|
44055
44103
|
var ABREN = /* @__PURE__ */ new Set(["ingreso", "pase_cama", "reingreso"]);
|
|
44056
44104
|
var CIERRAN = /* @__PURE__ */ new Set(["egreso"]);
|
|
44105
|
+
var ORDEN_EVENTO = { egreso: 0, ingreso: 1, reingreso: 1, pase_cama: 2 };
|
|
44106
|
+
var claveServicio = (s) => s.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/\s+/g, " ").trim();
|
|
44107
|
+
function repartir2(pesos4, unidades) {
|
|
44108
|
+
const suma = pesos4.reduce((a, b) => a + b, 0);
|
|
44109
|
+
const exactas = pesos4.map((p) => suma > 0 ? p / suma * unidades : 0);
|
|
44110
|
+
const enteras = exactas.map((x) => Math.floor(x));
|
|
44111
|
+
let resto = unidades - enteras.reduce((a, b) => a + b, 0);
|
|
44112
|
+
const orden = pesos4.map((_, i) => i).sort((a, b) => exactas[b] - enteras[b] - (exactas[a] - enteras[a]) || pesos4[b] - pesos4[a] || a - b);
|
|
44113
|
+
for (const i of orden) {
|
|
44114
|
+
if (resto <= 0) break;
|
|
44115
|
+
enteras[i] += 1;
|
|
44116
|
+
resto -= 1;
|
|
44117
|
+
}
|
|
44118
|
+
return enteras;
|
|
44119
|
+
}
|
|
44120
|
+
function repartirDecimas(pesos4, total) {
|
|
44121
|
+
const decimas = Math.round(total * 10);
|
|
44122
|
+
if (pesos4.length > decimas) return repartir2(pesos4, decimas);
|
|
44123
|
+
const suma = pesos4.reduce((a, b) => a + b, 0);
|
|
44124
|
+
const excedentes = pesos4.map((p) => Math.max(0, p / suma * decimas - 1));
|
|
44125
|
+
return repartir2(excedentes, decimas - pesos4.length).map((d) => d + 1);
|
|
44126
|
+
}
|
|
44057
44127
|
function diasPorServicio(l, hoy) {
|
|
44058
|
-
const
|
|
44059
|
-
const fin = Date.parse(l.egreso ?? `${hoy}T23:59:59`);
|
|
44128
|
+
const inicio = Date.parse(l.ingreso);
|
|
44129
|
+
const fin = Math.max(inicio, Date.parse(l.egreso ?? `${hoy}T23:59:59`));
|
|
44130
|
+
const recortar = (t6) => Math.min(fin, Math.max(inicio, t6));
|
|
44131
|
+
const evs = l.eventos.filter((e) => ABREN.has(e.tipo) || CIERRAN.has(e.tipo)).map((e) => ({ ...e, t: recortar(Date.parse(e.fecha)) })).sort((a, b) => a.t - b.t || (ORDEN_EVENTO[a.tipo] ?? 1) - (ORDEN_EVENTO[b.tipo] ?? 1) || a.fecha.localeCompare(b.fecha));
|
|
44060
44132
|
const tramos = /* @__PURE__ */ new Map();
|
|
44133
|
+
const sumar = (servicio, ms) => {
|
|
44134
|
+
const k = claveServicio(servicio);
|
|
44135
|
+
const t6 = tramos.get(k);
|
|
44136
|
+
if (t6) t6.ms += Math.max(0, ms);
|
|
44137
|
+
else tramos.set(k, { nombre: servicio, ms: Math.max(0, ms) });
|
|
44138
|
+
};
|
|
44061
44139
|
let abierto = null;
|
|
44062
44140
|
let ultimoServicio = "Sin servicio";
|
|
44063
44141
|
for (const e of evs) {
|
|
44064
|
-
|
|
44065
|
-
if (abierto) tramos.set(abierto.servicio, (tramos.get(abierto.servicio) ?? 0) + Math.max(0, t6 - abierto.desde));
|
|
44142
|
+
if (abierto) sumar(abierto.servicio, e.t - abierto.desde);
|
|
44066
44143
|
abierto = null;
|
|
44067
44144
|
if (ABREN.has(e.tipo)) {
|
|
44068
44145
|
ultimoServicio = e.servicio ?? ultimoServicio;
|
|
44069
|
-
abierto = { desde:
|
|
44146
|
+
abierto = { desde: e.t, servicio: ultimoServicio };
|
|
44070
44147
|
}
|
|
44071
44148
|
}
|
|
44072
|
-
if (abierto)
|
|
44073
|
-
if (tramos.size === 0)
|
|
44074
|
-
const totalMs = [...tramos.values()].reduce((a,
|
|
44149
|
+
if (abierto) sumar(abierto.servicio, fin - abierto.desde);
|
|
44150
|
+
if (tramos.size === 0) sumar(ultimoServicio, fin - inicio);
|
|
44151
|
+
const totalMs = [...tramos.values()].reduce((a, t6) => a + t6.ms, 0);
|
|
44075
44152
|
const total = Math.max(1, Math.ceil(totalMs / DIA_MS - 0.01));
|
|
44153
|
+
let activos = [...tramos.values()].filter((t6) => t6.ms > 0);
|
|
44154
|
+
if (activos.length === 0) activos = [{ ...tramos.get(claveServicio(ultimoServicio)) ?? { nombre: ultimoServicio }, ms: 1 }];
|
|
44155
|
+
const decimas = repartirDecimas(activos.map((t6) => t6.ms), total);
|
|
44156
|
+
const msActivos = activos.reduce((a, t6) => a + t6.ms, 0);
|
|
44076
44157
|
const out = /* @__PURE__ */ new Map();
|
|
44077
|
-
|
|
44078
|
-
|
|
44158
|
+
const exactos = /* @__PURE__ */ new Map();
|
|
44159
|
+
activos.forEach((t6, i) => {
|
|
44160
|
+
out.set(t6.nombre, decimas[i] / 10);
|
|
44161
|
+
exactos.set(t6.nombre, t6.ms / msActivos * total);
|
|
44162
|
+
});
|
|
44163
|
+
return { tramos: out, total, exactos };
|
|
44079
44164
|
}
|
|
44080
44165
|
function evaluarCostoInternacion(input2) {
|
|
44081
44166
|
const { lectura: l, hoy } = input2;
|
|
@@ -44088,7 +44173,7 @@ function evaluarCostoInternacion(input2) {
|
|
|
44088
44173
|
let honorarios = 0;
|
|
44089
44174
|
let sinRegla = 0;
|
|
44090
44175
|
for (const f of l.facturado) {
|
|
44091
|
-
if (!f.profesional_id) continue;
|
|
44176
|
+
if (!f.profesional_id || f.liquidable === false) continue;
|
|
44092
44177
|
if (!f.regla || f.regla.prof === null && f.regla.inst === null) sinRegla += 1;
|
|
44093
44178
|
honorarios += honorarioDe({ regla: f.regla, monto: f.monto, cantidad: f.cantidad });
|
|
44094
44179
|
}
|
|
@@ -44107,32 +44192,34 @@ function evaluarCostoInternacion(input2) {
|
|
|
44107
44192
|
}
|
|
44108
44193
|
insumos = redondear5(insumos);
|
|
44109
44194
|
if (sinCosto.length) faltas.push("insumo_sin_costo");
|
|
44110
|
-
const { tramos, total } = diasPorServicio(l, hoy);
|
|
44195
|
+
const { tramos, total, exactos } = diasPorServicio(l, hoy);
|
|
44111
44196
|
const porServicio = input2.costoDiaPorServicio ?? {};
|
|
44197
|
+
const porClave = /* @__PURE__ */ new Map();
|
|
44198
|
+
for (const [s, c] of Object.entries(porServicio)) if (!porClave.has(claveServicio(s))) porClave.set(claveServicio(s), c);
|
|
44112
44199
|
const general = input2.costoDiaCama ?? null;
|
|
44113
44200
|
let cama = 0;
|
|
44114
44201
|
let faltaCama = false;
|
|
44115
44202
|
const dias_por_servicio = [...tramos.entries()].map(([servicio, dias]) => {
|
|
44116
|
-
const costo_dia = porServicio[servicio] ?? general;
|
|
44203
|
+
const costo_dia = porServicio[servicio] ?? porClave.get(claveServicio(servicio)) ?? general;
|
|
44117
44204
|
if (costo_dia === null || costo_dia === void 0) faltaCama = true;
|
|
44118
|
-
else cama += dias * costo_dia;
|
|
44205
|
+
else cama += (exactos.get(servicio) ?? dias) * costo_dia;
|
|
44119
44206
|
return { servicio, dias, costo_dia: costo_dia ?? null };
|
|
44120
44207
|
});
|
|
44121
44208
|
cama = redondear5(cama);
|
|
44122
44209
|
if (faltaCama) faltas.push("sin_costo_cama");
|
|
44123
44210
|
const minutos = l.cirugias.reduce((a, c) => a + (c.minutos ?? 0), 0);
|
|
44124
|
-
if (l.cirugias.some((c) => c.minutos === null)) avisos.push("cirugia_sin_duracion");
|
|
44125
44211
|
let quirofano = 0;
|
|
44126
|
-
if (
|
|
44212
|
+
if (l.cirugias.length > 0) {
|
|
44127
44213
|
if (input2.costoHoraQuirofano === null || input2.costoHoraQuirofano === void 0) faltas.push("sin_costo_quirofano");
|
|
44128
44214
|
else quirofano = redondear5(minutos / 60 * input2.costoHoraQuirofano);
|
|
44129
44215
|
}
|
|
44216
|
+
if (l.cirugias.some((c) => c.minutos === null)) faltas.push("cirugia_sin_duracion");
|
|
44130
44217
|
const costo = redondear5(honorarios + insumos + cama + quirofano);
|
|
44131
|
-
const calculable = faltas.length === 0;
|
|
44132
|
-
const margen =
|
|
44133
|
-
const margen_pct = margen !== null
|
|
44218
|
+
const calculable = faltas.length === 0 && facturado > 0;
|
|
44219
|
+
const margen = calculable ? redondear5(facturado - costo) : null;
|
|
44220
|
+
const margen_pct = margen !== null ? Math.round(margen / facturado * 1e3) / 10 : null;
|
|
44134
44221
|
let clase2;
|
|
44135
|
-
if (
|
|
44222
|
+
if (margen === null || margen_pct === null) clase2 = "datos_incompletos";
|
|
44136
44223
|
else if (margen < 0) clase2 = "perdida";
|
|
44137
44224
|
else if (margen_pct < umbral) clase2 = "margen_bajo";
|
|
44138
44225
|
else clase2 = "rentable";
|
|
@@ -44142,12 +44229,14 @@ var NOMBRE_FALTA2 = {
|
|
|
44142
44229
|
sin_facturar: "no tiene nada facturado",
|
|
44143
44230
|
insumo_sin_costo: "hay insumos sin costo de compra en el HIS",
|
|
44144
44231
|
sin_costo_cama: "falta el costo del d\xEDa cama",
|
|
44145
|
-
sin_costo_quirofano: "falta el costo de la hora de quir\xF3fano"
|
|
44232
|
+
sin_costo_quirofano: "falta el costo de la hora de quir\xF3fano",
|
|
44233
|
+
cirugia_sin_duracion: "hay cirug\xEDas sin la duraci\xF3n en el parte quir\xFArgico"
|
|
44146
44234
|
};
|
|
44147
44235
|
var porcentaje2 = (n) => `${n.toLocaleString("es-AR", { maximumFractionDigits: 1 })} %`;
|
|
44236
|
+
var enumerar = (xs) => xs.length > 1 ? `${xs.slice(0, -1).join(", ")} y ${xs[xs.length - 1]}` : xs[0] ?? "";
|
|
44148
44237
|
function oracionCostoInternacion(l, e) {
|
|
44149
44238
|
const quien = `La internaci\xF3n ${l.internacion_id} con ${l.financiador} (${e.dias} ${e.dias === 1 ? "d\xEDa" : "d\xEDas"})`;
|
|
44150
|
-
if (e.clase === "datos_incompletos") return `${quien}: no se puede calcular el resultado porque ${e.faltas.map((f) => NOMBRE_FALTA2[f]
|
|
44239
|
+
if (e.clase === "datos_incompletos") return `${quien}: no se puede calcular el resultado porque ${enumerar(e.faltas.map((f) => NOMBRE_FALTA2[f] ?? f.replace(/_/g, " ")))}.`;
|
|
44151
44240
|
if (e.clase === "perdida") return `${quien} dio p\xE9rdida: se facturaron ${pesos2(e.facturado)} y cost\xF3 ${pesos2(e.costo)} (${pesos2(Math.abs(e.margen))} de p\xE9rdida).`;
|
|
44152
44241
|
if (e.clase === "margen_bajo") return `${quien} dej\xF3 un margen de ${porcentaje2(e.margen_pct)}, debajo del ${porcentaje2(e.umbral)} de la instituci\xF3n: se facturaron ${pesos2(e.facturado)} y cost\xF3 ${pesos2(e.costo)}.`;
|
|
44153
44242
|
return `${quien} dej\xF3 un margen de ${porcentaje2(e.margen_pct)}.`;
|
|
@@ -44472,10 +44561,22 @@ async function leerCasoCompleto(ctx, companyId, casoId) {
|
|
|
44472
44561
|
async function listarCasos(ctx, input2) {
|
|
44473
44562
|
const params = [input2.companyId];
|
|
44474
44563
|
const where = ["company_id = $1"];
|
|
44564
|
+
const despuesDe = str2(input2.despuesDe);
|
|
44565
|
+
if (despuesDe && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(despuesDe)) throw new OpsError("validacion", `despues_de tiene que ser el id de un caso (el \xFAltimo de la p\xE1gina anterior); vino \xAB${despuesDe}\xBB`);
|
|
44566
|
+
const porId = input2.orden === "id" || despuesDe !== null;
|
|
44567
|
+
if (despuesDe) {
|
|
44568
|
+
params.push(despuesDe);
|
|
44569
|
+
where.push(`id > $${params.length}`);
|
|
44570
|
+
}
|
|
44475
44571
|
if (input2.workflow) {
|
|
44476
44572
|
params.push(input2.workflow);
|
|
44477
44573
|
where.push(`workflow = $${params.length}`);
|
|
44478
44574
|
}
|
|
44575
|
+
const referencia = str2(input2.referencia);
|
|
44576
|
+
if (referencia) {
|
|
44577
|
+
params.push(referencia);
|
|
44578
|
+
where.push(`referencia = $${params.length}`);
|
|
44579
|
+
}
|
|
44479
44580
|
if (input2.estado) {
|
|
44480
44581
|
params.push(input2.estado);
|
|
44481
44582
|
where.push(`estado = $${params.length}`);
|
|
@@ -44486,14 +44587,18 @@ async function listarCasos(ctx, input2) {
|
|
|
44486
44587
|
});
|
|
44487
44588
|
where.push(`estado IN (${marks.join(", ")})`);
|
|
44488
44589
|
}
|
|
44489
|
-
const limit = Math.min(Math.max(Number(input2.limit ?? 50) || 50, 1),
|
|
44590
|
+
const limit = Math.min(Math.max(Number(input2.limit ?? 50) || 50, 1), 500);
|
|
44591
|
+
const offset = Math.min(Math.max(Math.floor(Number(input2.offset ?? 0)) || 0, 0), 1e6);
|
|
44490
44592
|
params.push(limit);
|
|
44593
|
+
const pLimit = params.length;
|
|
44594
|
+
params.push(offset);
|
|
44491
44595
|
const rows = await ctx.db.query(
|
|
44492
|
-
`SELECT ${CASO_COLS} FROM ${t3(ctx, "caso")} WHERE ${where.join(" AND ")} ORDER BY updated_at DESC LIMIT $${params.length}`,
|
|
44596
|
+
`SELECT ${CASO_COLS} FROM ${t3(ctx, "caso")} WHERE ${where.join(" AND ")} ORDER BY ${porId ? "id" : "updated_at DESC, id"} LIMIT $${pLimit} OFFSET $${params.length}`,
|
|
44493
44597
|
params
|
|
44494
44598
|
);
|
|
44495
44599
|
return rows.map(mapCaso);
|
|
44496
44600
|
}
|
|
44601
|
+
var CLAVE_UNA_POR_REFERENCIA = "una-por-referencia:";
|
|
44497
44602
|
async function abrirCaso(ctx, input2) {
|
|
44498
44603
|
const wf = getWorkflow(input2.workflow);
|
|
44499
44604
|
if (!wf) throw new OpsError("workflow_desconocido", `workflow desconocido: ${input2.workflow}. Disponibles: ${listarWorkflows().map((w) => w.clave).join(", ")}`);
|
|
@@ -44597,18 +44702,26 @@ async function abrirCaso(ctx, input2) {
|
|
|
44597
44702
|
extra.detectado_el = hoy;
|
|
44598
44703
|
}
|
|
44599
44704
|
if (referencia) {
|
|
44600
|
-
const
|
|
44601
|
-
|
|
44602
|
-
|
|
44705
|
+
const soloAbiertos = wf.clave !== "rentabilidad_internacion";
|
|
44706
|
+
const previos = await ctx.db.query(
|
|
44707
|
+
`SELECT ${CASO_COLS} FROM ${t3(ctx, "caso")} WHERE company_id = $1 AND workflow = $2 AND referencia = $3${soloAbiertos ? " AND cerrado_at IS NULL" : ""} ORDER BY created_at DESC LIMIT 1`,
|
|
44708
|
+
[input2.companyId, wf.clave, referencia]
|
|
44603
44709
|
);
|
|
44604
|
-
if (
|
|
44710
|
+
if (previos[0]) return { caso: mapCaso(previos[0]), creado: false };
|
|
44605
44711
|
}
|
|
44606
44712
|
const id3 = randomUUID3();
|
|
44607
44713
|
const datos = { ...input2.datos ?? {}, ...extra };
|
|
44608
|
-
|
|
44609
|
-
|
|
44610
|
-
|
|
44611
|
-
|
|
44714
|
+
const clave = wf.clave === "rentabilidad_internacion" && referencia ? `${CLAVE_UNA_POR_REFERENCIA}${referencia}` : idem;
|
|
44715
|
+
try {
|
|
44716
|
+
await ctx.db.execute(
|
|
44717
|
+
`INSERT INTO ${t3(ctx, "caso")} (id, company_id, workflow, estado, referencia, titulo, datos, abierto_por_tipo, abierto_por_id, agente_id, issue_id, idempotency_key) VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8, $9, $10, $11, $12)`,
|
|
44718
|
+
[id3, input2.companyId, wf.clave, wf.inicial, referencia, titulo, JSON.stringify(datos), input2.actor.tipo, input2.actor.id, input2.agenteId ?? null, input2.issueId ?? null, clave]
|
|
44719
|
+
);
|
|
44720
|
+
} catch (err) {
|
|
44721
|
+
const ganador = clave ? await ctx.db.query(`SELECT ${CASO_COLS} FROM ${t3(ctx, "caso")} WHERE company_id = $1 AND idempotency_key = $2 LIMIT 1`, [input2.companyId, clave]) : [];
|
|
44722
|
+
if (ganador[0]) return { caso: mapCaso(ganador[0]), creado: false };
|
|
44723
|
+
throw err;
|
|
44724
|
+
}
|
|
44612
44725
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
44613
44726
|
return {
|
|
44614
44727
|
creado: true,
|
|
@@ -44924,22 +45037,43 @@ async function transicionar(ctx, input2) {
|
|
|
44924
45037
|
delete datos.lectura;
|
|
44925
45038
|
}
|
|
44926
45039
|
if (caso.workflow === "rentabilidad_internacion") {
|
|
44927
|
-
for (const k of ["evaluacion", "oracion", "financiador", "ingreso", "egreso", "facturado", "consumos", "cirugias", "comprobado_el"]) delete datos[k];
|
|
45040
|
+
for (const k of ["evaluacion", "oracion", "financiador", "ingreso", "egreso", "facturado", "consumos", "cirugias", "comprobado_el", "revisada_sin_cambios", "revision_pedida_el", "revision_vence_el", "revision_facturado", "revision_costo"]) delete datos[k];
|
|
45041
|
+
const hoy = contexto.hoy ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
44928
45042
|
const r = contexto.costoInternacion;
|
|
44929
45043
|
const l = leerLecturaCostoInternacion(datos.lectura);
|
|
44930
|
-
|
|
45044
|
+
const nueva = r && !("error" in r) && !("error" in l) ? { lectura: l.lectura, evaluacion: r.evaluacion } : null;
|
|
45045
|
+
if (resultado.via === "aprobar") {
|
|
45046
|
+
const vista = caso.datos.evaluacion && typeof caso.datos.evaluacion === "object" ? caso.datos.evaluacion : {};
|
|
44931
45047
|
Object.assign(datos, {
|
|
44932
|
-
|
|
44933
|
-
|
|
44934
|
-
|
|
44935
|
-
|
|
44936
|
-
|
|
44937
|
-
|
|
44938
|
-
|
|
44939
|
-
|
|
45048
|
+
revision_pedida_el: hoy,
|
|
45049
|
+
revision_vence_el: sumarDias4(hoy, DIAS_REVISION_CUENTA),
|
|
45050
|
+
revision_facturado: typeof vista.facturado === "number" ? vista.facturado : null,
|
|
45051
|
+
revision_costo: typeof vista.costo === "number" ? vista.costo : null,
|
|
45052
|
+
revisada_sin_cambios: null
|
|
45053
|
+
});
|
|
45054
|
+
} else if (nueva && resultado.a === "pendiente_aprobacion") {
|
|
45055
|
+
if (caso.estado === "en_revision") datos.revisada_sin_cambios = resultadoRevisionCuenta(caso.datos, nueva.evaluacion, hoy) === "sin_cambios";
|
|
45056
|
+
else if (caso.datos.revisada_sin_cambios === true && resultadoRevisionCuenta(caso.datos, nueva.evaluacion, hoy) === "con_cambios") datos.revisada_sin_cambios = false;
|
|
45057
|
+
}
|
|
45058
|
+
if (nueva) {
|
|
45059
|
+
Object.assign(datos, {
|
|
45060
|
+
financiador: nueva.lectura.financiador,
|
|
45061
|
+
ingreso: nueva.lectura.ingreso,
|
|
45062
|
+
egreso: nueva.lectura.egreso,
|
|
45063
|
+
facturado: nueva.lectura.facturado,
|
|
45064
|
+
consumos: nueva.lectura.consumos,
|
|
45065
|
+
cirugias: nueva.lectura.cirugias,
|
|
45066
|
+
evaluacion: nueva.evaluacion,
|
|
44940
45067
|
comprobado_el: contexto.hoy ?? null
|
|
44941
45068
|
});
|
|
44942
45069
|
}
|
|
45070
|
+
const despues = { ...caso.datos, ...datos };
|
|
45071
|
+
const e = nueva?.evaluacion ?? (despues.evaluacion && typeof despues.evaluacion === "object" ? despues.evaluacion : null);
|
|
45072
|
+
if (e && typeof e.facturado === "number" && typeof e.costo === "number") {
|
|
45073
|
+
const quien = { internacion_id: str2(despues.internacion_id) ?? "", financiador: str2(despues.financiador) ?? "" };
|
|
45074
|
+
const nota = notaRevisionCuenta(despues, resultado.a, e, hoy);
|
|
45075
|
+
datos.oracion = `${oracionCostoInternacion(nueva?.lectura ?? quien, e)}${nota ? ` ${nota}` : ""}`;
|
|
45076
|
+
}
|
|
44943
45077
|
delete datos.lectura;
|
|
44944
45078
|
}
|
|
44945
45079
|
if (caso.workflow === "cobranza_financiador") {
|
|
@@ -45743,7 +45877,8 @@ var ESPERAN_PERSONA = {
|
|
|
45743
45877
|
credencial_profesional: ["observada"],
|
|
45744
45878
|
internacion_al_dia: ["con_pendientes"],
|
|
45745
45879
|
honorario_en_cero: ["para_cargar"],
|
|
45746
|
-
debito_profesional: ["aprobado", "con_diferencias"]
|
|
45880
|
+
debito_profesional: ["aprobado", "con_diferencias"],
|
|
45881
|
+
rentabilidad_internacion: ["en_revision"]
|
|
45747
45882
|
};
|
|
45748
45883
|
var CANALES_AVISO = ["mail", "whatsapp"];
|
|
45749
45884
|
var HORARIO_AVISOS = { desde: "08:00", hasta: "18:00" };
|
|
@@ -45825,6 +45960,10 @@ function pendientesDe(caso, hoy) {
|
|
|
45825
45960
|
const vence = texto8(d.vence_el);
|
|
45826
45961
|
return [{ ...base, que: `${bono}: sin presentar${vence ? `, vence el ${vence.slice(8, 10)}/${vence.slice(5, 7)}` : ""}`, responsable: rol("facturacion") }];
|
|
45827
45962
|
}
|
|
45963
|
+
if (caso.workflow === "rentabilidad_internacion") {
|
|
45964
|
+
const vence = texto8(d.revision_vence_el);
|
|
45965
|
+
return [{ ...base, que: `${caso.titulo}: revisar la cuenta (consumos sin facturar o m\xF3dulo con el financiador)${vence ? `, antes del ${vence.slice(8, 10)}/${vence.slice(5, 7)}` : ""}`, responsable: rol("facturacion") }];
|
|
45966
|
+
}
|
|
45828
45967
|
if (caso.workflow === "credencial_profesional") {
|
|
45829
45968
|
const id3 = texto8(d.profesional_id);
|
|
45830
45969
|
const nombre = texto8(d.profesional) ?? (id3 ? `Profesional ${id3}` : "Profesional");
|
|
@@ -46375,6 +46514,13 @@ function numOrNull(v) {
|
|
|
46375
46514
|
const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
|
|
46376
46515
|
return Number.isFinite(n) ? n : null;
|
|
46377
46516
|
}
|
|
46517
|
+
function listaTextos(v) {
|
|
46518
|
+
const crudos = (Array.isArray(v) ? v : [v]).flatMap((x) => typeof x === "string" ? x.split(",") : []);
|
|
46519
|
+
return [...new Set(crudos.map(str3).filter((s) => s !== null))].slice(0, 20);
|
|
46520
|
+
}
|
|
46521
|
+
function ordenCasos(orden, despuesDe) {
|
|
46522
|
+
return orden === "id" || despuesDe !== null ? "id" : null;
|
|
46523
|
+
}
|
|
46378
46524
|
function companyFrom(params, fallback) {
|
|
46379
46525
|
const companyId = str3(params.companyId) ?? str3(fallback);
|
|
46380
46526
|
if (!companyId) throw new OpsError("company_requerida", "companyId es obligatorio");
|
|
@@ -46404,10 +46550,19 @@ async function conErrores(fn) {
|
|
|
46404
46550
|
function registrarHerramientas(ctx) {
|
|
46405
46551
|
ctx.tools.register(TOOL_NAMES.listarCasos, toolSchema(TOOL_NAMES.listarCasos), async (params, runCtx) => conErrores(async () => {
|
|
46406
46552
|
const p = obj(params);
|
|
46407
|
-
const
|
|
46553
|
+
const workflow = str3(p.workflow);
|
|
46554
|
+
if (workflow && !getWorkflow(workflow)) throw new OpsError("workflow_desconocido", `workflow desconocido: ${workflow}. Disponibles: ${listarWorkflows().map((w) => w.clave).join(", ")}`);
|
|
46555
|
+
const despuesDe = str3(p.despues_de);
|
|
46556
|
+
const porId = ordenCasos(p.orden, despuesDe) === "id";
|
|
46557
|
+
const casos = await listarCasos(ctx, { companyId: runCtx.companyId, workflow, estado: str3(p.estado), estados: listaTextos(p.estados), referencia: str3(p.referencia), limit: numOrNull(p.limit), offset: numOrNull(p.offset), orden: ordenCasos(p.orden, despuesDe), despuesDe });
|
|
46558
|
+
const limite = Math.min(Math.max(numOrNull(p.limit) || 50, 1), 500);
|
|
46559
|
+
const desde = Math.max(Math.floor(numOrNull(p.offset) ?? 0), 0);
|
|
46560
|
+
const mas = casos.length < limite ? "" : porId ? `
|
|
46561
|
+
Puede haber m\xE1s casos: ped\xED la p\xE1gina siguiente con los mismos filtros, orden "id" y despues_de "${casos[casos.length - 1].id}" (limit ${limite}).` : `
|
|
46562
|
+
Puede haber m\xE1s casos: ped\xED la p\xE1gina siguiente con offset ${desde + casos.length} (limit ${limite}).`;
|
|
46408
46563
|
return {
|
|
46409
|
-
content: casos.length ? casos.map(resumenCaso).join("\n") : "No hay casos que coincidan.",
|
|
46410
|
-
data: { casos }
|
|
46564
|
+
content: casos.length ? `${casos.map(resumenCaso).join("\n")}${mas}` : "No hay casos que coincidan.",
|
|
46565
|
+
data: { casos, ...mas && porId ? { despues_de: casos[casos.length - 1].id } : {} }
|
|
46411
46566
|
};
|
|
46412
46567
|
}));
|
|
46413
46568
|
ctx.tools.register(TOOL_NAMES.leerCaso, toolSchema(TOOL_NAMES.leerCaso), async (params, runCtx) => conErrores(async () => {
|
|
@@ -46577,7 +46732,7 @@ function registrarDatosYAcciones(ctx) {
|
|
|
46577
46732
|
transiciones: w.transiciones.map((t6) => ({ via: t6.via, de: t6.de, a: typeof t6.a === "string" ? t6.a : "(seg\xFAn datos)", actor: t6.actor, nivelRequerido: t6.nivelRequerido ?? null, descripcion: t6.descripcion }))
|
|
46578
46733
|
})));
|
|
46579
46734
|
ctx.data.register(DATA_KEYS.tablero, async (params) => tablero(ctx, companyFrom(params), numOrNull(params.dias)));
|
|
46580
|
-
ctx.data.register(DATA_KEYS.casos, async (params) => listarCasos(ctx, { companyId: companyFrom(params), workflow: str3(params.workflow), estado: str3(params.estado), limit: numOrNull(params.limit) }));
|
|
46735
|
+
ctx.data.register(DATA_KEYS.casos, async (params) => listarCasos(ctx, { companyId: companyFrom(params), workflow: str3(params.workflow), estado: str3(params.estado), estados: listaTextos(params.estados), referencia: str3(params.referencia), limit: numOrNull(params.limit), offset: numOrNull(params.offset), orden: ordenCasos(params.orden, str3(params.despues_de)), despuesDe: str3(params.despues_de) }));
|
|
46581
46736
|
ctx.data.register(DATA_KEYS.caso, async (params) => {
|
|
46582
46737
|
const casoId = str3(params.casoId);
|
|
46583
46738
|
if (!casoId) throw new OpsError("caso_requerido", "casoId es obligatorio");
|
|
@@ -46643,7 +46798,7 @@ async function manejarApi(ctx, input2) {
|
|
|
46643
46798
|
case "tablero":
|
|
46644
46799
|
return respuesta(200, await tablero(ctx, companyId, numOrNull(qs("dias"))));
|
|
46645
46800
|
case "casos":
|
|
46646
|
-
return respuesta(200, { casos: await listarCasos(ctx, { companyId, workflow: qs("workflow"), estado: qs("estado"), limit: numOrNull(qs("limit")) }) });
|
|
46801
|
+
return respuesta(200, { casos: await listarCasos(ctx, { companyId, workflow: qs("workflow"), estado: qs("estado"), estados: listaTextos(q.estados), referencia: qs("referencia"), limit: numOrNull(qs("limit")), offset: numOrNull(qs("offset")), orden: ordenCasos(qs("orden"), qs("despues_de")), despuesDe: qs("despues_de") }) });
|
|
46647
46802
|
case "caso": {
|
|
46648
46803
|
const detalle = await leerCasoCompleto(ctx, companyId, input2.params.casoId ?? "");
|
|
46649
46804
|
return detalle ? respuesta(200, detalle) : respuesta(404, { error: "caso_inexistente" });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paperclip-plugin-autopilot-ops",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Autopilot Care · operación autónoma gobernada para instituciones de salud: workflows determinísticos, validaciones, registro de negocio, políticas (observa/propone/ejecuta/corte) y tablero del director, como plugin de Paperclip.",
|
|
6
6
|
"files": [
|