Saltar al contenido principal

Costeo Fiscal y Libro de Inventarios

Sub-proyecto 5 — Cumplimiento de obligaciones fiscales venezolanas para inventarios. Implementado: 2026-05-02. Marco legal: LISLR Art. 182, Código de Comercio Art. 35, VEN-NIIF para PYMES Sección 13, BA VEN-NIF 2 v4 (2025).

NormaExigenciaImplementación ACE
LISLR Art. 182 (Decreto 5.770)Métodos permitidos: costo promedio o PEPS (FIFO). UEPS prohibido. Cambios requieren autorización SENIAT y razones técnicascosting_method ENUM por categoría + audit log de cambios con justificación obligatoria
Código de Comercio Art. 35Libro de Inventarios anual con descripción detallada de bienes al cierreTabla inventory_book_snapshots (cabecera append-only) + inventory_book_snapshot_lines (detalle ítem-por-ítem)
VEN-NIIF para PYMES Sec 13 §17Costo: PEPS o promedio ponderado. Reconocer al menor entre costo y VNRPromedio ponderado en WeightedAverageCostService con FOR UPDATE. NRV en nrvService
BA VEN-NIF 2 v4 (2025)Reexpresión INPC obligatoria en Venezuela (hiperinflacionaria)inflationAdjustmentService.applyToInventories() con desglose por ítem

Método de costeo (LISLR Art. 182)

Cada categoría de inventario lleva un único método. El método se elige al crear la categoría (default WEIGHTED_AVERAGE) y debe aplicarse uniformemente. Cambiarlo exige:

  • Justificación técnica documentada (mínimo 50 caracteres)
  • Referencia a oficio SENIAT (opcional, recomendado)
  • Audit log inmutable en inventory_costing_method_changes

Métodos disponibles

  • WEIGHTED_AVERAGE (Costo Promedio Ponderado) — implementado en WeightedAverageCostService
  • FIFO (PEPS) — placeholder; activación futura requiere implementar cost layers

Endpoints

GET    /api/inventory/costing-methods                            # Lista por categoría
GET /api/inventory/costing-methods/categories/:id # Método de una categoría
GET /api/inventory/costing-methods/categories/:id/history # Audit log
GET /api/inventory/costing-methods/items/:id # Método derivado del ítem
POST /api/inventory/costing-methods/categories/:id/change # Cambiar (con justificación)

UI

Ruta: /inventory/costing-methods (permiso inventory:costing:read)

Navegación: Inventario → Métodos de Costeo

Libro de Inventarios (Código de Comercio Art. 35)

Snapshot anual append-only del estado de inventario al cierre fiscal. Estados:

DRAFT (creación) ──[close]──► CLOSED (immutable) ──[reopen + razón]──► REOPENED

Snapshot

La cabecera inventory_book_snapshots lleva:

  • fiscal_year UNIQUE — un snapshot por año
  • closing_date — default 31-dic
  • total_quantity, total_cost_value — totales agregados
  • total_reexpressed_value + inpc_index_used — si se aplicó reexpresión
  • costing_summary JSONB — desglose por categoría (método, qty, value, itemCount)

Líneas de detalle

Cada inventory_book_snapshot_lines captura inmutable:

  • Almacén + categoría + método de costeo aplicado
  • Ítem (código, nombre, UOM)
  • Cantidad, costo unitario, costo total
  • Reexpresión (si aplica): reexpressed_unit_cost, reexpressed_total
  • serial_count, lot_count — trazabilidad de unidades únicas

Cierre del Libro

Al cerrar (POST /:id/close) se puede aplicar reexpresión por inflación opcional:

  • Lee INPC de diciembre del año fiscal
  • Lee INPC de diciembre del año anterior (base)
  • Calcula factor INPC_cierre / INPC_base
  • Actualiza todas las líneas con reexpressed_unit_cost = unit_cost * factor
  • Calcula total_reexpressed_value

Reapertura

Sólo permiso inventory:book:reopen puede reabrir un libro CLOSED. Requiere razón obligatoria (>=20 caracteres) que se persiste en reopen_reason. La reapertura queda como evento de auditoría visible.

Endpoints

GET    /api/inventory/book                       # Listar snapshots (filtros: year, status)
POST /api/inventory/book # Crear DRAFT
GET /api/inventory/book/:id # Cabecera + totales
GET /api/inventory/book/:id/lines # Detalle paginado (warehouseId, categoryId, page, limit)
POST /api/inventory/book/:id/close # DRAFT → CLOSED (con applyReexpression)
POST /api/inventory/book/:id/reopen # CLOSED → REOPENED (con reason)
GET /api/inventory/book/:id/export.csv # Descarga CSV formato Art. 35 CCom

UI

  • Lista: /inventory/book (permiso inventory:book:read)
  • Detalle: /inventory/book/:id — stepper de estado, resumen por categoría, detalle ítem-a-ítem paginado, botones Cerrar / Reabrir / Exportar CSV

Reexpresión por inflación de inventarios (BA VEN-NIF 2)

