220 lines
7.3 KiB
Markdown
220 lines
7.3 KiB
Markdown
# 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 = <id>`.
|
|
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 = <new id>`.
|
|
|
|
#### `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
|