erp-core/docs/04-modelado/domain-models/inventory-domain.md

9.3 KiB

MODELO DE DOMINIO: Inventario y Compras

Módulos: MGN-005 (Inventario), MGN-006 (Compras) Fecha: 2025-11-24 Referencia Odoo: stock, purchase Referencia Gamilit: inventory_management, purchasing_management


Diagrama de Entidades (Texto UML)

[Product]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - name: String
  - code: String
  - barcode: String
  - product_type: ENUM (storable, consumable, service)
  - category_id: UUID (FK)
  - uom_id: UUID (FK)
  - cost_price: Decimal
  - sale_price: Decimal

  1 <----> * [StockMove]
  1 <----> * [PurchaseOrderLine]

[Warehouse]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - company_id: UUID (FK)
  - name: String
  - code: String

  1 <----> * [Location]

[Location]
  - id: UUID (PK)
  - warehouse_id: UUID (FK)
  - name: String
  - parent_id: UUID (FK self)
  - location_type: ENUM (physical, virtual, supplier, customer)

  1 <----> * [StockQuant]
  1 <----> * [StockMove] (origen/destino)

[StockQuant]
  - id: UUID (PK)
  - product_id: UUID (FK)
  - location_id: UUID (FK)
  - quantity: Decimal
  - lot_id: UUID (FK)
  - cost: Decimal

[StockMove]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - product_id: UUID (FK)
  - location_src_id: UUID (FK)
  - location_dest_id: UUID (FK)
  - quantity: Decimal
  - uom_id: UUID (FK)
  - status: ENUM (draft, confirmed, done, cancelled)
  - picking_id: UUID (FK)

[Picking]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - company_id: UUID (FK)
  - name: String
  - picking_type: ENUM (incoming, outgoing, internal)
  - partner_id: UUID (FK)
  - date: Date
  - status: ENUM (draft, ready, done, cancelled)

  1 <----> * [StockMove]

[Lot]
  - id: UUID (PK)
  - product_id: UUID (FK)
  - name: String
  - lot_date: Date
  - expiration_date: Date

[PurchaseOrder]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - company_id: UUID (FK)
  - partner_id: UUID (FK)
  - name: String
  - order_date: Date
  - expected_date: Date
  - status: ENUM (draft, confirmed, received, billed, cancelled)
  - amount_total: Decimal

  1 <----> * [PurchaseOrderLine]
  1 <----> * [Picking]

[PurchaseOrderLine]
  - id: UUID (PK)
  - order_id: UUID (FK)
  - product_id: UUID (FK)
  - description: String
  - quantity: Decimal
  - price_unit: Decimal
  - tax_ids: UUID[]
  - subtotal: Decimal
  - total: Decimal
  - analytic_account_id: UUID (FK)

Entidades Principales

1. Product (Producto)

Descripción: Producto almacenable, consumible o servicio.

Atributos:

  • id: UUID
  • name: Nombre del producto
  • code: Código interno
  • barcode: Código de barras
  • product_type: storable, consumable, service
  • category_id: Categoría
  • uom_id: Unidad de medida
  • cost_price: Precio de costo
  • sale_price: Precio de venta

Relaciones:

  • 1 Product → N StockMoves
  • 1 Product → N PurchaseOrderLines
  • 1 Product → N StockQuants

Patrón Odoo: product.product + product.template Tipos:

  • storable: Productos físicos con inventario
  • consumable: Productos que no se trackean (ej: tornillos)
  • service: Servicios (no tienen stock)

2. Warehouse (Almacén)

Descripción: Almacén físico de la empresa.

Atributos:

  • id: UUID
  • company_id: Empresa propietaria
  • name: Nombre del almacén
  • code: Código (ej: "WH-MEX")

Relaciones:

  • 1 Warehouse → N Locations

Patrón Odoo: stock.warehouse Almacenes típicos:

  • Almacén Principal
  • Almacén de Tránsito
  • Almacén de Obra (construcción)

3. Location (Ubicación)

Descripción: Ubicación física o virtual dentro de almacén.

Atributos:

  • id: UUID
  • warehouse_id: Almacén propietario
  • name: Nombre de ubicación
  • parent_id: Ubicación padre (jerarquía)
  • location_type: physical, virtual, supplier, customer

Relaciones:

  • 1 Location → N StockQuants
  • 1 Location → N StockMoves (origen/destino)

Patrón Odoo: stock.location Tipos:

  • physical: Ubicaciones físicas
  • virtual: Ubicaciones virtuales (proveedores, clientes, producción)
  • supplier: Stock de proveedores
  • customer: Stock de clientes

4. StockQuant (Cantidad en Stock)

Descripción: Cantidad de producto en ubicación específica.

Atributos:

  • id: UUID
  • product_id: Producto
  • location_id: Ubicación
  • quantity: Cantidad disponible
  • lot_id: Lote (opcional)
  • cost: Costo unitario

Relaciones:

  • N StockQuants → 1 Product
  • N StockQuants → 1 Location

Patrón Odoo: stock.quant Nota: Se actualiza automáticamente con cada movimiento

5. StockMove (Movimiento de Inventario)

Descripción: Movimiento de stock de una ubicación a otra.

