paperclip-plugin-autopilot-ops 0.1.26 → 0.1.28
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 +11 -3
- package/dist/ui/index.js +11 -3
- package/dist/worker.js +876 -309
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -3627,15 +3627,15 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def2) =
|
|
|
3627
3627
|
const syms = normalized.symbolKeys;
|
|
3628
3628
|
const doc = new Doc(["payload", "ctx"], { shape, inst, memo: memo2, syms });
|
|
3629
3629
|
const parseStr = (k) => `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`;
|
|
3630
|
-
const prefixStr = (
|
|
3631
|
-
let ${
|
|
3632
|
-
for (let i = 0; i < ${
|
|
3633
|
-
const iss = ${
|
|
3630
|
+
const prefixStr = (id2, k) => `
|
|
3631
|
+
let ${id2}_ab = false;
|
|
3632
|
+
for (let i = 0; i < ${id2}.issues.length; i++) {
|
|
3633
|
+
const iss = ${id2}.issues[i];
|
|
3634
3634
|
iss.path = iss.path ? [${k}, ...iss.path] : [${k}];
|
|
3635
3635
|
payload.issues.push(iss);
|
|
3636
|
-
if (iss.continue !== true) ${
|
|
3636
|
+
if (iss.continue !== true) ${id2}_ab = true;
|
|
3637
3637
|
}
|
|
3638
|
-
if (${
|
|
3638
|
+
if (${id2}_ab && ctx && ctx.abortEarly) {
|
|
3639
3639
|
payload.value = newResult;
|
|
3640
3640
|
return payload;
|
|
3641
3641
|
}`;
|
|
@@ -3649,34 +3649,34 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def2) =
|
|
|
3649
3649
|
for (const key of normalized.allKeys) {
|
|
3650
3650
|
if (key === "__proto__")
|
|
3651
3651
|
continue;
|
|
3652
|
-
const
|
|
3652
|
+
const id2 = ids[key];
|
|
3653
3653
|
const k = typeof key === "symbol" ? `syms[${syms.indexOf(key)}]` : esc(key);
|
|
3654
3654
|
const isPresent = `${k} in input`;
|
|
3655
3655
|
const schema = shape[key];
|
|
3656
3656
|
const optin = schema?._zod?.optin;
|
|
3657
3657
|
const isOptionalIn = optin !== void 0;
|
|
3658
3658
|
const isOptionalOut = schema?._zod?.optout === "optional";
|
|
3659
|
-
doc.write(`const ${
|
|
3659
|
+
doc.write(`const ${id2} = ${parseStr(k)};`);
|
|
3660
3660
|
if (isOptionalIn && isOptionalOut) {
|
|
3661
|
-
const assign = optin === "optional" ? `${
|
|
3661
|
+
const assign = optin === "optional" ? `${id2}_present` : `${id2}.value !== undefined || ${id2}_present`;
|
|
3662
3662
|
doc.write(`
|
|
3663
|
-
const ${
|
|
3664
|
-
if (!${
|
|
3665
|
-
if (${
|
|
3663
|
+
const ${id2}_present = ${isPresent};
|
|
3664
|
+
if (!${id2}.issues.length || ${id2}_present) {
|
|
3665
|
+
if (${id2}.issues.length) {${prefixStr(id2, k)}
|
|
3666
3666
|
}
|
|
3667
3667
|
|
|
3668
3668
|
if (${assign}) {
|
|
3669
|
-
newResult[${k}] = ${
|
|
3669
|
+
newResult[${k}] = ${id2}.value;
|
|
3670
3670
|
}
|
|
3671
3671
|
}
|
|
3672
3672
|
|
|
3673
3673
|
`);
|
|
3674
3674
|
} else if (!isOptionalIn) {
|
|
3675
3675
|
doc.write(`
|
|
3676
|
-
const ${
|
|
3677
|
-
if (${
|
|
3676
|
+
const ${id2}_present = ${isPresent};
|
|
3677
|
+
if (${id2}.issues.length) {${prefixStr(id2, k)}
|
|
3678
3678
|
}
|
|
3679
|
-
if (!${
|
|
3679
|
+
if (!${id2}_present && !${id2}.issues.length) {
|
|
3680
3680
|
payload.issues.push({
|
|
3681
3681
|
code: "invalid_type",
|
|
3682
3682
|
expected: "nonoptional",
|
|
@@ -3689,22 +3689,22 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def2) =
|
|
|
3689
3689
|
}
|
|
3690
3690
|
}
|
|
3691
3691
|
|
|
3692
|
-
if (${
|
|
3693
|
-
newResult[${k}] = ${
|
|
3692
|
+
if (${id2}_present) {
|
|
3693
|
+
newResult[${k}] = ${id2}.value;
|
|
3694
3694
|
}
|
|
3695
3695
|
|
|
3696
3696
|
`);
|
|
3697
3697
|
} else {
|
|
3698
3698
|
doc.write(`
|
|
3699
|
-
if (${
|
|
3699
|
+
if (${id2}.issues.length) {${prefixStr(id2, k)}
|
|
3700
3700
|
}
|
|
3701
3701
|
`);
|
|
3702
3702
|
if (optin === "defaulted") {
|
|
3703
|
-
doc.write(`newResult[${k}] = ${
|
|
3703
|
+
doc.write(`newResult[${k}] = ${id2}.value;`);
|
|
3704
3704
|
} else {
|
|
3705
3705
|
doc.write(`
|
|
3706
|
-
if (${
|
|
3707
|
-
newResult[${k}] = ${
|
|
3706
|
+
if (${id2}.value !== undefined || ${isPresent}) {
|
|
3707
|
+
newResult[${k}] = ${id2}.value;
|
|
3708
3708
|
}
|
|
3709
3709
|
`);
|
|
3710
3710
|
}
|
|
@@ -15732,26 +15732,26 @@ function extractDefs(ctx, schema) {
|
|
|
15732
15732
|
return;
|
|
15733
15733
|
const idToSchema = /* @__PURE__ */ new Map();
|
|
15734
15734
|
for (const entry of ctx.seen.entries()) {
|
|
15735
|
-
const
|
|
15736
|
-
if (
|
|
15737
|
-
const existing = idToSchema.get(
|
|
15735
|
+
const id2 = ctx.metadataRegistry.get(entry[0])?.id;
|
|
15736
|
+
if (id2) {
|
|
15737
|
+
const existing = idToSchema.get(id2);
|
|
15738
15738
|
if (existing && existing !== entry[0]) {
|
|
15739
|
-
throw new Error(`Duplicate schema id "${
|
|
15739
|
+
throw new Error(`Duplicate schema id "${id2}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);
|
|
15740
15740
|
}
|
|
15741
|
-
idToSchema.set(
|
|
15741
|
+
idToSchema.set(id2, entry[0]);
|
|
15742
15742
|
}
|
|
15743
15743
|
}
|
|
15744
15744
|
const makeURI = (entry) => {
|
|
15745
15745
|
const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
|
|
15746
15746
|
if (ctx.external) {
|
|
15747
15747
|
const externalId = ctx.external.registry.get(entry[0])?.id;
|
|
15748
|
-
const uriGenerator = ctx.external.uri ?? ((
|
|
15748
|
+
const uriGenerator = ctx.external.uri ?? ((id3) => id3);
|
|
15749
15749
|
if (externalId) {
|
|
15750
15750
|
return { ref: uriGenerator(externalId) };
|
|
15751
15751
|
}
|
|
15752
|
-
const
|
|
15753
|
-
entry[1].defId =
|
|
15754
|
-
return { defId:
|
|
15752
|
+
const id2 = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`;
|
|
15753
|
+
entry[1].defId = id2;
|
|
15754
|
+
return { defId: id2, ref: `${uriGenerator("__shared")}#/${defsSegment}/${encodeJSONPointerSegment(id2)}` };
|
|
15755
15755
|
}
|
|
15756
15756
|
const uriPrefix = `#`;
|
|
15757
15757
|
const defUriPrefix = `${uriPrefix}/${defsSegment}/`;
|
|
@@ -15799,8 +15799,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15799
15799
|
continue;
|
|
15800
15800
|
}
|
|
15801
15801
|
}
|
|
15802
|
-
const
|
|
15803
|
-
if (
|
|
15802
|
+
const id2 = ctx.metadataRegistry.get(entry[0])?.id;
|
|
15803
|
+
if (id2) {
|
|
15804
15804
|
extractToDef(entry);
|
|
15805
15805
|
continue;
|
|
15806
15806
|
}
|
|
@@ -16033,10 +16033,10 @@ function finalize(ctx, schema) {
|
|
|
16033
16033
|
} else {
|
|
16034
16034
|
}
|
|
16035
16035
|
if (ctx.external?.uri) {
|
|
16036
|
-
const
|
|
16037
|
-
if (!
|
|
16036
|
+
const id2 = ctx.external.registry.get(schema)?.id;
|
|
16037
|
+
if (!id2)
|
|
16038
16038
|
throw new Error("Schema is missing an `id` property");
|
|
16039
|
-
result.$id = ctx.external.uri(
|
|
16039
|
+
result.$id = ctx.external.uri(id2);
|
|
16040
16040
|
}
|
|
16041
16041
|
assignProps(result, root.defId ? root.schema : root.def ?? root.schema);
|
|
16042
16042
|
const rootMetaId = ctx.metadataRegistry.get(schema)?.id;
|
|
@@ -16642,7 +16642,7 @@ function stringifyKeyNames(bySchema, json2, visited) {
|
|
|
16642
16642
|
const values = json2.enum ?? (json2.const !== void 0 ? [json2.const] : void 0);
|
|
16643
16643
|
if (!numericType && !values?.some((v) => typeof v === "number"))
|
|
16644
16644
|
return json2;
|
|
16645
|
-
const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format, id, ...rest } = json2;
|
|
16645
|
+
const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format, id: id2, ...rest } = json2;
|
|
16646
16646
|
if (rest.enum)
|
|
16647
16647
|
rest.enum = rest.enum.map((v) => typeof v === "number" ? String(v) : v);
|
|
16648
16648
|
else if (typeof rest.const === "number")
|
|
@@ -29760,7 +29760,7 @@ var createAskUserQuestionsPayloadSchema = askUserQuestionsPayloadSchema.superRef
|
|
|
29760
29760
|
return;
|
|
29761
29761
|
const shown = new Set(value.questionSet.questions.map((question) => question.id));
|
|
29762
29762
|
const stored = new Set(value.questions.map((question) => question.id));
|
|
29763
|
-
if (shown.size !== stored.size || [...shown].some((
|
|
29763
|
+
if (shown.size !== stored.size || [...shown].some((id2) => !stored.has(id2))) {
|
|
29764
29764
|
ctx.addIssue({
|
|
29765
29765
|
code: external_exports.ZodIssueCode.custom,
|
|
29766
29766
|
path: ["questionSet", "questions"],
|
|
@@ -31268,7 +31268,7 @@ var pluginManifestV1Schema = external_exports.object({
|
|
|
31268
31268
|
if (manifest2.ui) {
|
|
31269
31269
|
if (manifest2.ui.slots) {
|
|
31270
31270
|
const slotIds = manifest2.ui.slots.map((s) => s.id);
|
|
31271
|
-
const duplicates = slotIds.filter((
|
|
31271
|
+
const duplicates = slotIds.filter((id2, i) => slotIds.indexOf(id2) !== i);
|
|
31272
31272
|
if (duplicates.length > 0) {
|
|
31273
31273
|
ctx.addIssue({
|
|
31274
31274
|
code: external_exports.ZodIssueCode.custom,
|
|
@@ -31284,7 +31284,7 @@ var pluginManifestV1Schema = external_exports.object({
|
|
|
31284
31284
|
];
|
|
31285
31285
|
if (allLaunchers.length > 0) {
|
|
31286
31286
|
const launcherIds = allLaunchers.map((launcher) => launcher.id);
|
|
31287
|
-
const duplicates = launcherIds.filter((
|
|
31287
|
+
const duplicates = launcherIds.filter((id2, i) => launcherIds.indexOf(id2) !== i);
|
|
31288
31288
|
if (duplicates.length > 0) {
|
|
31289
31289
|
ctx.addIssue({
|
|
31290
31290
|
code: external_exports.ZodIssueCode.custom,
|
|
@@ -38221,28 +38221,28 @@ var DUPLEX_CHANNEL_DATA_NOTIFICATION = "duplexChannel.data";
|
|
|
38221
38221
|
var DUPLEX_CHANNEL_EXIT_NOTIFICATION = "duplexChannel.exit";
|
|
38222
38222
|
var _nextId = 1;
|
|
38223
38223
|
var MAX_SAFE_RPC_ID = Number.MAX_SAFE_INTEGER - 1;
|
|
38224
|
-
function createRequest(method, params,
|
|
38224
|
+
function createRequest(method, params, id2) {
|
|
38225
38225
|
if (_nextId >= MAX_SAFE_RPC_ID) {
|
|
38226
38226
|
_nextId = 1;
|
|
38227
38227
|
}
|
|
38228
38228
|
return {
|
|
38229
38229
|
jsonrpc: JSONRPC_VERSION,
|
|
38230
|
-
id:
|
|
38230
|
+
id: id2 ?? _nextId++,
|
|
38231
38231
|
method,
|
|
38232
38232
|
params
|
|
38233
38233
|
};
|
|
38234
38234
|
}
|
|
38235
|
-
function createSuccessResponse(
|
|
38235
|
+
function createSuccessResponse(id2, result) {
|
|
38236
38236
|
return {
|
|
38237
38237
|
jsonrpc: JSONRPC_VERSION,
|
|
38238
|
-
id,
|
|
38238
|
+
id: id2,
|
|
38239
38239
|
result
|
|
38240
38240
|
};
|
|
38241
38241
|
}
|
|
38242
|
-
function createErrorResponse(
|
|
38242
|
+
function createErrorResponse(id2, code, message2, data) {
|
|
38243
38243
|
const response = {
|
|
38244
38244
|
jsonrpc: JSONRPC_VERSION,
|
|
38245
|
-
id,
|
|
38245
|
+
id: id2,
|
|
38246
38246
|
error: data !== void 0 ? { code, message: message2, data } : { code, message: message2 }
|
|
38247
38247
|
};
|
|
38248
38248
|
return response;
|
|
@@ -38401,7 +38401,7 @@ function startWorkerRpcHost(options) {
|
|
|
38401
38401
|
if (nextOutboundId >= MAX_OUTBOUND_ID) {
|
|
38402
38402
|
nextOutboundId = 1;
|
|
38403
38403
|
}
|
|
38404
|
-
const
|
|
38404
|
+
const id2 = nextOutboundId++;
|
|
38405
38405
|
const timeout = timeoutMs ?? rpcTimeoutMs;
|
|
38406
38406
|
let settled = false;
|
|
38407
38407
|
const settle2 = (fn, value) => {
|
|
@@ -38409,7 +38409,7 @@ function startWorkerRpcHost(options) {
|
|
|
38409
38409
|
return;
|
|
38410
38410
|
settled = true;
|
|
38411
38411
|
clearTimeout(timer);
|
|
38412
|
-
pendingRequests.delete(
|
|
38412
|
+
pendingRequests.delete(id2);
|
|
38413
38413
|
fn(value);
|
|
38414
38414
|
};
|
|
38415
38415
|
const timer = setTimeout(() => {
|
|
@@ -38418,7 +38418,7 @@ function startWorkerRpcHost(options) {
|
|
|
38418
38418
|
message: `Worker\u2192host call "${method}" timed out after ${timeout}ms`
|
|
38419
38419
|
}));
|
|
38420
38420
|
}, timeout);
|
|
38421
|
-
pendingRequests.set(
|
|
38421
|
+
pendingRequests.set(id2, {
|
|
38422
38422
|
resolve: (response) => {
|
|
38423
38423
|
if (isJsonRpcSuccessResponse(response)) {
|
|
38424
38424
|
settle2(resolve, response.result);
|
|
@@ -38433,7 +38433,7 @@ function startWorkerRpcHost(options) {
|
|
|
38433
38433
|
try {
|
|
38434
38434
|
const activeInvocation = invocationContextStorage.getStore();
|
|
38435
38435
|
const request = {
|
|
38436
|
-
...createRequest(method, params,
|
|
38436
|
+
...createRequest(method, params, id2),
|
|
38437
38437
|
...activeInvocation ? { paperclipInvocationId: activeInvocation.id } : {}
|
|
38438
38438
|
};
|
|
38439
38439
|
sendMessage(request);
|
|
@@ -39329,15 +39329,15 @@ function startWorkerRpcHost(options) {
|
|
|
39329
39329
|
}
|
|
39330
39330
|
const ctx = buildContext();
|
|
39331
39331
|
async function handleHostRequest(request) {
|
|
39332
|
-
const { id, method, params } = request;
|
|
39332
|
+
const { id: id2, method, params } = request;
|
|
39333
39333
|
try {
|
|
39334
39334
|
const invoke = () => dispatchMethod(method, params);
|
|
39335
39335
|
const result = request.paperclipInvocation ? await invocationContextStorage.run(request.paperclipInvocation, invoke) : await invoke();
|
|
39336
|
-
sendMessage(createSuccessResponse(
|
|
39336
|
+
sendMessage(createSuccessResponse(id2, result ?? null));
|
|
39337
39337
|
} catch (err) {
|
|
39338
39338
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
39339
39339
|
const errorCode = typeof err?.code === "number" ? err.code : PLUGIN_RPC_ERROR_CODES.WORKER_ERROR;
|
|
39340
|
-
sendMessage(createErrorResponse(
|
|
39340
|
+
sendMessage(createErrorResponse(id2, errorCode, errorMessage, method === "environmentAcquireLease" || method === "environmentDestroyLease" ? environmentCreationCleanupErrorData(err) : void 0));
|
|
39341
39341
|
}
|
|
39342
39342
|
}
|
|
39343
39343
|
async function dispatchMethod(method, params) {
|
|
@@ -39819,14 +39819,14 @@ function startWorkerRpcHost(options) {
|
|
|
39819
39819
|
return true;
|
|
39820
39820
|
}
|
|
39821
39821
|
function handleHostResponse(response) {
|
|
39822
|
-
const
|
|
39823
|
-
if (
|
|
39822
|
+
const id2 = response.id;
|
|
39823
|
+
if (id2 === null || id2 === void 0)
|
|
39824
39824
|
return;
|
|
39825
|
-
const pending = pendingRequests.get(
|
|
39825
|
+
const pending = pendingRequests.get(id2);
|
|
39826
39826
|
if (!pending)
|
|
39827
39827
|
return;
|
|
39828
39828
|
clearTimeout(pending.timer);
|
|
39829
|
-
pendingRequests.delete(
|
|
39829
|
+
pendingRequests.delete(id2);
|
|
39830
39830
|
pending.resolve(response);
|
|
39831
39831
|
}
|
|
39832
39832
|
function handleLine(line) {
|
|
@@ -39881,9 +39881,9 @@ function startWorkerRpcHost(options) {
|
|
|
39881
39881
|
readline.close();
|
|
39882
39882
|
readline = null;
|
|
39883
39883
|
}
|
|
39884
|
-
for (const [
|
|
39884
|
+
for (const [id2, pending] of pendingRequests) {
|
|
39885
39885
|
clearTimeout(pending.timer);
|
|
39886
|
-
pending.resolve(createErrorResponse(
|
|
39886
|
+
pending.resolve(createErrorResponse(id2, PLUGIN_RPC_ERROR_CODES.WORKER_UNAVAILABLE, "Worker RPC host is shutting down"));
|
|
39887
39887
|
}
|
|
39888
39888
|
pendingRequests.clear();
|
|
39889
39889
|
sessionEventCallbacks.clear();
|
|
@@ -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.28";
|
|
39936
39936
|
var DB_NAMESPACE_SLUG = "autopilot_ops";
|
|
39937
39937
|
var PAGE_ROUTE = "autopilot";
|
|
39938
39938
|
var TOOL_NAMES = {
|
|
@@ -40045,7 +40045,7 @@ var manifest = {
|
|
|
40045
40045
|
{
|
|
40046
40046
|
name: TOOL_NAMES.abrirCaso,
|
|
40047
40047
|
displayName: "Abrir caso",
|
|
40048
|
-
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), `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 obligatorio y la regla tiene que estar activa, persona_id, tipo de origen, estudio o especialidad o prestacion, fecha_origen AAAA-MM-DD, dias; el plugin 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.',
|
|
40048
|
+
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 obligatorio y la regla tiene que estar activa, persona_id, tipo de origen, estudio o especialidad o prestacion, fecha_origen AAAA-MM-DD, dias; el plugin 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.',
|
|
40049
40049
|
parametersSchema: {
|
|
40050
40050
|
type: "object",
|
|
40051
40051
|
properties: {
|
|
@@ -40062,7 +40062,7 @@ var manifest = {
|
|
|
40062
40062
|
{
|
|
40063
40063
|
name: TOOL_NAMES.transicionar,
|
|
40064
40064
|
displayName: "Transicionar caso",
|
|
40065
|
-
description: 'Aplica una transici\xF3n del workflow al caso (p. ej. `proponer`, `aplicar`, `verificar`). El plugin valida contra la tabla de transiciones, la pol\xEDtica vigente (observa / propone / ejecuta / corte) y las reglas de negocio; si algo falla, el caso no cambia y se devuelve el motivo. Las transiciones humanas (aprobar, rechazar, corregir) no est\xE1n disponibles para agentes. Cuando una persona de la instituci\xF3n carga a mano lo aprobado, el caso queda en `aplicado`: el agente lo comprueba releyendo el sistema y llamando `verificar` con `datos.valor_leido`. En `recupero_turno`: `proponer` con solicitud_id, solicitud_estado, solicitud_especialidad, cola (la lista de espera pendiente de esa especialidad tal como se vio: [{solicitud_id, prioridad, alta}]; el plugin la ordena y exige justificaci\xF3n para no elegir la primera) y fuente; si la instituci\xF3n pide consulta previa (ops_leer_caso lo dice), `ofrecer` con canal y esperar `aceptar`/`no_acepta`; **antes de escribir en el sistema, `autorizar`** (sin esa autorizaci\xF3n no se escribe); despu\xE9s de escribir, `asignar` con accion_id; `verificar` con leido_fecha, leido_hora, leido_profesional y leido_solicitud_id; `sin_candidato` y `descartar` con motivo. En `cuenta_completa` el agente solo lee: `observar` con bono_id, bono_estado (no_confirmado, confirmado o prefacturado), faltantes [{regla, detalle, item?}] con reglas del cat\xE1logo (autorizacion_faltante, validacion_faltante, afiliado_faltante, orden_faltante, prestacion_sin_valor, epicrisis_faltante), lectura_id (la lectura registrada con ops_registrar_accion, conector "base") y fuente; `comprobar` con faltantes_leidos (lista vac\xEDa si ya est\xE1 completo), bono_estado_leido y lectura_id; `descartar` con motivo si el bono se elimin\xF3 o anul\xF3. En `facturacion_pendiente` (solo lee): `observar` con bono_id, bono_estado, fecha_prestacion, obra_social, lectura_id (conector "base") y fuente; `comprobar` con bono_estado_leido y lectura_id (facturado/refacturado \u2192 facturada; prefacturado \u2192 en prefactura; si no, sigue por presentar); `descartar` con motivo. En `cobranza_financiador`, `circular_aranceles
|
|
40065
|
+
description: 'Aplica una transici\xF3n del workflow al caso (p. ej. `proponer`, `aplicar`, `verificar`). El plugin valida contra la tabla de transiciones, la pol\xEDtica vigente (observa / propone / ejecuta / corte) y las reglas de negocio; si algo falla, el caso no cambia y se devuelve el motivo. Las transiciones humanas (aprobar, rechazar, corregir) no est\xE1n disponibles para agentes. Cuando una persona de la instituci\xF3n carga a mano lo aprobado, el caso queda en `aplicado`: el agente lo comprueba releyendo el sistema y llamando `verificar` con `datos.valor_leido`. En `recupero_turno`: `proponer` con solicitud_id, solicitud_estado, solicitud_especialidad, cola (la lista de espera pendiente de esa especialidad tal como se vio: [{solicitud_id, prioridad, alta}]; el plugin la ordena y exige justificaci\xF3n para no elegir la primera) y fuente; si la instituci\xF3n pide consulta previa (ops_leer_caso lo dice), `ofrecer` con canal y esperar `aceptar`/`no_acepta`; **antes de escribir en el sistema, `autorizar`** (sin esa autorizaci\xF3n no se escribe); despu\xE9s de escribir, `asignar` con accion_id; `verificar` con leido_fecha, leido_hora, leido_profesional y leido_solicitud_id; `sin_candidato` y `descartar` con motivo. En `cuenta_completa` el agente solo lee: `observar` con bono_id, bono_estado (no_confirmado, confirmado o prefacturado), faltantes [{regla, detalle, item?}] con reglas del cat\xE1logo (autorizacion_faltante, validacion_faltante, afiliado_faltante, orden_faltante, prestacion_sin_valor, epicrisis_faltante), lectura_id (la lectura registrada con ops_registrar_accion, conector "base") y fuente; `comprobar` con faltantes_leidos (lista vac\xEDa si ya est\xE1 completo), bono_estado_leido y lectura_id; `descartar` con motivo si el bono se elimin\xF3 o anul\xF3. En `facturacion_pendiente` (solo lee): `observar` con bono_id, bono_estado, fecha_prestacion, obra_social, lectura_id (conector "base") y fuente; `comprobar` con bono_estado_leido y lectura_id (facturado/refacturado \u2192 facturada; prefacturado \u2192 en prefactura; si no, sigue por presentar); `descartar` con motivo. En `cobranza_financiador`, `circular_aranceles`, `internacion_al_dia` y los de honorarios los datos de cada v\xEDa est\xE1n en la skill del puesto (cobranzas, aranceles, internaciones, honorarios): el agente informa lo que ley\xF3 del HIS o del documento tal cual y el plugin decide qu\xE9 se reclama o se carga. En `demanda_pendiente`: `contactar` (nivel ejecuta; datos: canal igual al de la regla y accion_id de la escritura registrada; el plugin controla regla activa, intentos, espera entre intentos y horario), `responder` (respuesta: acepta|rechaza|no_contesta), `comprobar` (lectura_id de la relectura del HIS, turno_id y turno_estado del turno encontrado), `cerrar` (motivo; solo con los intentos agotados o el plazo vencido), `descartar` (motivo). `credencial_profesional` (solo lee): `verificar` con profesional_id, matricula y tipo_matricula (nacional|provincial) si hay matr\xEDcula, resultado = el objeto que devuelve verificar-matriculas.mjs tal cual ({sin_matricula, encontrada, coincide_nombre, situacion, sancion, profesion, provincia, emisor}), lectura_id (conector "api", la consulta al registro) y fuente; el plugin decide vigente u observada y fija la observaci\xF3n (sin_matricula, no_figura, otra_persona, inhabilitada, sancion); `descartar` con motivo si el profesional ya no est\xE1 activo.',
|
|
40066
40066
|
parametersSchema: {
|
|
40067
40067
|
type: "object",
|
|
40068
40068
|
properties: {
|
|
@@ -40302,6 +40302,14 @@ var manifest = {
|
|
|
40302
40302
|
capability: "api.routes.register",
|
|
40303
40303
|
companyResolution: { from: "body", key: "companyId" }
|
|
40304
40304
|
},
|
|
40305
|
+
{
|
|
40306
|
+
routeKey: "envio-liquidacion",
|
|
40307
|
+
method: "POST",
|
|
40308
|
+
path: "/casos/:casoId/envio-liquidacion",
|
|
40309
|
+
auth: "board",
|
|
40310
|
+
capability: "api.routes.register",
|
|
40311
|
+
companyResolution: { from: "body", key: "companyId" }
|
|
40312
|
+
},
|
|
40305
40313
|
{
|
|
40306
40314
|
routeKey: "respuesta-financiador",
|
|
40307
40315
|
method: "POST",
|
|
@@ -40482,8 +40490,8 @@ function mediana(v) {
|
|
|
40482
40490
|
const m = Math.floor(s.length / 2);
|
|
40483
40491
|
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
40484
40492
|
}
|
|
40485
|
-
function sumarDias(
|
|
40486
|
-
const d = /* @__PURE__ */ new Date(`${
|
|
40493
|
+
function sumarDias(fecha4, dias) {
|
|
40494
|
+
const d = /* @__PURE__ */ new Date(`${fecha4}T00:00:00Z`);
|
|
40487
40495
|
d.setUTCDate(d.getUTCDate() + dias);
|
|
40488
40496
|
return d.toISOString().slice(0, 10);
|
|
40489
40497
|
}
|
|
@@ -40675,8 +40683,8 @@ var REGLAS_INTERNACION = {
|
|
|
40675
40683
|
}
|
|
40676
40684
|
};
|
|
40677
40685
|
var fecha = (iso5) => `${iso5.slice(8, 10)}/${iso5.slice(5, 7)}`;
|
|
40678
|
-
function sumarDias2(
|
|
40679
|
-
const d = /* @__PURE__ */ new Date(`${
|
|
40686
|
+
function sumarDias2(dia4, n) {
|
|
40687
|
+
const d = /* @__PURE__ */ new Date(`${dia4}T12:00:00Z`);
|
|
40680
40688
|
d.setUTCDate(d.getUTCDate() + n);
|
|
40681
40689
|
return d.toISOString().slice(0, 10);
|
|
40682
40690
|
}
|
|
@@ -40698,8 +40706,8 @@ function verdad(v) {
|
|
|
40698
40706
|
function leerLecturaInternacion(v) {
|
|
40699
40707
|
if (!v || typeof v !== "object" || Array.isArray(v)) return { error: "lectura tiene que ser un objeto con la internaci\xF3n tal como la devuelve revisar-internaciones.mjs" };
|
|
40700
40708
|
const r = v;
|
|
40701
|
-
const
|
|
40702
|
-
if (!
|
|
40709
|
+
const id2 = texto(r.internacion_id);
|
|
40710
|
+
if (!id2 || !/^\d{1,12}$/.test(id2)) return { error: "lectura.internacion_id: el id num\xE9rico de la internaci\xF3n en el HIS" };
|
|
40703
40711
|
const ingreso = fechaHora(r.ingreso);
|
|
40704
40712
|
if (!ingreso) return { error: "lectura.ingreso: fecha y hora del ingreso (AAAA-MM-DD HH:MM)" };
|
|
40705
40713
|
const egreso = r.egreso == null || r.egreso === "" ? null : fechaHora(r.egreso);
|
|
@@ -40724,7 +40732,7 @@ function leerLecturaInternacion(v) {
|
|
|
40724
40732
|
}
|
|
40725
40733
|
return {
|
|
40726
40734
|
lectura: {
|
|
40727
|
-
internacion_id:
|
|
40735
|
+
internacion_id: id2,
|
|
40728
40736
|
ingreso,
|
|
40729
40737
|
egreso,
|
|
40730
40738
|
evoluciones: [...new Set(evoluciones)].sort(),
|
|
@@ -40780,6 +40788,207 @@ function estadoInternacion(e) {
|
|
|
40780
40788
|
return e.egresada ? "egresada" : e.pendientes.length ? "con_pendientes" : "al_dia";
|
|
40781
40789
|
}
|
|
40782
40790
|
|
|
40791
|
+
// src/honorarios.ts
|
|
40792
|
+
var redondear2 = (n) => Math.round(n * 100) / 100;
|
|
40793
|
+
var pesos2 = (n) => `$ ${n.toLocaleString("es-AR", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
40794
|
+
var fecha2 = (iso5) => `${iso5.slice(8, 10)}/${iso5.slice(5, 7)}/${iso5.slice(0, 4)}`;
|
|
40795
|
+
function texto2(v) {
|
|
40796
|
+
return typeof v === "string" && v.trim() ? v.trim() : typeof v === "number" && Number.isFinite(v) ? String(v) : null;
|
|
40797
|
+
}
|
|
40798
|
+
function num(v) {
|
|
40799
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
40800
|
+
if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))) return Number(v);
|
|
40801
|
+
return null;
|
|
40802
|
+
}
|
|
40803
|
+
function dia(v) {
|
|
40804
|
+
const s = texto2(v);
|
|
40805
|
+
return s && /^\d{4}-\d{2}-\d{2}/.test(s) ? s.slice(0, 10) : null;
|
|
40806
|
+
}
|
|
40807
|
+
function verdad2(v) {
|
|
40808
|
+
return v === true || v === 1 || v === "1" || v === "true";
|
|
40809
|
+
}
|
|
40810
|
+
function id(v) {
|
|
40811
|
+
const s = texto2(v);
|
|
40812
|
+
return s && /^\d{1,12}$/.test(s) ? s : null;
|
|
40813
|
+
}
|
|
40814
|
+
function leerProfesional(v) {
|
|
40815
|
+
if (!v || typeof v !== "object") return null;
|
|
40816
|
+
const r = v;
|
|
40817
|
+
const pid = id(r.id);
|
|
40818
|
+
return pid ? { id: pid, nombre: texto2(r.nombre)?.slice(0, 120) ?? null } : null;
|
|
40819
|
+
}
|
|
40820
|
+
function leerRegla(v) {
|
|
40821
|
+
if (!v || typeof v !== "object") return null;
|
|
40822
|
+
const r = v;
|
|
40823
|
+
const rid = id(r.id);
|
|
40824
|
+
if (!rid) return null;
|
|
40825
|
+
const prof = num(r.prof);
|
|
40826
|
+
const inst = num(r.inst);
|
|
40827
|
+
return { id: rid, prof: prof === null ? null : redondear2(prof), inst: inst === null ? null : redondear2(inst) };
|
|
40828
|
+
}
|
|
40829
|
+
function honorarioDe(input2) {
|
|
40830
|
+
const { regla, monto, cantidad } = input2;
|
|
40831
|
+
if (!regla) return 0;
|
|
40832
|
+
if (regla.prof !== null) return redondear2(regla.prof * cantidad);
|
|
40833
|
+
return redondear2(monto * cantidad * ((regla.inst ?? 0) / 100));
|
|
40834
|
+
}
|
|
40835
|
+
function motivoCero(regla, honorario) {
|
|
40836
|
+
if (honorario > 0) return null;
|
|
40837
|
+
return regla ? "regla_sin_valor" : "sin_regla";
|
|
40838
|
+
}
|
|
40839
|
+
function leerPrestaciones(v) {
|
|
40840
|
+
if (!Array.isArray(v)) return { error: "prestaciones tiene que ser la lista que devuelve leer-honorarios.mjs" };
|
|
40841
|
+
const out = [];
|
|
40842
|
+
for (const [i, e] of v.entries()) {
|
|
40843
|
+
if (!e || typeof e !== "object") return { error: `prestaciones[${i}] no es un objeto` };
|
|
40844
|
+
const r = e;
|
|
40845
|
+
const item = id(r.item_id);
|
|
40846
|
+
const bono = id(r.bono_id);
|
|
40847
|
+
const f = dia(r.fecha);
|
|
40848
|
+
const monto = num(r.monto);
|
|
40849
|
+
const cantidad = num(r.cantidad) ?? 1;
|
|
40850
|
+
if (!item || !bono || !f || monto === null) return { error: `prestaciones[${i}]: faltan item_id, bono_id, fecha o monto` };
|
|
40851
|
+
if (r.regla !== null && r.regla !== void 0 && !leerRegla(r.regla)) return { error: `prestaciones[${i}].regla: tiene que ser {id, prof, inst} o null` };
|
|
40852
|
+
out.push({ item_id: item, bono_id: bono, fecha: f, prestacion: texto2(r.prestacion)?.slice(0, 160) ?? "Prestaci\xF3n", obra_social: texto2(r.obra_social)?.slice(0, 120) ?? null, monto: redondear2(monto), cantidad: cantidad > 0 ? cantidad : 1, a_liquidar: verdad2(r.a_liquidar), liquidada: verdad2(r.liquidada), regla: leerRegla(r.regla) });
|
|
40853
|
+
}
|
|
40854
|
+
return { prestaciones: out };
|
|
40855
|
+
}
|
|
40856
|
+
function prestacionesEnCero(ps) {
|
|
40857
|
+
const items = [];
|
|
40858
|
+
for (const p of ps) {
|
|
40859
|
+
if (!p.a_liquidar || p.liquidada) continue;
|
|
40860
|
+
const motivo = motivoCero(p.regla, honorarioDe(p));
|
|
40861
|
+
if (motivo) items.push({ ...p, motivo });
|
|
40862
|
+
}
|
|
40863
|
+
items.sort((a, b) => a.fecha.localeCompare(b.fecha) || a.item_id.localeCompare(b.item_id));
|
|
40864
|
+
const fechas = items.map((p) => p.fecha).sort();
|
|
40865
|
+
return {
|
|
40866
|
+
items,
|
|
40867
|
+
resumen: {
|
|
40868
|
+
prestaciones: items.length,
|
|
40869
|
+
sin_regla: items.filter((p) => p.motivo === "sin_regla").length,
|
|
40870
|
+
regla_sin_valor: items.filter((p) => p.motivo === "regla_sin_valor").length,
|
|
40871
|
+
monto: redondear2(items.reduce((a, p) => a + p.monto * p.cantidad, 0)),
|
|
40872
|
+
obras_sociales: [...new Set(items.map((p) => p.obra_social).filter((x) => Boolean(x)))].sort(),
|
|
40873
|
+
desde: fechas[0] ?? null,
|
|
40874
|
+
hasta: fechas[fechas.length - 1] ?? null
|
|
40875
|
+
}
|
|
40876
|
+
};
|
|
40877
|
+
}
|
|
40878
|
+
function leerDebitos(v) {
|
|
40879
|
+
if (!Array.isArray(v)) return { error: "debitos tiene que ser la lista que devuelve leer-honorarios.mjs" };
|
|
40880
|
+
const out = [];
|
|
40881
|
+
for (const [i, e] of v.entries()) {
|
|
40882
|
+
if (!e || typeof e !== "object") return { error: `debitos[${i}] no es un objeto` };
|
|
40883
|
+
const r = e;
|
|
40884
|
+
const item = id(r.item_id);
|
|
40885
|
+
const bono = id(r.bono_id);
|
|
40886
|
+
const monto = num(r.monto_debitado);
|
|
40887
|
+
const nc = r.nota_credito && typeof r.nota_credito === "object" ? r.nota_credito : null;
|
|
40888
|
+
const ncId = nc ? id(nc.id) : null;
|
|
40889
|
+
if (!item || !bono || monto === null || !ncId) return { error: `debitos[${i}]: faltan item_id, bono_id, monto_debitado o nota_credito.id` };
|
|
40890
|
+
const montoItem = num(r.monto) ?? 0;
|
|
40891
|
+
const cantidad = num(r.cantidad) ?? 1;
|
|
40892
|
+
const regla = leerRegla(r.regla);
|
|
40893
|
+
const liquidada = verdad2(r.liquidada);
|
|
40894
|
+
const hon = liquidada ? honorarioDe({ regla, monto: montoItem, cantidad }) : null;
|
|
40895
|
+
const imp = liquidada ? redondear2(montoItem * cantidad) : null;
|
|
40896
|
+
out.push({
|
|
40897
|
+
item_id: item,
|
|
40898
|
+
bono_id: bono,
|
|
40899
|
+
prestacion: texto2(r.prestacion)?.slice(0, 160) ?? "Prestaci\xF3n",
|
|
40900
|
+
fecha_prestacion: dia(r.fecha_prestacion),
|
|
40901
|
+
obra_social: texto2(r.obra_social)?.slice(0, 120) ?? null,
|
|
40902
|
+
nota_credito: { id: ncId, numero: texto2(nc?.numero), fecha: dia(nc?.fecha), motivo: texto2(nc?.motivo)?.slice(0, 300) ?? null },
|
|
40903
|
+
monto_debitado: redondear2(Math.abs(monto)),
|
|
40904
|
+
liquidada,
|
|
40905
|
+
monto: redondear2(montoItem),
|
|
40906
|
+
cantidad: cantidad > 0 ? cantidad : 1,
|
|
40907
|
+
regla,
|
|
40908
|
+
liquidado: hon !== null && imp !== null ? { honorario: hon, importe: imp } : null,
|
|
40909
|
+
ya_trasladado: redondear2(Math.abs(num(r.ya_trasladado) ?? 0))
|
|
40910
|
+
});
|
|
40911
|
+
}
|
|
40912
|
+
return { debitos: out };
|
|
40913
|
+
}
|
|
40914
|
+
function evaluarDebito(d) {
|
|
40915
|
+
if (!d.liquidado) return { ...d, estado: "sin_liquidar", a_descontar: 0 };
|
|
40916
|
+
if (d.liquidado.importe <= 0 || d.liquidado.honorario <= 0 || d.monto_debitado <= 0) return { ...d, estado: "sin_monto", a_descontar: 0 };
|
|
40917
|
+
const proporcional = Math.min(d.liquidado.honorario, d.liquidado.honorario * d.monto_debitado / d.liquidado.importe);
|
|
40918
|
+
const falta = redondear2(proporcional - d.ya_trasladado);
|
|
40919
|
+
return falta >= 0.01 ? { ...d, estado: "a_trasladar", a_descontar: falta } : { ...d, estado: "ya_trasladado", a_descontar: 0 };
|
|
40920
|
+
}
|
|
40921
|
+
function resumenDebitos(ds) {
|
|
40922
|
+
const a = ds.filter((d) => d.estado === "a_trasladar");
|
|
40923
|
+
return { a_trasladar: a.length, total: redondear2(a.reduce((s, d) => s + d.a_descontar, 0)), sin_liquidar: ds.filter((d) => d.estado === "sin_liquidar").length, ya_trasladados: ds.filter((d) => d.estado === "ya_trasladado").length };
|
|
40924
|
+
}
|
|
40925
|
+
function leerLineasLiquidacion(v) {
|
|
40926
|
+
if (!Array.isArray(v) || v.length === 0) return { error: "lineas tiene que ser la lista (no vac\xEDa) de bonos de la liquidaci\xF3n, como la devuelve leer-honorarios.mjs" };
|
|
40927
|
+
const out = [];
|
|
40928
|
+
for (const [i, e] of v.entries()) {
|
|
40929
|
+
if (!e || typeof e !== "object") return { error: `lineas[${i}] no es un objeto` };
|
|
40930
|
+
const r = e;
|
|
40931
|
+
const bono = id(r.bono_id);
|
|
40932
|
+
if (!bono || !Array.isArray(r.items) || r.items.length === 0) return { error: `lineas[${i}]: faltan bono_id o items [{monto, cantidad, regla}]` };
|
|
40933
|
+
let importe = 0;
|
|
40934
|
+
let honorario = 0;
|
|
40935
|
+
let enCero = 0;
|
|
40936
|
+
for (const it of r.items) {
|
|
40937
|
+
const x = it && typeof it === "object" ? it : {};
|
|
40938
|
+
const monto = num(x.monto) ?? 0;
|
|
40939
|
+
const cantidad = num(x.cantidad) ?? 1;
|
|
40940
|
+
const regla = leerRegla(x.regla);
|
|
40941
|
+
const h = honorarioDe({ regla, monto, cantidad });
|
|
40942
|
+
importe += monto * cantidad;
|
|
40943
|
+
honorario += h;
|
|
40944
|
+
if (h <= 0) enCero += 1;
|
|
40945
|
+
}
|
|
40946
|
+
out.push({ bono_id: bono, fecha: dia(r.fecha), obra_social: texto2(r.obra_social)?.slice(0, 120) ?? null, importe: redondear2(importe), honorario: redondear2(honorario), en_cero: enCero });
|
|
40947
|
+
}
|
|
40948
|
+
return { lineas: out };
|
|
40949
|
+
}
|
|
40950
|
+
function resumirLiquidacion(lineas) {
|
|
40951
|
+
const por = /* @__PURE__ */ new Map();
|
|
40952
|
+
for (const l of lineas) {
|
|
40953
|
+
const k = l.obra_social ?? "Particular / sin obra social";
|
|
40954
|
+
const e = por.get(k) ?? { bonos: 0, honorario: 0 };
|
|
40955
|
+
e.bonos += 1;
|
|
40956
|
+
e.honorario = redondear2(e.honorario + l.honorario);
|
|
40957
|
+
por.set(k, e);
|
|
40958
|
+
}
|
|
40959
|
+
const fechas = lineas.map((l) => l.fecha).filter((x) => Boolean(x)).sort();
|
|
40960
|
+
return {
|
|
40961
|
+
bonos: lineas.length,
|
|
40962
|
+
honorario: redondear2(lineas.reduce((a, l) => a + l.honorario, 0)),
|
|
40963
|
+
importe: redondear2(lineas.reduce((a, l) => a + l.importe, 0)),
|
|
40964
|
+
en_cero: lineas.reduce((a, l) => a + l.en_cero, 0),
|
|
40965
|
+
por_obra_social: [...por.entries()].map(([obra_social, e]) => ({ obra_social, ...e })).sort((a, b) => b.honorario - a.honorario),
|
|
40966
|
+
desde: fechas[0] ?? null,
|
|
40967
|
+
hasta: fechas[fechas.length - 1] ?? null
|
|
40968
|
+
};
|
|
40969
|
+
}
|
|
40970
|
+
function redactarLiquidacion(input2) {
|
|
40971
|
+
const r = input2.resumen;
|
|
40972
|
+
const quien = input2.profesional.nombre ?? "Profesional";
|
|
40973
|
+
const periodo = r.desde && r.hasta ? ` (prestaciones del ${fecha2(r.desde)} al ${fecha2(r.hasta)})` : "";
|
|
40974
|
+
const asunto = `Liquidaci\xF3n de honorarios \xB7 ${input2.institucion} \xB7 ${fecha2(input2.fechaLiquidacion)} \xB7 ${pesos2(r.honorario)}`;
|
|
40975
|
+
const lineas = [
|
|
40976
|
+
`${quien}:`,
|
|
40977
|
+
"",
|
|
40978
|
+
`${input2.institucion} liquid\xF3 tus honorarios el ${fecha2(input2.fechaLiquidacion)}${periodo}.`,
|
|
40979
|
+
"",
|
|
40980
|
+
...r.por_obra_social.map((o) => `- ${o.obra_social}: ${o.bonos} ${o.bonos === 1 ? "prestaci\xF3n" : "prestaciones"}, ${pesos2(o.honorario)}`),
|
|
40981
|
+
"",
|
|
40982
|
+
`Total: ${pesos2(r.honorario)} en ${r.bonos} ${r.bonos === 1 ? "prestaci\xF3n" : "prestaciones"}.`,
|
|
40983
|
+
...input2.debitos ? ["", `Incluye d\xE9bitos de obras sociales por ${pesos2(input2.debitos)}.`] : [],
|
|
40984
|
+
"",
|
|
40985
|
+
"Si algo no coincide con lo que atendiste, respond\xE9 este correo y lo revisamos.",
|
|
40986
|
+
"",
|
|
40987
|
+
`${input2.institucion} \xB7 liquidaci\xF3n de honorarios`
|
|
40988
|
+
];
|
|
40989
|
+
return { asunto, texto: lineas.join("\n") };
|
|
40990
|
+
}
|
|
40991
|
+
|
|
40783
40992
|
// src/cobranzas.ts
|
|
40784
40993
|
var PLAZO_PAGO_POR_DEFECTO = 60;
|
|
40785
40994
|
var SALDO_MINIMO = 1;
|
|
@@ -40787,20 +40996,20 @@ var ATRASO_EXCEPCION = 365;
|
|
|
40787
40996
|
var MAX_RECLAMOS_POR_DEFECTO = 2;
|
|
40788
40997
|
var DIAS_ENTRE_RECLAMOS_POR_DEFECTO = 15;
|
|
40789
40998
|
var GRACIA_COMPROMISO = 7;
|
|
40790
|
-
var
|
|
40791
|
-
var
|
|
40792
|
-
var
|
|
40999
|
+
var redondear3 = (n) => Math.round(n * 100) / 100;
|
|
41000
|
+
var pesos3 = (n) => `$ ${n.toLocaleString("es-AR", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
41001
|
+
var fecha3 = (iso5) => `${iso5.slice(8, 10)}/${iso5.slice(5, 7)}/${iso5.slice(0, 4)}`;
|
|
40793
41002
|
var normalizar = (s) => s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/\s+/g, " ").trim();
|
|
40794
|
-
function
|
|
41003
|
+
function num2(v) {
|
|
40795
41004
|
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
40796
41005
|
if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))) return Number(v);
|
|
40797
41006
|
return null;
|
|
40798
41007
|
}
|
|
40799
|
-
function
|
|
41008
|
+
function texto3(v) {
|
|
40800
41009
|
return typeof v === "string" && v.trim() ? v.trim() : typeof v === "number" ? String(v) : null;
|
|
40801
41010
|
}
|
|
40802
|
-
function
|
|
40803
|
-
const s =
|
|
41011
|
+
function dia2(v) {
|
|
41012
|
+
const s = texto3(v);
|
|
40804
41013
|
return s && /^\d{4}-\d{2}-\d{2}/.test(s) ? s.slice(0, 10) : null;
|
|
40805
41014
|
}
|
|
40806
41015
|
function sumarDias3(fechaIso, dias) {
|
|
@@ -40818,16 +41027,16 @@ function leerFacturas(v) {
|
|
|
40818
41027
|
for (const [i, e] of v.entries()) {
|
|
40819
41028
|
if (!e || typeof e !== "object") return { error: `facturas[${i}] no es una factura` };
|
|
40820
41029
|
const r = e;
|
|
40821
|
-
const
|
|
40822
|
-
const emision =
|
|
40823
|
-
const monto =
|
|
40824
|
-
const saldo =
|
|
40825
|
-
if (!
|
|
40826
|
-
if (vistas.has(
|
|
40827
|
-
vistas.add(
|
|
40828
|
-
if (!emision) return { error: `factura ${
|
|
40829
|
-
if (monto === null || saldo === null) return { error: `factura ${
|
|
40830
|
-
out.push({ factura_id:
|
|
41030
|
+
const id2 = texto3(r.factura_id);
|
|
41031
|
+
const emision = dia2(r.fecha_emision);
|
|
41032
|
+
const monto = num2(r.monto_pesos);
|
|
41033
|
+
const saldo = num2(r.saldo_pesos);
|
|
41034
|
+
if (!id2) return { error: `facturas[${i}]: falta factura_id` };
|
|
41035
|
+
if (vistas.has(id2)) return { error: `la factura ${id2} est\xE1 repetida` };
|
|
41036
|
+
vistas.add(id2);
|
|
41037
|
+
if (!emision) return { error: `factura ${id2}: fecha_emision tiene que ser AAAA-MM-DD` };
|
|
41038
|
+
if (monto === null || saldo === null) return { error: `factura ${id2}: monto_pesos y saldo_pesos tienen que ser n\xFAmeros` };
|
|
41039
|
+
out.push({ factura_id: id2, numero_comprobante: texto3(r.numero_comprobante) ?? id2, fecha_emision: emision, periodo_desde: dia2(r.periodo_desde), periodo_hasta: dia2(r.periodo_hasta), monto_pesos: redondear3(monto), saldo_pesos: redondear3(saldo), anulada: r.anulada === true || r.anulada === 1 || r.anulada === "1" });
|
|
40831
41040
|
}
|
|
40832
41041
|
return { facturas: out };
|
|
40833
41042
|
}
|
|
@@ -40847,7 +41056,7 @@ function evaluarFacturas(input2) {
|
|
|
40847
41056
|
factura_id: f.factura_id,
|
|
40848
41057
|
numero_comprobante: f.numero_comprobante,
|
|
40849
41058
|
fecha_emision: f.fecha_emision,
|
|
40850
|
-
periodo: f.periodo_desde && f.periodo_hasta ? `${
|
|
41059
|
+
periodo: f.periodo_desde && f.periodo_hasta ? `${fecha3(f.periodo_desde)} al ${fecha3(f.periodo_hasta)}` : null,
|
|
40851
41060
|
monto_pesos: f.monto_pesos,
|
|
40852
41061
|
saldo_inicial: f.saldo_pesos,
|
|
40853
41062
|
saldo_pesos: f.saldo_pesos,
|
|
@@ -40859,7 +41068,7 @@ function evaluarFacturas(input2) {
|
|
|
40859
41068
|
};
|
|
40860
41069
|
});
|
|
40861
41070
|
const reclamadas = items.filter((i) => i.estado === "reclamada").sort((a, b) => b.dias_atraso - a.dias_atraso);
|
|
40862
|
-
const total =
|
|
41071
|
+
const total = redondear3(reclamadas.reduce((s, i) => s + i.saldo_pesos, 0));
|
|
40863
41072
|
return {
|
|
40864
41073
|
items: [...reclamadas, ...items.filter((i) => i.estado !== "reclamada")],
|
|
40865
41074
|
resumen: {
|
|
@@ -40878,17 +41087,17 @@ function evaluarFacturas(input2) {
|
|
|
40878
41087
|
}
|
|
40879
41088
|
function redactarReclamo(input2) {
|
|
40880
41089
|
const reclamadas = input2.items.filter((i) => i.estado === "reclamada" && i.cobro !== "cobrada");
|
|
40881
|
-
const total =
|
|
40882
|
-
const asunto = `${input2.numero > 1 ? "Segundo reclamo" : "Reclamo"} de pago \xB7 ${input2.institucion} \xB7 ${reclamadas.length} ${reclamadas.length === 1 ? "factura" : "facturas"} \xB7 ${
|
|
40883
|
-
const lineas = reclamadas.map((i) => `- Factura ${i.numero_comprobante} del ${
|
|
41090
|
+
const total = redondear3(reclamadas.reduce((s, i) => s + i.saldo_pesos, 0));
|
|
41091
|
+
const asunto = `${input2.numero > 1 ? "Segundo reclamo" : "Reclamo"} de pago \xB7 ${input2.institucion} \xB7 ${reclamadas.length} ${reclamadas.length === 1 ? "factura" : "facturas"} \xB7 ${pesos3(total)}`;
|
|
41092
|
+
const lineas = reclamadas.map((i) => `- Factura ${i.numero_comprobante} del ${fecha3(i.fecha_emision)}${i.periodo ? ` (per\xEDodo ${i.periodo})` : ""}: saldo ${pesos3(i.saldo_pesos)}, vencida hace ${i.dias_atraso} d\xEDas.`);
|
|
40884
41093
|
const cuerpo = [
|
|
40885
41094
|
`A ${input2.obraSocial}, \xE1rea de cuentas a pagar a prestadores:`,
|
|
40886
41095
|
"",
|
|
40887
|
-
`${input2.institucion} ${input2.numero > 1 ? "reitera el reclamo de" : "reclama"} el pago de las siguientes facturas, vencidas al ${
|
|
41096
|
+
`${input2.institucion} ${input2.numero > 1 ? "reitera el reclamo de" : "reclama"} el pago de las siguientes facturas, vencidas al ${fecha3(input2.hoy)}:`,
|
|
40888
41097
|
"",
|
|
40889
41098
|
...lineas,
|
|
40890
41099
|
"",
|
|
40891
|
-
`Total adeudado: ${
|
|
41100
|
+
`Total adeudado: ${pesos3(total)}.`,
|
|
40892
41101
|
"",
|
|
40893
41102
|
"Les pedimos que nos informen la fecha de pago o, si alguna factura tiene observaciones, el detalle para corregirla.",
|
|
40894
41103
|
"",
|
|
@@ -40901,10 +41110,10 @@ function leerSaldos(v) {
|
|
|
40901
41110
|
const saldos = /* @__PURE__ */ new Map();
|
|
40902
41111
|
for (const [i, e] of v.entries()) {
|
|
40903
41112
|
const r = e ?? {};
|
|
40904
|
-
const
|
|
40905
|
-
const saldo =
|
|
40906
|
-
if (!
|
|
40907
|
-
saldos.set(
|
|
41113
|
+
const id2 = texto3(r.factura_id);
|
|
41114
|
+
const saldo = num2(r.saldo_pesos);
|
|
41115
|
+
if (!id2 || saldo === null) return { error: `leidos[${i}]: hace falta factura_id y saldo_pesos` };
|
|
41116
|
+
saldos.set(id2, { saldo: redondear3(saldo), notasCredito: redondear3(num2(r.notas_credito_pesos) ?? 0), recibos: redondear3(num2(r.recibos_aplicados_pesos) ?? 0) });
|
|
40908
41117
|
}
|
|
40909
41118
|
return { saldos };
|
|
40910
41119
|
}
|
|
@@ -40920,14 +41129,14 @@ function compararSaldos(items, resumen, leidos, notasCreditoAntes = {}) {
|
|
|
40920
41129
|
return i;
|
|
40921
41130
|
}
|
|
40922
41131
|
const saldo = Math.max(0, s.saldo);
|
|
40923
|
-
const nc = Math.max(0,
|
|
41132
|
+
const nc = Math.max(0, redondear3(s.notasCredito - (notasCreditoAntes[i.factura_id] ?? 0)));
|
|
40924
41133
|
const cobro = saldo <= SALDO_MINIMO ? "cobrada" : saldo < i.saldo_inicial - SALDO_MINIMO ? "parcial" : "pendiente";
|
|
40925
41134
|
return { ...i, saldo_pesos: saldo, cobro, notas_credito_nuevas: nc };
|
|
40926
41135
|
});
|
|
40927
41136
|
const reclamadas = nuevos.filter((i) => i.estado === "reclamada");
|
|
40928
|
-
const pendiente =
|
|
40929
|
-
const debitos =
|
|
40930
|
-
const cobrado =
|
|
41137
|
+
const pendiente = redondear3(reclamadas.reduce((s, i) => s + (i.cobro === "cobrada" ? 0 : i.saldo_pesos), 0));
|
|
41138
|
+
const debitos = redondear3(reclamadas.reduce((s, i) => s + i.notas_credito_nuevas, 0));
|
|
41139
|
+
const cobrado = redondear3(Math.max(0, resumen.total_reclamado - pendiente - debitos));
|
|
40931
41140
|
return { items: nuevos, resumen: { ...resumen, cobrado, pendiente, posibles_debitos: debitos }, todoCobrado: reclamadas.length > 0 && reclamadas.every((i) => i.cobro === "cobrada") && faltan.length === 0, faltan };
|
|
40932
41141
|
}
|
|
40933
41142
|
var RESPUESTAS_FINANCIADOR = ["paga", "observa", "no_responde"];
|
|
@@ -40935,7 +41144,7 @@ var RESPUESTAS_FINANCIADOR = ["paga", "observa", "no_responde"];
|
|
|
40935
41144
|
// src/workflows.ts
|
|
40936
41145
|
var MODOS = ["corte", "observa", "propone", "ejecuta", "autonomo"];
|
|
40937
41146
|
var MODO_POR_DEFECTO = "propone";
|
|
40938
|
-
function
|
|
41147
|
+
function num3(v) {
|
|
40939
41148
|
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
40940
41149
|
if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))) return Number(v);
|
|
40941
41150
|
return null;
|
|
@@ -40943,7 +41152,7 @@ function num2(v) {
|
|
|
40943
41152
|
function fechaISO(v) {
|
|
40944
41153
|
return typeof v === "string" && /^\d{4}-\d{2}-\d{2}$/.test(v) && !Number.isNaN(Date.parse(v));
|
|
40945
41154
|
}
|
|
40946
|
-
function
|
|
41155
|
+
function texto4(v) {
|
|
40947
41156
|
return typeof v === "string" && v.trim().length > 0 ? v.trim() : null;
|
|
40948
41157
|
}
|
|
40949
41158
|
var ok = (regla, detalle) => ({ regla, ok: true, detalle });
|
|
@@ -40980,14 +41189,14 @@ var actualizacionArancel = {
|
|
|
40980
41189
|
descripcion: "Proponer el nuevo valor con vigencia y fuente.",
|
|
40981
41190
|
validar: (caso, datos) => {
|
|
40982
41191
|
const out = [];
|
|
40983
|
-
const nuevo =
|
|
40984
|
-
const actual =
|
|
41192
|
+
const nuevo = num3(datos.valor_nuevo);
|
|
41193
|
+
const actual = num3(datos.valor_actual ?? caso.datos.valor_actual);
|
|
40985
41194
|
out.push(nuevo !== null && nuevo > 0 ? ok("valor_nuevo_positivo") : falla("valor_nuevo_positivo", "valor_nuevo debe ser un n\xFAmero mayor a 0"));
|
|
40986
41195
|
out.push(fechaISO(datos.vigencia_desde) ? ok("vigencia_valida") : falla("vigencia_valida", "vigencia_desde debe ser una fecha AAAA-MM-DD"));
|
|
40987
|
-
out.push(
|
|
41196
|
+
out.push(texto4(datos.fuente) ? ok("fuente_presente") : falla("fuente_presente", "fuente (documento, circular o pantalla) es obligatoria"));
|
|
40988
41197
|
if (nuevo !== null && actual !== null && actual > 0) {
|
|
40989
41198
|
const variacion = Math.abs(nuevo - actual) / actual;
|
|
40990
|
-
if (variacion > VARIACION_MAX_SIN_JUSTIFICACION && !
|
|
41199
|
+
if (variacion > VARIACION_MAX_SIN_JUSTIFICACION && !texto4(datos.justificacion)) {
|
|
40991
41200
|
out.push(falla("variacion_razonable", `variaci\xF3n de ${(variacion * 100).toFixed(0)}% supera el ${VARIACION_MAX_SIN_JUSTIFICACION * 100}% y no trae justificaci\xF3n`));
|
|
40992
41201
|
} else {
|
|
40993
41202
|
out.push(ok("variacion_razonable", `${(variacion * 100).toFixed(1)}%`));
|
|
@@ -40998,8 +41207,8 @@ var actualizacionArancel = {
|
|
|
40998
41207
|
autonomia: {
|
|
40999
41208
|
aSinExcepcion: "aprobado",
|
|
41000
41209
|
excepciones: (caso, datos) => {
|
|
41001
|
-
const nuevo =
|
|
41002
|
-
const actual =
|
|
41210
|
+
const nuevo = num3(datos.valor_nuevo);
|
|
41211
|
+
const actual = num3(datos.valor_actual ?? caso.datos.valor_actual);
|
|
41003
41212
|
const variacion = nuevo !== null && actual !== null && actual > 0 ? Math.abs(nuevo - actual) / actual : null;
|
|
41004
41213
|
return [
|
|
41005
41214
|
excepcion("variacion_supera_umbral", variacion !== null && variacion > VARIACION_MAX_AUTONOMA, variacion === null ? "sin valor actual para comparar" : `${(variacion * 100).toFixed(1)}% (umbral ${VARIACION_MAX_AUTONOMA * 100}%)`),
|
|
@@ -41023,7 +41232,7 @@ var actualizacionArancel = {
|
|
|
41023
41232
|
a: "rechazado",
|
|
41024
41233
|
actor: ["humano"],
|
|
41025
41234
|
descripcion: "Rechazo con motivo.",
|
|
41026
|
-
validar: (_caso, datos) => [
|
|
41235
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "el rechazo requiere motivo")]
|
|
41027
41236
|
},
|
|
41028
41237
|
{
|
|
41029
41238
|
via: "aplicar",
|
|
@@ -41034,17 +41243,17 @@ var actualizacionArancel = {
|
|
|
41034
41243
|
cargaManual: true,
|
|
41035
41244
|
descripcion: "Cargar el valor aprobado en el sistema de gesti\xF3n y registrar la acci\xF3n.",
|
|
41036
41245
|
validar: (_caso, datos) => [
|
|
41037
|
-
|
|
41246
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "aplicar requiere accion_id de la escritura registrada con ops_registrar_accion")
|
|
41038
41247
|
]
|
|
41039
41248
|
},
|
|
41040
41249
|
{
|
|
41041
41250
|
via: "verificar",
|
|
41042
41251
|
de: ["aplicado"],
|
|
41043
|
-
a: (caso, datos) =>
|
|
41252
|
+
a: (caso, datos) => num3(datos.valor_leido) === num3(caso.datos.valor_nuevo) ? "verificado" : "con_diferencias",
|
|
41044
41253
|
actor: ["agente", "humano", "sistema"],
|
|
41045
41254
|
nivelRequerido: "observa",
|
|
41046
41255
|
descripcion: "Releer el valor en el sistema y compararlo con el aprobado. Si no coincide, el caso queda con diferencias.",
|
|
41047
|
-
validar: (_caso, datos) => [
|
|
41256
|
+
validar: (_caso, datos) => [num3(datos.valor_leido) !== null ? ok("valor_leido_presente") : falla("valor_leido_presente", "verificar requiere valor_leido num\xE9rico")]
|
|
41048
41257
|
},
|
|
41049
41258
|
{
|
|
41050
41259
|
// Una carga manual que no coincidió se corrige en el sistema y se vuelve a comprobar:
|
|
@@ -41057,7 +41266,7 @@ var actualizacionArancel = {
|
|
|
41057
41266
|
cargaManual: true,
|
|
41058
41267
|
descripcion: "Corregir a mano la carga en el sistema de gesti\xF3n (el valor aprobado no cambia) y volver a comprobar.",
|
|
41059
41268
|
validar: (_caso, datos) => [
|
|
41060
|
-
|
|
41269
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "corregir requiere accion_id de la escritura registrada con la carga corregida")
|
|
41061
41270
|
]
|
|
41062
41271
|
},
|
|
41063
41272
|
{
|
|
@@ -41066,7 +41275,7 @@ var actualizacionArancel = {
|
|
|
41066
41275
|
a: "cancelado",
|
|
41067
41276
|
actor: ["humano"],
|
|
41068
41277
|
descripcion: "Cancelaci\xF3n manual.",
|
|
41069
|
-
validar: (_caso, datos) => [
|
|
41278
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "la cancelaci\xF3n requiere motivo")]
|
|
41070
41279
|
}
|
|
41071
41280
|
]
|
|
41072
41281
|
};
|
|
@@ -41089,10 +41298,10 @@ var tareaOperativa = {
|
|
|
41089
41298
|
actor: ["agente", "humano"],
|
|
41090
41299
|
nivelRequerido: "propone",
|
|
41091
41300
|
descripcion: "Proponer el resultado para aprobaci\xF3n.",
|
|
41092
|
-
validar: (_caso, datos) => [
|
|
41301
|
+
validar: (_caso, datos) => [texto4(datos.resultado) ? ok("resultado_presente") : falla("resultado_presente", "proponer requiere un resultado descripto")],
|
|
41093
41302
|
autonomia: {
|
|
41094
41303
|
aSinExcepcion: "cerrada",
|
|
41095
|
-
excepciones: (_caso, datos) => [excepcion("resultado_con_observaciones", Boolean(
|
|
41304
|
+
excepciones: (_caso, datos) => [excepcion("resultado_con_observaciones", Boolean(texto4(datos.observaciones)), texto4(datos.observaciones) ? "el resultado trae observaciones para una persona" : "sin observaciones")]
|
|
41096
41305
|
}
|
|
41097
41306
|
},
|
|
41098
41307
|
{ via: "aprobar", de: ["pendiente_aprobacion"], a: "cerrada", actor: ["humano"], descripcion: "Aprobaci\xF3n y cierre." },
|
|
@@ -41102,7 +41311,7 @@ var tareaOperativa = {
|
|
|
41102
41311
|
a: "rechazada",
|
|
41103
41312
|
actor: ["humano"],
|
|
41104
41313
|
descripcion: "Rechazo con motivo.",
|
|
41105
|
-
validar: (_caso, datos) => [
|
|
41314
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "el rechazo requiere motivo")]
|
|
41106
41315
|
},
|
|
41107
41316
|
{ via: "cancelar", de: ["abierta", "en_curso", "pendiente_aprobacion"], a: "cancelada", actor: ["humano"], descripcion: "Cancelaci\xF3n manual." }
|
|
41108
41317
|
]
|
|
@@ -41110,13 +41319,13 @@ var tareaOperativa = {
|
|
|
41110
41319
|
var TOPE_DIARIO_RECUPERO = 20;
|
|
41111
41320
|
var TITULOS = /* @__PURE__ */ new Set(["dr", "dra", "doctor", "doctora", "lic", "licenciado", "licenciada", "prof"]);
|
|
41112
41321
|
function normalizarNombre(v) {
|
|
41113
|
-
const s =
|
|
41322
|
+
const s = texto4(v);
|
|
41114
41323
|
if (!s) return null;
|
|
41115
41324
|
const palabras = s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, " ").split(" ").filter((p) => p && !TITULOS.has(p));
|
|
41116
41325
|
return palabras.length ? palabras.sort().join(" ") : null;
|
|
41117
41326
|
}
|
|
41118
41327
|
function horaHM(v) {
|
|
41119
|
-
const s =
|
|
41328
|
+
const s = texto4(v);
|
|
41120
41329
|
const m = s ? /^(\d{1,2}):(\d{2})(?::\d{2})?$/.exec(s) : null;
|
|
41121
41330
|
if (!m) return null;
|
|
41122
41331
|
const h = Number(m[1]);
|
|
@@ -41125,10 +41334,10 @@ function horaHM(v) {
|
|
|
41125
41334
|
}
|
|
41126
41335
|
function refExterna(v) {
|
|
41127
41336
|
if (typeof v === "number" && Number.isFinite(v)) return String(v);
|
|
41128
|
-
return
|
|
41337
|
+
return texto4(v);
|
|
41129
41338
|
}
|
|
41130
41339
|
function fechaAISO(v) {
|
|
41131
|
-
const s =
|
|
41340
|
+
const s = texto4(v);
|
|
41132
41341
|
if (!s) return null;
|
|
41133
41342
|
if (fechaISO(s.slice(0, 10))) return s.slice(0, 10);
|
|
41134
41343
|
const m = /^(\d{1,2})\/(\d{1,2})\/(\d{4})/.exec(s);
|
|
@@ -41142,9 +41351,9 @@ function leerCola(v) {
|
|
|
41142
41351
|
for (const e of v) {
|
|
41143
41352
|
if (!e || typeof e !== "object") return null;
|
|
41144
41353
|
const r = e;
|
|
41145
|
-
const
|
|
41146
|
-
if (!
|
|
41147
|
-
out.push({ solicitud_id:
|
|
41354
|
+
const id2 = refExterna(r.solicitud_id);
|
|
41355
|
+
if (!id2) return null;
|
|
41356
|
+
out.push({ solicitud_id: id2, prioridad: texto4(r.prioridad), alta: fechaAISO(r.alta) });
|
|
41148
41357
|
}
|
|
41149
41358
|
return out;
|
|
41150
41359
|
}
|
|
@@ -41190,20 +41399,20 @@ function declinadas(caso) {
|
|
|
41190
41399
|
}
|
|
41191
41400
|
function validarLugar(caso, datos, contexto) {
|
|
41192
41401
|
const l = { ...caso.datos, ...datos };
|
|
41193
|
-
const completo = fechaISO(l.fecha) && horaHM(l.hora) !== null &&
|
|
41402
|
+
const completo = fechaISO(l.fecha) && horaHM(l.hora) !== null && texto4(l.profesional) !== null && texto4(l.especialidad) !== null;
|
|
41194
41403
|
const out = [completo ? ok("lugar_completo") : falla("lugar_completo", "el turno liberado necesita fecha (AAAA-MM-DD), hora (HH:MM), profesional y especialidad")];
|
|
41195
41404
|
if (fechaISO(l.fecha) && contexto.hoy) {
|
|
41196
|
-
const
|
|
41405
|
+
const fecha4 = String(l.fecha);
|
|
41197
41406
|
const hora = horaHM(l.hora);
|
|
41198
|
-
const futuro =
|
|
41199
|
-
out.push(futuro ? ok("lugar_futuro") : falla("lugar_futuro", `el turno del ${
|
|
41407
|
+
const futuro = fecha4 > contexto.hoy || fecha4 === contexto.hoy && (!contexto.horaActual || hora !== null && hora > contexto.horaActual);
|
|
41408
|
+
out.push(futuro ? ok("lugar_futuro") : falla("lugar_futuro", `el turno del ${fecha4}${hora ? ` a las ${hora}` : ""} ya pas\xF3: no se puede recuperar`));
|
|
41200
41409
|
}
|
|
41201
41410
|
return out;
|
|
41202
41411
|
}
|
|
41203
41412
|
var recuperoTurno = {
|
|
41204
41413
|
clave: "recupero_turno",
|
|
41205
41414
|
nombre: "Recupero de citas",
|
|
41206
|
-
puesto: "
|
|
41415
|
+
puesto: "Operaciones",
|
|
41207
41416
|
descripcion: "Detecta un turno que se liber\xF3 en la agenda, elige de la lista de espera (solicitudes de turno) a quien corresponde por especialidad, prioridad y antig\xFCedad, le asigna el turno en el sistema de gesti\xF3n y comprueba reley\xE9ndolo que qued\xF3 asignado.",
|
|
41208
41417
|
inicial: "detectado",
|
|
41209
41418
|
estados: [
|
|
@@ -41236,10 +41445,10 @@ var recuperoTurno = {
|
|
|
41236
41445
|
const out = validarLugar(caso, datos, contexto);
|
|
41237
41446
|
out.push(refExterna(datos.solicitud_id) ? ok("solicitud_presente") : falla("solicitud_presente", "proponer requiere solicitud_id: la solicitud de turno de la lista de espera"));
|
|
41238
41447
|
const estado = normalizarNombre(datos.solicitud_estado);
|
|
41239
|
-
out.push(estado === "pendiente" ? ok("solicitud_pendiente") : falla("solicitud_pendiente", `la solicitud tiene que estar pendiente (est\xE1: ${
|
|
41448
|
+
out.push(estado === "pendiente" ? ok("solicitud_pendiente") : falla("solicitud_pendiente", `la solicitud tiene que estar pendiente (est\xE1: ${texto4(datos.solicitud_estado) ?? "sin informar"})`));
|
|
41240
41449
|
const esp = normalizarNombre(l.especialidad);
|
|
41241
41450
|
const espSolicitud = normalizarNombre(datos.solicitud_especialidad);
|
|
41242
|
-
out.push(esp && espSolicitud && esp === espSolicitud ? ok("especialidad_coincide") : falla("especialidad_coincide", `la solicitud es de ${
|
|
41451
|
+
out.push(esp && espSolicitud && esp === espSolicitud ? ok("especialidad_coincide") : falla("especialidad_coincide", `la solicitud es de ${texto4(datos.solicitud_especialidad) ?? "(sin especialidad)"} y el turno es de ${texto4(l.especialidad) ?? "(sin especialidad)"}`));
|
|
41243
41452
|
out.push(contexto.solicitudEnOtroCaso ? falla("solicitud_libre", `esa solicitud ya tiene otro recupero en curso o asignado (${contexto.solicitudEnOtroCaso})`) : ok("solicitud_libre"));
|
|
41244
41453
|
const yaNo = declinadas(caso);
|
|
41245
41454
|
const elegida = refExterna(datos.solicitud_id);
|
|
@@ -41247,9 +41456,9 @@ var recuperoTurno = {
|
|
|
41247
41456
|
const { posicion, total } = posicionEnCola(datos, [...contexto.solicitudesEnCurso ?? [], ...yaNo]);
|
|
41248
41457
|
if (!leerCola(datos.cola)) out.push(falla("orden_de_la_cola", "cola es obligatoria: la lista de espera pendiente de esa especialidad tal como se vio, [{solicitud_id, prioridad, alta}]"));
|
|
41249
41458
|
else if (posicion === null) out.push(falla("orden_de_la_cola", "la solicitud elegida no est\xE1 en la cola informada"));
|
|
41250
|
-
else if (posicion > 1 && !
|
|
41459
|
+
else if (posicion > 1 && !texto4(datos.justificacion)) out.push(falla("orden_de_la_cola", `es la ${posicion}.\xAA de ${total} en la cola: pasarla adelante de las anteriores requiere justificacion`));
|
|
41251
41460
|
else out.push(ok("orden_de_la_cola", posicion === 1 ? `primera de ${total} en la cola` : `${posicion}.\xAA de ${total} en la cola, con justificaci\xF3n`));
|
|
41252
|
-
out.push(
|
|
41461
|
+
out.push(texto4(datos.fuente) ? ok("fuente_presente") : falla("fuente_presente", "fuente (pantalla donde se vio el turno libre y la solicitud) es obligatoria"));
|
|
41253
41462
|
return out;
|
|
41254
41463
|
},
|
|
41255
41464
|
autonomia: {
|
|
@@ -41264,8 +41473,8 @@ var recuperoTurno = {
|
|
|
41264
41473
|
const fuera = fueraDePreferencia(datos.solicitud_preferencia_horaria, horaHM(l.hora));
|
|
41265
41474
|
return [
|
|
41266
41475
|
excepcion("saltea_la_cola", posicion !== null && posicion > 1, posicion !== null && posicion > 1 ? `es la ${posicion}.\xAA de ${total} en la cola` : "primera de la cola"),
|
|
41267
|
-
excepcion("profesional_distinto", Boolean(pedido && profesional && pedido !== profesional), pedido ? pedido === profesional ? "es el profesional que pidi\xF3" : `pidi\xF3 a ${
|
|
41268
|
-
excepcion("fuera_de_preferencia_horaria", fuera, fuera ? `prefiere ${
|
|
41476
|
+
excepcion("profesional_distinto", Boolean(pedido && profesional && pedido !== profesional), pedido ? pedido === profesional ? "es el profesional que pidi\xF3" : `pidi\xF3 a ${texto4(datos.solicitud_profesional)}` : "no pidi\xF3 un profesional en particular"),
|
|
41477
|
+
excepcion("fuera_de_preferencia_horaria", fuera, fuera ? `prefiere ${texto4(datos.solicitud_preferencia_horaria)} y el turno es a las ${horaHM(l.hora)}` : "dentro de su preferencia o sin preferencia"),
|
|
41269
41478
|
excepcion("turno_para_hoy", paraHoy, paraHoy ? "el turno es para hoy" : "no es para hoy"),
|
|
41270
41479
|
excepcion("sobreturno", l.sobreturno === true, l.sobreturno === true ? "es un sobreturno" : "turno de la grilla"),
|
|
41271
41480
|
excepcion("reintento_tras_diferencias", caso.estado === "con_diferencias", caso.estado === "con_diferencias" ? "la asignaci\xF3n anterior no coincidi\xF3 al comprobar" : "primer intento"),
|
|
@@ -41287,7 +41496,7 @@ var recuperoTurno = {
|
|
|
41287
41496
|
a: "rechazado",
|
|
41288
41497
|
actor: ["humano"],
|
|
41289
41498
|
descripcion: "Rechazo con motivo.",
|
|
41290
|
-
validar: (_caso, datos) => [
|
|
41499
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "el rechazo requiere motivo")]
|
|
41291
41500
|
},
|
|
41292
41501
|
{
|
|
41293
41502
|
// Paso opcional: donde el hospital quiere que el paciente acepte antes de asignarle el turno.
|
|
@@ -41298,7 +41507,7 @@ var recuperoTurno = {
|
|
|
41298
41507
|
nivelRequerido: "ejecuta",
|
|
41299
41508
|
descripcion: "Ofrecerle la cita al paciente antes de asignarla (obligatorio donde la instituci\xF3n pide consulta previa).",
|
|
41300
41509
|
validar: (caso, datos, contexto) => [
|
|
41301
|
-
|
|
41510
|
+
texto4(datos.canal) ? ok("canal_informado") : falla("canal_informado", "ofrecer requiere canal (tel\xE9fono, WhatsApp, correo)"),
|
|
41302
41511
|
validarMargen(caso, contexto)
|
|
41303
41512
|
]
|
|
41304
41513
|
},
|
|
@@ -41309,7 +41518,7 @@ var recuperoTurno = {
|
|
|
41309
41518
|
actor: ["agente", "humano"],
|
|
41310
41519
|
nivelRequerido: "observa",
|
|
41311
41520
|
descripcion: "El paciente acept\xF3 el turno ofrecido.",
|
|
41312
|
-
validar: (_caso, datos) => [
|
|
41521
|
+
validar: (_caso, datos) => [texto4(datos.respuesta) ? ok("respuesta_registrada") : falla("respuesta_registrada", "aceptar requiere la respuesta del paciente")]
|
|
41313
41522
|
},
|
|
41314
41523
|
{
|
|
41315
41524
|
via: "no_acepta",
|
|
@@ -41318,7 +41527,7 @@ var recuperoTurno = {
|
|
|
41318
41527
|
actor: ["agente", "humano"],
|
|
41319
41528
|
nivelRequerido: "observa",
|
|
41320
41529
|
descripcion: "El paciente no acept\xF3 o no respondi\xF3: el turno vuelve a buscar candidato.",
|
|
41321
|
-
validar: (_caso, datos) => [
|
|
41530
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "no_acepta requiere motivo (no contest\xF3, no puede ese d\xEDa\u2026)")]
|
|
41322
41531
|
},
|
|
41323
41532
|
{
|
|
41324
41533
|
// El plugin autoriza ANTES de que se escriba en el sistema del hospital: la cita está a tiempo
|
|
@@ -41346,7 +41555,7 @@ var recuperoTurno = {
|
|
|
41346
41555
|
cargaManual: true,
|
|
41347
41556
|
descripcion: "Registrar la cita asignada en el sistema de gesti\xF3n, con la acci\xF3n de escritura.",
|
|
41348
41557
|
validar: (caso, datos, contexto) => [
|
|
41349
|
-
|
|
41558
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "asignar requiere accion_id de la escritura registrada con ops_registrar_accion"),
|
|
41350
41559
|
contexto.actor === "agente" && caso.estado !== "asignando" ? falla("escritura_autorizada", "un agente tiene que pedir autorizar antes de escribir en el sistema") : ok("escritura_autorizada"),
|
|
41351
41560
|
...caso.estado === "asignando" ? [] : [validarPacienteAcepto(caso, contexto)]
|
|
41352
41561
|
]
|
|
@@ -41356,14 +41565,14 @@ var recuperoTurno = {
|
|
|
41356
41565
|
de: ["asignado"],
|
|
41357
41566
|
a: (caso, datos) => {
|
|
41358
41567
|
const l = caso.datos;
|
|
41359
|
-
const coincide =
|
|
41568
|
+
const coincide = texto4(datos.leido_fecha) === texto4(l.fecha) && horaHM(datos.leido_hora) === horaHM(l.hora) && normalizarNombre(datos.leido_profesional) === normalizarNombre(l.profesional) && (refExterna(datos.leido_solicitud_id) === null || refExterna(datos.leido_solicitud_id) === refExterna(l.solicitud_id));
|
|
41360
41569
|
return coincide ? "verificado" : "con_diferencias";
|
|
41361
41570
|
},
|
|
41362
41571
|
actor: ["agente", "humano", "sistema"],
|
|
41363
41572
|
nivelRequerido: "observa",
|
|
41364
41573
|
descripcion: "Releer en el sistema el turno de la solicitud y compararlo con el aprobado (fecha, hora y profesional). Si no coincide, el caso queda con diferencias.",
|
|
41365
41574
|
validar: (_caso, datos) => [
|
|
41366
|
-
fechaISO(datos.leido_fecha) && horaHM(datos.leido_hora) !== null &&
|
|
41575
|
+
fechaISO(datos.leido_fecha) && horaHM(datos.leido_hora) !== null && texto4(datos.leido_profesional) ? ok("turno_leido_presente") : falla("turno_leido_presente", "verificar requiere leido_fecha (AAAA-MM-DD), leido_hora (HH:MM) y leido_profesional, rele\xEDdos en el sistema")
|
|
41367
41576
|
]
|
|
41368
41577
|
},
|
|
41369
41578
|
{
|
|
@@ -41374,7 +41583,7 @@ var recuperoTurno = {
|
|
|
41374
41583
|
cargaManual: true,
|
|
41375
41584
|
descripcion: "Corregir a mano el turno en el sistema de gesti\xF3n (lo aprobado no cambia) y volver a comprobar.",
|
|
41376
41585
|
validar: (_caso, datos) => [
|
|
41377
|
-
|
|
41586
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "corregir requiere accion_id de la escritura registrada con la correcci\xF3n")
|
|
41378
41587
|
]
|
|
41379
41588
|
},
|
|
41380
41589
|
{
|
|
@@ -41384,7 +41593,7 @@ var recuperoTurno = {
|
|
|
41384
41593
|
actor: ["agente", "humano"],
|
|
41385
41594
|
nivelRequerido: "observa",
|
|
41386
41595
|
descripcion: "No hay solicitudes pendientes que puedan tomar el turno liberado: queda libre.",
|
|
41387
|
-
validar: (_caso, datos) => [
|
|
41596
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "sin_candidato requiere motivo (qu\xE9 se busc\xF3 y por qu\xE9 no hay a qui\xE9n darlo)")]
|
|
41388
41597
|
},
|
|
41389
41598
|
{
|
|
41390
41599
|
via: "descartar",
|
|
@@ -41393,7 +41602,7 @@ var recuperoTurno = {
|
|
|
41393
41602
|
actor: ["agente", "humano"],
|
|
41394
41603
|
nivelRequerido: "observa",
|
|
41395
41604
|
descripcion: "El turno ya no est\xE1 libre (lo ocup\xF3 otra persona, se anul\xF3 la agenda o pas\xF3 la hora): se cierra sin asignar.",
|
|
41396
|
-
validar: (_caso, datos) => [
|
|
41605
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
41397
41606
|
}
|
|
41398
41607
|
]
|
|
41399
41608
|
};
|
|
@@ -41428,13 +41637,13 @@ var BONO_FACTURADO = ["facturado", "refacturado"];
|
|
|
41428
41637
|
function leerResponsable(v) {
|
|
41429
41638
|
if (!v || typeof v !== "object") return null;
|
|
41430
41639
|
const r = v;
|
|
41431
|
-
const tipo =
|
|
41640
|
+
const tipo = texto4(r.tipo);
|
|
41432
41641
|
if (tipo !== "profesional" && tipo !== "rol") return null;
|
|
41433
|
-
const
|
|
41434
|
-
const nombre =
|
|
41435
|
-
if (tipo === "profesional" && !
|
|
41436
|
-
if (tipo === "rol" && !
|
|
41437
|
-
return { tipo, id, nombre };
|
|
41642
|
+
const id2 = refExterna(r.id);
|
|
41643
|
+
const nombre = texto4(r.nombre)?.slice(0, 120) ?? null;
|
|
41644
|
+
if (tipo === "profesional" && !id2) return null;
|
|
41645
|
+
if (tipo === "rol" && !id2) return null;
|
|
41646
|
+
return { tipo, id: id2, nombre };
|
|
41438
41647
|
}
|
|
41439
41648
|
function leerFaltantes(v) {
|
|
41440
41649
|
if (!Array.isArray(v)) return null;
|
|
@@ -41442,8 +41651,8 @@ function leerFaltantes(v) {
|
|
|
41442
41651
|
for (const e of v) {
|
|
41443
41652
|
if (!e || typeof e !== "object") return null;
|
|
41444
41653
|
const r = e;
|
|
41445
|
-
const regla =
|
|
41446
|
-
const detalle =
|
|
41654
|
+
const regla = texto4(r.regla);
|
|
41655
|
+
const detalle = texto4(r.detalle);
|
|
41447
41656
|
if (!regla || !REGLAS_CUENTA[regla] || !detalle) return null;
|
|
41448
41657
|
const responsable = leerResponsable(r.responsable);
|
|
41449
41658
|
out.push(responsable ? { regla, detalle, item: refExterna(r.item), responsable } : { regla, detalle, item: refExterna(r.item) });
|
|
@@ -41459,7 +41668,7 @@ function validarFaltantes(campo, v, alMenosUno) {
|
|
|
41459
41668
|
return ok("faltantes_validos", lista2.length === 0 ? "sin faltantes" : lista2.length === 1 ? "1 faltante" : `${lista2.length} faltantes`);
|
|
41460
41669
|
}
|
|
41461
41670
|
function estadoBono(v) {
|
|
41462
|
-
const s =
|
|
41671
|
+
const s = texto4(v);
|
|
41463
41672
|
return s ? s.toLowerCase().replace(/[\s-]+/g, "_") : null;
|
|
41464
41673
|
}
|
|
41465
41674
|
var cuentaCompleta = {
|
|
@@ -41485,10 +41694,10 @@ var cuentaCompleta = {
|
|
|
41485
41694
|
const estado = estadoBono(datos.bono_estado);
|
|
41486
41695
|
return [
|
|
41487
41696
|
refExterna(l.bono_id) ? ok("bono_presente") : falla("bono_presente", "observar requiere bono_id: el n\xFAmero de bono en el HIS"),
|
|
41488
|
-
estado && BONO_POR_FACTURAR.includes(estado) ? ok("bono_sin_facturar", estado) : falla("bono_sin_facturar", `el bono tiene que estar sin facturar (${BONO_POR_FACTURAR.join(", ")}); est\xE1: ${
|
|
41697
|
+
estado && BONO_POR_FACTURAR.includes(estado) ? ok("bono_sin_facturar", estado) : falla("bono_sin_facturar", `el bono tiene que estar sin facturar (${BONO_POR_FACTURAR.join(", ")}); est\xE1: ${texto4(datos.bono_estado) ?? "sin informar"}`),
|
|
41489
41698
|
validarFaltantes("faltantes", datos.faltantes, true),
|
|
41490
|
-
|
|
41491
|
-
|
|
41699
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "observar requiere lectura_id: la lectura de la base registrada con ops_registrar_accion"),
|
|
41700
|
+
texto4(datos.fuente) ? ok("fuente_presente") : falla("fuente_presente", "fuente (base y consulta de donde salen los faltantes) es obligatoria")
|
|
41492
41701
|
];
|
|
41493
41702
|
}
|
|
41494
41703
|
},
|
|
@@ -41500,7 +41709,7 @@ var cuentaCompleta = {
|
|
|
41500
41709
|
cargaManual: true,
|
|
41501
41710
|
descripcion: "Una persona de la instituci\xF3n complet\xF3 en el HIS lo que faltaba. El puesto lo comprueba volviendo a leer.",
|
|
41502
41711
|
validar: (_caso, datos) => [
|
|
41503
|
-
|
|
41712
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "completar requiere accion_id de la carga registrada")
|
|
41504
41713
|
]
|
|
41505
41714
|
},
|
|
41506
41715
|
{
|
|
@@ -41521,7 +41730,7 @@ var cuentaCompleta = {
|
|
|
41521
41730
|
return [
|
|
41522
41731
|
validarFaltantes("faltantes_leidos", datos.faltantes_leidos, false),
|
|
41523
41732
|
estado && [...BONO_POR_FACTURAR, ...BONO_FACTURADO].includes(estado) ? ok("estado_leido", estado) : falla("estado_leido", `bono_estado_leido tiene que ser uno de: ${[...BONO_POR_FACTURAR, ...BONO_FACTURADO].join(", ")} (si el bono se elimin\xF3 o se anul\xF3, descartar)`),
|
|
41524
|
-
|
|
41733
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "comprobar requiere lectura_id: la lectura de la base registrada con ops_registrar_accion")
|
|
41525
41734
|
];
|
|
41526
41735
|
}
|
|
41527
41736
|
},
|
|
@@ -41531,7 +41740,7 @@ var cuentaCompleta = {
|
|
|
41531
41740
|
a: "no_corresponde",
|
|
41532
41741
|
actor: ["humano"],
|
|
41533
41742
|
descripcion: "El equipo indica que lo marcado no hace falta para esta prestaci\xF3n (por ejemplo, el financiador no pide autorizaci\xF3n). Queda registrado con el motivo.",
|
|
41534
|
-
validar: (_caso, datos) => [
|
|
41743
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "no_corresponde requiere motivo")]
|
|
41535
41744
|
},
|
|
41536
41745
|
{
|
|
41537
41746
|
via: "descartar",
|
|
@@ -41540,13 +41749,13 @@ var cuentaCompleta = {
|
|
|
41540
41749
|
actor: ["agente", "humano"],
|
|
41541
41750
|
nivelRequerido: "observa",
|
|
41542
41751
|
descripcion: "El bono se elimin\xF3, se anul\xF3 o qued\xF3 como no cobrable: ya no hay nada que completar.",
|
|
41543
|
-
validar: (_caso, datos) => [
|
|
41752
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
41544
41753
|
}
|
|
41545
41754
|
]
|
|
41546
41755
|
};
|
|
41547
41756
|
var PLAZO_PRESENTACION_POR_DEFECTO = 60;
|
|
41548
|
-
function sumarDias4(
|
|
41549
|
-
const d = /* @__PURE__ */ new Date(`${
|
|
41757
|
+
function sumarDias4(fecha4, dias) {
|
|
41758
|
+
const d = /* @__PURE__ */ new Date(`${fecha4}T00:00:00Z`);
|
|
41550
41759
|
d.setUTCDate(d.getUTCDate() + dias);
|
|
41551
41760
|
return d.toISOString().slice(0, 10);
|
|
41552
41761
|
}
|
|
@@ -41577,14 +41786,14 @@ var facturacionPendiente = {
|
|
|
41577
41786
|
validar: (caso, datos, contexto) => {
|
|
41578
41787
|
const l = { ...caso.datos, ...datos };
|
|
41579
41788
|
const estado = estadoBono(datos.bono_estado);
|
|
41580
|
-
const
|
|
41789
|
+
const fecha4 = fechaISO(l.fecha_prestacion) ? String(l.fecha_prestacion) : null;
|
|
41581
41790
|
return [
|
|
41582
41791
|
refExterna(l.bono_id) ? ok("bono_presente") : falla("bono_presente", "observar requiere bono_id: el n\xFAmero de bono en el HIS"),
|
|
41583
|
-
estado && BONO_POR_FACTURAR.includes(estado) ? ok("bono_sin_facturar", estado) : falla("bono_sin_facturar", `el bono tiene que estar sin facturar (${BONO_POR_FACTURAR.join(", ")}); est\xE1: ${
|
|
41584
|
-
|
|
41585
|
-
|
|
41586
|
-
|
|
41587
|
-
|
|
41792
|
+
estado && BONO_POR_FACTURAR.includes(estado) ? ok("bono_sin_facturar", estado) : falla("bono_sin_facturar", `el bono tiene que estar sin facturar (${BONO_POR_FACTURAR.join(", ")}); est\xE1: ${texto4(datos.bono_estado) ?? "sin informar"}`),
|
|
41793
|
+
fecha4 && (!contexto.hoy || fecha4 <= contexto.hoy) ? ok("fecha_prestacion_valida", fecha4) : falla("fecha_prestacion_valida", "fecha_prestacion (AAAA-MM-DD) es obligatoria y no puede ser futura"),
|
|
41794
|
+
texto4(l.obra_social) ? ok("obra_social_presente") : falla("obra_social_presente", "obra_social es obligatoria: con ella se busca el plazo de presentaci\xF3n"),
|
|
41795
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "observar requiere lectura_id: la lectura de la base registrada con ops_registrar_accion"),
|
|
41796
|
+
texto4(datos.fuente) ? ok("fuente_presente") : falla("fuente_presente", "fuente (base y consulta de donde sale la prestaci\xF3n) es obligatoria")
|
|
41588
41797
|
];
|
|
41589
41798
|
}
|
|
41590
41799
|
},
|
|
@@ -41596,7 +41805,7 @@ var facturacionPendiente = {
|
|
|
41596
41805
|
cargaManual: true,
|
|
41597
41806
|
descripcion: "Una persona de la instituci\xF3n present\xF3 la prestaci\xF3n (la prefactur\xF3 y factur\xF3). El puesto lo comprueba volviendo a leer.",
|
|
41598
41807
|
validar: (_caso, datos) => [
|
|
41599
|
-
|
|
41808
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "presentar requiere accion_id de la carga registrada")
|
|
41600
41809
|
]
|
|
41601
41810
|
},
|
|
41602
41811
|
{
|
|
@@ -41615,7 +41824,7 @@ var facturacionPendiente = {
|
|
|
41615
41824
|
const estado = estadoBono(datos.bono_estado_leido);
|
|
41616
41825
|
return [
|
|
41617
41826
|
estado && [...BONO_POR_FACTURAR, ...BONO_FACTURADO].includes(estado) ? ok("estado_leido", estado) : falla("estado_leido", `bono_estado_leido tiene que ser uno de: ${[...BONO_POR_FACTURAR, ...BONO_FACTURADO].join(", ")} (si el bono se elimin\xF3 o se anul\xF3, descartar)`),
|
|
41618
|
-
|
|
41827
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "comprobar requiere lectura_id: la lectura de la base registrada con ops_registrar_accion")
|
|
41619
41828
|
];
|
|
41620
41829
|
}
|
|
41621
41830
|
},
|
|
@@ -41625,7 +41834,7 @@ var facturacionPendiente = {
|
|
|
41625
41834
|
a: "no_corresponde",
|
|
41626
41835
|
actor: ["humano"],
|
|
41627
41836
|
descripcion: "El equipo indica que esta prestaci\xF3n no se presenta al financiador (por ejemplo, la pag\xF3 el paciente o no es facturable). Queda registrado con el motivo.",
|
|
41628
|
-
validar: (_caso, datos) => [
|
|
41837
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "no_corresponde requiere motivo")]
|
|
41629
41838
|
},
|
|
41630
41839
|
{
|
|
41631
41840
|
via: "descartar",
|
|
@@ -41634,7 +41843,7 @@ var facturacionPendiente = {
|
|
|
41634
41843
|
actor: ["agente", "humano"],
|
|
41635
41844
|
nivelRequerido: "observa",
|
|
41636
41845
|
descripcion: "El bono se elimin\xF3, se anul\xF3 o qued\xF3 como no cobrable: ya no hay nada que presentar.",
|
|
41637
|
-
validar: (_caso, datos) => [
|
|
41846
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
41638
41847
|
}
|
|
41639
41848
|
]
|
|
41640
41849
|
};
|
|
@@ -41652,9 +41861,9 @@ function leerResultadoRegistro(v) {
|
|
|
41652
41861
|
coincide_nombre: typeof r.coincide_nombre === "boolean" ? r.coincide_nombre : null,
|
|
41653
41862
|
situacion,
|
|
41654
41863
|
sancion: r.sancion === true,
|
|
41655
|
-
profesion:
|
|
41656
|
-
provincia:
|
|
41657
|
-
emisor:
|
|
41864
|
+
profesion: texto4(r.profesion),
|
|
41865
|
+
provincia: texto4(r.provincia),
|
|
41866
|
+
emisor: texto4(r.emisor)
|
|
41658
41867
|
};
|
|
41659
41868
|
}
|
|
41660
41869
|
function observacionDe(r) {
|
|
@@ -41689,13 +41898,13 @@ var credencialProfesional = {
|
|
|
41689
41898
|
validar: (caso, datos) => {
|
|
41690
41899
|
const l = { ...caso.datos, ...datos };
|
|
41691
41900
|
const r = leerResultadoRegistro(datos.resultado);
|
|
41692
|
-
const tipo =
|
|
41901
|
+
const tipo = texto4(datos.tipo_matricula);
|
|
41693
41902
|
return [
|
|
41694
41903
|
refExterna(l.profesional_id) ? ok("profesional_presente") : falla("profesional_presente", "verificar requiere profesional_id: el id del profesional en el HIS"),
|
|
41695
41904
|
r ? ok("resultado_valido", r.sin_matricula ? "sin matr\xEDcula cargada" : r.encontrada ? `encontrada \xB7 ${r.situacion}` : "no encontrada") : falla("resultado_valido", "resultado tiene que ser el objeto que devuelve verificar-matriculas.mjs: {sin_matricula, encontrada, coincide_nombre, situacion, sancion, profesion, provincia, emisor}"),
|
|
41696
41905
|
r && !r.sin_matricula && !(refExterna(datos.matricula) && tipo && TIPOS_MATRICULA.includes(tipo)) ? falla("matricula_consultada", `con matr\xEDcula cargada hacen falta matricula y tipo_matricula (${TIPOS_MATRICULA.join(" o ")})`) : ok("matricula_consultada"),
|
|
41697
|
-
|
|
41698
|
-
|
|
41906
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "verificar requiere lectura_id: la consulta al registro registrada con ops_registrar_accion"),
|
|
41907
|
+
texto4(datos.fuente) ? ok("fuente_presente") : falla("fuente_presente", "fuente (registro consultado y fecha) es obligatoria")
|
|
41699
41908
|
];
|
|
41700
41909
|
}
|
|
41701
41910
|
},
|
|
@@ -41707,7 +41916,7 @@ var credencialProfesional = {
|
|
|
41707
41916
|
cargaManual: true,
|
|
41708
41917
|
descripcion: "Una persona de la instituci\xF3n corrigi\xF3 la ficha del profesional en el HIS. El puesto vuelve a verificar.",
|
|
41709
41918
|
validar: (_caso, datos) => [
|
|
41710
|
-
|
|
41919
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "corregir requiere accion_id de la carga registrada")
|
|
41711
41920
|
]
|
|
41712
41921
|
},
|
|
41713
41922
|
{
|
|
@@ -41716,7 +41925,7 @@ var credencialProfesional = {
|
|
|
41716
41925
|
a: "no_corresponde",
|
|
41717
41926
|
actor: ["humano"],
|
|
41718
41927
|
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.",
|
|
41719
|
-
validar: (_caso, datos) => [
|
|
41928
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "no_corresponde requiere motivo")]
|
|
41720
41929
|
},
|
|
41721
41930
|
{
|
|
41722
41931
|
via: "descartar",
|
|
@@ -41725,7 +41934,7 @@ var credencialProfesional = {
|
|
|
41725
41934
|
actor: ["agente", "humano"],
|
|
41726
41935
|
nivelRequerido: "observa",
|
|
41727
41936
|
descripcion: "El profesional ya no est\xE1 activo en el sistema o no tiene agenda: no hay nada que verificar.",
|
|
41728
|
-
validar: (_caso, datos) => [
|
|
41937
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
41729
41938
|
}
|
|
41730
41939
|
]
|
|
41731
41940
|
};
|
|
@@ -41747,7 +41956,7 @@ function horaDentro(hora, desde, hasta) {
|
|
|
41747
41956
|
return h >= d && h <= t5;
|
|
41748
41957
|
}
|
|
41749
41958
|
function codigoContacto(v) {
|
|
41750
|
-
const s =
|
|
41959
|
+
const s = texto4(v);
|
|
41751
41960
|
return s ? s.toLowerCase().replace(/\s+/g, "_") : null;
|
|
41752
41961
|
}
|
|
41753
41962
|
function respuestaContacto(v) {
|
|
@@ -41761,7 +41970,7 @@ function canalContacto(v) {
|
|
|
41761
41970
|
var demandaPendiente = {
|
|
41762
41971
|
clave: "demanda_pendiente",
|
|
41763
41972
|
nombre: "Demanda pendiente",
|
|
41764
|
-
puesto: "
|
|
41973
|
+
puesto: "Operaciones",
|
|
41765
41974
|
descripcion: "Mueve la demanda que el hospital ya gener\xF3 y no se ejecut\xF3: \xF3rdenes de estudio sin turno, solicitudes de turno pendientes y controles peri\xF3dicos vencidos. Las reglas las arma el hospital en el portal; el plugin las aplica en cada contacto; el caso se cierra cuando el turno queda agendado.",
|
|
41766
41975
|
inicial: "detectado",
|
|
41767
41976
|
estados: [
|
|
@@ -41805,7 +42014,7 @@ var demandaPendiente = {
|
|
|
41805
42014
|
out.push(horaDentro(contexto.horaActual, regla.contacto.hora_desde, regla.contacto.hora_hasta) ? ok("horario_permitido") : falla("horario_permitido", `son las ${contexto.horaActual ?? "?"} y la regla contacta de ${regla.contacto.hora_desde} a ${regla.contacto.hora_hasta}`));
|
|
41806
42015
|
}
|
|
41807
42016
|
}
|
|
41808
|
-
out.push(
|
|
42017
|
+
out.push(texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "contactar requiere accion_id: la escritura (mensaje enviado o llamada hecha) registrada antes"));
|
|
41809
42018
|
return out;
|
|
41810
42019
|
}
|
|
41811
42020
|
},
|
|
@@ -41831,7 +42040,7 @@ var demandaPendiente = {
|
|
|
41831
42040
|
nivelRequerido: "observa",
|
|
41832
42041
|
descripcion: "Releer el HIS y encontrar el turno de esa orden, solicitud o control: con el turno, el caso se cierra como movido.",
|
|
41833
42042
|
validar: (_caso, datos) => [
|
|
41834
|
-
|
|
42043
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "comprobar requiere lectura_id: la relectura del HIS registrada antes"),
|
|
41835
42044
|
refExterna(datos.turno_id) ? ok("turno_presente") : falla("turno_presente", "comprobar requiere turno_id: el turno encontrado en el HIS; sin turno no hay nada que comprobar")
|
|
41836
42045
|
]
|
|
41837
42046
|
},
|
|
@@ -41843,7 +42052,7 @@ var demandaPendiente = {
|
|
|
41843
42052
|
nivelRequerido: "observa",
|
|
41844
42053
|
descripcion: "Cerrar sin turno: solo cuando se agotaron los intentos o venci\xF3 el plazo de la regla.",
|
|
41845
42054
|
validar: (_caso, datos, contexto) => {
|
|
41846
|
-
const out = [
|
|
42055
|
+
const out = [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "cerrar requiere motivo")];
|
|
41847
42056
|
const regla = contexto.regla ?? null;
|
|
41848
42057
|
if (regla) {
|
|
41849
42058
|
const hechos = contexto.intentosContacto ?? 0;
|
|
@@ -41862,7 +42071,7 @@ var demandaPendiente = {
|
|
|
41862
42071
|
actor: ["agente", "humano"],
|
|
41863
42072
|
nivelRequerido: "observa",
|
|
41864
42073
|
descripcion: "Descartar con motivo: el dato era err\xF3neo, el paciente ya lo hizo afuera, falleci\xF3 o pidi\xF3 no ser contactado.",
|
|
41865
|
-
validar: (_caso, datos) => [
|
|
42074
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
41866
42075
|
},
|
|
41867
42076
|
{
|
|
41868
42077
|
via: "no_corresponde",
|
|
@@ -41870,7 +42079,7 @@ var demandaPendiente = {
|
|
|
41870
42079
|
a: "no_corresponde",
|
|
41871
42080
|
actor: ["humano"],
|
|
41872
42081
|
descripcion: "Una persona de la instituci\xF3n decide que este caso no corresponde a la regla.",
|
|
41873
|
-
validar: (_caso, datos) => [
|
|
42082
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "no_corresponde requiere motivo")]
|
|
41874
42083
|
}
|
|
41875
42084
|
]
|
|
41876
42085
|
};
|
|
@@ -41902,16 +42111,16 @@ var circularAranceles = {
|
|
|
41902
42111
|
extraccionA: datos.extraccion_a,
|
|
41903
42112
|
extraccionB: datos.extraccion_b,
|
|
41904
42113
|
actual: datos.actual,
|
|
41905
|
-
filasDeclaradas:
|
|
41906
|
-
porcentajeDeclarado:
|
|
42114
|
+
filasDeclaradas: num3(l.filas_declaradas),
|
|
42115
|
+
porcentajeDeclarado: num3(l.porcentaje_declarado),
|
|
41907
42116
|
vigenciaDesde: l.vigencia_desde,
|
|
41908
42117
|
hoy: contexto.hoy ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
41909
42118
|
topeVariacion: contexto.topeVariacion ?? null
|
|
41910
42119
|
});
|
|
41911
42120
|
return [
|
|
41912
|
-
|
|
41913
|
-
|
|
41914
|
-
|
|
42121
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "extraer requiere lectura_id: la lectura del convenio en el HIS registrada con ops_registrar_accion"),
|
|
42122
|
+
texto4(datos.lectura_circular_id) ? ok("lectura_circular_registrada") : falla("lectura_circular_registrada", "extraer requiere lectura_circular_id: la lectura de la circular (conector archivo) registrada con ops_registrar_accion"),
|
|
42123
|
+
texto4(datos.fuente) ? ok("fuente_presente") : falla("fuente_presente", "fuente (la circular: nombre del archivo y de d\xF3nde vino) es obligatoria"),
|
|
41915
42124
|
cruce.ok ? ok("cruce_circular", `${cruce.resumen.propuestas} propuestas, ${cruce.resumen.excepciones} excepciones, ${cruce.resumen.revisar} a revisar, ${cruce.resumen.sin_convenio} sin convenio`) : falla("cruce_circular", cruce.errores.join(" \xB7 "))
|
|
41916
42125
|
];
|
|
41917
42126
|
}
|
|
@@ -41931,7 +42140,7 @@ var circularAranceles = {
|
|
|
41931
42140
|
aSinExcepcion: "aprobada",
|
|
41932
42141
|
excepciones: (caso, _datos, contexto) => {
|
|
41933
42142
|
const r = resumenDe(caso);
|
|
41934
|
-
const vigencia =
|
|
42143
|
+
const vigencia = texto4(caso.datos.vigencia_desde);
|
|
41935
42144
|
return [
|
|
41936
42145
|
excepcion("practicas_con_excepcion", (r?.excepciones ?? 0) > 0, `${r?.excepciones ?? 0} pr\xE1cticas con baja, suba sobre el tope o desv\xEDo`),
|
|
41937
42146
|
excepcion("lecturas_que_no_coinciden", (r?.revisar ?? 0) > 0, `${r?.revisar ?? 0} pr\xE1cticas a revisar`),
|
|
@@ -41967,7 +42176,7 @@ var circularAranceles = {
|
|
|
41967
42176
|
a: "rechazada",
|
|
41968
42177
|
actor: ["humano"],
|
|
41969
42178
|
descripcion: "Rechazo con motivo.",
|
|
41970
|
-
validar: (_caso, datos) => [
|
|
42179
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "el rechazo requiere motivo")]
|
|
41971
42180
|
},
|
|
41972
42181
|
{
|
|
41973
42182
|
via: "aplicar",
|
|
@@ -41978,10 +42187,10 @@ var circularAranceles = {
|
|
|
41978
42187
|
cargaManual: true,
|
|
41979
42188
|
descripcion: "Cargar en el HIS el archivo que gener\xF3 el plugin (Actualizaci\xF3n con archivo) y registrarlo, con el hash del archivo cargado.",
|
|
41980
42189
|
validar: (caso, datos) => {
|
|
41981
|
-
const esperado =
|
|
41982
|
-
const informado =
|
|
42190
|
+
const esperado = texto4(caso.datos.archivo_csv?.hash);
|
|
42191
|
+
const informado = texto4(datos.archivo_hash);
|
|
41983
42192
|
return [
|
|
41984
|
-
|
|
42193
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "aplicar requiere accion_id de la carga registrada"),
|
|
41985
42194
|
esperado && informado === esperado ? ok("archivo_aprobado") : falla("archivo_aprobado", esperado ? "el archivo cargado no es el que gener\xF3 el plugin para esta aprobaci\xF3n (archivo_hash distinto): descargarlo de nuevo y cargar ese" : "la circular no tiene archivo generado")
|
|
41986
42195
|
];
|
|
41987
42196
|
}
|
|
@@ -41999,7 +42208,7 @@ var circularAranceles = {
|
|
|
41999
42208
|
validar: (_caso, datos) => {
|
|
42000
42209
|
const r = compararRelectura([], datos.leidos);
|
|
42001
42210
|
return [
|
|
42002
|
-
|
|
42211
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "verificar requiere lectura_id: la relectura del convenio registrada"),
|
|
42003
42212
|
"error" in r ? falla("leidos_validos", r.error) : ok("leidos_validos")
|
|
42004
42213
|
];
|
|
42005
42214
|
}
|
|
@@ -42011,7 +42220,7 @@ var circularAranceles = {
|
|
|
42011
42220
|
actor: ["humano"],
|
|
42012
42221
|
cargaManual: true,
|
|
42013
42222
|
descripcion: "Corregir en el HIS las pr\xE1cticas que no coincidieron y volver a comprobar.",
|
|
42014
|
-
validar: (_caso, datos) => [
|
|
42223
|
+
validar: (_caso, datos) => [texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "corregir requiere accion_id de la correcci\xF3n registrada")]
|
|
42015
42224
|
},
|
|
42016
42225
|
{
|
|
42017
42226
|
via: "cancelar",
|
|
@@ -42020,7 +42229,7 @@ var circularAranceles = {
|
|
|
42020
42229
|
actor: ["humano", "agente"],
|
|
42021
42230
|
nivelRequerido: "observa",
|
|
42022
42231
|
descripcion: "Cancelar la circular (repetida, de otra regi\xF3n, ilegible).",
|
|
42023
|
-
validar: (_caso, datos) => [
|
|
42232
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "la cancelaci\xF3n requiere motivo")]
|
|
42024
42233
|
}
|
|
42025
42234
|
]
|
|
42026
42235
|
};
|
|
@@ -42032,7 +42241,7 @@ function resumenCobranzaDe(caso) {
|
|
|
42032
42241
|
function evaluarPropuestaCobranza(caso, datos, contexto) {
|
|
42033
42242
|
const l = leerFacturas(datos.facturas);
|
|
42034
42243
|
if ("error" in l) return l;
|
|
42035
|
-
return evaluarFacturas({ facturas: l.facturas, obraSocial:
|
|
42244
|
+
return evaluarFacturas({ facturas: l.facturas, obraSocial: texto4(caso.datos.obra_social) ?? "", plazos: contexto.plazosPago ?? {}, hoy: contexto.hoy ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), enOtroReclamo: contexto.facturasEnOtroReclamo ?? [] });
|
|
42036
42245
|
}
|
|
42037
42246
|
var cobranzaFinanciador = {
|
|
42038
42247
|
clave: "cobranza_financiador",
|
|
@@ -42055,7 +42264,7 @@ var cobranzaFinanciador = {
|
|
|
42055
42264
|
validar: (caso, datos, contexto) => {
|
|
42056
42265
|
const r = evaluarPropuestaCobranza(caso, datos, contexto);
|
|
42057
42266
|
return [
|
|
42058
|
-
|
|
42267
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "proponer requiere lectura_id: la lectura de las facturas registrada con ops_registrar_accion"),
|
|
42059
42268
|
"error" in r ? falla("facturas_validas", r.error) : ok("facturas_validas", `${r.items.length} facturas le\xEDdas`),
|
|
42060
42269
|
"error" in r ? falla("hay_que_reclamar", "sin facturas v\xE1lidas") : r.resumen.facturas_reclamadas > 0 ? ok("hay_que_reclamar", `${r.resumen.facturas_reclamadas} vencidas`) : falla("hay_que_reclamar", "no hay facturas vencidas con saldo para reclamar: descartar el caso")
|
|
42061
42270
|
];
|
|
@@ -42082,7 +42291,7 @@ var cobranzaFinanciador = {
|
|
|
42082
42291
|
a: "rechazado",
|
|
42083
42292
|
actor: ["humano"],
|
|
42084
42293
|
descripcion: "Rechazo con motivo (no se reclama).",
|
|
42085
|
-
validar: (_caso, datos) => [
|
|
42294
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "el rechazo requiere motivo")]
|
|
42086
42295
|
},
|
|
42087
42296
|
{
|
|
42088
42297
|
via: "enviar",
|
|
@@ -42097,7 +42306,7 @@ var cobranzaFinanciador = {
|
|
|
42097
42306
|
const espera = contexto.diasEntreReclamos ?? DIAS_ENTRE_RECLAMOS_POR_DEFECTO;
|
|
42098
42307
|
const desde = contexto.ultimoReclamo && contexto.hoy ? diasEntre2(contexto.ultimoReclamo, contexto.hoy) : null;
|
|
42099
42308
|
return [
|
|
42100
|
-
|
|
42309
|
+
texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "enviar requiere accion_id del env\xEDo registrado"),
|
|
42101
42310
|
hechos < max ? ok("reclamos_disponibles", `reclamo ${hechos + 1} de ${max}`) : falla("reclamos_disponibles", `ya se hicieron los ${max} reclamos: el caso va a la direcci\xF3n`),
|
|
42102
42311
|
caso.estado === "aprobado" || desde === null || desde >= espera ? ok("espera_cumplida") : falla("espera_cumplida", `el \xFAltimo reclamo fue hace ${desde} d\xEDas; el pr\xF3ximo va a partir de los ${espera}`)
|
|
42103
42312
|
];
|
|
@@ -42110,13 +42319,13 @@ var cobranzaFinanciador = {
|
|
|
42110
42319
|
actor: ["humano"],
|
|
42111
42320
|
descripcion: "Registrar la respuesta del financiador: paga en una fecha, observa facturas o no responde.",
|
|
42112
42321
|
validar: (_caso, datos, contexto) => {
|
|
42113
|
-
const r =
|
|
42322
|
+
const r = texto4(datos.respuesta);
|
|
42114
42323
|
const out = [RESPUESTAS_FINANCIADOR.includes(r ?? "") ? ok("respuesta_valida") : falla("respuesta_valida", `respuesta tiene que ser: ${RESPUESTAS_FINANCIADOR.join(", ")}`)];
|
|
42115
42324
|
if (r === "paga") {
|
|
42116
|
-
const f =
|
|
42325
|
+
const f = texto4(datos.fecha_compromiso);
|
|
42117
42326
|
out.push(f && fechaISO(f) && (!contexto.hoy || f >= sumarDias3(contexto.hoy, -1)) ? ok("fecha_compromiso") : falla("fecha_compromiso", "si paga, hace falta la fecha de pago (AAAA-MM-DD, desde hoy)"));
|
|
42118
42327
|
}
|
|
42119
|
-
if (r === "observa") out.push(
|
|
42328
|
+
if (r === "observa") out.push(texto4(datos.detalle) ? ok("detalle_presente") : falla("detalle_presente", "si observa facturas, anot\xE1 cu\xE1les y por qu\xE9"));
|
|
42120
42329
|
return out;
|
|
42121
42330
|
}
|
|
42122
42331
|
},
|
|
@@ -42135,7 +42344,7 @@ var cobranzaFinanciador = {
|
|
|
42135
42344
|
validar: (_caso, datos) => {
|
|
42136
42345
|
const r = leerSaldos(datos.leidos);
|
|
42137
42346
|
return [
|
|
42138
|
-
|
|
42347
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "comprobar requiere lectura_id: la relectura de las facturas registrada"),
|
|
42139
42348
|
"error" in r ? falla("leidos_validos", r.error) : ok("leidos_validos", `${r.saldos.size} facturas`)
|
|
42140
42349
|
];
|
|
42141
42350
|
}
|
|
@@ -42148,7 +42357,7 @@ var cobranzaFinanciador = {
|
|
|
42148
42357
|
nivelRequerido: "observa",
|
|
42149
42358
|
descripcion: "La fecha de pago comprometida pas\xF3 (m\xE1s 7 d\xEDas de gracia) y no entr\xF3 el cobro: se vuelve a reclamar.",
|
|
42150
42359
|
validar: (caso, _datos, contexto) => {
|
|
42151
|
-
const f =
|
|
42360
|
+
const f = texto4(caso.datos.fecha_compromiso);
|
|
42152
42361
|
return [f && contexto.hoy && sumarDias3(f, GRACIA_COMPROMISO) < contexto.hoy ? ok("compromiso_vencido") : falla("compromiso_vencido", f ? `el financiador comprometi\xF3 pagar el ${f}; se espera hasta ${sumarDias3(f, GRACIA_COMPROMISO)}` : "no hay fecha comprometida")];
|
|
42153
42362
|
}
|
|
42154
42363
|
},
|
|
@@ -42173,7 +42382,7 @@ var cobranzaFinanciador = {
|
|
|
42173
42382
|
a: "cerrado",
|
|
42174
42383
|
actor: ["humano"],
|
|
42175
42384
|
descripcion: "La direcci\xF3n cierra el caso (gesti\xF3n legal, acuerdo, incobrable).",
|
|
42176
|
-
validar: (_caso, datos) => [
|
|
42385
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "cerrar requiere motivo")]
|
|
42177
42386
|
},
|
|
42178
42387
|
{
|
|
42179
42388
|
via: "descartar",
|
|
@@ -42182,7 +42391,7 @@ var cobranzaFinanciador = {
|
|
|
42182
42391
|
actor: ["agente", "humano"],
|
|
42183
42392
|
nivelRequerido: "observa",
|
|
42184
42393
|
descripcion: "No queda nada vencido para reclamar.",
|
|
42185
|
-
validar: (_caso, datos) => [
|
|
42394
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
42186
42395
|
}
|
|
42187
42396
|
]
|
|
42188
42397
|
};
|
|
@@ -42195,11 +42404,11 @@ function numeros(v) {
|
|
|
42195
42404
|
}
|
|
42196
42405
|
function validarLecturaInternacion(caso, datos, contexto) {
|
|
42197
42406
|
const r = contexto.internacion;
|
|
42198
|
-
const propia =
|
|
42407
|
+
const propia = texto4(caso.datos.internacion_id);
|
|
42199
42408
|
return [
|
|
42200
42409
|
!r ? falla("lectura_valida", "falta lectura: la internaci\xF3n tal como la devuelve revisar-internaciones.mjs") : "error" in r ? falla("lectura_valida", r.error) : ok("lectura_valida", `${r.evaluacion.pendientes.length} pendientes, ${r.evaluacion.dias_sin_evolucion.length} d\xEDas sin evoluci\xF3n`),
|
|
42201
42410
|
r && !("error" in r) && propia && r.internacionId !== propia ? falla("misma_internacion", `la lectura es de la internaci\xF3n ${r.internacionId} y el caso es de la ${propia}`) : ok("misma_internacion"),
|
|
42202
|
-
|
|
42411
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "hace falta lectura_id: la lectura de la base registrada con ops_registrar_accion")
|
|
42203
42412
|
];
|
|
42204
42413
|
}
|
|
42205
42414
|
var destinoInternacion = (_caso, _datos, contexto) => {
|
|
@@ -42224,7 +42433,7 @@ var internacionAlDia = {
|
|
|
42224
42433
|
actor: ["agente", "humano", "sistema"],
|
|
42225
42434
|
nivelRequerido: "observa",
|
|
42226
42435
|
descripcion: "Primera lectura de la internaci\xF3n. El plugin decide los pendientes de hoy, los d\xEDas sin evoluci\xF3n y el estado.",
|
|
42227
|
-
validar: (caso, datos, contexto) => [...validarLecturaInternacion(caso, datos, contexto),
|
|
42436
|
+
validar: (caso, datos, contexto) => [...validarLecturaInternacion(caso, datos, contexto), texto4(datos.fuente) ? ok("fuente_presente") : falla("fuente_presente", "fuente (base y consulta de donde sale la lectura) es obligatoria")]
|
|
42228
42437
|
},
|
|
42229
42438
|
{
|
|
42230
42439
|
via: "comprobar",
|
|
@@ -42242,7 +42451,7 @@ var internacionAlDia = {
|
|
|
42242
42451
|
actor: ["humano"],
|
|
42243
42452
|
cargaManual: true,
|
|
42244
42453
|
descripcion: "Una persona de la instituci\xF3n indica que lo resolvi\xF3 en el HIS. El puesto lo comprueba volviendo a leer.",
|
|
42245
|
-
validar: (_caso, datos) => [
|
|
42454
|
+
validar: (_caso, datos) => [texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "completar requiere accion_id de la carga registrada")]
|
|
42246
42455
|
},
|
|
42247
42456
|
{
|
|
42248
42457
|
via: "descartar",
|
|
@@ -42251,11 +42460,259 @@ var internacionAlDia = {
|
|
|
42251
42460
|
actor: ["agente", "humano"],
|
|
42252
42461
|
nivelRequerido: "observa",
|
|
42253
42462
|
descripcion: "La internaci\xF3n se anul\xF3 o se borr\xF3 en el HIS.",
|
|
42254
|
-
validar: (_caso, datos) => [
|
|
42463
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
42464
|
+
}
|
|
42465
|
+
]
|
|
42466
|
+
};
|
|
42467
|
+
function leerItemsDebito(v) {
|
|
42468
|
+
return Array.isArray(v) ? v.filter((x) => x && typeof x === "object" && typeof x.item_id === "string") : [];
|
|
42469
|
+
}
|
|
42470
|
+
function faltaTrasladar(items, leidos) {
|
|
42471
|
+
const l = leerDebitos(leidos);
|
|
42472
|
+
if ("error" in l) return { faltan: [], error: l.error };
|
|
42473
|
+
const cargado = new Map(l.debitos.map((d) => [d.item_id, d.ya_trasladado]));
|
|
42474
|
+
const faltan = items.filter((i) => i.estado === "a_trasladar").filter((i) => (cargado.get(i.item_id) ?? 0) + 5e-3 < i.ya_trasladado + i.a_descontar).map((i) => i.item_id);
|
|
42475
|
+
return { faltan };
|
|
42476
|
+
}
|
|
42477
|
+
var honorarioEnCero = {
|
|
42478
|
+
clave: "honorario_en_cero",
|
|
42479
|
+
nombre: "Honorarios que se liquidar\xEDan en $0",
|
|
42480
|
+
puesto: "Control de honorarios",
|
|
42481
|
+
descripcion: "Lee en el HIS las prestaciones de cada profesional que todav\xEDa no se liquidaron y marca las que el HIS liquidar\xEDa en $0 porque no tienen regla de honorario (o la regla no tiene valores). El equipo carga la regla y el puesto lo comprueba volviendo a leer. El puesto no escribe en el sistema.",
|
|
42482
|
+
inicial: "detectado",
|
|
42483
|
+
estados: ["detectado", "para_cargar", "completado", "resuelto", "no_corresponde", "descartado"],
|
|
42484
|
+
finalesOk: ["resuelto"],
|
|
42485
|
+
finalesNoOk: ["no_corresponde", "descartado"],
|
|
42486
|
+
minutosAbsorbidos: 15,
|
|
42487
|
+
transiciones: [
|
|
42488
|
+
{
|
|
42489
|
+
via: "observar",
|
|
42490
|
+
de: ["detectado"],
|
|
42491
|
+
a: "para_cargar",
|
|
42492
|
+
actor: ["agente", "humano"],
|
|
42493
|
+
nivelRequerido: "observa",
|
|
42494
|
+
descripcion: "Informar las prestaciones del profesional como las lee el HIS, con su regla. El plugin calcula el honorario como el HIS y decide cu\xE1les quedan en $0.",
|
|
42495
|
+
validar: (_caso, datos) => {
|
|
42496
|
+
const l = leerPrestaciones(datos.prestaciones);
|
|
42497
|
+
const r = "error" in l ? null : prestacionesEnCero(l.prestaciones);
|
|
42498
|
+
return [
|
|
42499
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "observar requiere lectura_id: la lectura de la base registrada con ops_registrar_accion"),
|
|
42500
|
+
"error" in l ? falla("prestaciones_validas", l.error) : ok("prestaciones_validas", `${l.prestaciones.length} prestaciones le\xEDdas`),
|
|
42501
|
+
!r ? falla("hay_en_cero", "sin prestaciones v\xE1lidas") : r.resumen.prestaciones > 0 ? ok("hay_en_cero", `${r.resumen.prestaciones} en $0`) : falla("hay_en_cero", "no hay prestaciones que se liquiden en $0: descartar el caso")
|
|
42502
|
+
];
|
|
42503
|
+
}
|
|
42504
|
+
},
|
|
42505
|
+
{
|
|
42506
|
+
via: "completar",
|
|
42507
|
+
de: ["para_cargar"],
|
|
42508
|
+
a: "completado",
|
|
42509
|
+
actor: ["humano"],
|
|
42510
|
+
cargaManual: true,
|
|
42511
|
+
descripcion: "Una persona de la instituci\xF3n carg\xF3 en el HIS las reglas que faltaban. El puesto lo comprueba volviendo a leer.",
|
|
42512
|
+
validar: (_caso, datos) => [texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "completar requiere accion_id de la carga registrada")]
|
|
42513
|
+
},
|
|
42514
|
+
{
|
|
42515
|
+
via: "comprobar",
|
|
42516
|
+
de: ["para_cargar", "completado"],
|
|
42517
|
+
a: (caso, datos) => {
|
|
42518
|
+
const l = leerPrestaciones(datos.prestaciones);
|
|
42519
|
+
if ("error" in l) return caso.estado;
|
|
42520
|
+
return prestacionesEnCero(l.prestaciones).resumen.prestaciones === 0 ? "resuelto" : "para_cargar";
|
|
42521
|
+
},
|
|
42522
|
+
actor: ["agente", "humano", "sistema"],
|
|
42523
|
+
nivelRequerido: "observa",
|
|
42524
|
+
descripcion: "Volver a leer las prestaciones del profesional. El plugin decide: resuelto (ninguna en $0) o sigue para cargar.",
|
|
42525
|
+
validar: (_caso, datos) => {
|
|
42526
|
+
const l = leerPrestaciones(datos.prestaciones);
|
|
42527
|
+
return [
|
|
42528
|
+
"error" in l ? falla("prestaciones_validas", l.error) : ok("prestaciones_validas", `${l.prestaciones.length} prestaciones le\xEDdas`),
|
|
42529
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "comprobar requiere lectura_id")
|
|
42530
|
+
];
|
|
42531
|
+
}
|
|
42532
|
+
},
|
|
42533
|
+
{
|
|
42534
|
+
via: "no_corresponde",
|
|
42535
|
+
de: ["para_cargar", "completado"],
|
|
42536
|
+
a: "no_corresponde",
|
|
42537
|
+
actor: ["humano"],
|
|
42538
|
+
descripcion: "El equipo indica que esas prestaciones no se le liquidan a este profesional (por ejemplo, es personal de la instituci\xF3n). Queda con el motivo.",
|
|
42539
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "no_corresponde requiere motivo")]
|
|
42540
|
+
},
|
|
42541
|
+
{
|
|
42542
|
+
via: "descartar",
|
|
42543
|
+
de: ["detectado", "para_cargar", "completado"],
|
|
42544
|
+
a: "descartado",
|
|
42545
|
+
actor: ["agente", "humano"],
|
|
42546
|
+
nivelRequerido: "observa",
|
|
42547
|
+
descripcion: "No quedan prestaciones en $0 para este profesional.",
|
|
42548
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
42549
|
+
}
|
|
42550
|
+
]
|
|
42551
|
+
};
|
|
42552
|
+
function evaluarPropuestaDebito(datos) {
|
|
42553
|
+
const l = leerDebitos(datos.items);
|
|
42554
|
+
if ("error" in l) return l;
|
|
42555
|
+
const items = l.debitos.map(evaluarDebito);
|
|
42556
|
+
return { items, resumen: resumenDebitos(items) };
|
|
42557
|
+
}
|
|
42558
|
+
var debitoProfesional = {
|
|
42559
|
+
clave: "debito_profesional",
|
|
42560
|
+
nombre: "D\xE9bitos al profesional",
|
|
42561
|
+
puesto: "Control de honorarios",
|
|
42562
|
+
descripcion: "Cruza las notas de cr\xE9dito de las obras sociales con las prestaciones ya liquidadas a cada profesional y propone descontarle la parte de su honorario que la obra social debit\xF3. La direcci\xF3n aprueba, el equipo carga el d\xE9bito en el HIS y el puesto lo comprueba.",
|
|
42563
|
+
inicial: "detectado",
|
|
42564
|
+
estados: ["detectado", "pendiente_aprobacion", "aprobado", "aplicado", "verificado", "con_diferencias", "rechazado", "descartado"],
|
|
42565
|
+
finalesOk: ["verificado"],
|
|
42566
|
+
finalesNoOk: ["rechazado", "descartado"],
|
|
42567
|
+
minutosAbsorbidos: 20,
|
|
42568
|
+
transiciones: [
|
|
42569
|
+
{
|
|
42570
|
+
via: "proponer",
|
|
42571
|
+
de: ["detectado"],
|
|
42572
|
+
a: "pendiente_aprobacion",
|
|
42573
|
+
actor: ["agente", "humano"],
|
|
42574
|
+
nivelRequerido: "propone",
|
|
42575
|
+
descripcion: "Informar las prestaciones de la nota de cr\xE9dito como las lee el HIS (monto debitado, regla, si ya se liquid\xF3 y lo ya descontado). El plugin calcula cu\xE1nto se le descuenta al profesional.",
|
|
42576
|
+
validar: (_caso, datos) => {
|
|
42577
|
+
const r = evaluarPropuestaDebito(datos);
|
|
42578
|
+
return [
|
|
42579
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "proponer requiere lectura_id: la lectura de la base registrada con ops_registrar_accion"),
|
|
42580
|
+
"error" in r ? falla("items_validos", r.error) : ok("items_validos", `${r.items.length} prestaciones le\xEDdas`),
|
|
42581
|
+
"error" in r ? falla("hay_que_trasladar", "sin prestaciones v\xE1lidas") : r.resumen.a_trasladar > 0 ? ok("hay_que_trasladar", `${r.resumen.a_trasladar} prestaciones`) : falla("hay_que_trasladar", `no hay nada para descontar todav\xEDa (${r.resumen.sin_liquidar} sin liquidar, ${r.resumen.ya_trasladados} ya descontadas): descartar el caso`)
|
|
42582
|
+
];
|
|
42583
|
+
},
|
|
42584
|
+
autonomia: {
|
|
42585
|
+
aSinExcepcion: "aprobado",
|
|
42586
|
+
excepciones: (_caso, datos, contexto) => {
|
|
42587
|
+
const r = evaluarPropuestaDebito(datos);
|
|
42588
|
+
const total = "error" in r ? 0 : r.resumen.total;
|
|
42589
|
+
const umbral = contexto.umbralAprobacion ?? 0;
|
|
42590
|
+
return [excepcion("monto_sobre_umbral", umbral > 0 && total > umbral, umbral > 0 ? `umbral ${umbral}` : "sin umbral")];
|
|
42591
|
+
}
|
|
42592
|
+
}
|
|
42593
|
+
},
|
|
42594
|
+
{ via: "aprobar", de: ["pendiente_aprobacion"], a: "aprobado", actor: ["humano"], descripcion: "La direcci\xF3n aprueba descontarle al profesional." },
|
|
42595
|
+
{
|
|
42596
|
+
via: "rechazar",
|
|
42597
|
+
de: ["pendiente_aprobacion"],
|
|
42598
|
+
a: "rechazado",
|
|
42599
|
+
actor: ["humano"],
|
|
42600
|
+
descripcion: "La direcci\xF3n decide no descont\xE1rselo (lo absorbe la instituci\xF3n).",
|
|
42601
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "rechazar requiere motivo")]
|
|
42602
|
+
},
|
|
42603
|
+
{
|
|
42604
|
+
via: "aplicar",
|
|
42605
|
+
de: ["aprobado"],
|
|
42606
|
+
a: "aplicado",
|
|
42607
|
+
actor: ["humano"],
|
|
42608
|
+
cargaManual: true,
|
|
42609
|
+
descripcion: "Una persona del equipo carg\xF3 el d\xE9bito en el HIS (Honorarios M\xE9dicos \u203A Liquidaci\xF3n \u203A D\xE9bitos y cr\xE9ditos). El puesto lo comprueba volviendo a leer.",
|
|
42610
|
+
validar: (_caso, datos) => [texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "aplicar requiere accion_id de la carga registrada")]
|
|
42611
|
+
},
|
|
42612
|
+
{
|
|
42613
|
+
via: "comprobar",
|
|
42614
|
+
de: ["aplicado"],
|
|
42615
|
+
a: (caso, datos) => faltaTrasladar(leerItemsDebito(caso.datos.items), datos.leidos).faltan.length === 0 ? "verificado" : "con_diferencias",
|
|
42616
|
+
actor: ["agente", "humano", "sistema"],
|
|
42617
|
+
nivelRequerido: "observa",
|
|
42618
|
+
descripcion: "Volver a leer los d\xE9bitos cargados al profesional por esas prestaciones (leidos). El plugin compara con lo aprobado.",
|
|
42619
|
+
validar: (caso, datos) => {
|
|
42620
|
+
const f = faltaTrasladar(leerItemsDebito(caso.datos.items), datos.leidos);
|
|
42621
|
+
return [
|
|
42622
|
+
f.error ? falla("leidos_validos", f.error) : ok("leidos_validos"),
|
|
42623
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "comprobar requiere lectura_id")
|
|
42624
|
+
];
|
|
42625
|
+
}
|
|
42626
|
+
},
|
|
42627
|
+
{
|
|
42628
|
+
via: "corregir",
|
|
42629
|
+
de: ["con_diferencias"],
|
|
42630
|
+
a: "aplicado",
|
|
42631
|
+
actor: ["humano"],
|
|
42632
|
+
cargaManual: true,
|
|
42633
|
+
descripcion: "El equipo corrigi\xF3 el d\xE9bito en el HIS. El puesto lo vuelve a comprobar.",
|
|
42634
|
+
validar: (_caso, datos) => [texto4(datos.accion_id) ? ok("accion_registrada") : falla("accion_registrada", "corregir requiere accion_id")]
|
|
42635
|
+
},
|
|
42636
|
+
{
|
|
42637
|
+
via: "descartar",
|
|
42638
|
+
de: ["detectado", "pendiente_aprobacion"],
|
|
42639
|
+
a: "descartado",
|
|
42640
|
+
actor: ["agente", "humano"],
|
|
42641
|
+
nivelRequerido: "observa",
|
|
42642
|
+
descripcion: "No hay nada para descontar (sin liquidar todav\xEDa o ya descontado).",
|
|
42643
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
42255
42644
|
}
|
|
42256
42645
|
]
|
|
42257
42646
|
};
|
|
42258
|
-
var
|
|
42647
|
+
var liquidacionProfesional = {
|
|
42648
|
+
clave: "liquidacion_profesional",
|
|
42649
|
+
nombre: "Liquidaci\xF3n al profesional",
|
|
42650
|
+
puesto: "Control de honorarios",
|
|
42651
|
+
descripcion: "Cuando el HIS liquida los honorarios, arma para cada profesional el detalle de su liquidaci\xF3n (por obra social, sin datos de pacientes) y, con la aprobaci\xF3n de la direcci\xF3n, se lo manda. El puesto marca las prestaciones liquidadas en $0.",
|
|
42652
|
+
inicial: "detectado",
|
|
42653
|
+
estados: ["detectado", "pendiente_aprobacion", "aprobado", "enviada", "rechazado", "descartado"],
|
|
42654
|
+
finalesOk: ["enviada"],
|
|
42655
|
+
finalesNoOk: ["rechazado", "descartado"],
|
|
42656
|
+
minutosAbsorbidos: 10,
|
|
42657
|
+
transiciones: [
|
|
42658
|
+
{
|
|
42659
|
+
via: "preparar",
|
|
42660
|
+
de: ["detectado"],
|
|
42661
|
+
a: "pendiente_aprobacion",
|
|
42662
|
+
actor: ["agente", "humano"],
|
|
42663
|
+
nivelRequerido: "propone",
|
|
42664
|
+
descripcion: "Informar los bonos que el HIS liquid\xF3 al profesional ese d\xEDa, con sus prestaciones y su regla. El plugin calcula el honorario como el HIS y arma el mensaje.",
|
|
42665
|
+
validar: (_caso, datos) => {
|
|
42666
|
+
const l = leerLineasLiquidacion(datos.lineas);
|
|
42667
|
+
return [
|
|
42668
|
+
texto4(datos.lectura_id) ? ok("lectura_registrada") : falla("lectura_registrada", "preparar requiere lectura_id"),
|
|
42669
|
+
"error" in l ? falla("lineas_validas", l.error) : ok("lineas_validas", `${l.lineas.length} bonos`)
|
|
42670
|
+
];
|
|
42671
|
+
},
|
|
42672
|
+
autonomia: {
|
|
42673
|
+
aSinExcepcion: "aprobado",
|
|
42674
|
+
excepciones: (_caso, datos, contexto) => {
|
|
42675
|
+
const l = leerLineasLiquidacion(datos.lineas);
|
|
42676
|
+
const enCero = "error" in l ? 0 : l.lineas.reduce((a, x) => a + x.en_cero, 0);
|
|
42677
|
+
return [
|
|
42678
|
+
excepcion("prestaciones_en_cero", enCero > 0, `${enCero} prestaciones en $0`),
|
|
42679
|
+
excepcion("profesional_sin_correo", contexto.profesionalConCorreo === false, contexto.profesionalConCorreo ? "con correo" : "sin correo")
|
|
42680
|
+
];
|
|
42681
|
+
}
|
|
42682
|
+
}
|
|
42683
|
+
},
|
|
42684
|
+
{ via: "aprobar", de: ["pendiente_aprobacion"], a: "aprobado", actor: ["humano"], descripcion: "La direcci\xF3n aprueba mandarle la liquidaci\xF3n al profesional." },
|
|
42685
|
+
{
|
|
42686
|
+
via: "rechazar",
|
|
42687
|
+
de: ["pendiente_aprobacion"],
|
|
42688
|
+
a: "rechazado",
|
|
42689
|
+
actor: ["humano"],
|
|
42690
|
+
descripcion: "No se le manda (por ejemplo, la liquidaci\xF3n se va a revertir).",
|
|
42691
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "rechazar requiere motivo")]
|
|
42692
|
+
},
|
|
42693
|
+
{
|
|
42694
|
+
via: "enviar",
|
|
42695
|
+
de: ["aprobado"],
|
|
42696
|
+
a: "enviada",
|
|
42697
|
+
actor: ["humano"],
|
|
42698
|
+
descripcion: "Se le mand\xF3 la liquidaci\xF3n al profesional (por correo desde el portal o por la v\xEDa habitual). Es un aviso, no una carga en el HIS: no hay nada que releer.",
|
|
42699
|
+
validar: (_caso, datos) => [
|
|
42700
|
+
texto4(datos.aviso_id) ? ok("envio_registrado") : falla("envio_registrado", "enviar requiere aviso_id: el env\xEDo registrado"),
|
|
42701
|
+
texto4(datos.canal) ? ok("canal_informado", String(datos.canal)) : falla("canal_informado", "enviar requiere el canal")
|
|
42702
|
+
]
|
|
42703
|
+
},
|
|
42704
|
+
{
|
|
42705
|
+
via: "descartar",
|
|
42706
|
+
de: ["detectado", "pendiente_aprobacion"],
|
|
42707
|
+
a: "descartado",
|
|
42708
|
+
actor: ["agente", "humano"],
|
|
42709
|
+
nivelRequerido: "observa",
|
|
42710
|
+
descripcion: "La liquidaci\xF3n se revirti\xF3 o no corresponde mandarla.",
|
|
42711
|
+
validar: (_caso, datos) => [texto4(datos.motivo) ? ok("motivo_presente") : falla("motivo_presente", "descartar requiere motivo")]
|
|
42712
|
+
}
|
|
42713
|
+
]
|
|
42714
|
+
};
|
|
42715
|
+
var WORKFLOWS_SOLO_LECTURA = /* @__PURE__ */ new Set([cuentaCompleta.clave, facturacionPendiente.clave, credencialProfesional.clave, internacionAlDia.clave, honorarioEnCero.clave]);
|
|
42259
42716
|
var WORKFLOWS = {
|
|
42260
42717
|
[actualizacionArancel.clave]: actualizacionArancel,
|
|
42261
42718
|
[tareaOperativa.clave]: tareaOperativa,
|
|
@@ -42266,7 +42723,10 @@ var WORKFLOWS = {
|
|
|
42266
42723
|
[demandaPendiente.clave]: demandaPendiente,
|
|
42267
42724
|
[circularAranceles.clave]: circularAranceles,
|
|
42268
42725
|
[cobranzaFinanciador.clave]: cobranzaFinanciador,
|
|
42269
|
-
[internacionAlDia.clave]: internacionAlDia
|
|
42726
|
+
[internacionAlDia.clave]: internacionAlDia,
|
|
42727
|
+
[honorarioEnCero.clave]: honorarioEnCero,
|
|
42728
|
+
[debitoProfesional.clave]: debitoProfesional,
|
|
42729
|
+
[liquidacionProfesional.clave]: liquidacionProfesional
|
|
42270
42730
|
};
|
|
42271
42731
|
function getWorkflow(clave) {
|
|
42272
42732
|
return WORKFLOWS[clave] ?? null;
|
|
@@ -42654,17 +43114,17 @@ async function listarReglas(ctx, companyId, filtro = {}) {
|
|
|
42654
43114
|
const rows = await ctx.db.query(`SELECT ${COLS} FROM ${t(ctx, "regla")} WHERE ${where} ORDER BY created_at ASC`, params);
|
|
42655
43115
|
return rows.map(mapRegla);
|
|
42656
43116
|
}
|
|
42657
|
-
async function
|
|
42658
|
-
const rows = await ctx.db.query(`SELECT ${COLS} FROM ${t(ctx, "regla")} WHERE company_id = $1 AND id = $2 LIMIT 1`, [companyId,
|
|
43117
|
+
async function leerRegla2(ctx, companyId, id2) {
|
|
43118
|
+
const rows = await ctx.db.query(`SELECT ${COLS} FROM ${t(ctx, "regla")} WHERE company_id = $1 AND id = $2 LIMIT 1`, [companyId, id2]);
|
|
42659
43119
|
return rows[0] ? mapRegla(rows[0]) : null;
|
|
42660
43120
|
}
|
|
42661
|
-
async function requerirRegla(ctx, companyId,
|
|
42662
|
-
const r = await
|
|
42663
|
-
if (!r) throw new OpsError("regla_inexistente", `no existe la regla ${
|
|
43121
|
+
async function requerirRegla(ctx, companyId, id2) {
|
|
43122
|
+
const r = await leerRegla2(ctx, companyId, id2);
|
|
43123
|
+
if (!r) throw new OpsError("regla_inexistente", `no existe la regla ${id2} en esta instituci\xF3n`);
|
|
42664
43124
|
return r;
|
|
42665
43125
|
}
|
|
42666
|
-
function cambio(version2, actor,
|
|
42667
|
-
return { version: version2, fecha: (/* @__PURE__ */ new Date()).toISOString(), actorTipo: actor.tipo, actorId: actor.id, cambio:
|
|
43126
|
+
function cambio(version2, actor, texto7) {
|
|
43127
|
+
return { version: version2, fecha: (/* @__PURE__ */ new Date()).toISOString(), actorTipo: actor.tipo, actorId: actor.id, cambio: texto7 };
|
|
42668
43128
|
}
|
|
42669
43129
|
function soloPersonas(actor, que) {
|
|
42670
43130
|
if (actor.tipo !== "humano") throw new OpsError("actor_no_permitido", `${que} lo hace una persona de la instituci\xF3n desde el portal; el agente solo lee las reglas e informa la prueba`);
|
|
@@ -42673,15 +43133,15 @@ async function crearRegla(ctx, input2) {
|
|
|
42673
43133
|
soloPersonas(input2.actor, "crear una regla");
|
|
42674
43134
|
if (input2.workflow !== "demanda_pendiente") throw new OpsError("workflow_sin_reglas", `el puesto ${input2.workflow} no tiene reglas configurables`);
|
|
42675
43135
|
const v = validarRegla(input2);
|
|
42676
|
-
const
|
|
43136
|
+
const id2 = randomUUID();
|
|
42677
43137
|
const historial = [cambio(1, input2.actor, "creada")];
|
|
42678
43138
|
await ctx.db.execute(
|
|
42679
43139
|
`INSERT INTO ${t(ctx, "regla")} (id, company_id, workflow, nombre, tipo, parametros, contacto, cierre, estado, version, historial, actor_tipo, actor_id) VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7::jsonb, $8::jsonb, $9, $10, $11::jsonb, $12, $13)`,
|
|
42680
|
-
[
|
|
43140
|
+
[id2, input2.companyId, input2.workflow, v.nombre, v.tipo, JSON.stringify(v.parametros), JSON.stringify(v.contacto), JSON.stringify(v.cierre), "borrador", 1, JSON.stringify(historial), input2.actor.tipo, input2.actor.id]
|
|
42681
43141
|
);
|
|
42682
|
-
await ctx.activity.log({ companyId: input2.companyId, message: `Autopilot Care: regla \xAB${v.nombre}\xBB creada (${v.tipo}, borrador)`, metadata: { reglaId:
|
|
43142
|
+
await ctx.activity.log({ companyId: input2.companyId, message: `Autopilot Care: regla \xAB${v.nombre}\xBB creada (${v.tipo}, borrador)`, metadata: { reglaId: id2, workflow: input2.workflow } });
|
|
42683
43143
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42684
|
-
return { id, companyId: input2.companyId, workflow: input2.workflow, ...v, estado: "borrador", version: 1, historial, ultimaPrueba: null, actorTipo: input2.actor.tipo, actorId: input2.actor.id, createdAt: now, updatedAt: now };
|
|
43144
|
+
return { id: id2, companyId: input2.companyId, workflow: input2.workflow, ...v, estado: "borrador", version: 1, historial, ultimaPrueba: null, actorTipo: input2.actor.tipo, actorId: input2.actor.id, createdAt: now, updatedAt: now };
|
|
42685
43145
|
}
|
|
42686
43146
|
async function editarRegla(ctx, input2) {
|
|
42687
43147
|
soloPersonas(input2.actor, "editar una regla");
|
|
@@ -43073,10 +43533,19 @@ async function abrirCaso(ctx, input2) {
|
|
|
43073
43533
|
if (referencia !== `cobranza:${os}`) throw new OpsError("referencia_requerida", `en cobranza_financiador la referencia es obligatoria: cobranza:${os}`);
|
|
43074
43534
|
if (!str2(d.obra_social) || !str2(d.institucion)) throw new OpsError("validacion", "cobranza_financiador necesita obra_social (nombre) e institucion (nombre de la instituci\xF3n para el reclamo)");
|
|
43075
43535
|
}
|
|
43536
|
+
if (wf.clave === "honorario_en_cero" || wf.clave === "debito_profesional" || wf.clave === "liquidacion_profesional") {
|
|
43537
|
+
const d = input2.datos ?? {};
|
|
43538
|
+
const pid = str2(d.profesional_id);
|
|
43539
|
+
if (!pid || !/^\d{1,12}$/.test(pid)) throw new OpsError("validacion", `${wf.clave} necesita profesional_id (el id del profesional en el HIS)`);
|
|
43540
|
+
const esperada = wf.clave === "honorario_en_cero" ? `honorarios:${pid}` : wf.clave === "debito_profesional" ? `debito:${pid}:${str2(d.nota_credito_id) ?? ""}` : `liquidacion:${pid}:${str2(d.liquidado_el) ?? ""}`;
|
|
43541
|
+
if (wf.clave === "debito_profesional" && !/^\d{1,12}$/.test(str2(d.nota_credito_id) ?? "")) throw new OpsError("validacion", "debito_profesional necesita nota_credito_id");
|
|
43542
|
+
if (wf.clave === "liquidacion_profesional" && (!/^\d{4}-\d{2}-\d{2}$/.test(str2(d.liquidado_el) ?? "") || !str2(d.institucion))) throw new OpsError("validacion", "liquidacion_profesional necesita liquidado_el (AAAA-MM-DD) e institucion (nombre para el mensaje)");
|
|
43543
|
+
if (referencia !== esperada) throw new OpsError("referencia_requerida", `en ${wf.clave} la referencia es obligatoria: ${esperada}`);
|
|
43544
|
+
}
|
|
43076
43545
|
if (wf.clave === "internacion_al_dia") {
|
|
43077
|
-
const
|
|
43078
|
-
if (!
|
|
43079
|
-
if (referencia !== `internacion:${
|
|
43546
|
+
const id3 = str2(input2.datos?.internacion_id);
|
|
43547
|
+
if (!id3 || !/^\d{1,12}$/.test(id3)) throw new OpsError("validacion", "internacion_al_dia necesita internacion_id (el id de la internaci\xF3n en el HIS)");
|
|
43548
|
+
if (referencia !== `internacion:${id3}`) throw new OpsError("referencia_requerida", `en internacion_al_dia la referencia es obligatoria: internacion:${id3}`);
|
|
43080
43549
|
}
|
|
43081
43550
|
if (wf.clave === "circular_aranceles") {
|
|
43082
43551
|
const d = input2.datos ?? {};
|
|
@@ -43086,13 +43555,17 @@ async function abrirCaso(ctx, input2) {
|
|
|
43086
43555
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(String(d.vigencia_desde))) throw new OpsError("validacion", "vigencia_desde: AAAA-MM-DD");
|
|
43087
43556
|
}
|
|
43088
43557
|
const extra = {};
|
|
43558
|
+
if (wf.clave === "honorario_en_cero" || wf.clave === "debito_profesional" || wf.clave === "liquidacion_profesional") {
|
|
43559
|
+
const p = leerProfesional(input2.datos?.profesional) ?? leerProfesional({ id: input2.datos?.profesional_id, nombre: input2.datos?.profesional });
|
|
43560
|
+
extra.profesional = p?.nombre ?? null;
|
|
43561
|
+
}
|
|
43089
43562
|
if (wf.clave === "demanda_pendiente") {
|
|
43090
43563
|
if (!referencia || !/^(orden|solicitud|control):\S+$/.test(referencia)) {
|
|
43091
43564
|
throw new OpsError("referencia_requerida", "en demanda_pendiente la referencia es obligatoria: orden:<id>, solicitud:<id> o control:<persona_id>:<regla_id>");
|
|
43092
43565
|
}
|
|
43093
43566
|
const reglaId = str2(input2.datos?.regla_id);
|
|
43094
43567
|
if (!reglaId) throw new OpsError("regla_requerida", "en demanda_pendiente datos.regla_id es obligatorio: la regla activa que detect\xF3 el caso");
|
|
43095
|
-
const regla = await
|
|
43568
|
+
const regla = await leerRegla2(ctx, input2.companyId, reglaId);
|
|
43096
43569
|
if (!regla || regla.workflow !== wf.clave) throw new OpsError("regla_inexistente", `no existe la regla ${reglaId} en esta instituci\xF3n`);
|
|
43097
43570
|
if (regla.estado !== "activa") throw new OpsError("regla_inactiva", `la regla \xAB${regla.nombre}\xBB est\xE1 ${regla.estado}: no abre casos hasta que se active`);
|
|
43098
43571
|
const { hoy } = ahoraEnHospital();
|
|
@@ -43111,17 +43584,17 @@ async function abrirCaso(ctx, input2) {
|
|
|
43111
43584
|
);
|
|
43112
43585
|
if (abiertos[0]) return { caso: mapCaso(abiertos[0]), creado: false };
|
|
43113
43586
|
}
|
|
43114
|
-
const
|
|
43587
|
+
const id2 = randomUUID2();
|
|
43115
43588
|
const datos = { ...input2.datos ?? {}, ...extra };
|
|
43116
43589
|
await ctx.db.execute(
|
|
43117
43590
|
`INSERT INTO ${t2(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)`,
|
|
43118
|
-
[
|
|
43591
|
+
[id2, input2.companyId, wf.clave, wf.inicial, referencia, titulo, JSON.stringify(datos), input2.actor.tipo, input2.actor.id, input2.agenteId ?? null, input2.issueId ?? null, idem]
|
|
43119
43592
|
);
|
|
43120
43593
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
43121
43594
|
return {
|
|
43122
43595
|
creado: true,
|
|
43123
43596
|
caso: {
|
|
43124
|
-
id,
|
|
43597
|
+
id: id2,
|
|
43125
43598
|
companyId: input2.companyId,
|
|
43126
43599
|
workflow: wf.clave,
|
|
43127
43600
|
estado: wf.inicial,
|
|
@@ -43153,6 +43626,17 @@ async function contextoDe(ctx, companyId, caso, via, datos) {
|
|
|
43153
43626
|
contexto.plazosPresentacion = leerPlazos((await obtenerOpciones(ctx, companyId, caso.workflow)).plazos);
|
|
43154
43627
|
return contexto;
|
|
43155
43628
|
}
|
|
43629
|
+
if (caso.workflow === "debito_profesional") {
|
|
43630
|
+
const op = await obtenerOpciones(ctx, companyId, caso.workflow);
|
|
43631
|
+
contexto.umbralAprobacion = typeof op.umbral_aprobacion === "number" && op.umbral_aprobacion > 0 ? op.umbral_aprobacion : 0;
|
|
43632
|
+
return contexto;
|
|
43633
|
+
}
|
|
43634
|
+
if (caso.workflow === "liquidacion_profesional") {
|
|
43635
|
+
const pid = str2(caso.datos.profesional_id);
|
|
43636
|
+
const contacto = pid ? (await ctx.db.query(`SELECT id, mail, activo FROM ${t2(ctx, "contacto")} WHERE company_id = $1 AND clave = $2 LIMIT 1`, [companyId, `profesional:${pid}`]))[0] : void 0;
|
|
43637
|
+
contexto.profesionalConCorreo = Boolean(contacto && contacto.activo !== false && contacto.mail || str2(datos.mail_his) || str2(caso.datos.mail_his));
|
|
43638
|
+
return contexto;
|
|
43639
|
+
}
|
|
43156
43640
|
if (caso.workflow === "internacion_al_dia") {
|
|
43157
43641
|
if (via === "observar" || via === "comprobar") {
|
|
43158
43642
|
const op = await obtenerOpciones(ctx, companyId, caso.workflow);
|
|
@@ -43189,7 +43673,7 @@ async function contextoDe(ctx, companyId, caso, via, datos) {
|
|
|
43189
43673
|
}
|
|
43190
43674
|
if (caso.workflow === "demanda_pendiente") {
|
|
43191
43675
|
const reglaId = str2(caso.datos.regla_id);
|
|
43192
|
-
const regla = reglaId ? await
|
|
43676
|
+
const regla = reglaId ? await leerRegla2(ctx, companyId, reglaId) : null;
|
|
43193
43677
|
contexto.regla = regla ? reglaParaContexto(regla) : null;
|
|
43194
43678
|
const contactos = (await ctx.db.query(
|
|
43195
43679
|
`SELECT caso_id, via, created_at FROM ${t2(ctx, "transicion")} WHERE company_id = $1 AND caso_id = $2 AND via = $3 ORDER BY created_at DESC LIMIT 50`,
|
|
@@ -43312,6 +43796,50 @@ async function transicionar(ctx, input2) {
|
|
|
43312
43796
|
datos.verificada_el = contexto.hoy ?? null;
|
|
43313
43797
|
}
|
|
43314
43798
|
}
|
|
43799
|
+
if (caso.workflow === "honorario_en_cero") {
|
|
43800
|
+
for (const k of ["items", "resumen", "comprobado_el"]) delete datos[k];
|
|
43801
|
+
if (resultado.via === "observar" || resultado.via === "comprobar") {
|
|
43802
|
+
const l = leerPrestaciones(datos.prestaciones);
|
|
43803
|
+
if (!("error" in l)) {
|
|
43804
|
+
const e = prestacionesEnCero(l.prestaciones);
|
|
43805
|
+
datos.items = e.items;
|
|
43806
|
+
datos.resumen = e.resumen;
|
|
43807
|
+
datos.comprobado_el = `${contexto.hoy ?? ""} ${contexto.horaActual ?? ""}`.trim();
|
|
43808
|
+
}
|
|
43809
|
+
}
|
|
43810
|
+
delete datos.prestaciones;
|
|
43811
|
+
}
|
|
43812
|
+
if (caso.workflow === "debito_profesional") {
|
|
43813
|
+
for (const k of ["resumen", "faltan", "comprobado_el"]) delete datos[k];
|
|
43814
|
+
if (resultado.via === "proponer") {
|
|
43815
|
+
const l = leerDebitos(datos.items);
|
|
43816
|
+
if ("error" in l) delete datos.items;
|
|
43817
|
+
else {
|
|
43818
|
+
const items = l.debitos.map(evaluarDebito);
|
|
43819
|
+
datos.items = items;
|
|
43820
|
+
datos.resumen = resumenDebitos(items);
|
|
43821
|
+
}
|
|
43822
|
+
} else delete datos.items;
|
|
43823
|
+
if (resultado.via === "comprobar") {
|
|
43824
|
+
datos.faltan = faltaTrasladar(leerItemsDebito(caso.datos.items), datos.leidos).faltan;
|
|
43825
|
+
datos.comprobado_el = contexto.hoy ?? null;
|
|
43826
|
+
}
|
|
43827
|
+
delete datos.leidos;
|
|
43828
|
+
}
|
|
43829
|
+
if (caso.workflow === "liquidacion_profesional") {
|
|
43830
|
+
for (const k of ["resumen", "mensaje"]) delete datos[k];
|
|
43831
|
+
if (resultado.via === "preparar") {
|
|
43832
|
+
const l = leerLineasLiquidacion(datos.lineas);
|
|
43833
|
+
if ("error" in l) delete datos.lineas;
|
|
43834
|
+
else {
|
|
43835
|
+
const resumen = resumirLiquidacion(l.lineas);
|
|
43836
|
+
const profesional = leerProfesional({ id: caso.datos.profesional_id, nombre: caso.datos.profesional }) ?? { id: String(caso.datos.profesional_id ?? ""), nombre: str2(caso.datos.profesional) };
|
|
43837
|
+
datos.lineas = l.lineas;
|
|
43838
|
+
datos.resumen = resumen;
|
|
43839
|
+
datos.mensaje = redactarLiquidacion({ institucion: str2(caso.datos.institucion) ?? "La instituci\xF3n", profesional, fechaLiquidacion: str2(caso.datos.liquidado_el) ?? (contexto.hoy ?? ""), resumen });
|
|
43840
|
+
}
|
|
43841
|
+
} else delete datos.lineas;
|
|
43842
|
+
}
|
|
43315
43843
|
if (caso.workflow === "internacion_al_dia") {
|
|
43316
43844
|
for (const k of ["pendientes", "dias_sin_evolucion", "ultima_evolucion", "evoluciono_hoy", "egresada", "dias_internado", "comprobado_el", "ingreso", "egreso", "responsable", "servicio", "obra_social", "orden"]) delete datos[k];
|
|
43317
43845
|
const r = contexto.internacion;
|
|
@@ -43397,8 +43925,8 @@ async function transicionar(ctx, input2) {
|
|
|
43397
43925
|
}
|
|
43398
43926
|
}
|
|
43399
43927
|
if (caso.workflow === "facturacion_pendiente" && resultado.via === "observar") {
|
|
43400
|
-
const
|
|
43401
|
-
Object.assign(datos, calcularVencimiento(
|
|
43928
|
+
const fecha4 = String(datos.fecha_prestacion ?? caso.datos.fecha_prestacion ?? "");
|
|
43929
|
+
Object.assign(datos, calcularVencimiento(fecha4, datos.obra_social ?? caso.datos.obra_social, contexto));
|
|
43402
43930
|
}
|
|
43403
43931
|
if (caso.workflow === "demanda_pendiente") {
|
|
43404
43932
|
delete datos.intentos;
|
|
@@ -43489,7 +44017,7 @@ async function registrarAccion(ctx, input2) {
|
|
|
43489
44017
|
const modo = await obtenerModo(ctx, input2.companyId, caso.workflow);
|
|
43490
44018
|
if (!modoHabilita(modo, "ejecuta")) throw new OpsError("politica", `la pol\xEDtica vigente de ${caso.workflow} es "${modo}": un agente no puede registrar escrituras sobre el HIS`);
|
|
43491
44019
|
}
|
|
43492
|
-
const
|
|
44020
|
+
const id2 = randomUUID2();
|
|
43493
44021
|
const evidencia = { ...input2.evidencia ?? {} };
|
|
43494
44022
|
delete evidencia.fuera_de_flujo;
|
|
43495
44023
|
if (caso.workflow === "recupero_turno" && input2.tipo === "escritura" && input2.actor.tipo === "agente" && caso.estado !== "asignando") {
|
|
@@ -43497,14 +44025,14 @@ async function registrarAccion(ctx, input2) {
|
|
|
43497
44025
|
}
|
|
43498
44026
|
await ctx.db.execute(
|
|
43499
44027
|
`INSERT INTO ${t2(ctx, "accion")} (id, company_id, caso_id, tipo, conector, objetivo, resultado, evidencia, detalle, actor_tipo, actor_id, run_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10, $11, $12)`,
|
|
43500
|
-
[
|
|
44028
|
+
[id2, input2.companyId, caso.id, input2.tipo, input2.conector, objetivo, input2.resultado, JSON.stringify(evidencia), input2.detalle ?? null, input2.actor.tipo, input2.actor.id, input2.actor.runId ?? null]
|
|
43501
44029
|
);
|
|
43502
44030
|
await ctx.db.execute(
|
|
43503
44031
|
`UPDATE ${t2(ctx, "caso")} SET updated_at = now() WHERE company_id = $1 AND id = $2`,
|
|
43504
44032
|
[input2.companyId, caso.id]
|
|
43505
44033
|
);
|
|
43506
44034
|
return {
|
|
43507
|
-
id,
|
|
44035
|
+
id: id2,
|
|
43508
44036
|
casoId: caso.id,
|
|
43509
44037
|
tipo: input2.tipo,
|
|
43510
44038
|
conector: input2.conector,
|
|
@@ -43797,8 +44325,8 @@ async function serie(ctx, companyId, diasInput) {
|
|
|
43797
44325
|
puntos.set(d, { dia: d, abiertos: 0, cerradosOk: 0, rechazados: 0, minutos: 0, acciones: 0 });
|
|
43798
44326
|
}
|
|
43799
44327
|
const descartado = { dia: "", abiertos: 0, cerradosOk: 0, rechazados: 0, minutos: 0, acciones: 0 };
|
|
43800
|
-
const punto = (
|
|
43801
|
-
const k = typeof
|
|
44328
|
+
const punto = (dia4) => {
|
|
44329
|
+
const k = typeof dia4 === "string" ? dia4.slice(0, 10) : "";
|
|
43802
44330
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(k)) return descartado;
|
|
43803
44331
|
if (!puntos.has(k)) puntos.set(k, { dia: k, abiertos: 0, cerradosOk: 0, rechazados: 0, minutos: 0, acciones: 0 });
|
|
43804
44332
|
return puntos.get(k);
|
|
@@ -43854,6 +44382,27 @@ function errorParaAgente(err) {
|
|
|
43854
44382
|
const message2 = err instanceof Error ? err.message : String(err);
|
|
43855
44383
|
return { error: `error_interno: ${message2}`, data: { codigo: "error_interno" } };
|
|
43856
44384
|
}
|
|
44385
|
+
async function registrarEnvioLiquidacion(ctx, input2) {
|
|
44386
|
+
const caso = await leerCaso(ctx, input2.companyId, input2.casoId);
|
|
44387
|
+
if (!caso) throw new OpsError("caso_inexistente", `no existe el caso ${input2.casoId} en esta instituci\xF3n`);
|
|
44388
|
+
if (caso.workflow !== "liquidacion_profesional") throw new OpsError("workflow_invalido", "solo las liquidaciones se env\xEDan al profesional");
|
|
44389
|
+
if (caso.estado !== "aprobado") throw new OpsError("estado_invalido", caso.estado === "enviada" ? "ya figura como enviada" : `la liquidaci\xF3n est\xE1 ${caso.estado}: se env\xEDa cuando la direcci\xF3n la aprueba`);
|
|
44390
|
+
if (input2.actor.tipo !== "humano") throw new OpsError("actor_no_permitido", "el env\xEDo lo registra una persona");
|
|
44391
|
+
const canal = canalReclamo(input2.canal);
|
|
44392
|
+
const destinatario = str2(input2.destinatario);
|
|
44393
|
+
const persona = str2(input2.persona);
|
|
44394
|
+
const accion = await registrarAccion(ctx, {
|
|
44395
|
+
companyId: input2.companyId,
|
|
44396
|
+
casoId: caso.id,
|
|
44397
|
+
tipo: "aviso",
|
|
44398
|
+
conector: canal === "correo" ? "mail" : "manual",
|
|
44399
|
+
objetivo: `Liquidaci\xF3n enviada a ${str2(caso.datos.profesional) ?? leerProfesional(caso.datos.profesional)?.nombre ?? "el profesional"}`,
|
|
44400
|
+
resultado: "ok",
|
|
44401
|
+
evidencia: { canal, ...destinatario ? { destinatario } : {}, ...persona ? { registrado_por: persona } : {} },
|
|
44402
|
+
actor: input2.actor
|
|
44403
|
+
});
|
|
44404
|
+
return transicionar(ctx, { companyId: input2.companyId, casoId: caso.id, via: "enviar", datos: { aviso_id: accion.id, canal, ...destinatario ? { destinatario } : {}, ...persona ? { registrado_por: persona } : {} }, actor: input2.actor });
|
|
44405
|
+
}
|
|
43857
44406
|
function canalReclamo(v) {
|
|
43858
44407
|
return typeof v === "string" && CANALES_RECLAMO.includes(v) ? v : "otro";
|
|
43859
44408
|
}
|
|
@@ -43863,7 +44412,7 @@ import { randomUUID as randomUUID3 } from "node:crypto";
|
|
|
43863
44412
|
function t3(ctx, table) {
|
|
43864
44413
|
return `${ctx.db.namespace}.${table}`;
|
|
43865
44414
|
}
|
|
43866
|
-
function
|
|
44415
|
+
function texto5(v) {
|
|
43867
44416
|
return typeof v === "string" && v.trim().length > 0 ? v.trim() : typeof v === "number" ? String(v) : null;
|
|
43868
44417
|
}
|
|
43869
44418
|
function iso3(v) {
|
|
@@ -43871,7 +44420,7 @@ function iso3(v) {
|
|
|
43871
44420
|
if (typeof v === "string" && v) return v;
|
|
43872
44421
|
return null;
|
|
43873
44422
|
}
|
|
43874
|
-
function
|
|
44423
|
+
function dia3(v) {
|
|
43875
44424
|
if (v instanceof Date) return v.toISOString().slice(0, 10);
|
|
43876
44425
|
return String(v ?? "").slice(0, 10);
|
|
43877
44426
|
}
|
|
@@ -43892,13 +44441,16 @@ var ROLES = {
|
|
|
43892
44441
|
aranceles: "Aranceles y convenios",
|
|
43893
44442
|
facturacion: "Facturaci\xF3n",
|
|
43894
44443
|
internacion: "Internaci\xF3n",
|
|
44444
|
+
honorarios: "Honorarios",
|
|
43895
44445
|
personal: "Administraci\xF3n de personal"
|
|
43896
44446
|
};
|
|
43897
44447
|
var ESPERAN_PERSONA = {
|
|
43898
44448
|
cuenta_completa: ["para_completar", "con_faltantes"],
|
|
43899
44449
|
facturacion_pendiente: ["por_presentar"],
|
|
43900
44450
|
credencial_profesional: ["observada"],
|
|
43901
|
-
internacion_al_dia: ["con_pendientes"]
|
|
44451
|
+
internacion_al_dia: ["con_pendientes"],
|
|
44452
|
+
honorario_en_cero: ["para_cargar"],
|
|
44453
|
+
debito_profesional: ["aprobado", "con_diferencias"]
|
|
43902
44454
|
};
|
|
43903
44455
|
var CANALES_AVISO = ["mail", "whatsapp"];
|
|
43904
44456
|
var HORARIO_AVISOS = { desde: "08:00", hasta: "18:00" };
|
|
@@ -43919,7 +44471,7 @@ function pendientesDe(caso, hoy) {
|
|
|
43919
44471
|
const estados = ESPERAN_PERSONA[caso.workflow];
|
|
43920
44472
|
if (!estados || !estados.includes(caso.estado)) return [];
|
|
43921
44473
|
const d = caso.datos;
|
|
43922
|
-
const bono = `Bono ${
|
|
44474
|
+
const bono = `Bono ${texto5(d.bono_numero) ?? texto5(d.bono_id) ?? "sin n\xFAmero"}${texto5(d.obra_social) ? ` \xB7 ${texto5(d.obra_social)}` : ""}`;
|
|
43923
44475
|
const base = { casoId: caso.id, workflow: caso.workflow, titulo: caso.titulo };
|
|
43924
44476
|
if (caso.workflow === "cuenta_completa") {
|
|
43925
44477
|
const out = [];
|
|
@@ -43927,7 +44479,7 @@ function pendientesDe(caso, hoy) {
|
|
|
43927
44479
|
const nombreRegla = REGLAS_CUENTA[f.regla]?.nombre ?? f.regla;
|
|
43928
44480
|
if (f.regla === "epicrisis_faltante") {
|
|
43929
44481
|
const p = f.responsable?.tipo === "profesional" && f.responsable.id ? f.responsable : null;
|
|
43930
|
-
const internacion =
|
|
44482
|
+
const internacion = texto5(d.internacion_id) ? `Internaci\xF3n ${texto5(d.internacion_id)}` : bono;
|
|
43931
44483
|
out.push({
|
|
43932
44484
|
...base,
|
|
43933
44485
|
que: `${internacion}: falta la epicrisis`,
|
|
@@ -43941,21 +44493,32 @@ function pendientesDe(caso, hoy) {
|
|
|
43941
44493
|
}
|
|
43942
44494
|
return out;
|
|
43943
44495
|
}
|
|
44496
|
+
const profesionalH = texto5(d.profesional) ?? (d.profesional && typeof d.profesional === "object" ? texto5(d.profesional.nombre) : null);
|
|
44497
|
+
if (caso.workflow === "honorario_en_cero") {
|
|
44498
|
+
const r = d.resumen && typeof d.resumen === "object" ? d.resumen : {};
|
|
44499
|
+
const n = typeof r.prestaciones === "number" ? r.prestaciones : 0;
|
|
44500
|
+
return [{ ...base, que: `${profesionalH ?? "Un profesional"}: ${n === 1 ? "1 prestaci\xF3n se liquidar\xEDa" : `${n} prestaciones se liquidar\xEDan`} en $0 por falta de regla de honorario`, responsable: rol("honorarios") }];
|
|
44501
|
+
}
|
|
44502
|
+
if (caso.workflow === "debito_profesional") {
|
|
44503
|
+
const r = d.resumen && typeof d.resumen === "object" ? d.resumen : {};
|
|
44504
|
+
const total = typeof r.total === "number" ? r.total.toLocaleString("es-AR", { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : "";
|
|
44505
|
+
return [{ ...base, que: `${profesionalH ?? "Un profesional"}: cargar un d\xE9bito de $ ${total} aprobado por la direcci\xF3n (nota de cr\xE9dito de ${texto5(d.obra_social) ?? "la obra social"})`, responsable: rol("honorarios") }];
|
|
44506
|
+
}
|
|
43944
44507
|
if (caso.workflow === "internacion_al_dia") {
|
|
43945
|
-
const internacion = `Internaci\xF3n ${
|
|
44508
|
+
const internacion = `Internaci\xF3n ${texto5(d.internacion_id) ?? "sin n\xFAmero"}${texto5(d.servicio) ? ` (${texto5(d.servicio)})` : ""}`;
|
|
43946
44509
|
const resp = d.responsable && typeof d.responsable === "object" ? d.responsable : null;
|
|
43947
|
-
const medicoId = resp ?
|
|
44510
|
+
const medicoId = resp ? texto5(resp.id) : null;
|
|
43948
44511
|
const out = [];
|
|
43949
44512
|
for (const p of Array.isArray(d.pendientes) ? d.pendientes : []) {
|
|
43950
|
-
const regla =
|
|
44513
|
+
const regla = texto5(p.regla);
|
|
43951
44514
|
if (regla === "evolucion_de_hoy") {
|
|
43952
|
-
const
|
|
43953
|
-
if (!
|
|
44515
|
+
const dia4 = texto5(p.dia);
|
|
44516
|
+
if (!dia4 || hoy && dia4 !== hoy) continue;
|
|
43954
44517
|
out.push({
|
|
43955
44518
|
...base,
|
|
43956
44519
|
que: `${internacion}: todav\xEDa no tiene evoluci\xF3n hoy`,
|
|
43957
|
-
responsable: medicoId ? { clave: `profesional:${medicoId}`, nombre:
|
|
43958
|
-
marca: `evolucion:${
|
|
44520
|
+
responsable: medicoId ? { clave: `profesional:${medicoId}`, nombre: texto5(resp?.nombre) ?? `Profesional ${medicoId}`, reserva: "rol:internacion" } : rol("internacion"),
|
|
44521
|
+
marca: `evolucion:${dia4}`
|
|
43959
44522
|
});
|
|
43960
44523
|
} else if (regla === "alta_sin_registrar") {
|
|
43961
44524
|
out.push({ ...base, que: `${internacion}: ${REGLAS_INTERNACION.alta_sin_registrar.nombre.toLowerCase()}`, responsable: rol("internacion") });
|
|
@@ -43966,23 +44529,23 @@ function pendientesDe(caso, hoy) {
|
|
|
43966
44529
|
return out;
|
|
43967
44530
|
}
|
|
43968
44531
|
if (caso.workflow === "facturacion_pendiente") {
|
|
43969
|
-
const vence =
|
|
44532
|
+
const vence = texto5(d.vence_el);
|
|
43970
44533
|
return [{ ...base, que: `${bono}: sin presentar${vence ? `, vence el ${vence.slice(8, 10)}/${vence.slice(5, 7)}` : ""}`, responsable: rol("facturacion") }];
|
|
43971
44534
|
}
|
|
43972
44535
|
if (caso.workflow === "credencial_profesional") {
|
|
43973
|
-
const
|
|
43974
|
-
const nombre =
|
|
43975
|
-
const obs =
|
|
44536
|
+
const id2 = texto5(d.profesional_id);
|
|
44537
|
+
const nombre = texto5(d.profesional) ?? (id2 ? `Profesional ${id2}` : "Profesional");
|
|
44538
|
+
const obs = texto5(d.observacion);
|
|
43976
44539
|
const que = `${nombre}: ${(obs && OBSERVACIONES_MATRICULA[obs]) ?? "la matr\xEDcula tiene una observaci\xF3n del registro nacional"}`;
|
|
43977
|
-
return [{ ...base, que, responsable:
|
|
44540
|
+
return [{ ...base, que, responsable: id2 ? { clave: `profesional:${id2}`, nombre, reserva: "rol:personal" } : rol("personal") }];
|
|
43978
44541
|
}
|
|
43979
44542
|
return [];
|
|
43980
44543
|
}
|
|
43981
|
-
var CLAVE_RE = /^(profesional:[A-Za-z0-9_-]{1,40}|financiador:\d{1,12}|rol:(admision|aranceles|facturacion|internacion|personal))$/;
|
|
44544
|
+
var CLAVE_RE = /^(profesional:[A-Za-z0-9_-]{1,40}|financiador:\d{1,12}|rol:(admision|aranceles|facturacion|internacion|personal|honorarios))$/;
|
|
43982
44545
|
var MAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
|
|
43983
44546
|
var COLS_CONTACTO = "id, clave, nombre, mail, whatsapp, activo, updated_at";
|
|
43984
44547
|
function mapContacto(r) {
|
|
43985
|
-
return { id: String(r.id), clave: String(r.clave), nombre: String(r.nombre), mail:
|
|
44548
|
+
return { id: String(r.id), clave: String(r.clave), nombre: String(r.nombre), mail: texto5(r.mail), whatsapp: texto5(r.whatsapp), activo: r.activo !== false, actualizadoEn: iso3(r.updated_at) };
|
|
43986
44549
|
}
|
|
43987
44550
|
async function listarContactos(ctx, companyId) {
|
|
43988
44551
|
const rows = await ctx.db.query(`SELECT ${COLS_CONTACTO} FROM ${t3(ctx, "contacto")} WHERE company_id = $1 ORDER BY nombre ASC`, [companyId]);
|
|
@@ -43996,15 +44559,15 @@ function leerWhatsapp(v) {
|
|
|
43996
44559
|
}
|
|
43997
44560
|
async function guardarContacto(ctx, input2) {
|
|
43998
44561
|
if (input2.actor.tipo !== "humano") throw new OpsError("actor_no_permitido", "los contactos los carga una persona de la instituci\xF3n desde el portal");
|
|
43999
|
-
const clave =
|
|
44562
|
+
const clave = texto5(input2.clave) ?? "";
|
|
44000
44563
|
if (!CLAVE_RE.test(clave)) throw new OpsError("validacion", "clave: tiene que ser profesional:<id>, financiador:<id> o rol:<admision|aranceles|facturacion|internacion|personal>");
|
|
44001
|
-
const mail =
|
|
44564
|
+
const mail = texto5(input2.mail)?.toLowerCase() ?? null;
|
|
44002
44565
|
if (mail && !MAIL_RE.test(mail)) throw new OpsError("validacion", "mail: no tiene formato de correo");
|
|
44003
44566
|
const whatsapp = leerWhatsapp(input2.whatsapp);
|
|
44004
44567
|
const activo = input2.activo !== false;
|
|
44005
44568
|
if (activo && !mail && !whatsapp) throw new OpsError("validacion", "hace falta un mail o un WhatsApp para poder avisar");
|
|
44006
44569
|
const existente = (await ctx.db.query(`SELECT ${COLS_CONTACTO} FROM ${t3(ctx, "contacto")} WHERE company_id = $1 AND clave = $2 LIMIT 1`, [input2.companyId, clave]))[0];
|
|
44007
|
-
const nombre =
|
|
44570
|
+
const nombre = texto5(input2.nombre)?.slice(0, 120) ?? (existente ? String(existente.nombre) : clave.startsWith("rol:") ? ROLES[clave.slice(4)] ?? clave : null);
|
|
44008
44571
|
if (!nombre) throw new OpsError("validacion", "nombre: es obligatorio para un profesional nuevo");
|
|
44009
44572
|
if (existente) {
|
|
44010
44573
|
await ctx.db.execute(
|
|
@@ -44013,12 +44576,12 @@ async function guardarContacto(ctx, input2) {
|
|
|
44013
44576
|
);
|
|
44014
44577
|
return { id: String(existente.id), clave, nombre, mail, whatsapp, activo, actualizadoEn: (/* @__PURE__ */ new Date()).toISOString() };
|
|
44015
44578
|
}
|
|
44016
|
-
const
|
|
44579
|
+
const id2 = randomUUID3();
|
|
44017
44580
|
await ctx.db.execute(
|
|
44018
44581
|
`INSERT INTO ${t3(ctx, "contacto")} (id, company_id, clave, nombre, mail, whatsapp, activo, actor_tipo, actor_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
|
44019
|
-
[
|
|
44582
|
+
[id2, input2.companyId, clave, nombre, mail, whatsapp, activo, input2.actor.tipo, input2.actor.id]
|
|
44020
44583
|
);
|
|
44021
|
-
return { id, clave, nombre, mail, whatsapp, activo, actualizadoEn: (/* @__PURE__ */ new Date()).toISOString() };
|
|
44584
|
+
return { id: id2, clave, nombre, mail, whatsapp, activo, actualizadoEn: (/* @__PURE__ */ new Date()).toISOString() };
|
|
44022
44585
|
}
|
|
44023
44586
|
var COLS_AVISO = "id, clave, nombre, canal, destino, dia, casos, asunto, texto, estado, intentos_envio, error, proveedor_id, enviado_en, created_at";
|
|
44024
44587
|
function mapAviso(r) {
|
|
@@ -44028,14 +44591,14 @@ function mapAviso(r) {
|
|
|
44028
44591
|
nombre: String(r.nombre),
|
|
44029
44592
|
canal: String(r.canal) === "whatsapp" ? "whatsapp" : "mail",
|
|
44030
44593
|
destino: String(r.destino),
|
|
44031
|
-
dia:
|
|
44594
|
+
dia: dia3(r.dia),
|
|
44032
44595
|
casos: lista(r.casos).map((c) => ({ casoId: String(c.casoId), workflow: String(c.workflow), que: String(c.que), intento: Number(c.intento) || 1, ...typeof c.marca === "string" ? { marca: c.marca } : {} })),
|
|
44033
44596
|
asunto: String(r.asunto),
|
|
44034
44597
|
texto: String(r.texto),
|
|
44035
44598
|
estado: ["pendiente", "enviado", "fallido", "cancelado"].includes(String(r.estado)) ? String(r.estado) : "pendiente",
|
|
44036
44599
|
intentosEnvio: Number(r.intentos_envio) || 0,
|
|
44037
|
-
error:
|
|
44038
|
-
proveedorId:
|
|
44600
|
+
error: texto5(r.error),
|
|
44601
|
+
proveedorId: texto5(r.proveedor_id),
|
|
44039
44602
|
enviadoEn: iso3(r.enviado_en),
|
|
44040
44603
|
creadoEn: iso3(r.created_at)
|
|
44041
44604
|
};
|
|
@@ -44079,7 +44642,7 @@ function redactarAviso(nombre, institucion, pendientes) {
|
|
|
44079
44642
|
const repetidos = pendientes.filter((p) => p.intento > 1).length;
|
|
44080
44643
|
const asunto = `${n === 1 ? "1 pendiente" : `${n} pendientes`} para resolver en el HIS \xB7 ${institucion}`;
|
|
44081
44644
|
const lineas = pendientes.map((p) => `- ${p.que}${p.intento > 1 ? " (segundo aviso)" : ""}`);
|
|
44082
|
-
const
|
|
44645
|
+
const texto7 = [
|
|
44083
44646
|
`Hola ${nombre}:`,
|
|
44084
44647
|
"",
|
|
44085
44648
|
`Desde ${institucion}, Autopilot Opera te avisa que ${n === 1 ? "ten\xE9s 1 pendiente" : `ten\xE9s ${n} pendientes`} para resolver en el HIS:`,
|
|
@@ -44090,7 +44653,7 @@ function redactarAviso(nombre, institucion, pendientes) {
|
|
|
44090
44653
|
"",
|
|
44091
44654
|
"Autopilot Opera \xB7 avisos autom\xE1ticos de la administraci\xF3n"
|
|
44092
44655
|
].join("\n");
|
|
44093
|
-
return { asunto, texto:
|
|
44656
|
+
return { asunto, texto: texto7 };
|
|
44094
44657
|
}
|
|
44095
44658
|
async function generarAvisos(ctx, input2) {
|
|
44096
44659
|
const { hoy, hora } = ahoraEnHospital(input2.ahora);
|
|
@@ -44148,12 +44711,12 @@ async function generarAvisos(ctx, input2) {
|
|
|
44148
44711
|
const destino = canal === "mail" ? String(g.contacto.mail) : String(g.contacto.whatsapp);
|
|
44149
44712
|
const { asunto, texto: cuerpo } = redactarAviso(g.contacto.nombre, input2.institucion, g.pendientes);
|
|
44150
44713
|
const casos = g.pendientes.map(({ casoId, workflow, que, intento, marca }) => marca ? { casoId, workflow, que, intento, marca } : { casoId, workflow, que, intento });
|
|
44151
|
-
const
|
|
44714
|
+
const id2 = randomUUID3();
|
|
44152
44715
|
await ctx.db.execute(
|
|
44153
44716
|
`INSERT INTO ${t3(ctx, "aviso")} (id, company_id, clave, nombre, canal, destino, dia, casos, asunto, texto) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10)`,
|
|
44154
|
-
[
|
|
44717
|
+
[id2, input2.companyId, g.contacto.clave, g.contacto.nombre, canal, destino, hoy, JSON.stringify(casos), asunto, cuerpo]
|
|
44155
44718
|
);
|
|
44156
|
-
todos.push({ id, clave: g.contacto.clave, nombre: g.contacto.nombre, canal, destino, dia: hoy, casos, asunto, texto: cuerpo, estado: "pendiente", intentosEnvio: 0, error: null, proveedorId: null, enviadoEn: null, creadoEn: (/* @__PURE__ */ new Date()).toISOString() });
|
|
44719
|
+
todos.push({ id: id2, clave: g.contacto.clave, nombre: g.contacto.nombre, canal, destino, dia: hoy, casos, asunto, texto: cuerpo, estado: "pendiente", intentosEnvio: 0, error: null, proveedorId: null, enviadoEn: null, creadoEn: (/* @__PURE__ */ new Date()).toISOString() });
|
|
44157
44720
|
generados += 1;
|
|
44158
44721
|
}
|
|
44159
44722
|
return { avisos: pendientesHoy(), generados, sinContacto, fueraDeHorario: false };
|
|
@@ -44167,7 +44730,7 @@ async function informarResultadoAviso(ctx, input2) {
|
|
|
44167
44730
|
if (input2.resultado === "enviado") {
|
|
44168
44731
|
await ctx.db.execute(
|
|
44169
44732
|
`UPDATE ${t3(ctx, "aviso")} SET estado = $3, proveedor_id = $4, enviado_en = now(), intentos_envio = intentos_envio + 1, error = NULL, updated_at = now() WHERE company_id = $1 AND id = $2`,
|
|
44170
|
-
[input2.companyId, aviso.id, "enviado",
|
|
44733
|
+
[input2.companyId, aviso.id, "enviado", texto5(input2.proveedorId)]
|
|
44171
44734
|
);
|
|
44172
44735
|
for (const c of aviso.casos) {
|
|
44173
44736
|
await registrarAccion(ctx, {
|
|
@@ -44181,11 +44744,11 @@ async function informarResultadoAviso(ctx, input2) {
|
|
|
44181
44744
|
actor
|
|
44182
44745
|
});
|
|
44183
44746
|
}
|
|
44184
|
-
return { ...aviso, estado: "enviado", proveedorId:
|
|
44747
|
+
return { ...aviso, estado: "enviado", proveedorId: texto5(input2.proveedorId), enviadoEn: (/* @__PURE__ */ new Date()).toISOString(), intentosEnvio: aviso.intentosEnvio + 1, error: null };
|
|
44185
44748
|
}
|
|
44186
44749
|
const intentos = aviso.intentosEnvio + 1;
|
|
44187
44750
|
const estado = intentos >= MAX_INTENTOS_ENVIO ? "fallido" : "pendiente";
|
|
44188
|
-
const error62 =
|
|
44751
|
+
const error62 = texto5(input2.error)?.slice(0, 300) ?? "no se pudo enviar";
|
|
44189
44752
|
await ctx.db.execute(
|
|
44190
44753
|
`UPDATE ${t3(ctx, "aviso")} SET estado = $3, error = $4, intentos_envio = $5, updated_at = now() WHERE company_id = $1 AND id = $2`,
|
|
44191
44754
|
[input2.companyId, aviso.id, estado, error62, intentos]
|
|
@@ -44233,8 +44796,8 @@ var METRICAS = [
|
|
|
44233
44796
|
{ id: "monto_pendiente_de_facturar", version: 1, estado: "validada", nombre: "Monto pendiente de facturar", unidad: "$", definicion: "Importe de los bonos pendientes de facturar del per\xEDodo, por fecha de la prestaci\xF3n." },
|
|
44234
44797
|
{ id: "debitos_financiador", version: 1, estado: "a_definir", nombre: "D\xE9bitos de financiadores", unidad: "$", definicion: "No se puede calcular desde Alephoo: una nota de cr\xE9dito puede responder a un d\xE9bito del financiador o a un error de facturaci\xF3n, y Alephoo no guarda cu\xE1l es (Federico Calle, 15/10/2026). Los tableros muestran \xABnotas de cr\xE9dito\xBB, que s\xED es certificada; este n\xFAmero no se publica como oficial." }
|
|
44235
44798
|
];
|
|
44236
|
-
function metricaPorId(
|
|
44237
|
-
return METRICAS.find((m) => m.id ===
|
|
44799
|
+
function metricaPorId(id2) {
|
|
44800
|
+
return METRICAS.find((m) => m.id === id2) ?? null;
|
|
44238
44801
|
}
|
|
44239
44802
|
|
|
44240
44803
|
// src/tableros.ts
|
|
@@ -44262,7 +44825,7 @@ function arr(v) {
|
|
|
44262
44825
|
}
|
|
44263
44826
|
return [];
|
|
44264
44827
|
}
|
|
44265
|
-
function
|
|
44828
|
+
function texto6(v, max, campo, problemas, obligatorio = false) {
|
|
44266
44829
|
if (v === void 0 || v === null || v === "") {
|
|
44267
44830
|
if (obligatorio) problemas.push(`${campo} es obligatorio`);
|
|
44268
44831
|
return void 0;
|
|
@@ -44312,17 +44875,17 @@ function leerCalculo(v, ref, problemas) {
|
|
|
44312
44875
|
const metricas = [];
|
|
44313
44876
|
lista2.slice(0, 12).forEach((m, j) => {
|
|
44314
44877
|
const mo = m && typeof m === "object" ? m : {};
|
|
44315
|
-
const
|
|
44878
|
+
const id2 = typeof mo.id === "string" ? mo.id : "";
|
|
44316
44879
|
const version2 = Number(mo.version);
|
|
44317
|
-
const def2 = metricaPorId(
|
|
44880
|
+
const def2 = metricaPorId(id2);
|
|
44318
44881
|
if (!def2) {
|
|
44319
|
-
problemas.push(`${ref}.calculo.metricas[${j}]: \xAB${
|
|
44882
|
+
problemas.push(`${ref}.calculo.metricas[${j}]: \xAB${id2}\xBB no est\xE1 en el cat\xE1logo de m\xE9tricas; un n\xFAmero fuera del cat\xE1logo se publica sin calculo (queda como exploratorio)`);
|
|
44320
44883
|
return;
|
|
44321
44884
|
}
|
|
44322
|
-
if (def2.version !== version2) problemas.push(`${ref}.calculo.metricas[${j}]: \xAB${
|
|
44323
|
-
if (def2.estado === "a_definir") problemas.push(`${ref}.calculo.metricas[${j}]: \xAB${
|
|
44885
|
+
if (def2.version !== version2) problemas.push(`${ref}.calculo.metricas[${j}]: \xAB${id2}\xBB versi\xF3n ${Number.isFinite(version2) ? version2 : "?"} no es la vigente (${def2.version}): recalcular con calcular.mjs`);
|
|
44886
|
+
if (def2.estado === "a_definir") problemas.push(`${ref}.calculo.metricas[${j}]: \xAB${id2}\xBB todav\xEDa no tiene definici\xF3n aprobada y no se publica como n\xFAmero oficial`);
|
|
44324
44887
|
if (def2.estado === "propuesta") propuesta = true;
|
|
44325
|
-
metricas.push({ id, version: def2.version });
|
|
44888
|
+
metricas.push({ id: id2, version: def2.version });
|
|
44326
44889
|
});
|
|
44327
44890
|
const huella = typeof o.huella === "string" && /^[0-9a-f]{16}$/.test(o.huella) ? o.huella : "";
|
|
44328
44891
|
if (!huella) problemas.push(`${ref}.calculo.huella falta o no tiene la forma de calcular.mjs (16 caracteres hexadecimales)`);
|
|
@@ -44373,24 +44936,24 @@ function validarWidgets(entrada) {
|
|
|
44373
44936
|
const a = ancho(o.ancho);
|
|
44374
44937
|
switch (tipo) {
|
|
44375
44938
|
case "indicador": {
|
|
44376
|
-
const etiqueta =
|
|
44377
|
-
const valor = typeof o.valor === "number" && Number.isFinite(o.valor) ? o.valor :
|
|
44939
|
+
const etiqueta = texto6(o.etiqueta, 80, `${ref}.etiqueta`, problemas, true) ?? "";
|
|
44940
|
+
const valor = typeof o.valor === "number" && Number.isFinite(o.valor) ? o.valor : texto6(o.valor, 40, `${ref}.valor`, problemas, true) ?? "";
|
|
44378
44941
|
const tono = typeof o.tono === "string" && TONOS.includes(o.tono) ? o.tono : void 0;
|
|
44379
44942
|
if (o.tono !== void 0 && !tono) problemas.push(`${ref}.tono debe ser uno de ${TONOS.join(", ")}`);
|
|
44380
|
-
const unidad =
|
|
44943
|
+
const unidad = texto6(o.unidad, 16, `${ref}.unidad`, problemas);
|
|
44381
44944
|
if (unidad === "%" && !ES_VARIACION.test(etiqueta)) controlarPorcentaje(valor, `${ref}.valor`, problemas);
|
|
44382
44945
|
const { calculo, origen } = leerCalculo(o.calculo, ref, problemas);
|
|
44383
|
-
salida.push({ tipo, etiqueta, valor, unidad, contexto:
|
|
44946
|
+
salida.push({ tipo, etiqueta, valor, unidad, contexto: texto6(o.contexto, 160, `${ref}.contexto`, problemas), tono, ancho: a, ...calculo ? { calculo } : {}, origen });
|
|
44384
44947
|
break;
|
|
44385
44948
|
}
|
|
44386
44949
|
case "barras": {
|
|
44387
|
-
const titulo =
|
|
44950
|
+
const titulo = texto6(o.titulo, 120, `${ref}.titulo`, problemas, true) ?? "";
|
|
44388
44951
|
const series = arr(o.series);
|
|
44389
44952
|
if (series.length === 0 || series.length > 40) problemas.push(`${ref}.series debe tener entre 1 y 40 barras`);
|
|
44390
|
-
const unidad =
|
|
44953
|
+
const unidad = texto6(o.unidad, 16, `${ref}.unidad`, problemas);
|
|
44391
44954
|
const barras = series.slice(0, 40).map((s, j) => {
|
|
44392
44955
|
const so = s && typeof s === "object" ? s : {};
|
|
44393
|
-
return { etiqueta:
|
|
44956
|
+
return { etiqueta: texto6(so.etiqueta, 60, `${ref}.series[${j}].etiqueta`, problemas, true) ?? "", valor: numero2(so.valor, `${ref}.series[${j}].valor`, problemas) };
|
|
44394
44957
|
});
|
|
44395
44958
|
if (unidad === "%" && !ES_VARIACION.test(titulo)) barras.forEach((b, j) => controlarPorcentaje(b.valor, `${ref}.series[${j}].valor`, problemas));
|
|
44396
44959
|
const { calculo, origen } = leerCalculo(o.calculo, ref, problemas);
|
|
@@ -44398,13 +44961,13 @@ function validarWidgets(entrada) {
|
|
|
44398
44961
|
break;
|
|
44399
44962
|
}
|
|
44400
44963
|
case "linea": {
|
|
44401
|
-
const titulo =
|
|
44964
|
+
const titulo = texto6(o.titulo, 120, `${ref}.titulo`, problemas, true) ?? "";
|
|
44402
44965
|
const puntos = arr(o.puntos);
|
|
44403
44966
|
if (puntos.length === 0 || puntos.length > 400) problemas.push(`${ref}.puntos debe tener entre 1 y 400 puntos`);
|
|
44404
|
-
const unidad =
|
|
44967
|
+
const unidad = texto6(o.unidad, 16, `${ref}.unidad`, problemas);
|
|
44405
44968
|
const serie2 = puntos.slice(0, 400).map((p, j) => {
|
|
44406
44969
|
const po = p && typeof p === "object" ? p : {};
|
|
44407
|
-
return { x:
|
|
44970
|
+
return { x: texto6(po.x, 40, `${ref}.puntos[${j}].x`, problemas, true) ?? "", y: numero2(po.y, `${ref}.puntos[${j}].y`, problemas) };
|
|
44408
44971
|
});
|
|
44409
44972
|
if (unidad === "%" && !ES_VARIACION.test(titulo)) serie2.forEach((p, j) => controlarPorcentaje(p.y, `${ref}.puntos[${j}].y`, problemas));
|
|
44410
44973
|
const { calculo, origen } = leerCalculo(o.calculo, ref, problemas);
|
|
@@ -44412,12 +44975,12 @@ function validarWidgets(entrada) {
|
|
|
44412
44975
|
break;
|
|
44413
44976
|
}
|
|
44414
44977
|
case "tabla": {
|
|
44415
|
-
const titulo =
|
|
44978
|
+
const titulo = texto6(o.titulo, 120, `${ref}.titulo`, problemas, true) ?? "";
|
|
44416
44979
|
const columnas = arr(o.columnas);
|
|
44417
44980
|
if (columnas.length === 0 || columnas.length > 12) problemas.push(`${ref}.columnas debe tener entre 1 y 12 columnas`);
|
|
44418
44981
|
const filas = arr(o.filas);
|
|
44419
44982
|
if (filas.length > 200) problemas.push(`${ref}.filas admite hasta 200 filas`);
|
|
44420
|
-
const cols = columnas.slice(0, 12).map((c, j) =>
|
|
44983
|
+
const cols = columnas.slice(0, 12).map((c, j) => texto6(c, 60, `${ref}.columnas[${j}]`, problemas, true) ?? "");
|
|
44421
44984
|
const celdasTabla = filas.slice(0, 200).map((f, j) => {
|
|
44422
44985
|
const celdas = arr(f);
|
|
44423
44986
|
if (celdas.length !== cols.length) problemas.push(`${ref}.filas[${j}] tiene ${celdas.length} celdas y la tabla ${cols.length} columnas`);
|
|
@@ -44433,7 +44996,7 @@ function validarWidgets(entrada) {
|
|
|
44433
44996
|
break;
|
|
44434
44997
|
}
|
|
44435
44998
|
case "texto": {
|
|
44436
|
-
salida.push({ tipo, titulo:
|
|
44999
|
+
salida.push({ tipo, titulo: texto6(o.titulo, 120, `${ref}.titulo`, problemas), texto: texto6(o.texto, 4e3, `${ref}.texto`, problemas, true) ?? "", ancho: a });
|
|
44437
45000
|
break;
|
|
44438
45001
|
}
|
|
44439
45002
|
}
|
|
@@ -44492,15 +45055,15 @@ async function publicarTablero(ctx, input2) {
|
|
|
44492
45055
|
tablero: { ...previo, titulo, descripcion: limpio(input2.descripcion, 600), pedido: limpio(input2.pedido, 1e3) ?? previo.pedido, periodo: limpio(input2.periodo, 80), fuentes, widgets, agenteId: input2.agenteId ?? previo.agenteId, issueId: input2.issueId ?? previo.issueId, publicadoPorTipo: input2.actor.tipo, publicadoPorId: input2.actor.id, versiones: previo.versiones + 1, updatedAt: now }
|
|
44493
45056
|
};
|
|
44494
45057
|
}
|
|
44495
|
-
const
|
|
45058
|
+
const id2 = randomUUID4();
|
|
44496
45059
|
await ctx.db.execute(
|
|
44497
45060
|
`INSERT INTO ${t4(ctx, "tablero")} (id, company_id, clave, titulo, descripcion, pedido, periodo, fuentes, widgets, agente_id, issue_id, publicado_por_tipo, publicado_por_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9::jsonb, $10, $11, $12, $13)`,
|
|
44498
|
-
[
|
|
45061
|
+
[id2, input2.companyId, clave, titulo, limpio(input2.descripcion, 600), limpio(input2.pedido, 1e3), limpio(input2.periodo, 80), JSON.stringify(fuentes), JSON.stringify(widgets), input2.agenteId ?? null, input2.issueId ?? null, input2.actor.tipo, input2.actor.id]
|
|
44499
45062
|
);
|
|
44500
45063
|
await ctx.activity.log({ companyId: input2.companyId, message: `Autopilot Care: tablero \xAB${titulo}\xBB publicado (${clave})`, metadata: { clave, widgets: widgets.length, agentId: input2.agenteId ?? null, issueId: input2.issueId ?? null } });
|
|
44501
45064
|
return {
|
|
44502
45065
|
creado: true,
|
|
44503
|
-
tablero: { id, companyId: input2.companyId, clave, titulo, descripcion: limpio(input2.descripcion, 600), pedido: limpio(input2.pedido, 1e3), periodo: limpio(input2.periodo, 80), fuentes, widgets, agenteId: input2.agenteId ?? null, issueId: input2.issueId ?? null, publicadoPorTipo: input2.actor.tipo, publicadoPorId: input2.actor.id, versiones: 1, createdAt: now, updatedAt: now }
|
|
45066
|
+
tablero: { id: id2, companyId: input2.companyId, clave, titulo, descripcion: limpio(input2.descripcion, 600), pedido: limpio(input2.pedido, 1e3), periodo: limpio(input2.periodo, 80), fuentes, widgets, agenteId: input2.agenteId ?? null, issueId: input2.issueId ?? null, publicadoPorTipo: input2.actor.tipo, publicadoPorId: input2.actor.id, versiones: 1, createdAt: now, updatedAt: now }
|
|
44504
45067
|
};
|
|
44505
45068
|
}
|
|
44506
45069
|
|
|
@@ -44774,7 +45337,7 @@ async function manejarApi(ctx, input2) {
|
|
|
44774
45337
|
return respuesta(200, await transicionar(ctx, { companyId, casoId: input2.params.casoId ?? "", via: "no_corresponde", motivo: motivoConPersona(str3(body.motivo)), datos: conPersona(obj(body.datos)), idempotencyKey: str3(body.idempotencyKey), actor }));
|
|
44775
45338
|
}
|
|
44776
45339
|
case "version":
|
|
44777
|
-
return respuesta(200, { version: manifest_default.version, capacidades: ["carga-manual", "recupero-turnos", "ofrecer-primero", "cuenta-completa", "metricas-certificadas", "facturacion-pendiente", "credenciales", "demanda-pendiente", "reglas", "avisos", "circular-aranceles", "cobranzas", "internaciones"], workflows: listarWorkflows().map((w) => w.clave) });
|
|
45340
|
+
return respuesta(200, { version: manifest_default.version, capacidades: ["carga-manual", "recupero-turnos", "ofrecer-primero", "cuenta-completa", "metricas-certificadas", "facturacion-pendiente", "credenciales", "demanda-pendiente", "reglas", "avisos", "circular-aranceles", "cobranzas", "internaciones", "honorarios"], workflows: listarWorkflows().map((w) => w.clave) });
|
|
44778
45341
|
case "politicas":
|
|
44779
45342
|
return respuesta(200, { politicas: await listarPoliticas(ctx, companyId) });
|
|
44780
45343
|
case "serie":
|
|
@@ -44810,6 +45373,10 @@ async function manejarApi(ctx, input2) {
|
|
|
44810
45373
|
}
|
|
44811
45374
|
case "contacto":
|
|
44812
45375
|
return respuesta(200, await registrarContacto(ctx, { companyId, casoId: input2.params.casoId ?? "", canal: body.canal, respuesta: body.respuesta, comentario: str3(body.comentario), persona: decididoPor, idempotencyKey: str3(body.idempotencyKey), actor }));
|
|
45376
|
+
case "envio-liquidacion": {
|
|
45377
|
+
if (actor.tipo !== "humano") return respuesta(403, { error: "actor_no_permitido", motivo: "el env\xEDo lo registra una persona" });
|
|
45378
|
+
return respuesta(200, await registrarEnvioLiquidacion(ctx, { companyId, casoId: input2.params.casoId ?? "", canal: body.canal, destinatario: str3(body.destinatario), persona: decididoPor, actor }));
|
|
45379
|
+
}
|
|
44813
45380
|
case "respuesta-financiador": {
|
|
44814
45381
|
if (actor.tipo !== "humano") return respuesta(403, { error: "actor_no_permitido", motivo: "la respuesta del financiador la registra una persona" });
|
|
44815
45382
|
if (str3(body.respuesta) === "cerrar") {
|