9.2 KiB
MODELO DE DOMINIO: Financiero
Módulos: MGN-004 (Financiero Básico) Fecha: 2025-11-24 Referencia Odoo: account Referencia Gamilit: financial_management schema
Diagrama de Entidades (Texto UML)
[Account]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- code: String
- name: String
- account_type: ENUM (asset, liability, equity, income, expense)
- parent_id: UUID (FK self)
- currency_id: UUID (FK)
1 <----> * [JournalEntry]
[Journal]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- name: String
- code: String
- type: ENUM (sales, purchase, bank, cash, general)
1 <----> * [JournalEntry]
[JournalEntry]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- journal_id: UUID (FK)
- name: String
- date: Date
- status: ENUM (draft, posted, cancelled)
1 <----> * [JournalLine]
[JournalLine]
- id: UUID (PK)
- entry_id: UUID (FK)
- account_id: UUID (FK)
- partner_id: UUID (FK)
- debit: Decimal
- credit: Decimal
- analytic_account_id: UUID (FK)
- description: String
[Invoice]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- partner_id: UUID (FK)
- invoice_type: ENUM (customer, vendor)
- number: String
- date: Date
- due_date: Date
- status: ENUM (draft, open, paid, cancelled)
- amount_total: Decimal
- amount_paid: Decimal
- journal_entry_id: UUID (FK)
1 <----> * [InvoiceLine]
* <----> * [Payment] (through PaymentInvoice)
[InvoiceLine]
- id: UUID (PK)
- invoice_id: UUID (FK)
- product_id: UUID (FK)
- description: String
- quantity: Decimal
- price_unit: Decimal
- tax_ids: UUID[] (FK array)
- subtotal: Decimal
- total: Decimal
- analytic_account_id: UUID (FK)
[Payment]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- partner_id: UUID (FK)
- payment_type: ENUM (inbound, outbound)
- amount: Decimal
- date: Date
- payment_method: ENUM (cash, bank_transfer, check, card)
- journal_entry_id: UUID (FK)
* <----> * [Invoice] (through PaymentInvoice)
[PaymentInvoice] (many-to-many)
- payment_id: UUID (FK)
- invoice_id: UUID (FK)
- amount: Decimal
[Tax]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- name: String
- code: String
- rate: Decimal
- type: ENUM (sales, purchase, all)
- account_id: UUID (FK)
Entidades Principales
1. Account (Cuenta Contable)
Descripción: Cuenta del plan de cuentas contables.
Atributos:
id: UUIDcode: Código de cuenta (ej: "110.01.001")name: Nombre (ej: "Bancos - BBVA")account_type: Tipo (asset, liability, equity, income, expense)parent_id: Cuenta padre (jerarquía)currency_id: Moneda
Relaciones:
- 1 Account → N Journal Lines
- N Accounts → 1 Company
Patrón Odoo: account.account Validaciones:
- code único por company
- Cuentas tipo 'view' no pueden tener movimientos
2. Journal (Diario Contable)
Descripción: Diario para agrupar asientos contables por tipo.
Atributos:
id: UUIDname: Nombre del diariocode: Código (ej: "SALES", "BANK")type: Tipo (sales, purchase, bank, cash, general)
Relaciones:
- 1 Journal → N Journal Entries
Patrón Odoo: account.journal Diarios estándar:
- Sales Journal (facturas de cliente)
- Purchase Journal (facturas de proveedor)
- Bank Journal (movimientos bancarios)
- Cash Journal (efectivo)
- Miscellaneous Journal (asientos manuales)
3. JournalEntry (Asiento Contable)
Descripción: Asiento contable con múltiples líneas (débito/crédito).
Atributos:
id: UUIDjournal_id: Diario asociadoname: Número de asientodate: Fecha del asientostatus: draft, posted, cancelled
Relaciones:
- 1 JournalEntry → N JournalLines
- N JournalEntries → 1 Journal
Patrón Odoo: account.move Regla fundamental: SUM(debit) = SUM(credit)
4. JournalLine (Línea de Asiento)
Descripción: Línea individual de un asiento (débito o crédito).
Atributos:
id: UUIDentry_id: Asiento propietarioaccount_id: Cuenta contablepartner_id: Partner (cliente/proveedor)debit: Monto débitocredit: Monto créditoanalytic_account_id: Cuenta analítica (opcional)
Relaciones:
- N JournalLines → 1 JournalEntry
- N JournalLines → 1 Account
Patrón Odoo: account.move.line Validación: En cada línea, debit XOR credit (no ambos)
5. Invoice (Factura)
Descripción: Factura de cliente o proveedor.
Atributos:
id: UUIDpartner_id: Cliente/Proveedorinvoice_type: customer, vendornumber: Número de facturadate: Fecha de emisióndue_date: Fecha de vencimientostatus: draft, open, paid, cancelledamount_total: Monto totalamount_paid: Monto pagado
Relaciones:
- 1 Invoice → N InvoiceLines
- 1 Invoice → 1 JournalEntry (al validar)
- N Invoices ←→ N Payments
Patrón Odoo: account.move (type=invoice) Estados:
- draft: Borrador (editable)
- open: Validada (genera asiento)
- paid: Pagada completamente
- cancelled: Cancelada
6. InvoiceLine (Línea de Factura)
Descripción: Línea de producto/servicio en factura.
Atributos:
id: UUIDinvoice_id: Factura propietariaproduct_id: Producto/serviciodescription: Descripciónquantity: Cantidadprice_unit: Precio unitariotax_ids: Impuestos aplicadossubtotal: Subtotal sin impuestostotal: Total con impuestos
Relaciones:
- N InvoiceLines → 1 Invoice
Patrón Odoo: account.move.line (con invoice_line_id) Cálculo: total = (quantity * price_unit) + taxes
7. Payment (Pago)
Descripción: Registro de pago de cliente o a proveedor.
Atributos:
id: UUIDpartner_id: Cliente/Proveedorpayment_type: inbound (cliente), outbound (proveedor)amount: Monto del pagodate: Fecha del pagopayment_method: cash, bank_transfer, check, cardjournal_entry_id: Asiento generado
Relaciones:
- N Payments ←→ N Invoices (reconciliación)
- 1 Payment → 1 JournalEntry
Patrón Odoo: account.payment Flujo:
- Crear payment
- Validar payment → genera journal entry
- Reconciliar payment con invoice(s)
8. Tax (Impuesto)
Descripción: Configuración de impuestos (IVA, retenciones).
Atributos:
id: UUIDname: Nombre (ej: "IVA 16%")code: Código (ej: "IVA16")rate: Tasa (0.16 para 16%)type: sales, purchase, allaccount_id: Cuenta contable para impuesto
Relaciones:
- N Taxes → N InvoiceLines
Patrón Odoo: account.tax Impuestos comunes México:
- IVA 16% (ventas y compras)
- IVA 8% (zona frontera)
- Retención IVA 10.67%
- Retención ISR 10%
Reglas de Negocio
RN-FIN-001: Balance de Asientos
- TODO asiento debe cumplir: SUM(debit) = SUM(credit)
- Validación obligatoria antes de posted
RN-FIN-002: Asientos Inmutables
- Asientos con status=posted NO pueden editarse
- Para corregir: crear asiento de reversa
RN-FIN-003: Generación Automática de Asientos
- Validar factura → genera journal entry automáticamente
- Validar pago → genera journal entry automáticamente
RN-FIN-004: Multi-Moneda
- Transacciones en moneda extranjera se convierten a moneda de company
- Usar tasa de cambio del día de la transacción
- Gain/Loss se registra en cuenta especial
RN-FIN-005: Conciliación de Pagos
- Payment puede aplicarse a múltiples invoices (parcial)
- Invoice puede recibir múltiples payments
- amount_paid se actualiza automáticamente
Casos de Uso Principales
- UC-FIN-001: Contador crea asiento contable manual
- UC-FIN-002: Usuario crea factura de cliente
- UC-FIN-003: Sistema genera asiento al validar factura
- UC-FIN-004: Usuario registra pago de cliente
- UC-FIN-005: Usuario concilia pago con facturas
- UC-FIN-006: Contador genera Balance General
- UC-FIN-007: Contador genera Estado de Resultados
- UC-FIN-008: Usuario crea factura en USD (empresa en MXN)
Validaciones y Constraints
-- Asiento balanceado
CHECK (SUM(debit) = SUM(credit) per entry_id)
-- Debit XOR Credit (no ambos)
CHECK ((debit > 0 AND credit = 0) OR (credit > 0 AND debit = 0))
-- Invoice number único por company y tipo
UNIQUE (tenant_id, company_id, invoice_type, number)
-- Status transitions válidos
-- (implementar con state machine)
Índices Requeridos
CREATE INDEX idx_accounts_company_id ON financial.accounts(company_id);
CREATE INDEX idx_accounts_code ON financial.accounts(code);
CREATE INDEX idx_journal_entries_company_id ON financial.journal_entries(company_id);
CREATE INDEX idx_journal_entries_date ON financial.journal_entries(date);
CREATE INDEX idx_journal_lines_account_id ON financial.journal_lines(account_id);
CREATE INDEX idx_invoices_partner_id ON financial.invoices(partner_id);
CREATE INDEX idx_invoices_status ON financial.invoices(status);
CREATE INDEX idx_payments_partner_id ON financial.payments(partner_id);