Synaplan
开源 AI 软件平台,面向企业:自托管 AI 代理,符合 GDPR 的聊天机器人小部件,RAG 知识库,WhatsApp 与 Outlook AI,MCP,多模型路由。支持 Docker、Kubernetes 或在 Germ 托管。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗App de una sola página (index.source.html), instalada como "Aplicación local" en
amsac.bitrix24.es, igual que amsac-transporte-bitrix24. La identidad, permisos y
listado de empleados/departamentos vienen del contexto de sesión de Bitrix24
(BX24.js); los datos de los gastos se guardan en el mismo proyecto Supabase
que ya usa la app de transporte, en tablas nuevas y separadas (gastos_*).
Toda la app tiene dos modos, según el ancho de pantalla (punto de corte: 900px, el mismo donde el menú lateral pasa de fijo a hamburguesa):
Fondo/Área solicitante, Descripción/
Justificación, etc.) para no obligar a hacer scroll vertical
innecesario.Este comportamiento es puramente CSS (clase .row y el ancho de .wrap
según media query) — no depende de detectar el dispositivo, así que
también se adapta si alguien cambia el tamaño de la ventana en escritorio.
Un administrador del portal ve y puede hacer todo. Para el resto de usuarios, el acceso a cada pantalla depende de a cuál de estos grupos pertenezcan:
Estos grupos son independientes entre sí: un usuario puede pertenecer a ninguno, a uno o a varios a la vez (además de ser o no administrador del portal, que da acceso a todo sin excepción).
El menú "Solicitud" agrupa cinco pantallas (se puede colapsar/expandir haciendo clic en su encabezado):
BITRIX24_WEBHOOK_URL está configurada) con dos enlaces, "✅
Autorizar" y "❌ Denegar", que la llevan directo a esta pantalla ya
abierta en esa solicitud — y si entró justo desde uno de esos
enlaces, el cuadro de confirmación de esa decisión ya aparece armado,
solo falta confirmarlo. Además de por notificación, esta pantalla
también se usa entrando normalmente por el menú: tabla con las
solicitudes donde esa persona es
la gerencia responsable (un administrador ve las de todos). "Ver
detalle" muestra la misma información completa que Desembolso de
fondos (área, descripción, justificación, ítems, cotización, monto
solicitado). Mientras la solicitud está aparecen los
botones y : autorizarla la deja lista
para que un certificador la certifique; denegarla la archiva en
estado (guarda quién y cuándo decidió) y ahí termina su
proceso — no se puede editar, eliminar, certificar ni continuar de
ninguna forma. Una solicitud ya autorizada, certificada, desembolsada,
facturada, denegada o eliminada no muestra estos botones (ya se
decidió o ya avanzó). El servidor exige que quien autorice o deniegue
sea justo la gerencia responsable asignada a esa solicitud (o un
administrador), no solo la pantalla.amsac-transporte-bitrix24.schema.sql.
Crea gastos_registros, gastos_historial, gastos_fondos,
gastos_fondo_usuarios, gastos_solicitudes, gastos_tesoreria y
gastos_gestiones; no toca ninguna tabla transporte_*. El script es
seguro de volver a correr aunque las tablas ya existan (usa if not exists / migraciones idempotentes), por ejemplo para agregar la columna
estado, solicitud_id, numero_comprobante_retencion,
jefatura_solicitante, gerencia_responsable_unidad o gestion_id.cotizaciones (mismo bucket para ambas). No hace falta
crearlo a mano: api/upload.js lo crea automáticamente (público, solo
PDF, 3 MB máx. por archivo) la primera vez que alguien adjunta un
archivo. Si prefieres crearlo tú antes, ve a Storage → New bucket en
el panel de Supabase, nómbralo cotizaciones y márcalo como público.Mismas credenciales que ya usa el proyecto de transporte (mismo proyecto Supabase):
SUPABASE_URLSUPABASE_SECRET (service role key — solo se usa en las funciones api/*.js, nunca en el navegador)BITRIX24_WEBHOOK_URL: webhook entrante de Bitrix24 con scopes im y
disk (ver "Instalación en Bitrix24" para cómo crearlo). Con solo
im (opcional) la app funciona igual salvo por el aviso a la gerencia
responsable, que simplemente no se envía. disk es obligatorio desde
que existe "Confirmar revisado" en Certificación presupuestaria →
"Revisión de reintegros y liquidaciones": esa acción sube el comprobante PDF
a Bitrix24 Disk como paso obligatorio (no best-effort, ver "Notas
técnicas") — sin ese scope, "Confirmar revisado" falla con un error
claro en vez de completarse a medias.BITRIX24_APP_URL (opcional): la URL con la que Bitrix24 abre esta app
embebida dentro del portal — se ve en la barra de direcciones al abrir la
app desde el menú de aplicaciones, tiene la forma
https://<tu-portal>.bitrix24.es/marketplace/app/<id>/. Se usa para que
los enlaces "Autorizar"/"Denegar" de la notificación reabran la app
autenticada dentro de Bitrix24, en vez de como una pestaña suelta del
navegador (donde BX24.init() no puede autenticar y la app se queda
cargando para siempre). Si no se configura, esos enlaces usan la URL
directa de la app (https://<host>/index.html) — funciona solo si ya hay
una sesión de Bitrix24 activa en el mismo navegador al hacer clic.index.source.html es el archivo fuente editable. api/handler.js es un
archivo generado: sirve el HTML como string desde una función serverless. Tras
editar index.source.html, regenera handler.js con:
node build.js
No edites api/handler.js directamente; los cambios se perderían en el próximo build.
Igual que transporte: conectar la carpeta a un proyecto Vercel (vercel.json ya
trae el rewrite /index.html → /api/handler) y configurar las variables de
entorno anteriores.
https://<tu-proyecto>.vercel.app/index.html).Gastos de Baja Cuantía.user (para user.current, user.admin,
user.get, department.get) — no necesita calendar como transporte.im (busca "im" y elige la opción cuyo código sea exactamente
(im), por ejemplo "Chat y Notificaciones (im)" — no
messageservice, im.import ni imconnector, que son otra cosa) —
opcional, habilita el aviso a la gerencia responsable y al
administrador de fondo.disk (busca "disk" o "Bitrix24.Disk" y elige esa opción) —
obligatorio, es donde se guardan los comprobantes PDF de
"Confirmar revisado" (ver "Notas técnicas").
Guarda. Copia la URL generada (tiene la forma
https://<tu-portal>.bitrix24.es/rest/<id>/<código>/) y agrégala como
BITRIX24_WEBHOOK_URL en las variables de entorno de Vercel (sección
anterior). Las notificaciones y los archivos quedan como si los enviara/
subiera el usuario dueño del webhook — por eso los comprobantes de
todos los administradores de fondo terminan en subcarpetas dentro del
Disk de esa misma cuenta (ver "Notas técnicas"), no en el Disk personal
de cada uno.https://<tu-portal>.bitrix24.es/marketplace/app/<id>/) y agrégala como
BITRIX24_APP_URL en Vercel.actor_id, actor_is_admin)
llega desde el navegador en cada llamada a /api/gastos, igual modelo de
confianza que transporte_* (herramienta interna, no expuesta al público).WORK_POSITION y UF_DEPARTMENT de
user.get/department.get de Bitrix24, no se guardan en la tabla de gastos.jefatura_solicitante,
gerencia_responsable_unidad y gerencia_responsable_id/nombre se
calculan en el navegador (resolverResponsables) con los departamentos y
el jefe (UF_HEAD) de cada uno, en Crear Solicitud:
gerencia_responsable_nombre).xlsx.full.min.js por CDN)
en el navegador; PDF usa jsPDF + jspdf-autotable, igual que en
transporte. El PDF de Desembolso además usa pdf-lib (CDN) para anexarle
las cotizaciones adjuntas como páginas extra.api/upload.js las sube a Supabase Storage (bucket
cotizaciones, público) usando la service role key; el navegador nunca
ve esa key, solo manda el PDF en base64 a este endpoint. Al ser un bucket
público, cualquiera con el enlace exacto (una URL larga con un sufijo
aleatorio) puede abrir el archivo — igual de "protegido por oscuridad"
que el resto de esta herramienta interna, no es un control de acceso
real. Límite de 3 MB por archivo (margen para el límite de payload de
las funciones de Vercel); se puede subir más de un PDF por solicitud.
Es obligatorio al una solicitud (al menos un PDF); al
(Certificación presupuestaria) no se vuelve a exigir,
para no bloquear solicitudes creadas antes de que este campo existiera
— ese formulario solo las conserva de solo lectura, no ofrece forma de
agregarlas.Desde esta versión, certificar una solicitud depende de lo aprobado por el
Departamento de Presupuesto para baja cuantía en el sistema Presupuesto
2027 (D:\Presupuesto inventario 2027\sistema). Ambos sistemas usan el
mismo proyecto Supabase; esta app solo lee el esquema presupuesto
(bc_presupuestos / bc_items) a través de api/presupuesto.js — no copia
ni duplica montos, no necesita variables de entorno nuevas ni migraciones.
Todo aumento, disminución, específico agregado o quitado lo hace Presupuesto
desde su sistema y se refleja aquí al instante.
Reglas (las aplica el servidor en action=update de api/solicitudes.js,
no solo la pantalla):
gastos_fondos.anio). Para usar 2028
basta crear el fondo 2028 aquí y que Presupuesto cargue/apruebe el 2028
allá. Si Presupuesto todavía no tiene ningún presupuesto de baja
cuantía de ese año (hoy el fondo 2026), no se aplica control.caja_chica; Fondo circulante → fondo_circulante
más fondo_flotas si esa unidad lo tiene (Monitoreo y Mantenimiento de
Flotas).En el formulario de Certificación aparece el panel "Disponibilidad presupuestaria" (aprobado, ya comprometido, disponible y lo que pide esta solicitud, resaltando en rojo lo que excede).
pendiente.revisado.entregado. Se avisa
al administrador.cerrado.
Mientras no confirme no puede usar ese fondo (el servidor bloquea crear
solicitudes, desembolsar y registrar gastos con ese fondo); al confirmar
puede iniciar un nuevo ciclo. Aplica a fondo circulante y caja chica.
(Las liquidaciones no pasan por entregado: Tesorería las cierra.)Fuente: Reglamento para la Administración de los Fondos para las Compras de
Baja Cuantía y Compras en Línea (Decreto 3/2025, Concejo Municipal de Santa
Ana Centro). Las reglas las valida el servidor (api/gestiones.js,
acción crear), no solo la pantalla.
gastos_fondos.monto_total, variable por fondo; el reglamento fija hasta
$300,000 en circulante y $24,000 en caja chica). La referencia mensual es
ese monto entre 12, con redondeo acumulado en centavos para que los 12
meses sumen exactamente el total anual (sin descuadres).documento_fisico_* de
gastos_registros, migración migracion-documento-fisico.sql). Solo lo
puede marcar el administrador del fondo (o un administrador del portal
verificado contra Bitrix24) y solo mientras el gasto siga "registrado". Los
gastos anteriores a esta regla quedan como "pendiente de recibir".Ningún número del reglamento está escrito en el código: todos viven en la
tabla gastos_reglas y se cambian desde el menú Consulta y administración →
Reglas de fondos (solo administrador del portal, verificado contra
Bitrix24). Si el reglamento se reforma, basta con editar ahí; los cambios se
aplican de inmediato a nuevas solicitudes, desembolsos y reintegros (el
servidor guarda los valores en memoria hasta 15 s) y cada cambio queda en un
historial (quién, cuándo, valor anterior → nuevo). Hay un bloque por tipo
de fondo (circulante y caja chica) más el salario mínimo de referencia.
| Parámetro (por tipo de fondo) | Qué controla |
|---|---|
| El solicitante es siempre el administrador del fondo | todos los usuarios asignados quedan como administradores y solo ellos pueden crear solicitudes |
| Exigir autorización de la gerencia responsable | si no, la solicitud nace autorizada y pasa directo a Presupuesto |
| Monto máximo anual | tope al crear o editar un fondo de ese tipo (0 = sin tope) |
| Límite de compra ordinaria | lo que lo supera es compra excepcional |
| Formas de pago permitidas | efectivo / transferencia / cheque |
| Efectivo: máximo por compra | tope por compra en efectivo (0 = sin tope) |
| Parte del fondo en efectivo (%) | el resto queda en banco; se ajusta solo a 100% si solo hay efectivo y a 0% si no se permite efectivo |
| Permitir compras excepcionales | si no, toda compra sobre el límite se rechaza |
| Exigir acuerdo administrativo (PDF) | para compras excepcionales |
| Máximo excepcional (salarios mínimos) | × salario mínimo de referencia (0 = sin tope) |
| Tope de lo excepcional (% de la referencia mensual) | una sola compra excepcional o varias no pueden sumar más; 0 = sin tope |
| Contar el tope por ciclo | si está activo (por defecto) el tope rige por ciclo del fondo, hasta que Tesorería entrega el reintegro; si no, por mes calendario |
| Margen de las facturas sobre lo autorizado (%) | las facturas de una solicitud no pueden sumar más que su monto (0 = exacto) |
| Retener IVA y exigir comprobante de retención | antes del desembolso de toda compra que llegue al mínimo (ordinaria o excepcional); activo en ambos tipos de fondo |
| Porcentaje a retener | 1%, sobre el valor sin IVA |
| Valor mínimo para retener (sin IVA) | $100 |
| IVA (%) (parámetros generales) | 13; los montos de las solicitudes incluyen IVA y con esto se separa |
| % de la referencia para poder pedir reintegro | umbral del reintegro |
| Permitir reintegro al cierre del mes | aunque no se llegue al % |
| Exigir documento físico recibido | para incluir un gasto en un reintegro |
"Cargar valores iniciales" vuelve a poner en el formulario los valores del
reglamento de 2025 (sin guardar hasta pulsar "Guardar reglas"). Los valores
iniciales están también en api/gestiones.js (DEFAULTS) y sirven de respaldo
si la tabla no se puede leer. Migración: migracion-reglas-parametros.sql.
API: GET fondos?action=reglas y POST fondos con action=guardar_reglas.
Reglamento Art. 19: el solicitante tiene 3 días hábiles para presentar la
factura o documento equivalente. Se controla así (módulo api/plazos.js,
tabla gastos_plazos, migración migracion-plazos-comprobantes.sql):
vercel.json → crons: 14:00 UTC = 8:00 a. m.
hora de El Salvador, GET /api/plazos). Si defines la variable
CRON_SECRET en Vercel, solo Vercel puede invocarla. Un administrador del
portal también puede pulsar "Enviar recordatorios ahora" en la pantalla
de cumplimiento.calendar.settings.get con el webhook BITRIX24_WEBHOOK_URL, alcance
calendar), así el plazo usa los mismos feriados que el resto de la empresa:
En caja chica el solicitante y el administrador del fondo son siempre la
misma persona y la solicitud no necesita autorización de gerencia
(parámetros solicitanteEsAdministrador y exigeAutorizacionGerencia de
"Reglas de fondos"; en circulante siguen como antes). Consecuencias, todas
validadas en el servidor:
fondos → asignar): todos los usuarios que se asignan a una
caja chica quedan como administradores del fondo (aunque se marque lo
contrario).gerencia_decision_por_nombre = "No requiere autorización de gerencia"),
no se notifica a ninguna gerencia y no se exige gerente responsable: de
Bitrix24 solo se necesita el área del usuario. Pasa directo a
Certificación presupuestaria (Presupuesto), luego Desembolso.reintegroExigeDocumento queda
en "No" y no se muestra la marca de documento recibido.Los valores de la tabla de abajo son los iniciales (reglamento de 2025); los vigentes son los que estén en "Reglas de fondos".
Las valida el servidor (api/gestiones.js: evaluarCuantia y
calcularSaldoFondo) al crear la solicitud, al certificarla si cambian
los montos y al desembolsar. La pantalla de Crear Solicitud avisa en vivo,
pero no es la que decide. Migración: migracion-limites-excepcionales.sql.
| Fondo circulante | Caja chica | |
|---|---|---|
| Compra ordinaria (Art. 6) | hasta $1,000 | hasta $100 |
| Forma de pago | efectivo solo hasta $500 por compra (Art. 11); transferencia o cheque sin tope | solo efectivo (Art. 12) |
| Reparto del fondo | 40% efectivo / 60% banco de la referencia mensual | 100% efectivo |
| Compra excepcional (supera el límite ordinario) | exige el acuerdo administrativo del Alcalde Municipal en PDF (Art. 7); máximo 20 salarios mínimos de comercio y servicios; lo excepcional de cada ciclo no pasa del 50% de la referencia mensual | sin acuerdo; lo excepcional de cada ciclo no pasa del 50% de la referencia mensual (Art. 8) y exige comprobante de retención tramitado con Tesorería antes de la compra |
GET fondos?action=saldo&fondoId=).excepcional.Estados de gastos_gestiones: pendiente → revisado → (entregado) →
cerrado. Columnas nuevas (migración migracion-reintegro-v2.sql):
fecha_desde, fecha_hasta, cuenta_bancaria, acuerdo_*,
comprobante_*, tesoreria_*. Acciones de api/gestiones.js: crear,
revisar, registrar_tesoreria, confirmar y cerrar (esta última solo
para liquidaciones).
BX24.getAuth()), se lo pregunta a Bitrix24 (método profile) y solo
acepta si el ID coincide y ADMIN es verdadero.gastos_gestiones) creadas desde "Solicitud de reintegro o liquidación" que siguen
pendiente de revisión, cada una con sus gastos agrupados (mismo
fondo, mismo mes, mismo tipo — Reintegro o Liquidación). Cada gasto
tiene un botón "Editar" (mismo formulario de "Registrar factura",
por si hace falta corregir algo antes de cerrar la gestión) y cada
gestión tiene un botón "Confirmar revisado": genera un
comprobante en PDF (con fecha y hora de generación, nombrado con
el administrador del fondo, el mes y la fecha), lo sube a una carpeta
de Bitrix24 Disk y le avisa por Messenger al administrador del
fondo que ya puede imprimirlo y pedir el trámite en Tesorería (ver
"Notas técnicas" para el detalle técnico de la subida a Disk).registrado.Un gasto ya registrado se edita desde Historial o Informe de
Gastos (solo quien lo creó, mientras esté en estado registrado, o un
administrador en cualquier estado); el formulario de edición muestra de
solo lectura a qué solicitud e ítem pertenece (eso no cambia, solo se
corrige fecha/documento/proveedor/montos). El N° de comprobante de
retención y los PDF de factura adjuntos no tienen campo en este
formulario reducido, así que se conservan tal cual quedaron al
registrarse. Eliminar es un borrado
lógico: el gasto no se borra de la base de datos, pasa a estado
eliminado (guardando el estado anterior) y deja de ser visible para
todos salvo un administrador. Un gasto informado solo puede
editarse/eliminarse por un administrador.
Historial: lista de gastos (los administradores ven todos, solo los
propios, o los eliminados; el resto de usuarios autorizados solo ve los
suyos, nunca los eliminados). Desde la vista "Eliminados" (solo admin) se
puede restablecer un gasto a su estado anterior (registrado o
informado).
Solicitud de reintegro o liquidación (acceso: administradores de fondo y del portal, ver
"Modelo de permisos"): el administrador elige Fondo y un rango de
fechas Desde / Hasta, y ve los gastos con factura o documento
equivalente registrado en ese rango (estado registrado, de ese fondo,
sin importar quién los registró). Todos vienen marcados: marca o
desmarca los que quiere reintegrar o liquidar (hay "Seleccionar todos"
y un resumen con la cantidad y el total). En el fondo circulante además
indica la cuenta bancaria (banco y número) donde Tesorería hará la
transferencia. "Gestionar Reembolso o liquidación" pregunta si es
Reintegro o Liquidación (queda guardado) y crea la gestión con
solo los gastos marcados, que pasan a informado. Un administrador
del portal puede elegir de qué administrador de fondo ver la
información. Arriba aparece un aviso si tiene un reintegro de caja chica
por confirmar (ver "Reintegro de fondos").
Reportes (una sola pantalla que reemplaza al antiguo "Dashboard" y al antiguo "Reportes"; disponible para todo usuario habilitado). Una barra de filtros compartida (Tipo de fondo, Año del fondo, Estado, Usuario, Cargo, Unidad, Fecha desde/hasta; Cargo y Unidad salen de Bitrix24) alimenta dos pestañas, con una sola carga de datos:
fondo_id) de cada
gasto, más totales por fondo y tarjetas de resumen. Botón "Descargar
resumen (PDF)" si hay algún monto informado.Visibilidad (verificada en el servidor, acción reporte de
api/gastos.js, no en el navegador): el administrador del portal ve
todo (se verifica con su token de sesión de Bitrix24); un administrador de
fondo ve los gastos de sus fondos más los suyos; cualquier otro usuario ve
solo los gastos que él registró. En el resumen, además, solo se listan los
fondos y usuarios que le corresponden. La pantalla indica el alcance
vigente bajo el título. Los datos se recalculan al abrir la pestaña o al
pulsar "Actualizar datos".
El menú "Dashboard" desapareció: ahora es la pestaña "Resumen por fondo".
Tesorería (acceso: personal del Departamento de Tesorería, ver "Modelo de permisos"): menú con "Reintegro de fondos" y "Liquidación de Fondos". Solo aparece lo que Presupuesto ya autorizó.
comprobantes de
Supabase Storage (se crea solo, PDF + JPG/PNG/WEBP).Configurar usuarios (solo administradores): tiene tres partes.
gastos_certificadores quedó sin uso).gastos_tesoreria quedó sin uso).
Ya no se usa app.option para nada de esto — todo se deriva de
gastos_fondo_usuarios (con su columna es_administrador),
gastos_certificadores y gastos_tesoreria, guardadas en Supabase.fondo_id: cada gasto guarda a qué fondo específico pertenece (columna
fondo_id en gastos_registros). Los gastos creados antes de que
existiera esta columna quedan con fondo_id vacío; en ese caso el Dashboard y
el "Fondo" mostrado en Historial/Informe/Reportes recurren como respaldo a
los fondos del usuario que lo registró, y solo lo resuelven sin ambigüedad si
ese usuario pertenece a un único fondo.solicitud_id: desde que existe "Crear Solicitud", cada gasto se crea
eligiendo una solicitud (gastos_solicitudes) y el servidor copia de ahí
fondo_id, area_solicitante, nombre_proceso, descripcion y
justificacion hacia la fila del gasto — nunca se confía en esos valores si los manda el navegador. Por
eso Historial, Solicitud de reintegro o liquidación, Reportes y las exportaciones no cambiaron:
siguen leyendo esos campos directo del gasto. Editar un gasto (incluidos los
creados antes de que existiera este flujo) exige elegir una solicitud, igual
como ya exigía elegir un fondo antes de este cambio.item_numero: "Registrar factura o documento equivalente" guarda una
factura por ítem de la solicitud (no una por toda la solicitud), así
que cada gasto creado desde ahí queda enlazado al numero del ítem dentro
de gastos_solicitudes.items (jsonb). El servidor exige que ese ítem
exista en la solicitud y que la solicitud esté en estado desembolsado o
facturado antes de aceptar la factura (facturado se acepta para poder
corregir una factura ya registrada aun cuando la solicitud ya esté
completa). Los gastos creados antes de este cambio (o antes de que
existiera "Registrar factura") quedan con item_numero vacío.pendiente (recién creada, a la
espera de que su gerencia responsable decida) → autorizada (la
gerencia responsable la aprueba desde "Autorización de gerencia") o
denegado (la rechaza; queda archivada ahí, fin del proceso) →
certificado (solo una solicitud autorizada se puede certificar; al
guardar cambios en Certificación presupuestaria, con Específico
Presupuestario/CEP completos) → desembolsado (al presionar
"Desembolsar" en Desembolso de fondos, lo único que habilita "Registrar
factura" para esa solicitud) → facturado (automático: api/gastos.js
recalcula tras cada alta/edición/borrado/restauración de un gasto con
item_numero si TODOS los ítems de la solicitud tienen ya una factura
activa; si se elimina la de algún ítem, vuelve solo a desembolsado,
nunca hace falta tocarlo a mano). eliminada es un borrado lógico
posible desde pendiente, autorizada o certificado; una solicitud
desembolsada, facturada o denegada ya no se puede editar ni
eliminar. desembolsado_at, desembolsado_por_id y
desembolsado_por_nombre quedan guardados para trazabilidad y se usan
en el PDF del comprobante; gerencia_decision_at,
gerencia_decision_por_id y gerencia_decision_por_nombre guardan
quién autorizó o denegó y cuándo.gastos_fondo_usuarios.es_administrador y
gastos_certificadores): ver "Modelo de permisos" más arriba. Las
acciones desembolsar, autorizar y denegar en api/solicitudes.js
validan en el servidor (no solo en la pantalla) que quien las invoca sea
administrador del portal, administrador del fondo de esa solicitud
específica (para desembolsar), o justo la gerencia responsable asignada
a esa solicitud (para autorizar/denegar) — así que ni siquiera llamando
directo a la API se puede saltar esas restricciones. action=update
(certificar) también valida en el servidor que la solicitud esté
autorizada o ya certificado antes de aceptar el cambio. Crear
Solicitud no tiene ese refuerzo (mismo modelo de confianza que el resto
de la app, ver el primer punto de esta sección); estas otras acciones sí
lo tienen por mover fondos reales o decidir el rumbo del proceso.numero_comprobante_retencion / factura_urls: campos opcionales de
"Registrar factura o documento equivalente", uno por ítem/gasto. El
comprobante es texto libre; factura_urls es un array {url, nombre}
igual que cotizacion_urls, subido con el mismo api/upload.js al mismo
bucket cotizaciones. Al editar un gasto desde Historial (formulario
reducido, sin estos campos) el servidor exige que el navegador reenvíe
ambos valores sin cambios para no perderlos — el frontend los captura al
cargar el formulario y los reenvía tal cual.create en api/solicitudes.js), si BITRIX24_WEBHOOK_URL está
configurada, el servidor llama a im.notify.system.add de Bitrix24 (best
effort — si falla o no está configurada, no bloquea la creación) con un
mensaje en BBCode que incluye [URL=...]Autorizar[/URL] y
[URL=...]Denegar[/URL] apuntando a BITRIX24_APP_URL (o, si no está
configurada, a la URL directa de esta app deducida de los headers de la
petición) con ?solicitud=<id>&accion=autorizar|denegar agregado.
im.notify/im.notify.system.add no admiten autorización por sesión
(BX24.callMethod desde el navegador) — devuelven WRONG_AUTH_TYPE — por
eso este aviso solo puede enviarse desde el servidor con un webhook, y el
webhook necesita el scope im específicamente (con otro scope,
Bitrix24 responde 401 insufficient_scope). Al abrir ese enlace, el
frontend (manejarDeepLinkAutorizacion en index.source.html) lee
?solicitud=/?accion=. Bitrix24 embebe la app en un <iframe> con su
propio src fijo (la URL "Handler" configurada al instalar la app), sin
reenviarle el query string del enlace de la notificación — ese
?solicitud=&accion= se queda en la URL de la pestaña/página que
contiene el iframe, no en la del iframe mismo, así que
window.location.search llega vacío. Por eso primero se intenta ahí y,
si viene vacío, se cae de vuelta a document.referrer (que sí conserva
la URL completa de la página que embebió el iframe, confirmado con una
prueba con un iframe real). Una vez leídos, limpia la barra de
direcciones, abre "Autorización de gerencia" directo en esa solicitud y,
si la acción es autorizar/denegar y sigue pendiente, deja el modal de
confirmación ya abierto. Esto solo funciona si el enlace abre la app embebida dentro de
Bitrix24 (autenticada vía BX24.js) — de ahí BITRIX24_APP_URL
apuntando a la URL tipo marketplace/app/<id>/ con la que Bitrix24 abre
la app desde su propio menú; sin esa variable, o si el enlace igual abre
una pestaña suelta del navegador fuera de Bitrix24, BX24.init() nunca
logra autenticar y la app se queda cargando — por eso hay además un
timeout de 6 segundos que reemplaza el "Cargando..." por un mensaje
explicando que hay que entrar desde el menú de aplicaciones de Bitrix24 y
buscar "Autorización de gerencia" ahí.gastos_gestiones, api/gestiones.js):
agrupa los gastos registrado de un fondo, un mes y un tipo
(Reintegro o Liquidación) en una sola fila, y pasa todos esos gastos a
informado marcados con gestion_id. Flujo de estados: pendiente
(recién creada desde Solicitud de reintegro o liquidación) → revisado (un certificador
confirma en "Revisión de reintegros y liquidaciones"; genera y sube el PDF) →
cerrado (Tesorería confirma el reintegro emitido o acepta la
liquidación). action=crear valida en el servidor que quien la crea sea
administrador de ese fondo específico (gastos_fondo_usuarios.es_administrador)
o un administrador del portal; en este último caso, si el administrador
del portal gestionó en nombre de otro administrador de fondo (elegido
en el selector de Solicitud de reintegro o liquidación), administrador_id/
administrador_nombre en la gestión quedan con esa persona, no con quien
ejecutó la acción (actor_id) — así el comprobante y la notificación
llegan a quien realmente administra el fondo. action=revisar exige ser
personal del Departamento de Presupuesto (verificado contra Bitrix24), y subir el PDF a Bitrix24 Disk es un
requisito duro, no best-effort: si falla (por ejemplo, falta el scope
disk en el webhook, o los métodos disk.storage.addfolder/
disk.folder.addsubfolder no se comportan como se infirió de la
documentación — su forma exacta de parámetros no está 100% confirmada,
a diferencia de disk.folder.uploadfile que sí se verificó), la gestión
se queda en pendiente y el certificador ve el error tal cual en
pantalla, sin registrar nada a medias. action=cerrar exige ser
Tesorería o administrador, y que la gestión ya esté revisado.subirPdfADisk() en api/gestiones.js usa el primer almacenamiento que
devuelve disk.storage.getlist (el del usuario dueño del webhook) y
crea ahí, la primera vez, una carpeta raíz "Gastos de Baja Cuantía"
con una subcarpeta por administrador de fondo (nombrada igual que la
persona); los PDF posteriores de ese mismo administrador se acumulan en
su subcarpeta ya existente. disk.folder.uploadfile (la única llamada
cuya forma de parámetros está confirmada en la documentación) sube el
archivo en base64 con generateUniqueName: true, así que dos
comprobantes con el mismo nombre no se pisan.jsPDF +
jspdf-autotable (mismo patrón que el comprobante de Desembolso),
nombrado <Administrador>_<Reintegro|Liquidación>_<Mes>_<Año>_<fecha>.pdf
e incluye fecha y hora de generación. El servidor nunca genera PDF —
solo recibe el base64 ya armado y lo sube a Disk.year_holidaysyear_workdays): cuentan como hábiles aunque estén en
la lista de feriados (hoy 31 de diciembre).AAAA-MM-DD que
se suman a las de Bitrix24; sirven para lo que cambia cada año.
Vienen cargados Jueves y Viernes Santo y los del Código de Trabajo de 2026
y 2027.