# RF-FIN-004: Asientos Contables ## Identificacion | Campo | Valor | |-------|-------| | **ID** | RF-FIN-004 | | **Modulo** | MGN-010 Financial | | **Titulo** | Asientos Contables | | **Prioridad** | P0 - Critica | | **Estado** | Draft | | **Fecha** | 2025-12-05 | --- ## Descripcion El sistema debe permitir registrar asientos contables (journal entries) con multiples lineas de debe y haber, validando que el asiento este cuadrado y afectando los saldos de las cuentas. --- ## Requisitos Funcionales ### RF-FIN-004.1: Estructura del Asiento ```typescript interface JournalEntry { id: UUID; tenantId: UUID; periodId: UUID; // Periodo contable entryNumber: string; // "POL-2025-001234" entryDate: Date; // Fecha contable description: string; // Concepto/glosa reference?: string; // Referencia externa sourceType?: string; // "invoice", "payment", "manual" sourceId?: UUID; // ID del documento origen status: EntryStatus; postedAt?: TIMESTAMPTZ; postedBy?: UUID; reversedEntryId?: UUID; // Si es reverso createdBy: UUID; createdAt: TIMESTAMPTZ; updatedAt: TIMESTAMPTZ; } enum EntryStatus { DRAFT = 'draft', // En edicion PENDING = 'pending', // Pendiente aprobacion POSTED = 'posted', // Contabilizado REVERSED = 'reversed' // Reversado } ``` ### RF-FIN-004.2: Estructura de Linea ```typescript interface JournalLine { id: UUID; entryId: UUID; lineNumber: number; accountId: UUID; // Cuenta contable costCenterId?: UUID; // Centro de costo description?: string; // Detalle de linea debit: Decimal; // Debe credit: Decimal; // Haber currencyId: UUID; // Moneda del movimiento exchangeRate: Decimal; // Tipo de cambio debitBase: Decimal; // Debe en moneda base creditBase: Decimal; // Haber en moneda base partnerId?: UUID; // Tercero (cliente/proveedor) tags?: string[]; // Etiquetas reconciled: boolean; // Conciliado reconciledAt?: TIMESTAMPTZ; } ``` ### RF-FIN-004.3: Validaciones del Asiento ```typescript interface EntryValidation { isValid: boolean; errors: ValidationError[]; warnings: ValidationWarning[]; } // Validaciones obligatorias const VALIDATIONS = [ 'entry_balanced', // Debe = Haber 'date_in_open_period', // Fecha en periodo abierto 'accounts_are_detail', // Cuentas de detalle 'accounts_active', // Cuentas activas 'amounts_positive', // Montos positivos 'currency_valid', // Moneda valida 'exchange_rate_valid' // Tipo de cambio valido ]; // Ejemplo de validacion function validateEntry(entry: JournalEntry): EntryValidation { const totalDebit = entry.lines.reduce((sum, l) => sum + l.debitBase, 0); const totalCredit = entry.lines.reduce((sum, l) => sum + l.creditBase, 0); if (Math.abs(totalDebit - totalCredit) > 0.01) { return { isValid: false, errors: [{ code: 'UNBALANCED', message: `Asiento descuadrado: Debe=${totalDebit}, Haber=${totalCredit}` }] }; } // ... mas validaciones } ``` ### RF-FIN-004.4: Numeracion de Asientos ```typescript interface EntryNumbering { tenantId: UUID; prefix: string; // "POL", "ING", "EGR" yearFormat: string; // "YYYY" o "YY" separator: string; // "-" sequenceLength: number; // 6 digitos resetYearly: boolean; // Reiniciar cada año lastNumber: number; // Ultimo numero usado } // Genera: POL-2025-000001 function generateEntryNumber(config: EntryNumbering, date: Date): string { const year = format(date, config.yearFormat); const sequence = (config.lastNumber + 1).toString().padStart(config.sequenceLength, '0'); return `${config.prefix}${config.separator}${year}${config.separator}${sequence}`; } ``` ### RF-FIN-004.5: Mayorizar Asiento Al contabilizar (post) un asiento: 1. Validar que este cuadrado 2. Validar fecha en periodo abierto 3. Actualizar saldos de cuentas 4. Marcar como posted 5. Registrar en audit log ```typescript interface PostResult { entryId: UUID; entryNumber: string; postedAt: TIMESTAMPTZ; affectedAccounts: { accountId: UUID; previousBalance: Decimal; newBalance: Decimal; }[]; } ``` ### RF-FIN-004.6: Reversar Asiento ```typescript interface ReversalEntry { originalEntryId: UUID; reversalEntryId: UUID; reversalDate: Date; reason: string; } // El asiento de reverso: // - Tiene las mismas lineas pero Debe/Haber invertidos // - Referencia al asiento original // - Anula efecto en saldos ``` ### RF-FIN-004.7: Asientos desde Documentos Los modulos de negocio generan asientos: | Documento | Asiento | |-----------|---------| | Factura de Venta | Debe: CxC, Haber: Ingresos + IVA | | Factura de Compra | Debe: Gastos + IVA, Haber: CxP | | Pago Recibido | Debe: Banco, Haber: CxC | | Pago Emitido | Debe: CxP, Haber: Banco | | Ajuste Inventario | Debe/Haber: Inventario vs Ajustes | --- ## Operaciones ### Listar Asientos ```typescript GET /api/v1/financial/journal?periodId=uuid&status=posted Response: { "data": [ { "id": "uuid", "entryNumber": "POL-2025-001234", "entryDate": "2025-12-05", "description": "Pago a proveedor XYZ", "status": "posted", "totalDebit": 10000, "linesCount": 3 } ] } ``` ### Crear Asiento ```typescript POST /api/v1/financial/journal { "entryDate": "2025-12-05", "description": "Registro de venta", "lines": [ { "accountId": "uuid-cxc", "debit": 11600, "credit": 0, "description": "Cliente ABC" }, { "accountId": "uuid-ingresos", "debit": 0, "credit": 10000, "description": "Venta de servicios" }, { "accountId": "uuid-iva", "debit": 0, "credit": 1600, "description": "IVA 16%" } ] } Response: { "id": "uuid", "entryNumber": "POL-2025-001235", "status": "draft", "totalDebit": 11600, "totalCredit": 11600, "isBalanced": true } ``` ### Contabilizar Asiento ```typescript POST /api/v1/financial/journal/:id/post Response: { "id": "uuid", "status": "posted", "postedAt": "2025-12-05T10:00:00Z", "affectedAccounts": 3 } ``` ### Reversar Asiento ```typescript POST /api/v1/financial/journal/:id/reverse { "reversalDate": "2025-12-06", "reason": "Error en monto" } Response: { "originalEntryId": "uuid-original", "reversalEntryId": "uuid-reverso", "reversalNumber": "POL-2025-001236" } ``` --- ## Reglas de Negocio | ID | Regla | Severidad | |----|-------|-----------| | BR-001 | Asiento debe estar cuadrado para contabilizar | Error | | BR-002 | Fecha debe estar en periodo abierto | Error | | BR-003 | Solo cuentas de detalle en asientos | Error | | BR-004 | Asiento contabilizado no es editable | Error | | BR-005 | Reverso de asiento ya reversado no permitido | Error | --- ## Criterios de Aceptacion - [ ] CRUD de asientos contables - [ ] Validacion automatica de cuadre - [ ] Numeracion automatica configurable - [ ] Mayorizar asiento (post) - [ ] Reversar asiento - [ ] Soporte multi-moneda - [ ] Centros de costo opcionales - [ ] Integracion con documentos --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-05 | Requirements-Analyst | Creacion inicial |