paperclip-plugin-autopilot-ops 0.1.62 → 0.1.64
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 +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/worker.js +39 -20
- package/package.json +1 -1
package/dist/manifest.js
CHANGED
package/dist/ui/index.js
CHANGED
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.64";
|
|
39936
39936
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
39937
39937
|
var PAGE_ROUTE = "autopilot";
|
|
39938
39938
|
var TOOL_NAMES = {
|
|
@@ -44453,7 +44453,7 @@ function dia3(v) {
|
|
|
44453
44453
|
var LIQUIDACIONES_MINIMAS = 3;
|
|
44454
44454
|
var INSUMOS_CAUSA_PCT = 10;
|
|
44455
44455
|
var PLANES_SIN_VALOR_PCT = 10;
|
|
44456
|
-
function honorarioDeRegla(regla, valor) {
|
|
44456
|
+
function honorarioDeRegla(regla, valor, rutina = "nueva") {
|
|
44457
44457
|
const pct = (n2) => `${n2.toLocaleString("es-AR", { maximumFractionDigits: 2 })} %`;
|
|
44458
44458
|
const importe = regla.importe ?? null;
|
|
44459
44459
|
if (importe !== null && importe > 0) {
|
|
@@ -44461,6 +44461,7 @@ function honorarioDeRegla(regla, valor) {
|
|
|
44461
44461
|
if (regla.inst !== null) return { honorario: redondear5(importe * (1 - regla.inst / 100)), fuente: "importe", detalle: `honorario ${pesos4(importe)} menos ${pct(regla.inst)} de la instituci\xF3n` };
|
|
44462
44462
|
return { honorario: importe, fuente: "importe", detalle: `honorario fijo ${pesos4(importe)}` };
|
|
44463
44463
|
}
|
|
44464
|
+
if (rutina === "mensual" && (regla.prof !== null || regla.inst !== null)) return { honorario: 0, fuente: "importe", detalle: "la liquidaci\xF3n mensual por obra social del HIS liquida en $ 0 una regla sin honorario base" };
|
|
44464
44465
|
if (regla.prof !== null) return { honorario: regla.prof, fuente: "monto_fijo", detalle: `\xABprof\xBB ${regla.prof.toLocaleString("es-AR", { maximumFractionDigits: 2 })} sin honorario base: el HIS liquida ${pesos4(regla.prof)} fijos` };
|
|
44465
44466
|
if (regla.inst !== null) return { honorario: redondear5(valor * regla.inst / 100), fuente: "porcentaje", detalle: `${pct(regla.inst)} de lo que paga el convenio` };
|
|
44466
44467
|
return null;
|
|
@@ -44469,7 +44470,6 @@ var HONORARIO_MINIMO_PCT = 1;
|
|
|
44469
44470
|
var HONORARIO_FIJO_MINIMO_PCT = 10;
|
|
44470
44471
|
var INSUMOS_A_VERIFICAR_PCT = 50;
|
|
44471
44472
|
function noEsPractica(l) {
|
|
44472
|
-
if (l.honorarios.length > 0) return false;
|
|
44473
44473
|
return /medicament|descartable|insumo|material|farmac|internaci|hoteler/i.test(l.tipo ?? "") || /(comprimid|ampolla|frasco|sachet|cateter|catéter|guantes?\b|jeringa|gasas?\b|capsula|cápsula|\d\s*(mg|mcg|ml|ui)\b|d[ií]as? (en )?cama|d[ií]a de internaci|pensi[oó]n|habitaci[oó]n)/i.test(l.nombre);
|
|
44474
44474
|
}
|
|
44475
44475
|
function leerLecturaRentabilidad(v) {
|
|
@@ -44624,7 +44624,7 @@ function evaluarRentabilidad(input2) {
|
|
|
44624
44624
|
if (l.honorarios.length === 0) faltas.push("sin_profesional");
|
|
44625
44625
|
for (const h of l.honorarios) {
|
|
44626
44626
|
const nombre = h.profesional ?? h.profesional_id;
|
|
44627
|
-
const deRegla = h.regla ? honorarioDeRegla(h.regla, valor) : null;
|
|
44627
|
+
const deRegla = h.regla ? honorarioDeRegla(h.regla, valor, input2.rutina ?? "nueva") : null;
|
|
44628
44628
|
let hon;
|
|
44629
44629
|
const pocasLiquidaciones = Boolean(h.liquidado && deRegla && typeof h.liquidado.muestra === "number" && h.liquidado.muestra < LIQUIDACIONES_MINIMAS);
|
|
44630
44630
|
const reglaProporcional = deRegla?.fuente === "porcentaje";
|
|
@@ -44674,6 +44674,7 @@ function evaluarRentabilidad(input2) {
|
|
|
44674
44674
|
const descuento = redondear5(valor * descuentoPct / 100);
|
|
44675
44675
|
const ind = indirectosDe(l, valor, input2.indirectos ?? [], input2.bases ?? null);
|
|
44676
44676
|
for (const a of ind.avisos) if (!avisos.includes(a)) avisos.push(a);
|
|
44677
|
+
if (l.minutos_estimados && (input2.indirectos ?? []).some((c) => c.activo !== false && c.reparto === "minuto")) avisos.push("duracion_estimada");
|
|
44677
44678
|
const medidoCon = input2.medirCon === "total" && input2.bases ? "total" : "directo";
|
|
44678
44679
|
const indUsado = medidoCon === "total" ? ind.total : 0;
|
|
44679
44680
|
const margen = honorarioBase !== null && valor > 0 ? redondear5(valor - descuento - insumos - honorarioBase) : null;
|
|
@@ -44719,7 +44720,7 @@ function evaluarRentabilidad(input2) {
|
|
|
44719
44720
|
if ((clase2 === "perdida" || clase2 === "margen_bajo") && honorarioBase !== null) {
|
|
44720
44721
|
const sinInsumos = valor - descuento - honorarioBase - indUsado;
|
|
44721
44722
|
const llegan = reparto.filter((r) => r.margen >= minimo);
|
|
44722
|
-
const noLlegan = reparto.filter((r) => r.margen < minimo);
|
|
44723
|
+
const noLlegan = reparto.filter((r) => r.margen < minimo).sort((a, b) => a.margen - b.margen);
|
|
44723
44724
|
if (llegan.length > 0 && noLlegan.length > 0) {
|
|
44724
44725
|
causa = "honorario_profesional";
|
|
44725
44726
|
causaProfesionales = noLlegan.map((r) => ({ profesional_id: r.profesional_id, profesional: r.profesional, honorario: r.honorario, margen: r.margen }));
|
|
@@ -44770,7 +44771,7 @@ function evaluarRentabilidad(input2) {
|
|
|
44770
44771
|
insumos_objetivo: causa === "insumos" ? insumosObjetivo : null,
|
|
44771
44772
|
descuento,
|
|
44772
44773
|
descuento_pct: descuentoPct,
|
|
44773
|
-
no_es_practica: noEsPractica(l),
|
|
44774
|
+
no_es_practica: !input2.esPractica && noEsPractica(l),
|
|
44774
44775
|
perdida_menor: impacto !== null && impacto < 0 && Math.abs(impacto) < perdidaMenor,
|
|
44775
44776
|
porque: null,
|
|
44776
44777
|
faltas,
|
|
@@ -45213,7 +45214,9 @@ function opcionesRentabilidad(op) {
|
|
|
45213
45214
|
perdidaMenor: enteroEntre(op.perdida_menor, 0, 1e7) ?? PERDIDA_MENOR_POR_DEFECTO,
|
|
45214
45215
|
sinInsumos: Array.isArray(op.practicas_sin_insumos) ? op.practicas_sin_insumos.map(String).slice(0, 5e3) : [],
|
|
45215
45216
|
descuento: porcentajeDescuento(op.descuento_cobro) ?? 0,
|
|
45216
|
-
descuentoPorFinanciador: leerDescuentos(op.descuentos_financiador)
|
|
45217
|
+
descuentoPorFinanciador: leerDescuentos(op.descuentos_financiador),
|
|
45218
|
+
rutina: op.rutina_liquidacion === "mensual" ? "mensual" : "nueva",
|
|
45219
|
+
sonPracticas: Array.isArray(op.son_practicas) ? op.son_practicas.map(String).slice(0, 5e3) : []
|
|
45217
45220
|
};
|
|
45218
45221
|
}
|
|
45219
45222
|
async function leerBases(ctx, companyId) {
|
|
@@ -45223,7 +45226,7 @@ async function leerBases(ctx, companyId) {
|
|
|
45223
45226
|
async function recalcularBases(ctx, companyId, costos) {
|
|
45224
45227
|
const ms = await listarMediciones(ctx, companyId);
|
|
45225
45228
|
if (!ms.length) return null;
|
|
45226
|
-
const lecturas = ms.map((m) => ({ minutos: m.minutos, tipo: m.tipo, volumen: m.evaluacion.volumen ?? 0, dias: m.evaluacion.dias ?? 90, componentes: m.componentes }));
|
|
45229
|
+
const lecturas = ms.filter((m) => !m.evaluacion.no_es_practica).map((m) => ({ minutos: m.minutos, tipo: m.tipo, volumen: m.evaluacion.volumen ?? 0, dias: m.evaluacion.dias ?? 90, componentes: m.componentes }));
|
|
45227
45230
|
const bases = basesIndirectos(lecturas, costos);
|
|
45228
45231
|
await ctx.db.execute(
|
|
45229
45232
|
`INSERT INTO ${t3(ctx, "rentabilidad_base")} (company_id, bases, practicas, calculada_el) VALUES ($1, $2::jsonb, $3, now())
|
|
@@ -45678,6 +45681,7 @@ function describirOpciones(antes, despues) {
|
|
|
45678
45681
|
if (antes.meses_precio !== despues.meses_precio && despues.meses_precio !== void 0) partes.push(`meses para avisar un precio de insumo viejo: ${String(despues.meses_precio)}`);
|
|
45679
45682
|
if (antes.medir_con !== despues.medir_con && despues.medir_con !== void 0) partes.push(despues.medir_con === "total" ? "mide con el margen total (despu\xE9s de los costos indirectos)" : "mide con el margen directo (antes de los costos indirectos)");
|
|
45680
45683
|
if (antes.perdida_menor !== despues.perdida_menor && despues.perdida_menor !== void 0) partes.push(`p\xE9rdida menor por mes: $ ${Number(despues.perdida_menor).toLocaleString("es-AR")}`);
|
|
45684
|
+
if (antes.rutina_liquidacion !== despues.rutina_liquidacion && despues.rutina_liquidacion !== void 0) partes.push(despues.rutina_liquidacion === "mensual" ? "honorarios con la liquidaci\xF3n mensual por obra social del HIS" : "honorarios con la liquidaci\xF3n nueva del HIS");
|
|
45681
45685
|
if (antes.descuento_cobro !== despues.descuento_cobro && despues.descuento_cobro !== void 0) partes.push(`se pierde al cobrar: ${Number(despues.descuento_cobro).toLocaleString("es-AR")} % de lo facturado`);
|
|
45682
45686
|
if (JSON.stringify(antes.descuentos_financiador ?? {}) !== JSON.stringify(despues.descuentos_financiador ?? {}) && despues.descuentos_financiador !== void 0) {
|
|
45683
45687
|
const d = Object.entries(despues.descuentos_financiador ?? {});
|
|
@@ -45741,11 +45745,16 @@ function imputarMinutos(lecturas) {
|
|
|
45741
45745
|
const o = [...xs].sort((a, b) => a - b);
|
|
45742
45746
|
return o.length ? o[Math.floor(o.length / 2)] : null;
|
|
45743
45747
|
};
|
|
45744
|
-
const conDuracion = lecturas.filter((l) => l.minutos !== null);
|
|
45745
|
-
const general = mediana2(conDuracion.map((l) => l.minutos));
|
|
45746
45748
|
const porTipo = /* @__PURE__ */ new Map();
|
|
45747
|
-
for (const l of
|
|
45748
|
-
for (const l of lecturas)
|
|
45749
|
+
for (const l of lecturas) if (l.minutos !== null && l.tipo) porTipo.set(l.tipo, [...porTipo.get(l.tipo) ?? [], l.minutos]);
|
|
45750
|
+
for (const l of lecturas) {
|
|
45751
|
+
if (l.minutos !== null || !l.tipo) continue;
|
|
45752
|
+
const m = mediana2(porTipo.get(l.tipo) ?? []);
|
|
45753
|
+
if (m !== null) {
|
|
45754
|
+
l.minutos = m;
|
|
45755
|
+
l.minutos_estimados = true;
|
|
45756
|
+
}
|
|
45757
|
+
}
|
|
45749
45758
|
}
|
|
45750
45759
|
function resultadoPedido(d, e) {
|
|
45751
45760
|
const accion = str2(d.accion) ?? "pedir_aumento";
|
|
@@ -45762,7 +45771,7 @@ function resultadoPedido(d, e) {
|
|
|
45762
45771
|
return { accion, pedido: null, ahora: null, cumple: e.clase === "rentable" ? true : null };
|
|
45763
45772
|
}
|
|
45764
45773
|
function evaluarConOpciones(l, hoy, op, bases) {
|
|
45765
|
-
return evaluarRentabilidad({ lectura: l, hoy, umbral: op.umbral, mesesPrecio: op.mesesPrecio, indirectos: op.indirectos, bases, medirCon: op.medirCon, perdidaMenor: op.perdidaMenor, sinInsumos: op.sinInsumos.includes(normalizarCodigo(l.codigo) ?? ""), descuento: descuentoDe(op, l.financiador) });
|
|
45774
|
+
return evaluarRentabilidad({ lectura: l, hoy, umbral: op.umbral, mesesPrecio: op.mesesPrecio, indirectos: op.indirectos, bases, medirCon: op.medirCon, perdidaMenor: op.perdidaMenor, sinInsumos: op.sinInsumos.includes(normalizarCodigo(l.codigo) ?? ""), descuento: descuentoDe(op, l.financiador), rutina: op.rutina, esPractica: op.sonPracticas.includes(normalizarCodigo(l.codigo) ?? "") });
|
|
45766
45775
|
}
|
|
45767
45776
|
async function evaluarRentabilidades(ctx, companyId, lecturas) {
|
|
45768
45777
|
if (!Array.isArray(lecturas)) throw new OpsError("validacion", "lecturas: tiene que ser una lista");
|
|
@@ -45776,11 +45785,11 @@ async function evaluarRentabilidades(ctx, companyId, lecturas) {
|
|
|
45776
45785
|
imputarMinutos(validas);
|
|
45777
45786
|
const anteriores = new Map((await listarMediciones(ctx, companyId)).map((m) => [m.referencia, m]));
|
|
45778
45787
|
const completa = validas.length > 0 && validas.length >= anteriores.size * 0.8;
|
|
45779
|
-
const
|
|
45788
|
+
const practicas = validas.filter((l) => opciones.sonPracticas.includes(normalizarCodigo(l.codigo) ?? "") || !noEsPractica(l));
|
|
45789
|
+
const bases = completa ? await guardarBases(ctx, companyId, practicas, opciones.indirectos) : await leerBases(ctx, companyId);
|
|
45780
45790
|
const pedidos = await ultimosPedidos(ctx, companyId);
|
|
45781
45791
|
const medidas = [];
|
|
45782
45792
|
const resultados = [];
|
|
45783
|
-
const noSonPracticas = [];
|
|
45784
45793
|
for (const [indice, l] of leidas.entries()) {
|
|
45785
45794
|
if ("error" in l) {
|
|
45786
45795
|
resultados.push({ indice, error: l.error });
|
|
@@ -45789,8 +45798,7 @@ async function evaluarRentabilidades(ctx, companyId, lecturas) {
|
|
|
45789
45798
|
const evaluacion = evaluarConOpciones(l.lectura, hoy, opciones, bases);
|
|
45790
45799
|
const referencia = `rentabilidad:${l.lectura.prestacion_id}:${l.lectura.financiador_id}`;
|
|
45791
45800
|
const previa = anteriores.get(referencia);
|
|
45792
|
-
if (evaluacion.no_es_practica)
|
|
45793
|
-
else await registrarCambiosHis(ctx, {
|
|
45801
|
+
if (!evaluacion.no_es_practica) await registrarCambiosHis(ctx, {
|
|
45794
45802
|
companyId,
|
|
45795
45803
|
referencia,
|
|
45796
45804
|
codigo: l.lectura.codigo,
|
|
@@ -45798,11 +45806,11 @@ async function evaluarRentabilidades(ctx, companyId, lecturas) {
|
|
|
45798
45806
|
antes: previa ? { valor: previa.evaluacion.valor, honorarios: (previa.evaluacion.honorarios ?? []).map((h) => ({ profesional_id: h.profesional_id, profesional: h.profesional, honorario: h.honorario })) } : null,
|
|
45799
45807
|
despues: { valor: evaluacion.valor, honorarios: evaluacion.honorarios.map((h) => ({ profesional_id: h.profesional_id, profesional: h.profesional, honorario: h.honorario })) }
|
|
45800
45808
|
});
|
|
45801
|
-
|
|
45809
|
+
medidas.push({ lectura: l.lectura, evaluacion });
|
|
45802
45810
|
const apertura = decidirApertura(evaluacion, pedidos.get(referencia) ?? null, hoy, opciones.perdidaMenor);
|
|
45803
45811
|
resultados.push({ clave: `${l.lectura.prestacion_id}:${l.lectura.financiador_id}`, referencia, codigo: l.lectura.codigo, practica: l.lectura.nombre, financiador: l.lectura.financiador, evaluacion, oracion: oracionRentabilidad(l.lectura, evaluacion), abrir: apertura.abrir, motivo_abrir: apertura.motivo });
|
|
45804
45812
|
}
|
|
45805
|
-
await guardarMediciones(ctx, companyId, medidas
|
|
45813
|
+
await guardarMediciones(ctx, companyId, medidas);
|
|
45806
45814
|
return { resultados, opciones };
|
|
45807
45815
|
}
|
|
45808
45816
|
function enteroEntre2(v, min, max) {
|
|
@@ -45912,7 +45920,12 @@ async function cambiarPolitica(ctx, input2) {
|
|
|
45912
45920
|
if (v === null) throw new OpsError("validacion", "descuento_cobro: tiene que ser un porcentaje entre 0 y 60");
|
|
45913
45921
|
opciones.descuento_cobro = v;
|
|
45914
45922
|
}
|
|
45923
|
+
if (opciones.rutina_liquidacion !== void 0 && opciones.rutina_liquidacion !== "nueva" && opciones.rutina_liquidacion !== "mensual") throw new OpsError("validacion", "rutina_liquidacion: tiene que ser \xABnueva\xBB o \xABmensual\xBB");
|
|
45915
45924
|
if (opciones.descuentos_financiador !== void 0) opciones.descuentos_financiador = leerDescuentos(opciones.descuentos_financiador);
|
|
45925
|
+
if (opciones.son_practicas !== void 0) {
|
|
45926
|
+
if (!Array.isArray(opciones.son_practicas)) throw new OpsError("validacion", "son_practicas: tiene que ser una lista de c\xF3digos");
|
|
45927
|
+
opciones.son_practicas = [...new Set(opciones.son_practicas.map((c) => normalizarCodigo(String(c ?? ""))).filter((c) => Boolean(c)))].slice(0, 5e3);
|
|
45928
|
+
}
|
|
45916
45929
|
if (opciones.practicas_sin_insumos !== void 0) {
|
|
45917
45930
|
if (!Array.isArray(opciones.practicas_sin_insumos)) throw new OpsError("validacion", "practicas_sin_insumos: tiene que ser una lista de c\xF3digos");
|
|
45918
45931
|
opciones.practicas_sin_insumos = [...new Set(opciones.practicas_sin_insumos.map((c) => normalizarCodigo(String(c ?? ""))).filter((c) => Boolean(c)))].slice(0, 5e3);
|
|
@@ -46217,7 +46230,13 @@ async function contextoDe(ctx, companyId, caso, via, datos) {
|
|
|
46217
46230
|
if (via === "evaluar" || via === "comprobar") {
|
|
46218
46231
|
const op = opcionesRentabilidad(await obtenerOpciones(ctx, companyId, caso.workflow));
|
|
46219
46232
|
const l = leerLecturaRentabilidad(datos.lectura);
|
|
46220
|
-
if (!("error" in l))
|
|
46233
|
+
if (!("error" in l)) {
|
|
46234
|
+
conInsumosDeOpera(l.lectura, await insumosPorCodigo(ctx, companyId));
|
|
46235
|
+
if (l.lectura.minutos === null) {
|
|
46236
|
+
const guardada = (await listarMediciones(ctx, companyId)).find((m) => m.referencia === `rentabilidad:${l.lectura.prestacion_id}:${l.lectura.financiador_id}`);
|
|
46237
|
+
if (guardada?.minutos) Object.assign(l.lectura, { minutos: guardada.minutos, minutos_estimados: true });
|
|
46238
|
+
}
|
|
46239
|
+
}
|
|
46221
46240
|
contexto.rentabilidad = "error" in l ? { error: l.error } : { clave: `${l.lectura.prestacion_id}:${l.lectura.financiador_id}`, evaluacion: evaluarConOpciones(l.lectura, hoy, op, await leerBases(ctx, companyId)) };
|
|
46222
46241
|
}
|
|
46223
46242
|
return contexto;
|
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.64",
|
|
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": [
|