panels-origin/docs/plan-pendientes-arctec.md
Alberto Martinez f09b982127 Plan de pendientes: facturas, nómina, IMSS y proveedores (#27)
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Resumen

Análisis de las observaciones de *Pendientes página* (facturas, nómina, IMSS/SUA) contra el sistema actual, y plan de implementación en `docs/plan-pendientes-arctec.md`.

No cambia pantallas ni base de datos. Define el orden de trabajo y la decisión de reutilizar el catálogo de proveedores que ya existe.

## Hallazgos

- Proveedores ya se administran en Configuración y se usan en Gastos y almacén. No hace falta un segundo catálogo; hay que completar estatus y usarlo como maestro de las facturas (match por RFC).
- Gastos no son facturas: no hay UUID, carga Excel ni filtros por proveedor, monto, RFC o UUID. Las emitidas no caben en egresos.
- Nómina semanal cubre jornal, destajo, administración, préstamo al pagar y CSV. Faltan bono, descuento con motivo, horas, festivos, Excel/PDF, edición de préstamos, finiquitos, dispersión, historial de alta/baja/reingreso y reportes mensual/anual.
- IMSS guarda un solo jornal y fechas sueltas de alta/baja. No hay jornal de cotización ni consulta de cuotas para cotejar el SUA.

## Orden propuesto

1. Completar proveedores.
2. Facturas recibidas/emitidas con Excel y clasificación a obra.
3. Ajustes de nómina (bono, descuentos, horas, festivos).
4. Préstamos editables y estado de cuenta.
5. Finiquitos.
6. Dispersión con corte semanal y comprobante.
7. Historial de movimientos.
8. Reportes Excel/PDF.
9. Jornal IMSS y consulta de cuotas (sin archivo SUA en esta etapa).

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a href="https://cursor.com/agents/bc-5e23dc3b-921e-4091-9650-7091d3a52bbf?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-5e23dc3b-921e-4091-9650-7091d3a52bbf&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>
2026-09-25 03:26:26 +00:00

218 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pendientes arctec-ar: análisis y plan de implementación
Fuente: observaciones de *Pendientes página* (facturas, nómina, IMSS/SUA).
Alcance de este documento: contrastar cada punto con el sistema actual y definir el orden de construcción. No implementa las pantallas ni las migraciones.
## Resumen
El sistema ya cubre captura manual de gastos, catálogo de proveedores, nómina semanal (jornal, destajo y administrativa), préstamos con descuento al pagar la semana, y datos básicos de IMSS en el padrón. No existe un módulo de facturas CFDI, ni descuentos varios estructurados, ni finiquitos, ni dispersión, ni historial de movimientos de personal, ni reportes de nómina por mes o año, ni jornal distinto para el IMSS.
La administración de proveedores **ya existe** y debe reutilizarse. No conviene un segundo catálogo. Las facturas y los gastos deben resolver el proveedor por `supplier_id` y por RFC.
## Qué hay hoy
| Área | Dónde vive | Qué hace |
| --- | --- | --- |
| Proveedores | `core.suppliers`, `fn_supplier_list/create/update`, `GET/POST/PATCH /v1/suppliers`, pestaña Proveedores en Configuración, `SupplierFormDialog` | Alta y edición de nombre, razón social, RFC único por tenant, contacto y domicilio. Estatus `activo` / `inactivo` en base, sin baja en la pantalla. |
| Uso del proveedor | Gastos (`expense_entries.supplier_id`) y materiales de almacén (`warehouse_material_suppliers`) | En Gastos se elige del catálogo. El RFC se copia al gasto. |
| Gastos | `expense_entries`, página Gastos | Captura uno a uno: empresa, obra, fecha, concepto de presupuesto, importes, IVA y PDF. Filtro de texto (descripción, proveedor, concepto) y “sin clasificar”. El listado de API filtra obra, empresa, fechas, concepto y origen. |
| Nómina | `payroll_weeks` (`draft` / `assembled` / `paid`), hojas `obra`, `destajo`, `admin` | Asistencia por día (presente o falta). Jornal = días × `workers.daily_wage`. Se arma desde el jueves. Al pagar se descuenta el préstamo y se sincroniza el gasto. Exportación: CSV de la semana. PDF solo de recibos de préstamo. |
| Préstamos | `loans`, `loan_payments`, ficha del trabajador | Alta, saldo en ficha y recuperación en el tablero. No hay edición del préstamo ya registrado. |
| Personal | `workers.status`, `imss_alta_at`, `imss_baja_at`, `last_rehire_at`, `assignments.start_date/end_date` | Una fecha de reingreso y una alta/baja IMSS. No hay bitácora de varios movimientos. |
| IMSS | Empresa: registro patronal y clase de riesgo. Persona: NSS, salario diario único, estatus y fechas de alta/baja, documentos `alta_imss` / `baja_imss` | No hay jornal IMSS separado, ni desglose de cuotas, ni archivo SUA. |
## Análisis por observación
### 1. Facturas y comprobantes
**Carga masiva de Excel (recibidas o emitidas) y concepto de material a la obra.**
No existe. Gastos se capturan de uno en uno y solo modelan egresos. Una factura emitida (ingreso) no cabe en `expense_entries` sin un tipo de movimiento. El concepto de presupuesto ya se puede ligar a un gasto manual (`budget_item_id`), pero no desde un Excel ni por línea de material.
**Filtros en facturas recibidas (proveedor, monto, RFC, UUID).**
No hay UUID, folio fiscal ni serie. La búsqueda de Gastos es un texto libre en el cliente. El API de gastos no filtra por proveedor, RFC ni rango de monto.
Decisión: las facturas son un registro propio, ligado al proveedor del catálogo. Una factura recibida clasificada puede generar o actualizar un gasto. Una emitida queda como ingreso y no entra al control de costos.
### 2. Nómina
**Bono.**
No hay concepto de percepción aparte del jornal, el destajo o el sueldo administrativo. `payroll_week_lines` tiene `gross`, `discounts` y `loan_discount`, sin tipo de percepción.
**Descuentos varios con observación.**
La columna `discounts` es un importe. El periodo legado acepta `extra_discounts` como número por trabajador, sin concepto, fecha, obra ni motivo. La pantalla de nómina no captura ese dato.
**Ajuste por horas trabajadas.**
La asistencia es sí/no por día (`attendance.present`). `days` es la cuenta de días presentes. No hay horas ni fracción de jornal por hora.
**Días festivos.**
No hay calendario ni regla (pagar el día, no descontarlo, o pagarlo doble). Un festivo hoy se trata como falta si no se marca presente.
**Consulta y descarga Excel y PDF.**
Hay CSV de la semana abierta (`fn_payroll_week_csv`). No hay libro Excel ni PDF de la nómina. El generador PDF actual solo arma recibos de préstamo (`api/pdf.ts`).
### Descuentos varios (sección propia)
No existe tabla ni pantalla. Cada descuento del pendiente pide concepto, importe, fecha, trabajador, obra y observación. Eso es un movimiento, no un campo suelto en la línea semanal. Al armar la semana, los descuentos vigentes de esa obra y persona se suman a `discounts`.
### Préstamos
Alta y lectura sí. `fn_loan_create` fija entregado, saldo, cuota, comisión y plan. No hay `fn_loan_update`. El saldo se ve en la ficha y el descuento de la semana en la línea (`loan_label`, `loan_discount`). No hay un estado de cuenta: saldo inicial, descuentos aplicados y saldo pendiente en un solo lugar. Editar un préstamo con pagos ya aplicados debe quedar restringido (solo nota, cuota futura o corrección si la semana sigue en borrador).
### Finiquitos y liquidaciones
No hay módulo. La baja de padrón cambia `status` / `pipeline_status` y no calcula proporcional, vacaciones, aguinaldo, prima ni finiquito. Hace falta un cálculo consultable (conceptos e importe final) y un pago que no se mezcle con el jornal semanal.
### Dispersión
No hay entidad de dispersión. Lo más cercano es el estado de la semana: borrador, armada y pagada. Después de pagada no se edita, y no se anexa el comprobante de la transferencia. El “corte semanal” hoy es la propia semana de nómina (se arma el jueves). Falta un corte explícito: congelar el neto a dispersar, permitir corrección mientras no sea definitivo, y adjuntar el comprobante al cerrarlo.
### Historial de movimientos del trabajador
Se guarda el estado actual y, como mucho, una fecha: `imss_alta_at`, `imss_baja_at`, `last_rehire_at`, inicio y fin de asignación. Un segundo reingreso pisa `last_rehire_at`. No se puede listar alta, baja y reingresos sucesivos.
### Reportes de nómina
No hay reporte mensual ni anual, ni filtro combinado por trabajador, obra y periodo, ni exportación Excel/PDF de ese corte. El CSV semanal no sustituye esos reportes.
### 3. IMSS / SUA
`workers.daily_wage` es el único jornal. No se distingue el jornal real del jornal diario para IMSS (salario base de cotización diario). La empresa tiene registro patronal y clase de riesgo; la persona tiene NSS y movimiento de alta/baja como fechas sueltas. No se calculan ni se consultan cuotas (enfermedad, invalidez, retiro, cesantía, infonavit, riesgo de trabajo) ni se arma el layout del SUA. El pendiente pide facilitar la revisión, no sustituir al SUA: guardar el jornal IMSS, los movimientos y el desglose usado en el cálculo, y poder exportarlo para cotejo.
## Proveedores: reutilizar el catálogo
La opción de administrar proveedores ya está hecha y es la base de facturas y almacén.
Se mantiene:
- Un solo catálogo por tenant (`core.suppliers`).
- RFC único cuando viene informado.
- Alta desde Configuración y, como atajo, desde Gastos y desde el catálogo de materiales.
- El gasto y la factura guardan `supplier_id` y una copia de nombre y RFC por si el catálogo cambia después.
Se completa, sin abrir otro módulo:
- Activar e inactivar desde la pestaña Proveedores (el campo `status` ya existe; la tabla no lo muestra ni lo edita).
- Búsqueda en servidor por nombre y RFC, alineada al filtro de facturas.
- Al importar Excel de facturas, emparejar por RFC. Si el RFC no existe, la fila queda en revisión para crear el proveedor o asignarlo; no se duplica el catálogo en silencio.
- Datos que el catálogo aún no tiene y la factura sí va a necesitar: régimen fiscal y código postal fiscal, opcionales, para cotejar el CFDI. Cuenta bancaria no entra en esta fase; la dispersión es de nómina, no de proveedores.
## Plan de implementación
Cada fase cierra con migración Liquibase en `db/core/changesets/`, funciones `core.fn_*`, rutas en la API y pantalla en `web-panel`. Los permisos siguen el patrón `modulo.view/create/update/delete`.
### Fase 1. Proveedores listos para facturas
Objetivo: el catálogo que ya existe queda usable como maestro de las facturas.
- Mostrar estatus y permitir pasarlo a `inactivo` (no se borra si tiene gastos o facturas).
- Campos opcionales `regimen_fiscal` y `codigo_postal`.
- Listado filtrable por nombre, RFC y estatus.
- Prueba de API: alta, RFC duplicado, inactivar, y que Gastos solo ofrezca activos.
No cambia el flujo de captura de un gasto.
### Fase 2. Facturas recibidas y emitidas
Objetivo: registrar comprobantes en lote y clasificar la recibida a la obra.
Tablas nuevas:
- `invoices`: tenant, dirección `recibida` | `emitida`, `supplier_id`, nombre y RFC copiados, UUID, serie, folio, fecha, subtotal, IVA, total, moneda, estatus `borrador` | `registrada` | `clasificada` | `anulada`.
- `invoice_lines`: factura, descripción, cantidad, unidad, importe, `project_id`, `budget_item_id`.
- UUID único por tenant cuando viene informado.
Excel de carga (una fila por partida, se agrupa por UUID o, si no hay UUID, por RFC + folio + fecha):
- Dirección, RFC, nombre proveedor, UUID, serie, folio, fecha, descripción, cantidad, unidad, importe, IVA, total, clave de obra, clave de concepto.
Reglas:
- RFC conocido asigna `supplier_id`. RFC nuevo no crea proveedor hasta que alguien lo confirme en la revisión.
- Concepto y obra vacíos dejan la factura recibida como `registrada` (equivalente al gasto sin clasificar). Al asignar concepto se puede generar el gasto con `source = 'invoice'` y `source_ref_id` = id de factura, reusando la unicidad que ya tiene `expense_entries`.
- La emitida no genera gasto.
- Filtros del listado de recibidas: proveedor (id o nombre), RFC, UUID, folio, rango de monto, rango de fechas, obra, con o sin concepto.
- Edición de concepto y obra mientras la factura no esté anulada. Si ya generó gasto confirmado, la reclasificación pasa por la misma regla que `fn_expense_update`.
Pantalla: apartado Facturas, pestañas Recibidas y Emitidas, acción Importar Excel y diálogo de clasificación. Gastos sigue siendo la captura manual y el reflejo de nómina; no se le pide que sea el CFDI.
### Fase 3. Conceptos de nómina de la semana
Objetivo: bono, descuento con motivo, horas y festivo dentro del cálculo semanal que ya arma y paga.
- Percepciones de la línea: jornal, bono (importe y nota). El bruto pasa a ser jornal + bono + destajo o sueldo admin, según la hoja.
- `payroll_adjustments`: tipo `descuento` | `bono` | `horas`, trabajador, obra opcional, semana o fecha, concepto, importe o horas, observación. Un descuento sin observación no se guarda.
- Horas: además del día presente/ausente, un ajuste de horas × (jornal / jornada, por defecto 8). Puede sumar o restar del jornal de esa semana. No reemplaza la asistencia por día.
- `holidays`: fecha, nombre, tenant. Si el día cae en la semana y la persona está asignada, cuenta como día pagado aunque no haya marca de asistencia, y se identifica en la línea. No se paga doble en esta fase; si más adelante se pide festivo trabajado, será otro tipo de ajuste.
- El armado de la semana (`fn_payroll_week_assemble`) suma estos conceptos antes de congelar `payable_net`. En semana `paid` no se editan.
- Pantalla Nómina: captura de bono y de descuento (concepto, importe, obra, observación) sobre la persona de la semana, y marcas de festivo en el calendario de la semana.
La sección “Descuentos varios” del pendiente es esta misma captura, también consultable fuera de la semana: listado por trabajador, obra y fechas. No es un módulo aparte del cálculo.
### Fase 4. Préstamos editables y estado de cuenta
- `fn_loan_update` mientras no haya `loan_payments`, o solo nota y cuota si ya hay pagos. El saldo no se teclea: se recalcula como entregado − suma de pagos.
- Ficha y diálogo de préstamo: entregado, comisión, cuota, saldo pendiente y tabla de descuentos aplicados (semana, importe, etiqueta).
- Corregir un préstamo no reabre una semana ya pagada.
### Fase 5. Finiquitos y liquidaciones
- `settlements`: trabajador, tipo `finiquito` | `liquidacion`, fecha de baja, obra, estatus `borrador` | `pagado`.
- `settlement_lines`: concepto (sueldo pendiente, vacaciones, prima vacacional, aguinaldo, otro), días o base, importe, observación.
- El importe final es la suma de líneas menos descuentos y saldo de préstamo vigentes, mostrados en el detalle antes de pagar.
- Pagar el finiquito no lo mete en la semana de jornal. Puede generar un gasto de nómina distinto, con referencia al finiquito, para que el control de costos lo vea.
Los factores (días de aguinaldo, porcentaje de prima) salen de configuración del tenant, con valores editables. El primer corte usa los días capturados en cada línea para no bloquear el módulo por una tabla fiscal incompleta.
### Fase 6. Dispersión y corte semanal
- `payroll_dispersions`: semana, estatus `abierta` | `corte` | `definitiva`, neto, nota.
- Mientras está `abierta` o en `corte`, se puede corregir el neto por persona (ajuste que también queda en la línea de la semana si la semana no está pagada).
- `definitiva` bloquea la edición y exige, o al menos permite, el comprobante (mismo almacenamiento cifrado que los PDF de gastos).
- El corte semanal es la acción que pasa la dispersión a `corte` con el `payable_net` de esa semana. No crea otra periodicidad: la semana de nómina sigue siendo el periodo.
### Fase 7. Historial de movimientos
- `worker_movements`: trabajador, tipo `alta` | `baja` | `reingreso`, fecha, motivo, usuario.
- Alta de persona, baja de padrón y reactivación escriben un renglón. Las fechas actuales (`last_rehire_at`, alta y baja IMSS) se siguen actualizando para no romper el expediente.
- La ficha muestra la lista en orden de fecha. No se edita el pasado desde la ficha; una corrección es otro movimiento o una nota.
### Fase 8. Reportes de nómina
- Consulta por periodo (semana, mes o año), trabajador y obra, leyendo líneas de semanas, ajustes, préstamos y finiquitos pagados en el rango.
- Exportación Excel (libro con el mismo detalle que la pantalla) y PDF (resumen por persona y totales). El CSV semanal se conserva.
- Mes y año agrupan por `week_start` / fecha del movimiento, en la zona horaria del tenant.
### Fase 9. Jornal IMSS y apoyo a SUA
- `workers.imss_daily_wage`: jornal diario para cotización. Si está vacío, el cálculo usa `daily_wage` y lo indica en pantalla.
- Movimientos IMSS que alimentan el historial de la fase 7 con tipo `alta_imss`, `baja_imss`, `modificacion_salario`, más registro patronal de la empresa.
- Consulta por persona y periodo: jornal real, jornal IMSS, días, salario base de cotización del periodo y cuotas calculadas con las tasas vigentes guardadas en configuración (no hardcodeadas en la pantalla).
- Exportación de esa consulta a Excel para cotejar contra el SUA. No se genera el archivo propietario del SUA en esta fase: faltan tablas de ausentismo, incapacidades y el layout oficial completo. Eso queda como fase posterior si el cotejo en Excel no basta.
## Orden y dependencias
1. Proveedores (fase 1) antes que facturas, porque el Excel casa por RFC.
2. Facturas (fase 2) no bloquea nómina. Puede ir en paralelo con la fase 3 después de la 1.
3. Ajustes de nómina (fase 3) antes que reportes (fase 8) y antes que dispersión (fase 6), para que el neto a dispersar ya incluya bono, horas, festivo y descuentos.
4. Préstamos (fase 4) antes que finiquitos (fase 5), porque el finiquito resta el saldo.
5. Historial (fase 7) puede avanzar en paralelo con nómina; la fase 9 lo reutiliza para movimientos IMSS.
6. IMSS/SUA (fase 9) al final: depende del jornal y de los movimientos, y no cambia el pago semanal.
## Fuera de este plan
- Timbrado CFDI o descarga automática del SAT.
- Archivo de pago bancario (layout de dispersión del banco).
- Archivo SUA de carga directa.
- Sustituir la asistencia por día con un reloj checador.
## Verificación por fase
- Fase 1: crear, editar, RFC repetido, inactivar, y que un gasto nuevo no liste al inactivo.
- Fase 2: Excel con proveedor existente, RFC desconocido, UUID repetido, clasificación a concepto y gasto generado una sola vez.
- Fase 3: semana con bono, descuento con motivo, horas y un festivo; el neto armado cuadra con la suma; semana pagada rechaza cambios.
- Fase 4: editar préstamo sin pagos; con pagos, el saldo es entregado menos pagos.
- Fase 5: detalle de conceptos igual al importe a pagar.
- Fase 6: corrección antes de definitiva; comprobante adjunto; definitiva no editable.
- Fase 7: alta, baja y reingreso aparecen en orden y no se pierden al repetir el ciclo.
- Fase 8: el mes suma las semanas del mes; Excel y PDF coinciden con la pantalla.
- Fase 9: jornal IMSS distinto del real se ve en la consulta de cuotas y en el Excel.