Bug-fix crítico

Antes (sub-1..4): inflationAdjustmentService.isNonMonetary() clasificaba como inventarios las cuentas con prefijo '1.1.0'. Pero en producción ACE las cuentas 1.1.0/1.1.1/1.1.2 son CAJAS y BANCOS (monetarias). Si se hubiera aplicado REI, habría reexpresado caja erradamente.

Sub-5: la regla cambió a '1.1.5' (cuentas inventario reales: CRUDO, MATERIALES, EQUIPOS, ARTÍCULOS) + soporte para subtype explícito 'INVENTORY'. Por suerte la tabla inpc_indices estaba vacía en producción → el bug nunca afectó datos.

Trazabilidad ítem-a-ítem

Antes applyAdjustment() reexpresaba el saldo agregado de la cuenta inventario sin desglose por ítem.

Sub-5 añade inflationAdjustmentService.applyToInventories(adjustmentId):

  • Lee INPC del período del ajuste y INPC base (período anterior)
  • Calcula factor de reexpresión
  • Actualiza cada warehouse_stock con reexpressed_value = quantity * avg_cost * factor
  • Sella last_inflation_adjustment_at y last_inflation_adjustment_id

Datos INPC

Se sembraron 6 índices placeholder (2025-12 .. 2026-05) marcados con notes 'Placeholder sub5-M7'. El operador debe actualizar mensualmente con el índice oficial publicado por el BCV en Gaceta Oficial.

Permisos sub-5

CódigoDescripciónAsignado a roles
inventory:costing:readVer método por categoríaSuper Admin, Director Técnico, Director Financiero, Contador, Gerente Logística, Auditor
inventory:costing:changeCambiar método (con justificación)Super Admin, Director Financiero, Contador
inventory:book:readConsultar Libro de InventariosSuper Admin, Director Técnico, Director Financiero, Contador, Gerente Logística, Auditor
inventory:book:closeCerrar Libro anualSuper Admin, Director Financiero, Contador
inventory:book:reopenReabrir Libro cerradoSuper Admin, Director Financiero, Contador

Hallazgos del audit retrospectivo

Datos pre-sub5 en producción (auditoría 2026-05-02)

  • 354 stocks totales; 215 sin avg_cost o avg_cost=0
  • 115 stocks con qty>0 pero sin total_value
  • 1.000 movimientos; 617 sin unit_cost (datos demo)
  • Total inventario valorizado: USD 330.374,73

La migración M5 ejecuta backfill conservador: para cada (warehouse_id, item_id) con qty>0 sin valor, calcula promedio histórico desde inventory_movements con unit_cost > 0. Sólo escribe si el cálculo da resultado > 0; stocks sin historial valorizado quedan como están (visibles para corrección manual).

Migraciones aplicadas (sub-5)

#ArchivoPropósito
M120260502120001-sub5-inventory-costing-methodEnum + cols categorías + audit log
M220260502120002-sub5-warehouse-stocks-reexpressionSello reexpresión por stock
M320260502120003-sub5-inventory-book-tablesSnapshots + lines
M420260502120004-sub5-inventory-book-permissions5 permisos + asignaciones a roles
M520260502120005-sub5-backfill-stock-costsRecalcular avg_cost desde movimientos
M6(fix de código inflationAdjustmentService.js)Prefijo 1.1.01.1.5
M720260502120006-sub5-seed-inpc-baseline6 INPC placeholder (BCV)
M820260502120007-sub5-seed-costing-baselineAsignar WEIGHTED_AVERAGE a categorías + log baseline

Gap dimensional sub-1 cerrado

inventoryAccountingService ahora completa budget_position_id en cada journal_entry_line mediante _enrichLinesWithBudgetPosition() que consulta account_budget_position_links con role DEBIT_DEFAULT o CREDIT_DEFAULT. Esto cierra el gap dimensional dejado por sub-1 sin modificar los 9 métodos individuales del servicio.

Capturas de producción (E2E Chrome MCP en https://erp-aceog.com)

Métodos de Costeo Lista de 28 categorías con método "Costo Promedio" — captura tras deploy en producción.

Modal de cambio de método Cambio LISLR Art. 182 con justificación obligatoria >=50ch. Botón Confirmar deshabilitado sin razón.

Historial baseline Audit log inicial registrado por M8: justificación de adopción WEIGHTED_AVERAGE.

Libro de Inventarios — Lista vacía Estado inicial sin snapshots. Botón "Nuevo Snapshot Anual" para empezar.

Libro de Inventarios — Detalle Snapshot 2026 con 201 ítems, USD 330.374,73 valor total, resumen por 12 categorías y detalle ítem-por-ítem.

Modal cierre con reexpresión Confirmación de cierre con flag de reexpresión por inflación opcional (BA VEN-NIF 2).

Libro Cerrado Estado tras cerrar: chip "Cerrado" en verde, botón cambia a "Reabrir Libro".

Lista con snapshot cerrado Snapshot año fiscal 2026 cerrado con totales finales.