erp-core-database-v2/ddl/18-warehouses.sql
rckrdmrd 5043a640e4 refactor: Restructure DDL with numbered schema files
- Replace old DDL structure with new numbered files (01-24)
- Update migrations and seeds for new schema
- Clean up deprecated files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 00:40:32 -06:00

183 lines
7.0 KiB
SQL

-- =============================================================
-- ARCHIVO: 18-warehouses.sql
-- DESCRIPCION: Almacenes y ubicaciones
-- VERSION: 1.0.0
-- PROYECTO: ERP-Core V2
-- FECHA: 2026-01-13
-- =============================================================
-- =====================
-- SCHEMA: inventory (compartido con 19-inventory.sql)
-- =====================
CREATE SCHEMA IF NOT EXISTS inventory;
-- =====================
-- TABLA: warehouses
-- Almacenes/bodegas para inventario
-- =====================
CREATE TABLE IF NOT EXISTS inventory.warehouses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
branch_id UUID REFERENCES core.branches(id) ON DELETE SET NULL,
-- Identificacion
code VARCHAR(20) NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
-- Tipo
warehouse_type VARCHAR(20) DEFAULT 'standard', -- standard, transit, returns, quarantine, virtual
-- Direccion
address_line1 VARCHAR(200),
address_line2 VARCHAR(200),
city VARCHAR(100),
state VARCHAR(100),
postal_code VARCHAR(20),
country VARCHAR(3) DEFAULT 'MEX',
-- Contacto
manager_name VARCHAR(100),
phone VARCHAR(30),
email VARCHAR(255),
-- Geolocalizacion
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
-- Capacidad
capacity_units INTEGER, -- Capacidad en unidades
capacity_volume DECIMAL(10, 4), -- Capacidad en m3
capacity_weight DECIMAL(10, 4), -- Capacidad en kg
-- Configuracion
settings JSONB DEFAULT '{}',
-- Ejemplo: {"allow_negative": false, "auto_reorder": true}
-- Estado
is_active BOOLEAN DEFAULT TRUE,
is_default BOOLEAN DEFAULT FALSE,
-- 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,
UNIQUE(tenant_id, code)
);
-- Indices para warehouses
CREATE INDEX IF NOT EXISTS idx_warehouses_tenant ON inventory.warehouses(tenant_id);
CREATE INDEX IF NOT EXISTS idx_warehouses_branch ON inventory.warehouses(branch_id);
CREATE INDEX IF NOT EXISTS idx_warehouses_code ON inventory.warehouses(code);
CREATE INDEX IF NOT EXISTS idx_warehouses_type ON inventory.warehouses(warehouse_type);
CREATE INDEX IF NOT EXISTS idx_warehouses_active ON inventory.warehouses(is_active) WHERE is_active = TRUE;
CREATE INDEX IF NOT EXISTS idx_warehouses_default ON inventory.warehouses(tenant_id, is_default) WHERE is_default = TRUE;
-- =====================
-- TABLA: warehouse_locations
-- Ubicaciones dentro de almacenes (pasillos, racks, estantes)
-- =====================
CREATE TABLE IF NOT EXISTS inventory.warehouse_locations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
warehouse_id UUID NOT NULL REFERENCES inventory.warehouses(id) ON DELETE CASCADE,
parent_id UUID REFERENCES inventory.warehouse_locations(id) ON DELETE SET NULL,
-- Identificacion
code VARCHAR(30) NOT NULL,
name VARCHAR(100) NOT NULL,
barcode VARCHAR(50),
-- Tipo de ubicacion
location_type VARCHAR(20) DEFAULT 'shelf', -- zone, aisle, rack, shelf, bin
-- Jerarquia
hierarchy_path TEXT, -- /warehouse-01/zone-a/rack-1/shelf-2
hierarchy_level INTEGER DEFAULT 0,
-- Coordenadas dentro del almacen
aisle VARCHAR(10),
rack VARCHAR(10),
shelf VARCHAR(10),
bin VARCHAR(10),
-- Capacidad
capacity_units INTEGER,
capacity_volume DECIMAL(10, 4),
capacity_weight DECIMAL(10, 4),
-- Restricciones
allowed_product_types TEXT[] DEFAULT '{}', -- Tipos de producto permitidos
temperature_range JSONB, -- {"min": -20, "max": 4} para productos refrigerados
humidity_range JSONB, -- {"min": 30, "max": 50}
-- Estado
is_active BOOLEAN DEFAULT TRUE,
is_pickable BOOLEAN DEFAULT TRUE, -- Se puede tomar inventario
is_receivable BOOLEAN DEFAULT TRUE, -- Se puede recibir inventario
-- Metadata
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMPTZ,
UNIQUE(warehouse_id, code)
);
-- Indices para warehouse_locations
CREATE INDEX IF NOT EXISTS idx_warehouse_locations_warehouse ON inventory.warehouse_locations(warehouse_id);
CREATE INDEX IF NOT EXISTS idx_warehouse_locations_parent ON inventory.warehouse_locations(parent_id);
CREATE INDEX IF NOT EXISTS idx_warehouse_locations_code ON inventory.warehouse_locations(code);
CREATE INDEX IF NOT EXISTS idx_warehouse_locations_type ON inventory.warehouse_locations(location_type);
CREATE INDEX IF NOT EXISTS idx_warehouse_locations_hierarchy ON inventory.warehouse_locations(hierarchy_path);
CREATE INDEX IF NOT EXISTS idx_warehouse_locations_active ON inventory.warehouse_locations(is_active) WHERE is_active = TRUE;
CREATE INDEX IF NOT EXISTS idx_warehouse_locations_barcode ON inventory.warehouse_locations(barcode);
-- =====================
-- TABLA: warehouse_zones
-- Zonas logicas de almacen (para organizacion)
-- =====================
CREATE TABLE IF NOT EXISTS inventory.warehouse_zones (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
warehouse_id UUID NOT NULL REFERENCES inventory.warehouses(id) ON DELETE CASCADE,
-- Identificacion
code VARCHAR(20) NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
color VARCHAR(20),
-- Tipo de zona
zone_type VARCHAR(20) DEFAULT 'storage', -- storage, picking, packing, shipping, receiving, quarantine
-- Estado
is_active BOOLEAN DEFAULT TRUE,
-- Metadata
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
UNIQUE(warehouse_id, code)
);
-- Indices para warehouse_zones
CREATE INDEX IF NOT EXISTS idx_warehouse_zones_warehouse ON inventory.warehouse_zones(warehouse_id);
CREATE INDEX IF NOT EXISTS idx_warehouse_zones_type ON inventory.warehouse_zones(zone_type);
-- =====================
-- COMENTARIOS
-- =====================
COMMENT ON TABLE inventory.warehouses IS 'Almacenes y bodegas para gestion de inventario';
COMMENT ON COLUMN inventory.warehouses.warehouse_type IS 'Tipo: standard, transit (en transito), returns (devoluciones), quarantine (cuarentena), virtual';
COMMENT ON COLUMN inventory.warehouses.is_default IS 'Almacen por defecto para operaciones';
COMMENT ON TABLE inventory.warehouse_locations IS 'Ubicaciones fisicas dentro de almacenes (racks, estantes, bins)';
COMMENT ON COLUMN inventory.warehouse_locations.location_type IS 'Tipo: zone, aisle, rack, shelf, bin';
COMMENT ON COLUMN inventory.warehouse_locations.is_pickable IS 'Se puede hacer picking desde esta ubicacion';
COMMENT ON COLUMN inventory.warehouse_locations.is_receivable IS 'Se puede recibir inventario en esta ubicacion';
COMMENT ON TABLE inventory.warehouse_zones IS 'Zonas logicas para organizar el almacen';
COMMENT ON COLUMN inventory.warehouse_zones.zone_type IS 'Tipo: storage, picking, packing, shipping, receiving, quarantine';