paperclip-plugin-autopilot-ops 0.1.47 → 0.1.49
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 -1
- package/dist/ui/index.js +9 -1
- package/dist/worker.js +58 -12
- 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.49";
|
|
4
4
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
5
5
|
var PAGE_ROUTE = "autopilot";
|
|
6
6
|
var TOOL_NAMES = {
|
|
@@ -345,6 +345,14 @@ var manifest = {
|
|
|
345
345
|
capability: "api.routes.register",
|
|
346
346
|
companyResolution: { from: "body", key: "companyId" }
|
|
347
347
|
},
|
|
348
|
+
{
|
|
349
|
+
routeKey: "suspender-agenda",
|
|
350
|
+
method: "POST",
|
|
351
|
+
path: "/casos/:casoId/suspender-agenda",
|
|
352
|
+
auth: "board",
|
|
353
|
+
capability: "api.routes.register",
|
|
354
|
+
companyResolution: { from: "body", key: "companyId" }
|
|
355
|
+
},
|
|
348
356
|
{
|
|
349
357
|
routeKey: "version",
|
|
350
358
|
method: "GET",
|
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.49";
|
|
12
12
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
13
13
|
var PAGE_ROUTE = "autopilot";
|
|
14
14
|
var TOOL_NAMES = {
|
|
@@ -353,6 +353,14 @@ var manifest = {
|
|
|
353
353
|
capability: "api.routes.register",
|
|
354
354
|
companyResolution: { from: "body", key: "companyId" }
|
|
355
355
|
},
|
|
356
|
+
{
|
|
357
|
+
routeKey: "suspender-agenda",
|
|
358
|
+
method: "POST",
|
|
359
|
+
path: "/casos/:casoId/suspender-agenda",
|
|
360
|
+
auth: "board",
|
|
361
|
+
capability: "api.routes.register",
|
|
362
|
+
companyResolution: { from: "body", key: "companyId" }
|
|
363
|
+
},
|
|
356
364
|
{
|
|
357
365
|
routeKey: "version",
|
|
358
366
|
method: "GET",
|
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.49";
|
|
39936
39936
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
39937
39937
|
var PAGE_ROUTE = "autopilot";
|
|
39938
39938
|
var TOOL_NAMES = {
|
|
@@ -40277,6 +40277,14 @@ var manifest = {
|
|
|
40277
40277
|
capability: "api.routes.register",
|
|
40278
40278
|
companyResolution: { from: "body", key: "companyId" }
|
|
40279
40279
|
},
|
|
40280
|
+
{
|
|
40281
|
+
routeKey: "suspender-agenda",
|
|
40282
|
+
method: "POST",
|
|
40283
|
+
path: "/casos/:casoId/suspender-agenda",
|
|
40284
|
+
auth: "board",
|
|
40285
|
+
capability: "api.routes.register",
|
|
40286
|
+
companyResolution: { from: "body", key: "companyId" }
|
|
40287
|
+
},
|
|
40280
40288
|
{
|
|
40281
40289
|
routeKey: "version",
|
|
40282
40290
|
method: "GET",
|
|
@@ -42494,15 +42502,16 @@ function observacionDe(r) {
|
|
|
42494
42502
|
if (r.situacion !== "habilitado") return "inhabilitada";
|
|
42495
42503
|
return null;
|
|
42496
42504
|
}
|
|
42505
|
+
var GRAVES_MATRICULA = ["inhabilitada", "sancion", "otra_persona"];
|
|
42497
42506
|
var credencialProfesional = {
|
|
42498
42507
|
clave: "credencial_profesional",
|
|
42499
|
-
nombre: "
|
|
42508
|
+
nombre: "Control de matr\xEDculas",
|
|
42500
42509
|
puesto: "Personal y profesionales",
|
|
42501
|
-
descripcion: "Lee en el HIS la matr\xEDcula de cada profesional con agenda y la verifica contra el registro nacional de profesionales de la salud (REFEPS). Si no figura, est\xE1 a nombre de otra persona, est\xE1 inhabilitada o falta cargarla, avisa al equipo con d\xF3nde se corrige. El
|
|
42510
|
+
descripcion: "Lee en el HIS la matr\xEDcula de cada profesional con agenda y la verifica contra el registro nacional de profesionales de la salud (REFEPS). Si no figura, est\xE1 a nombre de otra persona, est\xE1 inhabilitada o falta cargarla, avisa al equipo con d\xF3nde se corrige. El agente no escribe en el sistema.",
|
|
42502
42511
|
inicial: "detectado",
|
|
42503
|
-
estados: ["detectado", "vigente", "observada", "corregida", "no_corresponde", "descartado"],
|
|
42512
|
+
estados: ["detectado", "vigente", "observada", "corregida", "no_corresponde", "agenda_suspendida", "descartado"],
|
|
42504
42513
|
finalesOk: ["vigente"],
|
|
42505
|
-
finalesNoOk: ["no_corresponde", "descartado"],
|
|
42514
|
+
finalesNoOk: ["no_corresponde", "agenda_suspendida", "descartado"],
|
|
42506
42515
|
minutosAbsorbidos: 5,
|
|
42507
42516
|
transiciones: [
|
|
42508
42517
|
{
|
|
@@ -42534,7 +42543,7 @@ var credencialProfesional = {
|
|
|
42534
42543
|
a: "corregida",
|
|
42535
42544
|
actor: ["humano"],
|
|
42536
42545
|
cargaManual: true,
|
|
42537
|
-
descripcion: "Una persona de la instituci\xF3n corrigi\xF3 la ficha del profesional en el HIS. El
|
|
42546
|
+
descripcion: "Una persona de la instituci\xF3n corrigi\xF3 la ficha del profesional en el HIS. El agente vuelve a consultar el registro.",
|
|
42538
42547
|
validar: (_caso, datos) => [
|
|
42539
42548
|
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "corregir requiere accion_id de la carga registrada")
|
|
42540
42549
|
]
|
|
@@ -42547,6 +42556,17 @@ var credencialProfesional = {
|
|
|
42547
42556
|
descripcion: "El equipo indica que la observaci\xF3n no aplica (por ejemplo, personal no matriculado o matr\xEDcula provincial confirmada con el colegio). Queda registrado con el motivo.",
|
|
42548
42557
|
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "no_corresponde requiere motivo")]
|
|
42549
42558
|
},
|
|
42559
|
+
{
|
|
42560
|
+
via: "suspender_agenda",
|
|
42561
|
+
de: ["observada"],
|
|
42562
|
+
a: "agenda_suspendida",
|
|
42563
|
+
actor: ["humano"],
|
|
42564
|
+
descripcion: "La matr\xEDcula est\xE1 de verdad inhabilitada, con sanci\xF3n o a nombre de otra persona: la instituci\xF3n suspendi\xF3 la agenda del profesional hasta que lo regularice. Queda registrado qui\xE9n lo decidi\xF3 y por qu\xE9.",
|
|
42565
|
+
validar: (caso, datos) => [
|
|
42566
|
+
GRAVES_MATRICULA.includes(texto4(caso.datos.observacion) ?? "") ? ok("observacion_grave") : falla("observacion_grave", "suspender la agenda es para una matr\xEDcula inhabilitada, con sanci\xF3n o a nombre de otra persona"),
|
|
42567
|
+
texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "suspender_agenda requiere motivo")
|
|
42568
|
+
]
|
|
42569
|
+
},
|
|
42550
42570
|
{
|
|
42551
42571
|
via: "descartar",
|
|
42552
42572
|
de: ["detectado", "observada", "corregida"],
|
|
@@ -44956,6 +44976,11 @@ function opcionesCostos(op) {
|
|
|
44956
44976
|
function opcionesRentabilidad(op) {
|
|
44957
44977
|
return { umbral: enteroEntre(op.umbral_margen, 0, 90) ?? UMBRAL_MARGEN_POR_DEFECTO, mesesPrecio: enteroEntre(op.meses_precio, 1, 36) ?? MESES_PRECIO_POR_DEFECTO };
|
|
44958
44978
|
}
|
|
44979
|
+
function pareceNoProfesional(nombre) {
|
|
44980
|
+
const n = nombre.trim();
|
|
44981
|
+
const [apellido = "", nombres = ""] = n.split(",").map((x) => x.trim().toLowerCase());
|
|
44982
|
+
return /^[^a-záéíóúñü]/i.test(n) || /\d/.test(n) || apellido !== "" && apellido === nombres || /\b(admin|administrador|prueba|test|sistema|usuario)\b/i.test(n);
|
|
44983
|
+
}
|
|
44959
44984
|
async function evaluarRentabilidades(ctx, companyId, lecturas) {
|
|
44960
44985
|
if (!Array.isArray(lecturas)) throw new OpsError("validacion", "lecturas: tiene que ser una lista");
|
|
44961
44986
|
if (lecturas.length > 2e3) throw new OpsError("validacion", "lecturas: como m\xE1ximo 2000 por llamada");
|
|
@@ -45459,12 +45484,14 @@ async function transicionar(ctx, input2) {
|
|
|
45459
45484
|
const lecturaId = str2(datos.lectura_id);
|
|
45460
45485
|
if (lecturaId) {
|
|
45461
45486
|
const rows = await ctx.db.query(
|
|
45462
|
-
`SELECT id, caso_id, tipo, resultado, created_at FROM ${t3(ctx, "accion")} WHERE company_id = $1 AND id = $2 LIMIT 1`,
|
|
45487
|
+
`SELECT id, caso_id, tipo, resultado, evidencia, created_at FROM ${t3(ctx, "accion")} WHERE company_id = $1 AND id = $2 LIMIT 1`,
|
|
45463
45488
|
[input2.companyId, lecturaId]
|
|
45464
45489
|
);
|
|
45465
45490
|
const lectura = rows[0];
|
|
45491
|
+
const evidencia = lectura && lectura.evidencia && typeof lectura.evidencia === "object" ? lectura.evidencia : null;
|
|
45492
|
+
const distinta = lectura && caso.workflow === "credencial_profesional" && resultado.via === "verificar" && evidencia ? evidencia.profesional_id !== void 0 && String(evidencia.profesional_id) !== String(datos.profesional_id ?? caso.datos.profesional_id ?? "") ? `la lectura ${lecturaId} es de otro profesional (${String(evidencia.profesional_id)})` : evidencia.matricula !== void 0 && datos.matricula !== void 0 && datos.matricula !== null && String(evidencia.matricula) !== String(datos.matricula) ? `la lectura ${lecturaId} es de la matr\xEDcula ${String(evidencia.matricula)} y se informa la ${String(datos.matricula)}` : null : null;
|
|
45466
45493
|
let vieja = false;
|
|
45467
|
-
if (lectura && (resultado.via === "comprobar" || (caso.workflow === "circular_aranceles" || caso.workflow === "ajuste_convenio") && resultado.via === "verificar")) {
|
|
45494
|
+
if (lectura && (resultado.via === "comprobar" || (caso.workflow === "circular_aranceles" || caso.workflow === "ajuste_convenio") && resultado.via === "verificar" || caso.workflow === "credencial_profesional" && resultado.via === "verificar" && caso.estado === "corregida")) {
|
|
45468
45495
|
const ultima = await ctx.db.query(
|
|
45469
45496
|
`SELECT max(created_at) AS ultima FROM ${t3(ctx, "transicion")} WHERE company_id = $1 AND caso_id = $2`,
|
|
45470
45497
|
[input2.companyId, caso.id]
|
|
@@ -45472,7 +45499,7 @@ async function transicionar(ctx, input2) {
|
|
|
45472
45499
|
const desde = ultima[0]?.ultima ? Date.parse(iso2(ultima[0].ultima)) : NaN;
|
|
45473
45500
|
vieja = Number.isFinite(desde) && Date.parse(iso2(lectura.created_at)) <= desde;
|
|
45474
45501
|
}
|
|
45475
|
-
const problema = !lectura ? `lectura_id ${lecturaId} no existe en esta instituci\xF3n` : String(lectura.caso_id) !== caso.id ? `la lectura ${lecturaId} pertenece a otro caso` : !["lectura", "verificacion"].includes(String(lectura.tipo)) ? `la acci\xF3n ${lecturaId} es de tipo ${String(lectura.tipo)}; hace falta una lectura o verificaci\xF3n` : String(lectura.resultado) !== "ok" ? `la lectura ${lecturaId} termin\xF3 con resultado ${String(lectura.resultado)}` : vieja ? `la lectura ${lecturaId} es anterior al \xFAltimo cambio del caso: volver a leer
|
|
45502
|
+
const problema = !lectura ? `lectura_id ${lecturaId} no existe en esta instituci\xF3n` : String(lectura.caso_id) !== caso.id ? `la lectura ${lecturaId} pertenece a otro caso` : !["lectura", "verificacion"].includes(String(lectura.tipo)) ? `la acci\xF3n ${lecturaId} es de tipo ${String(lectura.tipo)}; hace falta una lectura o verificaci\xF3n` : String(lectura.resultado) !== "ok" ? `la lectura ${lecturaId} termin\xF3 con resultado ${String(lectura.resultado)}` : vieja ? `la lectura ${lecturaId} es anterior al \xFAltimo cambio del caso: volver a leer y registrar esa lectura` : distinta;
|
|
45476
45503
|
if (problema) {
|
|
45477
45504
|
throw new OpsError("validacion", `lectura_registrada: ${problema}`, { validaciones: [{ regla: "lectura_registrada", ok: false, detalle: problema }], estado: caso.estado });
|
|
45478
45505
|
}
|
|
@@ -45799,6 +45826,18 @@ async function transicionar(ctx, input2) {
|
|
|
45799
45826
|
datos.observacion = observacionDe(r);
|
|
45800
45827
|
datos.verificada_el = contexto.hoy ?? null;
|
|
45801
45828
|
}
|
|
45829
|
+
if (caso.estado === "corregida") {
|
|
45830
|
+
const antes = [caso.datos.matricula_nacional, caso.datos.matricula_provincial].map((v) => String(v ?? "").replace(/\D/g, ""));
|
|
45831
|
+
const ahora = [datos.matricula_nacional ?? caso.datos.matricula_nacional, datos.matricula_provincial ?? caso.datos.matricula_provincial].map((v) => String(v ?? "").replace(/\D/g, ""));
|
|
45832
|
+
datos.ficha_sin_cambios = datos.observacion !== null && antes.join("|") === ahora.join("|");
|
|
45833
|
+
} else delete datos.ficha_sin_cambios;
|
|
45834
|
+
datos.posible_no_profesional = pareceNoProfesional(String(datos.profesional ?? caso.datos.profesional ?? caso.titulo.split(" \xB7 ")[0] ?? ""));
|
|
45835
|
+
const ag = datos.agenda && typeof datos.agenda === "object" ? datos.agenda : null;
|
|
45836
|
+
if (ag) {
|
|
45837
|
+
const proximo = typeof ag.proximo_turno === "string" && /^\d{4}-\d{2}-\d{2}( \d{2}:\d{2})?$/.test(ag.proximo_turno) ? ag.proximo_turno : null;
|
|
45838
|
+
const n = Number(ag.turnos_7_dias);
|
|
45839
|
+
datos.agenda = { proximo_turno: proximo, turnos_7_dias: Number.isInteger(n) && n >= 0 && n < 1e4 ? n : 0, leida_el: contexto.hoy ?? null };
|
|
45840
|
+
} else delete datos.agenda;
|
|
45802
45841
|
}
|
|
45803
45842
|
if (caso.workflow === "facturacion_pendiente" && resultado.via === "observar") {
|
|
45804
45843
|
const fecha5 = String(datos.fecha_prestacion ?? caso.datos.fecha_prestacion ?? "");
|
|
@@ -46581,7 +46620,8 @@ var ROLES = {
|
|
|
46581
46620
|
facturacion: "Facturaci\xF3n",
|
|
46582
46621
|
internacion: "Internaci\xF3n",
|
|
46583
46622
|
honorarios: "Honorarios",
|
|
46584
|
-
personal: "Administraci\xF3n de personal"
|
|
46623
|
+
personal: "Administraci\xF3n de personal",
|
|
46624
|
+
direccion_medica: "Direcci\xF3n m\xE9dica"
|
|
46585
46625
|
};
|
|
46586
46626
|
var ESPERAN_PERSONA = {
|
|
46587
46627
|
cuenta_completa: ["para_completar", "con_faltantes"],
|
|
@@ -46681,11 +46721,12 @@ function pendientesDe(caso, hoy) {
|
|
|
46681
46721
|
const nombre = texto8(d.profesional) ?? (id3 ? `Profesional ${id3}` : "Profesional");
|
|
46682
46722
|
const obs = texto8(d.observacion);
|
|
46683
46723
|
const que = `${nombre}: ${(obs && OBSERVACIONES_MATRICULA[obs]) ?? "la matr\xEDcula tiene una observaci\xF3n del registro nacional"}`;
|
|
46684
|
-
|
|
46724
|
+
const grave = obs === "inhabilitada" || obs === "sancion" || obs === "otra_persona";
|
|
46725
|
+
return [{ ...base, que, responsable: rol("personal") }, ...grave ? [{ ...base, que, responsable: rol("direccion_medica") }] : []];
|
|
46685
46726
|
}
|
|
46686
46727
|
return [];
|
|
46687
46728
|
}
|
|
46688
|
-
var CLAVE_RE = /^(profesional:[A-Za-z0-9_-]{1,40}|financiador:\d{1,12}|rol:(admision|aranceles|facturacion|internacion|personal|honorarios))$/;
|
|
46729
|
+
var CLAVE_RE = /^(profesional:[A-Za-z0-9_-]{1,40}|financiador:\d{1,12}|rol:(admision|aranceles|facturacion|internacion|personal|honorarios|direccion_medica))$/;
|
|
46689
46730
|
var MAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
|
|
46690
46731
|
var COLS_CONTACTO = "id, clave, nombre, mail, whatsapp, activo, updated_at";
|
|
46691
46732
|
function mapContacto(r) {
|
|
@@ -47672,6 +47713,11 @@ async function manejarApi(ctx, input2) {
|
|
|
47672
47713
|
return respuesta(200, await registrarCargaManual(ctx, { companyId, casoId: input2.params.casoId ?? "", valorCargado: body.valorCargado, archivoHash: str3(body.archivoHash), canal: str3(body.canal), destinatario: str3(body.destinatario), comentario: str3(body.comentario), persona: decididoPor, idempotencyKey: str3(body.idempotencyKey), actor }));
|
|
47673
47714
|
case "respuesta-paciente":
|
|
47674
47715
|
return respuesta(200, await registrarRespuestaPaciente(ctx, { companyId, casoId: input2.params.casoId ?? "", acepto: body.acepto === true, comentario: str3(body.comentario), persona: decididoPor, idempotencyKey: str3(body.idempotencyKey), actor }));
|
|
47716
|
+
case "suspender-agenda": {
|
|
47717
|
+
if (actor.tipo !== "humano") return respuesta(403, { error: "actor_no_permitido", motivo: "suspender la agenda lo decide una persona de la instituci\xF3n" });
|
|
47718
|
+
if (!str3(body.motivo)) return respuesta(422, { error: "validacion", motivo: "motivo_presente: suspender_agenda requiere motivo" });
|
|
47719
|
+
return respuesta(200, await transicionar(ctx, { companyId, casoId: input2.params.casoId ?? "", via: "suspender_agenda", motivo: motivoConPersona(str3(body.motivo)), datos: conPersona(obj(body.datos)), idempotencyKey: str3(body.idempotencyKey), actor }));
|
|
47720
|
+
}
|
|
47675
47721
|
case "no-corresponde": {
|
|
47676
47722
|
if (actor.tipo !== "humano") return respuesta(403, { error: "actor_no_permitido", motivo: "no_corresponde lo decide una persona de la instituci\xF3n" });
|
|
47677
47723
|
if (!str3(body.motivo)) return respuesta(422, { error: "validacion", motivo: "motivo_presente: no_corresponde requiere motivo" });
|
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.49",
|
|
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": [
|