paperclip-plugin-autopilot-ops 0.1.52 → 0.1.53

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/manifest.ts
2
2
  var PLUGIN_ID = "alephoo.autopilot-ops";
3
- var PLUGIN_VERSION = "0.1.52";
3
+ var PLUGIN_VERSION = "0.1.53";
4
4
  var DB_NAMESPACE_SLUG = "autopilot_ops";
5
5
  var PAGE_ROUTE = "autopilot";
6
6
  var TOOL_NAMES = {
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.52";
11
+ var PLUGIN_VERSION = "0.1.53";
12
12
  var DB_NAMESPACE_SLUG = "autopilot_ops";
13
13
  var PAGE_ROUTE = "autopilot";
14
14
  var TOOL_NAMES = {
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.52";
39935
+ var PLUGIN_VERSION = "0.1.53";
39936
39936
  var DB_NAMESPACE_SLUG = "autopilot_ops";
39937
39937
  var PAGE_ROUTE = "autopilot";
39938
39938
  var TOOL_NAMES = {
@@ -42498,6 +42498,7 @@ function observacionDe(r) {
42498
42498
  if (r.sin_matricula) return "sin_matricula";
42499
42499
  if (!r.encontrada) return "no_figura";
42500
42500
  if (r.coincide_nombre === false) return "otra_persona";
42501
+ if (r.coincide_nombre !== true) return "sin_comparar";
42501
42502
  if (r.sancion) return "sancion";
42502
42503
  if (r.situacion !== "habilitado") return "inhabilitada";
42503
42504
  return null;
@@ -42511,15 +42512,45 @@ function matriculaInvalida(cargada, tipo) {
42511
42512
  if (/^(\d)\1+$/.test(d)) return true;
42512
42513
  return "01234567890".includes(d) || "9876543210".includes(d);
42513
42514
  }
42514
- function tienePropiaHabilitada(enRegistro) {
42515
- return Array.isArray(enRegistro) && enRegistro.some((m) => m && typeof m === "object" && m.situacion === "habilitado" && m.sancion !== true);
42515
+ var sinTildes = (s) => String(s ?? "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
42516
+ var PROFESION_POR_ESPECIALIDAD = [
42517
+ [/odonto|ortodonc|endodonc|periodonc|implantolog/, "odontolog"],
42518
+ [/kinesiolog|kinesiterap/, "kinesiolog"],
42519
+ [/psicolog(?!.*psiquiatr)/, "psicolog"],
42520
+ [/nutricion|nutricionista/, "nutricion"],
42521
+ [/fonoaudiolog/, "fonoaudiolog"],
42522
+ [/enfermer/, "enfermer"],
42523
+ [/bioquimic/, "bioquimic"],
42524
+ [/farmac(ia|eutic)/, "farmac"],
42525
+ [/instrumentac/, "instrumentad"],
42526
+ [/terapia ocupacional|terapista ocupacional/, "terapista ocupacional"],
42527
+ [/podolog/, "podolog"]
42528
+ ];
42529
+ function profesionEsperada(especialidades) {
42530
+ const lista3 = (Array.isArray(especialidades) ? especialidades.map(String) : String(especialidades ?? "").split(/[,;·]/)).map(sinTildes).map((s) => s.trim()).filter(Boolean);
42531
+ if (!lista3.length) return null;
42532
+ const halladas = new Set(lista3.map((e) => PROFESION_POR_ESPECIALIDAD.find(([re]) => re.test(e))?.[1] ?? "medic"));
42533
+ return halladas.size === 1 ? [...halladas][0] : null;
42534
+ }
42535
+ function mismaProfesion(profesion, esperada) {
42536
+ return !esperada || !texto4(profesion) || sinTildes(profesion).includes(esperada);
42537
+ }
42538
+ function tienePropiaHabilitada(enRegistro, esperada) {
42539
+ return Array.isArray(enRegistro) && enRegistro.some((m) => m && typeof m === "object" && m.situacion === "habilitado" && m.sancion !== true && mismaProfesion(m.profesion, esperada));
42540
+ }
42541
+ function fichaMatricula(d) {
42542
+ const tipo = String(d.tipo_matricula ?? "");
42543
+ const cargada = tipo === "provincial" ? d.matricula_provincial : tipo === "nacional" ? d.matricula_nacional : void 0;
42544
+ return { cargada: cargada ?? d.matricula, tipo: tipo || null, enRegistro: d.en_registro, especialidades: d.especialidades ?? d.especialidad };
42516
42545
  }
42517
42546
  function observacionMatricula(r, ficha) {
42518
42547
  const obs = observacionDe(r);
42519
- if ((obs === "otra_persona" || obs === "no_figura") && (matriculaInvalida(ficha.cargada, ficha.tipo) || tienePropiaHabilitada(ficha.enRegistro))) return "numero_mal_cargado";
42548
+ const esperada = profesionEsperada(ficha.especialidades);
42549
+ if ((obs === "otra_persona" || obs === "no_figura") && (matriculaInvalida(ficha.cargada, ficha.tipo) || tienePropiaHabilitada(ficha.enRegistro, esperada))) return "numero_mal_cargado";
42550
+ if (obs === null && !mismaProfesion(r.profesion, esperada)) return "profesion_distinta";
42520
42551
  return obs;
42521
42552
  }
42522
- var GRAVES_MATRICULA = ["inhabilitada", "sancion", "otra_persona"];
42553
+ var GRAVES_MATRICULA = ["inhabilitada", "sancion", "otra_persona", "profesion_distinta"];
42523
42554
  var credencialProfesional = {
42524
42555
  clave: "credencial_profesional",
42525
42556
  nombre: "Control de matr\xEDculas",
@@ -42536,7 +42567,7 @@ var credencialProfesional = {
42536
42567
  de: ["detectado", "corregida"],
42537
42568
  a: (_caso, datos) => {
42538
42569
  const r = leerResultadoRegistro(datos.resultado);
42539
- return r && observacionDe(r) === null ? "vigente" : "observada";
42570
+ return r && observacionMatricula(r, fichaMatricula({ ..._caso.datos, ...datos })) === null ? "vigente" : "observada";
42540
42571
  },
42541
42572
  actor: ["agente", "humano", "sistema"],
42542
42573
  nivelRequerido: "observa",
@@ -42580,7 +42611,7 @@ var credencialProfesional = {
42580
42611
  actor: ["humano"],
42581
42612
  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.",
42582
42613
  validar: (caso, datos) => [
42583
- 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"),
42614
+ 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, a nombre de otra persona o de otra profesi\xF3n"),
42584
42615
  // A nombre de otra persona: solo con la búsqueda por nombre hecha (sin ella puede ser un número mal cargado).
42585
42616
  caso.datos.observacion !== "otra_persona" || Array.isArray(caso.datos.en_registro) ? ok("busqueda_por_nombre") : falla("busqueda_por_nombre", "a nombre de otra persona sin buscar al profesional por su nombre en el registro: volver a verificarlo antes de suspender"),
42586
42617
  texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "suspender_agenda requiere motivo")
@@ -42592,8 +42623,11 @@ var credencialProfesional = {
42592
42623
  a: "descartado",
42593
42624
  actor: ["agente", "humano"],
42594
42625
  nivelRequerido: "observa",
42595
- descripcion: "El profesional ya no est\xE1 activo en el sistema o no tiene agenda: no hay nada que verificar.",
42596
- validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
42626
+ descripcion: "El profesional ya no est\xE1 activo en el sistema o no tiene agenda: no hay nada que verificar. Una matr\xEDcula grave la cierra una persona, no el agente.",
42627
+ validar: (caso, datos, contexto) => [
42628
+ texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo"),
42629
+ contexto.actor === "humano" || !(caso.estado === "observada" && GRAVES_MATRICULA.includes(texto4(caso.datos.observacion) ?? "")) ? ok("grave_la_cierra_una_persona") : falla("grave_la_cierra_una_persona", "una matr\xEDcula grave no la descarta el agente: la decide la direcci\xF3n m\xE9dica")
42630
+ ]
42597
42631
  }
42598
42632
  ]
42599
42633
  };
@@ -44888,15 +44922,11 @@ function resultadoDistinto(leido, informado) {
44888
44922
  }
44889
44923
  return null;
44890
44924
  }
44891
- function fichaMatricula(d) {
44892
- const tipo = String(d.tipo_matricula ?? "");
44893
- const cargada = tipo === "provincial" ? d.matricula_provincial : tipo === "nacional" ? d.matricula_nacional : void 0;
44894
- return { cargada: cargada ?? d.matricula, tipo: tipo || null, enRegistro: d.en_registro };
44895
- }
44896
44925
  function conMarcasMatricula(workflow, datos, titulo) {
44897
44926
  if (workflow !== "credencial_profesional") return datos;
44898
44927
  let d = datos;
44899
- if (typeof d.posible_no_profesional !== "boolean") d = { ...d, posible_no_profesional: pareceNoProfesional(String(d.profesional ?? titulo.split(" \xB7 ")[0] ?? "")) };
44928
+ const np = posibleNoProfesional(d, titulo);
44929
+ if (d.posible_no_profesional !== np) d = { ...d, posible_no_profesional: np };
44900
44930
  const r = leerResultadoRegistro(d.resultado);
44901
44931
  if (r && (d.observacion === "otra_persona" || d.observacion === "no_figura")) {
44902
44932
  const obs = observacionMatricula(r, fichaMatricula(d));
@@ -45020,6 +45050,11 @@ function opcionesCostos(op) {
45020
45050
  function opcionesRentabilidad(op) {
45021
45051
  return { umbral: enteroEntre(op.umbral_margen, 0, 90) ?? UMBRAL_MARGEN_POR_DEFECTO, mesesPrecio: enteroEntre(op.meses_precio, 1, 36) ?? MESES_PRECIO_POR_DEFECTO };
45022
45052
  }
45053
+ function posibleNoProfesional(d, titulo) {
45054
+ const tieneEspecialidad = Array.isArray(d.especialidades) ? d.especialidades.length > 0 : Boolean(String(d.especialidades ?? "").trim());
45055
+ const tieneMatricula = Boolean(String(d.matricula_nacional ?? "").trim() || String(d.matricula_provincial ?? "").trim());
45056
+ return !tieneEspecialidad && !tieneMatricula && pareceNoProfesional(String(d.profesional ?? titulo.split(" \xB7 ")[0] ?? ""));
45057
+ }
45023
45058
  function pareceNoProfesional(nombre) {
45024
45059
  const n = nombre.trim();
45025
45060
  const [apellido = "", nombres = ""] = n.split(",").map((x) => x.trim().toLowerCase());
@@ -45533,7 +45568,7 @@ async function transicionar(ctx, input2) {
45533
45568
  );
45534
45569
  const lectura = rows[0];
45535
45570
  const evidencia = lectura && lectura.evidencia && typeof lectura.evidencia === "object" ? lectura.evidencia : null;
45536
- 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)}` : leerResultadoRegistro(evidencia.resultado) === null ? `la lectura ${lecturaId} no guard\xF3 el resultado del registro (evidencia.resultado): sin eso no se puede comprobar lo que se informa` : evidencia.matricula === void 0 && leerResultadoRegistro(datos.resultado)?.sin_matricula !== true ? `la lectura ${lecturaId} no guard\xF3 qu\xE9 matr\xEDcula se consult\xF3 (evidencia.matricula)` : resultadoDistinto(evidencia.resultado, datos.resultado) ? `lo que se informa no es lo que devolvi\xF3 el registro en la lectura ${lecturaId}: ${resultadoDistinto(evidencia.resultado, datos.resultado)}` : null : null;
45571
+ 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)}` : datos.en_registro !== void 0 && JSON.stringify(evidencia.en_registro ?? null) !== JSON.stringify(datos.en_registro ?? null) ? `lo que se informa como encontrado a su nombre (en_registro) no es lo que guard\xF3 la lectura ${lecturaId}` : leerResultadoRegistro(evidencia.resultado) === null ? `la lectura ${lecturaId} no guard\xF3 el resultado del registro (evidencia.resultado): sin eso no se puede comprobar lo que se informa` : evidencia.matricula === void 0 && leerResultadoRegistro(datos.resultado)?.sin_matricula !== true ? `la lectura ${lecturaId} no guard\xF3 qu\xE9 matr\xEDcula se consult\xF3 (evidencia.matricula)` : resultadoDistinto(evidencia.resultado, datos.resultado) ? `lo que se informa no es lo que devolvi\xF3 el registro en la lectura ${lecturaId}: ${resultadoDistinto(evidencia.resultado, datos.resultado)}` : null : null;
45537
45572
  let vieja = false;
45538
45573
  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")) {
45539
45574
  const ultima = await ctx.db.query(
@@ -45876,7 +45911,7 @@ async function transicionar(ctx, input2) {
45876
45911
  const ahora = [datos.matricula_nacional ?? caso.datos.matricula_nacional, datos.matricula_provincial ?? caso.datos.matricula_provincial].map((v) => String(v ?? "").replace(/\D/g, ""));
45877
45912
  datos.ficha_sin_cambios = datos.observacion !== null && antes.join("|") === ahora.join("|");
45878
45913
  } else delete datos.ficha_sin_cambios;
45879
- datos.posible_no_profesional = pareceNoProfesional(String(datos.profesional ?? caso.datos.profesional ?? caso.titulo.split(" \xB7 ")[0] ?? ""));
45914
+ datos.posible_no_profesional = posibleNoProfesional({ ...caso.datos, ...datos }, caso.titulo);
45880
45915
  const ag = datos.agenda && typeof datos.agenda === "object" ? datos.agenda : null;
45881
45916
  if (ag) {
45882
45917
  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;
@@ -46692,6 +46727,11 @@ var OBSERVACIONES_MATRICULA = {
46692
46727
  sancion: "la matr\xEDcula tiene una sanci\xF3n registrada"
46693
46728
  };
46694
46729
  var rol = (clave) => ({ clave: `rol:${clave}`, nombre: ROLES[clave] ?? clave, reserva: null });
46730
+ function sumarDiasIso(fecha5, n) {
46731
+ const d = /* @__PURE__ */ new Date(`${fecha5}T12:00:00Z`);
46732
+ d.setUTCDate(d.getUTCDate() + n);
46733
+ return d.toISOString().slice(0, 10);
46734
+ }
46695
46735
  function pendientesDe(caso, hoy) {
46696
46736
  const estados = ESPERAN_PERSONA[caso.workflow];
46697
46737
  if (!estados || !estados.includes(caso.estado)) return [];
@@ -46766,8 +46806,10 @@ function pendientesDe(caso, hoy) {
46766
46806
  const nombre = texto8(d.profesional) ?? (id3 ? `Profesional ${id3}` : "Profesional");
46767
46807
  const obs = texto8(d.observacion);
46768
46808
  const que = `${nombre}: ${(obs && OBSERVACIONES_MATRICULA[obs]) ?? "la matr\xEDcula tiene una observaci\xF3n del registro nacional"}`;
46769
- const grave = obs === "inhabilitada" || obs === "sancion" || obs === "otra_persona";
46770
- return [{ ...base, que, responsable: rol("personal") }, ...grave ? [{ ...base, que, responsable: rol("direccion_medica") }] : []];
46809
+ const grave = (obs === "inhabilitada" || obs === "sancion" || obs === "otra_persona" || obs === "profesion_distinta") && d.posible_no_profesional !== true;
46810
+ const proximo = d.agenda && typeof d.agenda === "object" ? texto8(d.agenda.proximo_turno) : null;
46811
+ const atiendePronto = !grave && d.posible_no_profesional !== true && proximo !== null && proximo.slice(0, 10) <= sumarDiasIso(hoy ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), 2);
46812
+ return [{ ...base, que, responsable: rol("personal") }, ...grave || atiendePronto ? [{ ...base, que: atiendePronto ? `${que} (atiende el ${proximo.slice(8, 10)}/${proximo.slice(5, 7)})` : que, responsable: rol("direccion_medica") }] : []];
46771
46813
  }
46772
46814
  return [];
46773
46815
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-plugin-autopilot-ops",
3
- "version": "0.1.52",
3
+ "version": "0.1.53",
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": [