Atributos:

  • id: UUID
  • product_id: Producto movido
  • location_src_id: Ubicación origen
  • location_dest_id: Ubicación destino
  • quantity: Cantidad movida
  • status: draft, confirmed, done, cancelled
  • picking_id: Picking asociado

Relaciones:

  • N StockMoves → 1 Product
  • N StockMoves → 1 Picking

Patrón Odoo: stock.move Flujo: draft → confirmed → done

6. Picking (Albarán)

Descripción: Agrupación de movimientos de stock.

Atributos:

  • id: UUID
  • name: Número de albarán
  • picking_type: incoming (recepción), outgoing (entrega), internal (transferencia)
  • partner_id: Partner asociado
  • date: Fecha
  • status: draft, ready, done, cancelled

Relaciones:

  • 1 Picking → N StockMoves

Patrón Odoo: stock.picking Tipos:

  • incoming: Recepción de proveedores
  • outgoing: Entrega a clientes
  • internal: Transferencias internas

7. Lot (Lote)

Descripción: Lote de producción o número de serie.

Atributos:

  • id: UUID
  • product_id: Producto
  • name: Número de lote/serie
  • lot_date: Fecha de producción
  • expiration_date: Fecha de caducidad

Relaciones:

  • N Lots → 1 Product

Patrón Odoo: stock.production.lot Uso: Trazabilidad completa

8. PurchaseOrder (Orden de Compra)

Descripción: Orden de compra a proveedor.

Atributos:

  • id: UUID
  • partner_id: Proveedor
  • name: Número de orden
  • order_date: Fecha de orden
  • expected_date: Fecha esperada de entrega
  • status: draft, confirmed, received, billed, cancelled
  • amount_total: Monto total

Relaciones:

  • 1 PurchaseOrder → N PurchaseOrderLines
  • 1 PurchaseOrder → N Pickings (recepciones)

Patrón Odoo: purchase.order Flujo: draft → confirmed → received → billed

9. PurchaseOrderLine (Línea de Orden de Compra)

Descripción: Línea de producto en orden de compra.

Atributos:

  • id: UUID
  • order_id: Orden propietaria
  • product_id: Producto
  • description: Descripción
  • quantity: Cantidad ordenada
  • price_unit: Precio unitario
  • tax_ids: Impuestos
  • analytic_account_id: Cuenta analítica (opcional)

Relaciones:

  • N PurchaseOrderLines → 1 PurchaseOrder

Patrón Odoo: purchase.order.line

Reglas de Negocio

RN-INV-001: Movimientos Atómicos

  • TODO movimiento de stock debe tener origen y destino
  • Cantidad debe ser > 0
  • Producto debe ser tipo 'storable' para afectar stock

RN-INV-002: Actualización Automática de Quants

  • Al confirmar StockMove (status=done), actualizar StockQuants
  • Decrementar en location_src
  • Incrementar en location_dest

RN-INV-003: Valoración de Inventario

  • Método FIFO por defecto
  • Calcular costo promedio automáticamente
  • Generar asientos contables si valoración automática activa

RN-INV-004: Trazabilidad

  • Productos con tracking='lot' requieren lot_id en movimientos
  • Productos con tracking='serial' requieren quantity=1 por movimiento

RN-INV-005: Integración Compras-Inventario

  • Al confirmar PO, generar Picking automáticamente
  • Al validar Picking, marcar PO como 'received'

RN-INV-006: 3-Way Match

  • Validar: PO quantity = Picking quantity = Invoice quantity
  • Permitir tolerancias configurables (ej: +/- 5%)

Casos de Uso Principales

  1. UC-INV-001: Usuario crea producto almacenable
  2. UC-INV-002: Usuario crea almacén con ubicaciones
  3. UC-INV-003: Usuario realiza transferencia interna
  4. UC-INV-004: Usuario crea orden de compra
  5. UC-INV-005: Sistema genera picking al confirmar PO
  6. UC-INV-006: Usuario valida recepción de productos
  7. UC-INV-007: Sistema actualiza stock automáticamente
  8. UC-INV-008: Usuario consulta inventario por ubicación

Validaciones y Constraints

-- Product code único por tenant
UNIQUE (tenant_id, code)

-- Cantidad > 0 en movimientos
CHECK (quantity > 0)

-- Ubicaciones no pueden ser su propio padre
CHECK (parent_id != id)

-- Status transitions válidos
-- (state machine)

Índices Requeridos

CREATE INDEX idx_products_code ON inventory.products(code);
CREATE INDEX idx_products_barcode ON inventory.products(barcode);
CREATE INDEX idx_stock_quants_product_id ON inventory.stock_quants(product_id);
CREATE INDEX idx_stock_quants_location_id ON inventory.stock_quants(location_id);
CREATE INDEX idx_stock_moves_product_id ON inventory.stock_moves(product_id);
CREATE INDEX idx_stock_moves_picking_id ON inventory.stock_moves(picking_id);
CREATE INDEX idx_purchase_orders_partner_id ON purchase.purchase_orders(partner_id);
CREATE INDEX idx_purchase_orders_status ON purchase.purchase_orders(status);

Referencias