# Modulo de Conciliacion — Spec **Fecha:** 2026-04-12 **Estado:** Aprobado --- ## Objetivo Permitir al usuario conciliar CFDIs emitidos y recibidos mes a mes, registrando fecha de pago y banco. Solo se permite conciliar del ano actual en adelante. --- ## Modelo de datos (BD tenant — raw SQL) ### Tabla `bancos` (nueva) ```sql CREATE TABLE IF NOT EXISTS bancos ( id SERIAL PRIMARY KEY, banco VARCHAR(100) NOT NULL, terminacion_cuenta VARCHAR(4) NOT NULL, creado_en TIMESTAMP DEFAULT NOW() ); ``` ### Tabla `conciliaciones` (nueva) ```sql CREATE TABLE IF NOT EXISTS conciliaciones ( id SERIAL PRIMARY KEY, anio VARCHAR(4) NOT NULL, mes VARCHAR(2) NOT NULL, id_cfdi INTEGER NOT NULL UNIQUE REFERENCES cfdis(id), fecha_de_pago DATE NOT NULL, id_banco INTEGER NOT NULL REFERENCES bancos(id), creado_en TIMESTAMP DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_conciliaciones_anio_mes ON conciliaciones(anio, mes); CREATE INDEX IF NOT EXISTS idx_conciliaciones_id_cfdi ON conciliaciones(id_cfdi); ``` ### Columnas en `cfdis` - `conciliado VARCHAR(50)` — ya existe. Se actualiza a `'true'` al conciliar, `NULL` al desconciliar. - `id_conciliacion INTEGER REFERENCES conciliaciones(id)` — nueva. FK a la conciliacion asociada. NULL si no conciliado. Al conciliar: se crean registros en `conciliaciones`, se actualiza `cfdis.conciliado = 'true'` y `cfdis.id_conciliacion = conciliaciones.id`. Al desconciliar: se pone `cfdis.conciliado = NULL`, `cfdis.id_conciliacion = NULL`, y se elimina el registro de `conciliaciones`. ### DDL para tenants nuevos Agregar `bancos`, `conciliaciones` en `database.ts` -> `createTables()` despues de `alertas`. Agregar `id_conciliacion INTEGER REFERENCES conciliaciones(id)` en la tabla `cfdis`. ### Migracion para tenants existentes `CREATE TABLE IF NOT EXISTS` para `bancos` y `conciliaciones`, luego `ALTER TABLE cfdis ADD COLUMN IF NOT EXISTS id_conciliacion INTEGER REFERENCES conciliaciones(id)`. --- ## Reglas de negocio 1. Solo se concilian CFDIs del **ano de alta del tenant en adelante** (se obtiene del `createdAt` del tenant en la BD central). Esto permite que una empresa registrada en 2025 pueda conciliar 2025, 2026, etc. 2. `anio` y `mes` de `conciliaciones` se derivan automaticamente de `fecha_de_pago`. 3. Un CFDI solo puede tener una conciliacion (`id_cfdi` es UNIQUE en conciliaciones, `id_conciliacion` en cfdis). 4. Solo CFDIs vigentes (`status NOT IN ('Cancelado', '0')`). 5. Al conciliar: INSERT en `conciliaciones` + UPDATE `cfdis` SET `conciliado = 'true'`, `id_conciliacion = `. 6. Al desconciliar: UPDATE `cfdis` SET `conciliado = NULL`, `id_conciliacion = NULL` + DELETE de `conciliaciones`. 7. No se puede eliminar un banco que tenga conciliaciones asociadas. --- ## API endpoints ### Conciliacion | Metodo | Ruta | Descripcion | Auth | |--------|------|-------------|------| | GET | `/conciliacion` | Lista CFDIs con estado de conciliacion | JWT + Tenant | | POST | `/conciliacion` | Conciliar CFDIs (batch) | JWT + Tenant + admin/contador | | DELETE | `/conciliacion/:id` | Desconciliar un CFDI | JWT + Tenant + admin/contador | #### `GET /conciliacion` **Query params:** - `tipo`: `EMITIDO` | `RECIBIDO` (requerido) - `fechaInicio`, `fechaFin`: rango de fecha de emision - `regimen`: clave de regimen fiscal (opcional) - `estado`: `conciliado` | `pendiente` (opcional, default: todos) **Response:** Array de CFDIs con campo adicional `conciliacion` (null si pendiente, objeto si conciliado): ```json { "id": 1, "uuid": "...", "rfcEmisor": "...", "nombreEmisor": "...", "total": 1000, "totalMxn": 1000, "fechaEmision": "...", "conciliado": "true", "idConciliacion": 5, "conciliacion": { "id": 5, "fechaDePago": "2026-04-10", "banco": "BBVA", "terminacionCuenta": "1234" } } ``` #### `POST /conciliacion` **Body:** ```json { "cfdiIds": [1, 2, 3], "fechaDePago": "2026-04-10", "idBanco": 1 } ``` **Logica:** 1. Validar que todos los CFDIs existen, estan vigentes, y no estan ya conciliados. 2. Validar que `fechaDePago` es del ano actual en adelante. 3. Derivar `anio` y `mes` de `fechaDePago`. 4. Para cada CFDI: INSERT en `conciliaciones`, UPDATE `cfdis` SET `conciliado = 'true'`, `id_conciliacion = `. #### `DELETE /conciliacion/:id` 1. Buscar la conciliacion por id. 2. UPDATE `cfdis` SET `conciliado = NULL`, `id_conciliacion = NULL` WHERE `id_conciliacion = :id`. 3. DELETE FROM `conciliaciones` WHERE `id = :id`. ### Bancos | Metodo | Ruta | Descripcion | Auth | |--------|------|-------------|------| | GET | `/bancos` | Listar bancos del tenant | JWT + Tenant | | POST | `/bancos` | Crear banco | JWT + Tenant + admin | | PUT | `/bancos/:id` | Editar banco | JWT + Tenant + admin | | DELETE | `/bancos/:id` | Eliminar banco (si no tiene conciliaciones) | JWT + Tenant + admin | --- ## Frontend ### Pagina `/conciliacion` **Acceso:** Feature-gated por `conciliacion` (Business, Enterprise). Roles: admin y contador (lectura+escritura), visor (solo lectura). **Layout:** ``` [Header: "Conciliacion"] [Filtros: PeriodSelector | RegimenSelector] [Tabs: Emitidas | Recibidas] [Seccion: "Por conciliar" — tabla con checkboxes] [Barra de accion: Banco (dropdown) + Fecha de pago (date) + Boton "Conciliar"] [Seccion: "Conciliadas" — tabla con info de conciliacion + boton desconciliar] ``` **Tabla "Por conciliar":** - Checkbox (no visible para visor) - UUID (corto), Fecha emision, RFC Emisor/Receptor, Nombre, Total MXN, Metodo Pago - Boton "Ver factura" (CfdiViewerModal) **Tabla "Conciliadas":** - UUID, Fecha emision, RFC, Nombre, Total MXN - Fecha de pago, Banco (nombre + terminacion) - Boton "Desconciliar" (no visible para visor) - Boton "Ver factura" **Flujo de conciliacion:** 1. Usuario selecciona checkboxes en "Por conciliar" 2. Aparece barra de accion sticky en la parte inferior 3. Selecciona banco (dropdown de bancos del tenant) y fecha de pago 4. Click "Conciliar N facturas" 5. Confirmacion -> POST `/conciliacion` -> refresh datos ### Seccion de bancos en `/configuracion` Solo visible para admin. Card con: - Lista de bancos existentes: Nombre + terminacion + boton eliminar - Formulario inline: Nombre banco + Terminacion (max 4 digitos) + boton agregar ### Navegacion Agregar "Conciliacion" al sidebar con feature gate `conciliacion`, visible para admin, contador, visor. Ubicacion: despues de Reportes. --- ## Archivos a crear/modificar ### Backend (crear) - `apps/api/src/services/conciliacion.service.ts` - `apps/api/src/controllers/conciliacion.controller.ts` - `apps/api/src/routes/conciliacion.routes.ts` - `apps/api/src/services/bancos.service.ts` - `apps/api/src/controllers/bancos.controller.ts` - `apps/api/src/routes/bancos.routes.ts` ### Backend (modificar) - `apps/api/src/app.ts` — registrar rutas de conciliacion y bancos - `apps/api/src/config/database.ts` — agregar tablas `bancos` y `conciliaciones` en `createTables()`, agregar `id_conciliacion` en `cfdis` ### Frontend (crear) - `apps/web/app/(dashboard)/conciliacion/page.tsx` - `apps/web/lib/api/conciliacion.ts` - `apps/web/lib/api/bancos.ts` - `apps/web/lib/hooks/use-conciliacion.ts` - `apps/web/lib/hooks/use-bancos.ts` ### Frontend (modificar) - `apps/web/components/layouts/sidebar.tsx` (y variantes) — agregar nav item - `apps/web/app/(dashboard)/configuracion/page.tsx` — agregar seccion de bancos ### Migracion - Aplicar DDL a tenant existente (`horux_ede123456ab1`): crear tablas + agregar columna