- 00-auth-base.sql: Extracted auth.tenants+users from recreate-database.sh - 03b-core-companies.sql: DDL for auth.companies entity - 21b-inventory-extended.sql: 7 new tables for inventory entities without DDL - 24-invoices.sql: billing→operations schema to resolve duplication - 27/28/29-cfdi: Track existing CFDI DDL files - recreate-database.sh: Updated ddl_files array (17→43 entries) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
479 lines
21 KiB
SQL
479 lines
21 KiB
SQL
-- =============================================================
|
|
-- ARCHIVO: 21b-inventory-extended.sql
|
|
-- DESCRIPCION: Tablas extendidas de inventario (Odoo-style)
|
|
-- Incluye: locations, products (inventory-specific), stock_quants,
|
|
-- stock_moves, stock_valuation_layers, inventory_adjustments,
|
|
-- inventory_adjustment_lines
|
|
-- VERSION: 1.0.0
|
|
-- PROYECTO: ERP-Core V2
|
|
-- FECHA: 2026-02-05
|
|
-- DEPENDE DE: 18-warehouses.sql, 21-inventory.sql
|
|
-- COHERENCIA: Entidades TypeORM sin DDL previo
|
|
-- =============================================================
|
|
|
|
-- =====================
|
|
-- SCHEMA: inventory (ya creado en 18-warehouses.sql)
|
|
-- =====================
|
|
|
|
-- =====================
|
|
-- TIPO ENUM: location_type
|
|
-- Tipos de ubicacion Odoo-style
|
|
-- =====================
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'location_type_enum') THEN
|
|
CREATE TYPE inventory.location_type_enum AS ENUM (
|
|
'internal',
|
|
'supplier',
|
|
'customer',
|
|
'inventory',
|
|
'production',
|
|
'transit'
|
|
);
|
|
END IF;
|
|
END$$;
|
|
|
|
-- =====================
|
|
-- TIPO ENUM: product_type
|
|
-- Tipos de producto para inventario
|
|
-- =====================
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'inv_product_type_enum') THEN
|
|
CREATE TYPE inventory.inv_product_type_enum AS ENUM (
|
|
'storable',
|
|
'consumable',
|
|
'service'
|
|
);
|
|
END IF;
|
|
END$$;
|
|
|
|
-- =====================
|
|
-- TIPO ENUM: tracking_type
|
|
-- Tipo de seguimiento de producto
|
|
-- =====================
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'tracking_type_enum') THEN
|
|
CREATE TYPE inventory.tracking_type_enum AS ENUM (
|
|
'none',
|
|
'lot',
|
|
'serial'
|
|
);
|
|
END IF;
|
|
END$$;
|
|
|
|
-- =====================
|
|
-- TIPO ENUM: valuation_method
|
|
-- Metodo de valuacion de inventario
|
|
-- =====================
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'valuation_method_enum') THEN
|
|
CREATE TYPE inventory.valuation_method_enum AS ENUM (
|
|
'standard',
|
|
'fifo',
|
|
'average'
|
|
);
|
|
END IF;
|
|
END$$;
|
|
|
|
-- =====================
|
|
-- TIPO ENUM: adjustment_status
|
|
-- Estado de ajuste de inventario
|
|
-- =====================
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'adjustment_status_enum') THEN
|
|
CREATE TYPE inventory.adjustment_status_enum AS ENUM (
|
|
'draft',
|
|
'confirmed',
|
|
'done',
|
|
'cancelled'
|
|
);
|
|
END IF;
|
|
END$$;
|
|
|
|
-- =====================
|
|
-- TABLA: locations
|
|
-- Ubicaciones logicas de inventario (Odoo-style)
|
|
-- Complementa warehouse_locations con modelo Odoo de ubicaciones virtuales
|
|
-- (supplier, customer, inventory loss, production, transit)
|
|
-- Coherencia: location.entity.ts
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS inventory.locations (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
warehouse_id UUID REFERENCES inventory.warehouses(id) ON DELETE SET NULL,
|
|
|
|
-- Identificacion
|
|
name VARCHAR(255) NOT NULL,
|
|
complete_name VARCHAR(500),
|
|
|
|
-- Tipo de ubicacion
|
|
location_type inventory.location_type_enum NOT NULL,
|
|
|
|
-- Jerarquia (auto-referencia)
|
|
parent_id UUID REFERENCES inventory.locations(id) ON DELETE SET NULL,
|
|
|
|
-- Flags especiales
|
|
is_scrap_location BOOLEAN NOT NULL DEFAULT FALSE,
|
|
is_return_location BOOLEAN NOT NULL DEFAULT FALSE,
|
|
|
|
-- Estado
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Indices para locations
|
|
CREATE INDEX IF NOT EXISTS idx_locations_tenant_id ON inventory.locations(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_locations_warehouse_id ON inventory.locations(warehouse_id) WHERE warehouse_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_locations_parent_id ON inventory.locations(parent_id) WHERE parent_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_locations_type ON inventory.locations(location_type);
|
|
CREATE INDEX IF NOT EXISTS idx_locations_active ON inventory.locations(active) WHERE active = TRUE;
|
|
CREATE INDEX IF NOT EXISTS idx_locations_scrap ON inventory.locations(is_scrap_location) WHERE is_scrap_location = TRUE;
|
|
CREATE INDEX IF NOT EXISTS idx_locations_return ON inventory.locations(is_return_location) WHERE is_return_location = TRUE;
|
|
|
|
-- =====================
|
|
-- TABLA: products
|
|
-- Productos especificos de inventario (Odoo-style)
|
|
-- Diferente de products.products: este es para gestion de almacen,
|
|
-- valuacion, tracking por lote/serie, mientras products.products
|
|
-- es para comercio/retail con codigos SAT, impuestos, etc.
|
|
-- Coherencia: product.entity.ts (inventory module)
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS inventory.products (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Identificacion
|
|
name VARCHAR(255) NOT NULL,
|
|
code VARCHAR(100),
|
|
barcode VARCHAR(100),
|
|
description TEXT,
|
|
|
|
-- Clasificacion
|
|
product_type inventory.inv_product_type_enum NOT NULL DEFAULT 'storable',
|
|
tracking inventory.tracking_type_enum NOT NULL DEFAULT 'none',
|
|
category_id UUID,
|
|
|
|
-- Unidades de medida
|
|
uom_id UUID NOT NULL,
|
|
purchase_uom_id UUID,
|
|
|
|
-- Precios y costo
|
|
cost_price DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
|
list_price DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
|
|
|
-- Valuacion
|
|
valuation_method inventory.valuation_method_enum NOT NULL DEFAULT 'fifo',
|
|
|
|
-- Flags
|
|
is_storable BOOLEAN NOT NULL DEFAULT TRUE,
|
|
can_be_sold BOOLEAN NOT NULL DEFAULT TRUE,
|
|
can_be_purchased BOOLEAN NOT NULL DEFAULT TRUE,
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
|
|
-- Medidas fisicas
|
|
weight DECIMAL(12, 4),
|
|
volume DECIMAL(12, 4),
|
|
|
|
-- Imagen
|
|
image_url VARCHAR(500),
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
deleted_at TIMESTAMPTZ,
|
|
deleted_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Indices para products
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_tenant_id ON inventory.products(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_code ON inventory.products(code) WHERE deleted_at IS NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_barcode ON inventory.products(barcode) WHERE deleted_at IS NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_category_id ON inventory.products(category_id) WHERE category_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_active ON inventory.products(active) WHERE deleted_at IS NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_type ON inventory.products(product_type);
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_tracking ON inventory.products(tracking) WHERE tracking != 'none';
|
|
CREATE INDEX IF NOT EXISTS idx_inv_products_valuation ON inventory.products(valuation_method);
|
|
|
|
-- Unique code per tenant (soft-delete aware)
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_inv_products_tenant_code
|
|
ON inventory.products(tenant_id, code) WHERE deleted_at IS NULL AND code IS NOT NULL;
|
|
|
|
-- =====================
|
|
-- TABLA: stock_quants
|
|
-- Cantidades de stock por producto/ubicacion/lote (modelo Odoo)
|
|
-- Representa la cantidad real de un producto en una ubicacion especifica,
|
|
-- opcionalmente separada por lote
|
|
-- Coherencia: stock-quant.entity.ts
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS inventory.stock_quants (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Producto y ubicacion
|
|
product_id UUID NOT NULL REFERENCES inventory.products(id) ON DELETE CASCADE,
|
|
location_id UUID NOT NULL REFERENCES inventory.locations(id) ON DELETE CASCADE,
|
|
|
|
-- Lote (opcional)
|
|
lot_id UUID REFERENCES inventory.lots(id) ON DELETE SET NULL,
|
|
|
|
-- Cantidades
|
|
quantity DECIMAL(16, 4) NOT NULL DEFAULT 0,
|
|
reserved_quantity DECIMAL(16, 4) NOT NULL DEFAULT 0,
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- Unicidad: un solo registro por combinacion producto+ubicacion+lote
|
|
UNIQUE(product_id, location_id, COALESCE(lot_id, '00000000-0000-0000-0000-000000000000'::UUID))
|
|
);
|
|
|
|
-- Indices para stock_quants
|
|
CREATE INDEX IF NOT EXISTS idx_stock_quants_tenant_id ON inventory.stock_quants(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_quants_product_id ON inventory.stock_quants(product_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_quants_location_id ON inventory.stock_quants(location_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_quants_lot_id ON inventory.stock_quants(lot_id) WHERE lot_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_stock_quants_quantity ON inventory.stock_quants(quantity) WHERE quantity != 0;
|
|
CREATE INDEX IF NOT EXISTS idx_stock_quants_reserved ON inventory.stock_quants(reserved_quantity) WHERE reserved_quantity != 0;
|
|
|
|
-- =====================
|
|
-- TABLA: stock_moves
|
|
-- Movimientos individuales de stock vinculados a un picking (Odoo-style)
|
|
-- Cada linea de un picking genera un stock_move
|
|
-- Coherencia: stock-move.entity.ts
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS inventory.stock_moves (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Picking padre
|
|
picking_id UUID NOT NULL REFERENCES inventory.pickings(id) ON DELETE CASCADE,
|
|
|
|
-- Producto
|
|
product_id UUID NOT NULL REFERENCES inventory.products(id) ON DELETE RESTRICT,
|
|
product_uom_id UUID NOT NULL,
|
|
|
|
-- Ubicaciones origen y destino
|
|
location_id UUID NOT NULL REFERENCES inventory.locations(id),
|
|
location_dest_id UUID NOT NULL REFERENCES inventory.locations(id),
|
|
|
|
-- Cantidades
|
|
product_qty DECIMAL(16, 4) NOT NULL,
|
|
quantity_done DECIMAL(16, 4) NOT NULL DEFAULT 0,
|
|
|
|
-- Lote (opcional)
|
|
lot_id UUID REFERENCES inventory.lots(id) ON DELETE SET NULL,
|
|
|
|
-- Estado (reutiliza move_status_enum de 21-inventory.sql)
|
|
status inventory.move_status_enum NOT NULL DEFAULT 'draft',
|
|
|
|
-- Fecha del movimiento
|
|
date TIMESTAMPTZ,
|
|
|
|
-- Documento origen
|
|
origin VARCHAR(255),
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Indices para stock_moves
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_tenant_id ON inventory.stock_moves(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_picking_id ON inventory.stock_moves(picking_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_product_id ON inventory.stock_moves(product_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_status ON inventory.stock_moves(status);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_date ON inventory.stock_moves(date) WHERE date IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_location ON inventory.stock_moves(location_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_location_dest ON inventory.stock_moves(location_dest_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_lot_id ON inventory.stock_moves(lot_id) WHERE lot_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_stock_moves_origin ON inventory.stock_moves(origin) WHERE origin IS NOT NULL;
|
|
|
|
-- =====================
|
|
-- TABLA: stock_valuation_layers
|
|
-- Capas de valuacion de inventario (FIFO/AVCO/Standard)
|
|
-- Cada movimiento de stock genera una capa de valuacion para
|
|
-- rastrear el costo historico del inventario
|
|
-- Coherencia: stock-valuation-layer.entity.ts
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS inventory.stock_valuation_layers (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Producto y empresa
|
|
product_id UUID NOT NULL REFERENCES inventory.products(id) ON DELETE RESTRICT,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
-- Cantidades y valores
|
|
quantity DECIMAL(16, 4) NOT NULL,
|
|
unit_cost DECIMAL(12, 2) NOT NULL,
|
|
value DECIMAL(16, 2) NOT NULL,
|
|
|
|
-- Remanente (para FIFO)
|
|
remaining_qty DECIMAL(16, 4) NOT NULL,
|
|
remaining_value DECIMAL(16, 2) NOT NULL,
|
|
|
|
-- Movimiento de stock origen
|
|
stock_move_id UUID REFERENCES inventory.stock_moves(id) ON DELETE SET NULL,
|
|
|
|
-- Descripcion
|
|
description VARCHAR(255),
|
|
|
|
-- Contabilidad (referencia a asientos contables)
|
|
account_move_id UUID,
|
|
journal_entry_id UUID,
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Indices para stock_valuation_layers
|
|
CREATE INDEX IF NOT EXISTS idx_valuation_layers_tenant_id ON inventory.stock_valuation_layers(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_valuation_layers_product_id ON inventory.stock_valuation_layers(product_id);
|
|
CREATE INDEX IF NOT EXISTS idx_valuation_layers_company_id ON inventory.stock_valuation_layers(company_id);
|
|
CREATE INDEX IF NOT EXISTS idx_valuation_layers_stock_move_id ON inventory.stock_valuation_layers(stock_move_id) WHERE stock_move_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_valuation_layers_remaining_qty ON inventory.stock_valuation_layers(remaining_qty) WHERE remaining_qty > 0;
|
|
CREATE INDEX IF NOT EXISTS idx_valuation_layers_account_move ON inventory.stock_valuation_layers(account_move_id) WHERE account_move_id IS NOT NULL;
|
|
|
|
-- =====================
|
|
-- TABLA: inventory_adjustments
|
|
-- Ajustes de inventario (conteos y correcciones)
|
|
-- Agrupa lineas de ajuste para una ubicacion y fecha especifica
|
|
-- Coherencia: inventory-adjustment.entity.ts
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS inventory.inventory_adjustments (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
-- Identificacion
|
|
name VARCHAR(100) NOT NULL,
|
|
|
|
-- Ubicacion de ajuste
|
|
location_id UUID NOT NULL REFERENCES inventory.locations(id),
|
|
|
|
-- Fecha del ajuste
|
|
date DATE NOT NULL,
|
|
|
|
-- Estado
|
|
status inventory.adjustment_status_enum NOT NULL DEFAULT 'draft',
|
|
|
|
-- Notas
|
|
notes TEXT,
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Indices para inventory_adjustments
|
|
CREATE INDEX IF NOT EXISTS idx_adjustments_tenant_id ON inventory.inventory_adjustments(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_adjustments_company_id ON inventory.inventory_adjustments(company_id);
|
|
CREATE INDEX IF NOT EXISTS idx_adjustments_status ON inventory.inventory_adjustments(status);
|
|
CREATE INDEX IF NOT EXISTS idx_adjustments_date ON inventory.inventory_adjustments(date);
|
|
CREATE INDEX IF NOT EXISTS idx_adjustments_location ON inventory.inventory_adjustments(location_id);
|
|
|
|
-- =====================
|
|
-- TABLA: inventory_adjustment_lines
|
|
-- Lineas individuales de ajuste de inventario
|
|
-- Cada linea compara cantidad teorica vs contada para un producto
|
|
-- Coherencia: inventory-adjustment-line.entity.ts
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS inventory.inventory_adjustment_lines (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
adjustment_id UUID NOT NULL REFERENCES inventory.inventory_adjustments(id) ON DELETE CASCADE,
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Producto y ubicacion
|
|
product_id UUID NOT NULL REFERENCES inventory.products(id) ON DELETE RESTRICT,
|
|
location_id UUID NOT NULL REFERENCES inventory.locations(id),
|
|
|
|
-- Lote (opcional)
|
|
lot_id UUID REFERENCES inventory.lots(id) ON DELETE SET NULL,
|
|
|
|
-- Cantidades
|
|
theoretical_qty DECIMAL(16, 4) NOT NULL DEFAULT 0,
|
|
counted_qty DECIMAL(16, 4) NOT NULL DEFAULT 0,
|
|
difference_qty DECIMAL(16, 4) GENERATED ALWAYS AS (counted_qty - theoretical_qty) STORED,
|
|
|
|
-- Unidad de medida
|
|
uom_id UUID,
|
|
|
|
-- Notas
|
|
notes TEXT,
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices para inventory_adjustment_lines
|
|
CREATE INDEX IF NOT EXISTS idx_adjustment_lines_adjustment_id ON inventory.inventory_adjustment_lines(adjustment_id);
|
|
CREATE INDEX IF NOT EXISTS idx_adjustment_lines_product_id ON inventory.inventory_adjustment_lines(product_id);
|
|
CREATE INDEX IF NOT EXISTS idx_adjustment_lines_location_id ON inventory.inventory_adjustment_lines(location_id);
|
|
CREATE INDEX IF NOT EXISTS idx_adjustment_lines_lot_id ON inventory.inventory_adjustment_lines(lot_id) WHERE lot_id IS NOT NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_adjustment_lines_tenant_id ON inventory.inventory_adjustment_lines(tenant_id);
|
|
|
|
-- =====================
|
|
-- COMENTARIOS
|
|
-- =====================
|
|
|
|
-- locations
|
|
COMMENT ON TABLE inventory.locations IS 'Ubicaciones logicas de inventario (Odoo-style). Incluye ubicaciones virtuales: supplier, customer, inventory loss, production, transit';
|
|
COMMENT ON COLUMN inventory.locations.location_type IS 'Tipo: internal (almacen), supplier (proveedor virtual), customer (cliente virtual), inventory (perdida/ajuste), production (produccion), transit (en transito)';
|
|
COMMENT ON COLUMN inventory.locations.complete_name IS 'Nombre completo con jerarquia (ej: WH/Stock/Zone-A)';
|
|
COMMENT ON COLUMN inventory.locations.is_scrap_location IS 'Si es TRUE, productos movidos aqui se consideran scrap/desperdicio';
|
|
COMMENT ON COLUMN inventory.locations.is_return_location IS 'Si es TRUE, esta ubicacion se usa para devoluciones';
|
|
|
|
-- products (inventory)
|
|
COMMENT ON TABLE inventory.products IS 'Productos para gestion de inventario (Odoo-style). Diferente de products.products que es para comercio/retail';
|
|
COMMENT ON COLUMN inventory.products.product_type IS 'Tipo: storable (se almacena), consumable (se consume sin tracking), service (no se almacena)';
|
|
COMMENT ON COLUMN inventory.products.tracking IS 'Seguimiento: none, lot (por lote), serial (numero de serie unico)';
|
|
COMMENT ON COLUMN inventory.products.valuation_method IS 'Metodo de valuacion: standard (costo fijo), fifo (primero en entrar), average (costo promedio)';
|
|
COMMENT ON COLUMN inventory.products.is_storable IS 'Flag derivado de product_type=storable. Facilita filtros directos';
|
|
|
|
-- stock_quants
|
|
COMMENT ON TABLE inventory.stock_quants IS 'Cantidades reales de stock por producto/ubicacion/lote (modelo Odoo quant)';
|
|
COMMENT ON COLUMN inventory.stock_quants.quantity IS 'Cantidad total disponible en esta ubicacion';
|
|
COMMENT ON COLUMN inventory.stock_quants.reserved_quantity IS 'Cantidad reservada para pickings pendientes';
|
|
|
|
-- stock_moves
|
|
COMMENT ON TABLE inventory.stock_moves IS 'Movimientos individuales de stock vinculados a un picking. Cada linea de picking genera un move';
|
|
COMMENT ON COLUMN inventory.stock_moves.product_qty IS 'Cantidad solicitada del movimiento';
|
|
COMMENT ON COLUMN inventory.stock_moves.quantity_done IS 'Cantidad realmente procesada';
|
|
COMMENT ON COLUMN inventory.stock_moves.status IS 'Estado: draft, waiting, confirmed, assigned, done, cancelled';
|
|
COMMENT ON COLUMN inventory.stock_moves.origin IS 'Documento origen (ej: PO-2026-001, SO-2026-001)';
|
|
|
|
-- stock_valuation_layers
|
|
COMMENT ON TABLE inventory.stock_valuation_layers IS 'Capas de valuacion de inventario para FIFO/AVCO/Standard. Cada movimiento crea una capa';
|
|
COMMENT ON COLUMN inventory.stock_valuation_layers.remaining_qty IS 'Cantidad restante en esta capa (para FIFO: se consume de las capas mas antiguas)';
|
|
COMMENT ON COLUMN inventory.stock_valuation_layers.remaining_value IS 'Valor monetario restante en esta capa';
|
|
COMMENT ON COLUMN inventory.stock_valuation_layers.account_move_id IS 'Referencia al asiento contable generado (si aplica)';
|
|
|
|
-- inventory_adjustments
|
|
COMMENT ON TABLE inventory.inventory_adjustments IS 'Ajustes de inventario para corregir diferencias entre stock teorico y real';
|
|
COMMENT ON COLUMN inventory.inventory_adjustments.status IS 'Estado: draft (borrador), confirmed (confirmado), done (aplicado), cancelled';
|
|
|
|
-- inventory_adjustment_lines
|
|
COMMENT ON TABLE inventory.inventory_adjustment_lines IS 'Lineas de ajuste: cada una compara cantidad teorica vs contada para un producto en una ubicacion';
|
|
COMMENT ON COLUMN inventory.inventory_adjustment_lines.theoretical_qty IS 'Cantidad segun el sistema antes del conteo';
|
|
COMMENT ON COLUMN inventory.inventory_adjustment_lines.counted_qty IS 'Cantidad real contada fisicamente';
|
|
COMMENT ON COLUMN inventory.inventory_adjustment_lines.difference_qty IS 'Diferencia calculada: counted_qty - theoretical_qty (columna generada)';
|