190 lines
7.8 KiB
SQL
190 lines
7.8 KiB
SQL
-- ============================================================================
|
|
-- INVENTORY EXTENSIONS - FASE 8 ERP-Core
|
|
-- ERP Clínicas (Base Genérica)
|
|
-- ============================================================================
|
|
-- Fecha: 2026-01-04
|
|
-- Versión: 1.0
|
|
-- ============================================================================
|
|
|
|
-- Schema
|
|
CREATE SCHEMA IF NOT EXISTS inventory;
|
|
|
|
-- ============================================================================
|
|
-- TABLAS
|
|
-- ============================================================================
|
|
|
|
-- Tipos de paquete
|
|
CREATE TABLE IF NOT EXISTS inventory.package_types (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL,
|
|
name VARCHAR(100) NOT NULL,
|
|
height NUMERIC(10,2),
|
|
width NUMERIC(10,2),
|
|
length NUMERIC(10,2),
|
|
base_weight NUMERIC(10,2),
|
|
max_weight NUMERIC(10,2),
|
|
sequence INTEGER DEFAULT 10,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
COMMENT ON TABLE inventory.package_types IS 'Tipos de paquete - FASE 8';
|
|
|
|
-- Paquetes
|
|
CREATE TABLE IF NOT EXISTS inventory.packages (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL,
|
|
package_type_id UUID REFERENCES inventory.package_types(id),
|
|
name VARCHAR(100),
|
|
product_id UUID,
|
|
-- Extensiones clínica (medicamentos)
|
|
lote VARCHAR(50),
|
|
fecha_fabricacion DATE,
|
|
fecha_caducidad DATE,
|
|
laboratorio VARCHAR(100),
|
|
registro_sanitario VARCHAR(50),
|
|
-- Control
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
COMMENT ON TABLE inventory.packages IS 'Paquetes/lotes de productos - FASE 8';
|
|
COMMENT ON COLUMN inventory.packages.lote IS 'Número de lote del fabricante';
|
|
COMMENT ON COLUMN inventory.packages.registro_sanitario IS 'Registro sanitario COFEPRIS';
|
|
|
|
-- Categorías de almacenamiento
|
|
CREATE TABLE IF NOT EXISTS inventory.storage_categories (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL,
|
|
name VARCHAR(100) NOT NULL,
|
|
max_weight NUMERIC(10,2),
|
|
allow_new_product VARCHAR(20) DEFAULT 'mixed',
|
|
-- Extensiones clínica
|
|
requiere_refrigeracion BOOLEAN DEFAULT false,
|
|
temperatura_min NUMERIC(5,2),
|
|
temperatura_max NUMERIC(5,2),
|
|
es_controlado BOOLEAN DEFAULT false,
|
|
requiere_receta BOOLEAN DEFAULT false,
|
|
-- Control
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
COMMENT ON TABLE inventory.storage_categories IS 'Categorías de almacenamiento - FASE 8';
|
|
COMMENT ON COLUMN inventory.storage_categories.es_controlado IS 'Medicamento controlado (requiere receta especial)';
|
|
COMMENT ON COLUMN inventory.storage_categories.requiere_refrigeracion IS 'Requiere cadena de frío';
|
|
|
|
-- Reglas de ubicación
|
|
CREATE TABLE IF NOT EXISTS inventory.putaway_rules (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL,
|
|
name VARCHAR(100),
|
|
product_id UUID,
|
|
category_id UUID REFERENCES inventory.storage_categories(id),
|
|
warehouse_id UUID,
|
|
location_in_id UUID,
|
|
location_out_id UUID,
|
|
sequence INTEGER DEFAULT 10,
|
|
active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
COMMENT ON TABLE inventory.putaway_rules IS 'Reglas de ubicación automática - FASE 8';
|
|
|
|
-- Estrategias de remoción
|
|
CREATE TABLE IF NOT EXISTS inventory.removal_strategies (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
code VARCHAR(20) NOT NULL UNIQUE,
|
|
name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
COMMENT ON TABLE inventory.removal_strategies IS 'Estrategias de remoción (FIFO, FEFO, etc.) - FASE 8';
|
|
|
|
-- ============================================================================
|
|
-- CAMPOS ADICIONALES A PRODUCTS (si existe)
|
|
-- ============================================================================
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables
|
|
WHERE table_schema = 'inventory' AND table_name = 'products') THEN
|
|
|
|
-- tracking
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'inventory' AND table_name = 'products'
|
|
AND column_name = 'tracking') THEN
|
|
ALTER TABLE inventory.products ADD COLUMN tracking VARCHAR(20) DEFAULT 'none';
|
|
END IF;
|
|
|
|
-- removal_strategy_id
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'inventory' AND table_name = 'products'
|
|
AND column_name = 'removal_strategy_id') THEN
|
|
ALTER TABLE inventory.products ADD COLUMN removal_strategy_id UUID
|
|
REFERENCES inventory.removal_strategies(id);
|
|
END IF;
|
|
|
|
-- sale_ok
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'inventory' AND table_name = 'products'
|
|
AND column_name = 'sale_ok') THEN
|
|
ALTER TABLE inventory.products ADD COLUMN sale_ok BOOLEAN DEFAULT true;
|
|
END IF;
|
|
|
|
-- purchase_ok
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'inventory' AND table_name = 'products'
|
|
AND column_name = 'purchase_ok') THEN
|
|
ALTER TABLE inventory.products ADD COLUMN purchase_ok BOOLEAN DEFAULT true;
|
|
END IF;
|
|
|
|
END IF;
|
|
END $$;
|
|
|
|
-- ============================================================================
|
|
-- ÍNDICES
|
|
-- ============================================================================
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_package_types_tenant ON inventory.package_types(tenant_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_packages_tenant ON inventory.packages(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_packages_type ON inventory.packages(package_type_id);
|
|
CREATE INDEX IF NOT EXISTS idx_packages_lote ON inventory.packages(tenant_id, lote);
|
|
CREATE INDEX IF NOT EXISTS idx_packages_caducidad ON inventory.packages(tenant_id, fecha_caducidad);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_storage_categories_tenant ON inventory.storage_categories(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_storage_categories_controlado
|
|
ON inventory.storage_categories(tenant_id, es_controlado) WHERE es_controlado = true;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_putaway_rules_tenant ON inventory.putaway_rules(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_putaway_rules_category ON inventory.putaway_rules(category_id);
|
|
|
|
-- ============================================================================
|
|
-- RLS
|
|
-- ============================================================================
|
|
|
|
ALTER TABLE inventory.package_types ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE inventory.packages ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE inventory.storage_categories ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE inventory.putaway_rules ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS tenant_isolation_package_types ON inventory.package_types;
|
|
CREATE POLICY tenant_isolation_package_types ON inventory.package_types
|
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
|
|
|
DROP POLICY IF EXISTS tenant_isolation_packages ON inventory.packages;
|
|
CREATE POLICY tenant_isolation_packages ON inventory.packages
|
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
|
|
|
DROP POLICY IF EXISTS tenant_isolation_storage_categories ON inventory.storage_categories;
|
|
CREATE POLICY tenant_isolation_storage_categories ON inventory.storage_categories
|
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
|
|
|
DROP POLICY IF EXISTS tenant_isolation_putaway_rules ON inventory.putaway_rules;
|
|
CREATE POLICY tenant_isolation_putaway_rules ON inventory.putaway_rules
|
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
|
|
|
-- ============================================================================
|
|
-- FIN INVENTORY EXTENSIONS
|
|
-- ============================================================================
|