erp-mecanicas-diesel-database/init/05-vehicle-management-tables.sql

366 lines
13 KiB
PL/PgSQL

-- ===========================================
-- MECANICAS DIESEL - Schema vehicle_management
-- ===========================================
-- Vehículos diesel, flotas, motores
SET search_path TO vehicle_management, public;
-- -------------------------------------------
-- ENGINE_CATALOG - Catálogo de motores (global)
-- -------------------------------------------
CREATE TABLE vehicle_management.engine_catalog (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
make VARCHAR(50) NOT NULL,
model VARCHAR(50) NOT NULL,
cylinders INTEGER CHECK (cylinders > 0),
displacement DECIMAL(5,2) CHECK (displacement > 0),
fuel_type VARCHAR(20) DEFAULT 'diesel',
horsepower_min INTEGER CHECK (horsepower_min > 0),
horsepower_max INTEGER CHECK (horsepower_max > 0),
torque_max INTEGER CHECK (torque_max > 0),
injection_system VARCHAR(50),
year_start INTEGER CHECK (year_start >= 1950),
year_end INTEGER CHECK (year_end >= 1950),
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT uq_engine_model UNIQUE (make, model),
CONSTRAINT chk_horsepower CHECK (horsepower_max >= horsepower_min),
CONSTRAINT chk_years CHECK (year_end IS NULL OR year_end >= year_start)
);
-- Datos iniciales de motores comunes
INSERT INTO vehicle_management.engine_catalog (make, model, cylinders, displacement, horsepower_min, horsepower_max, torque_max, injection_system) VALUES
('Cummins', 'ISX15', 6, 14.9, 400, 600, 2050, 'common_rail'),
('Cummins', 'ISL9', 6, 8.9, 260, 380, 1250, 'common_rail'),
('Cummins', 'X15', 6, 14.9, 400, 605, 2050, 'common_rail'),
('Cummins', 'ISB6.7', 6, 6.7, 200, 325, 750, 'common_rail'),
('Detroit', 'DD15', 6, 14.8, 400, 505, 1850, 'common_rail'),
('Detroit', 'DD13', 6, 12.8, 350, 470, 1650, 'common_rail'),
('Paccar', 'MX-13', 6, 12.9, 380, 510, 1850, 'common_rail'),
('Paccar', 'MX-11', 6, 10.8, 355, 430, 1550, 'common_rail'),
('Navistar', 'MaxxForce 13', 6, 12.4, 410, 475, 1700, 'common_rail'),
('Volvo', 'D13', 6, 12.8, 375, 500, 1850, 'unit_injector'),
('Caterpillar', 'C15', 6, 15.2, 435, 625, 2050, 'unit_injector'),
('Caterpillar', 'C13', 6, 12.5, 380, 520, 1750, 'unit_injector');
-- -------------------------------------------
-- FLEETS - Flotas de vehículos
-- -------------------------------------------
CREATE TABLE vehicle_management.fleets (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
name VARCHAR(200) NOT NULL,
code VARCHAR(20),
contact_name VARCHAR(200),
contact_email VARCHAR(200),
contact_phone VARCHAR(20),
-- Condiciones comerciales
discount_labor_pct DECIMAL(5,2) DEFAULT 0 CHECK (discount_labor_pct >= 0 AND discount_labor_pct <= 100),
discount_parts_pct DECIMAL(5,2) DEFAULT 0 CHECK (discount_parts_pct >= 0 AND discount_parts_pct <= 100),
credit_days INTEGER DEFAULT 0 CHECK (credit_days >= 0),
credit_limit DECIMAL(12,2) DEFAULT 0 CHECK (credit_limit >= 0),
vehicle_count INTEGER DEFAULT 0 CHECK (vehicle_count >= 0),
notes TEXT,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_fleets_tenant ON vehicle_management.fleets(tenant_id);
CREATE INDEX idx_fleets_name ON vehicle_management.fleets(name);
CREATE TRIGGER trg_fleets_updated_at
BEFORE UPDATE ON vehicle_management.fleets
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
SELECT create_tenant_rls_policies('vehicle_management', 'fleets');
-- -------------------------------------------
-- VEHICLES - Vehículos registrados
-- -------------------------------------------
CREATE TABLE vehicle_management.vehicles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
customer_id UUID NOT NULL, -- core.partners
fleet_id UUID REFERENCES vehicle_management.fleets(id),
vin VARCHAR(17),
license_plate VARCHAR(15) NOT NULL,
economic_number VARCHAR(20),
make VARCHAR(50) NOT NULL,
model VARCHAR(100) NOT NULL,
year INTEGER NOT NULL CHECK (year >= 1950 AND year <= 2100),
color VARCHAR(30),
vehicle_type VARCHAR(30) DEFAULT 'truck'
CHECK (vehicle_type IN ('truck', 'trailer', 'bus', 'pickup', 'other')),
current_odometer INTEGER CHECK (current_odometer >= 0),
odometer_updated_at TIMESTAMP WITH TIME ZONE,
photo_url VARCHAR(500),
status VARCHAR(20) DEFAULT 'active'
CHECK (status IN ('active', 'inactive', 'sold')),
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT uq_vehicle_plate UNIQUE (tenant_id, license_plate)
);
CREATE INDEX idx_vehicles_tenant ON vehicle_management.vehicles(tenant_id);
CREATE INDEX idx_vehicles_customer ON vehicle_management.vehicles(customer_id);
CREATE INDEX idx_vehicles_fleet ON vehicle_management.vehicles(fleet_id);
CREATE INDEX idx_vehicles_vin ON vehicle_management.vehicles(vin);
CREATE INDEX idx_vehicles_plate ON vehicle_management.vehicles(license_plate);
CREATE TRIGGER trg_vehicles_updated_at
BEFORE UPDATE ON vehicle_management.vehicles
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
SELECT create_tenant_rls_policies('vehicle_management', 'vehicles');
-- -------------------------------------------
-- VEHICLE_ENGINES - Especificaciones del motor
-- -------------------------------------------
CREATE TABLE vehicle_management.vehicle_engines (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
vehicle_id UUID NOT NULL REFERENCES vehicle_management.vehicles(id) ON DELETE CASCADE,
engine_catalog_id UUID REFERENCES vehicle_management.engine_catalog(id),
serial_number VARCHAR(50),
horsepower INTEGER CHECK (horsepower > 0),
torque INTEGER CHECK (torque > 0),
ecm_model VARCHAR(50),
ecm_software VARCHAR(50),
injection_system VARCHAR(50),
rail_pressure_max DECIMAL(10,2) CHECK (rail_pressure_max > 0),
injector_count INTEGER CHECK (injector_count > 0),
turbo_type VARCHAR(50) CHECK (turbo_type IN ('VGT', 'wastegate', 'twin', 'compound')),
turbo_make VARCHAR(50),
turbo_model VARCHAR(50),
manufacture_date DATE,
rebuild_date DATE,
rebuild_odometer INTEGER CHECK (rebuild_odometer >= 0),
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_vehicle_engines_vehicle ON vehicle_management.vehicle_engines(vehicle_id);
CREATE INDEX idx_vehicle_engines_serial ON vehicle_management.vehicle_engines(serial_number);
CREATE INDEX idx_vehicle_engines_catalog ON vehicle_management.vehicle_engines(engine_catalog_id);
CREATE TRIGGER trg_vehicle_engines_updated_at
BEFORE UPDATE ON vehicle_management.vehicle_engines
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
-- -------------------------------------------
-- VEHICLE_HISTORY - Historial de cambios
-- -------------------------------------------
CREATE TABLE vehicle_management.vehicle_history (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
vehicle_id UUID NOT NULL REFERENCES vehicle_management.vehicles(id) ON DELETE CASCADE,
field_name VARCHAR(50) NOT NULL,
old_value TEXT,
new_value TEXT,
changed_by UUID,
changed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_vehicle_history_vehicle ON vehicle_management.vehicle_history(vehicle_id);
CREATE INDEX idx_vehicle_history_date ON vehicle_management.vehicle_history(changed_at DESC);
-- -------------------------------------------
-- MAINTENANCE_REMINDERS - Recordatorios
-- -------------------------------------------
CREATE TABLE vehicle_management.maintenance_reminders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
vehicle_id UUID NOT NULL REFERENCES vehicle_management.vehicles(id) ON DELETE CASCADE,
service_type VARCHAR(100) NOT NULL,
service_id UUID,
frequency_type VARCHAR(20) NOT NULL CHECK (frequency_type IN ('time', 'odometer', 'both')),
interval_days INTEGER CHECK (interval_days > 0),
interval_km INTEGER CHECK (interval_km > 0),
last_service_date DATE,
last_service_km INTEGER,
next_due_date DATE,
next_due_km INTEGER,
notify_days_before INTEGER DEFAULT 7 CHECK (notify_days_before >= 0),
notify_km_before INTEGER DEFAULT 1000 CHECK (notify_km_before >= 0),
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'paused', 'completed')),
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_reminders_tenant ON vehicle_management.maintenance_reminders(tenant_id);
CREATE INDEX idx_reminders_vehicle ON vehicle_management.maintenance_reminders(vehicle_id);
CREATE INDEX idx_reminders_due_date ON vehicle_management.maintenance_reminders(next_due_date);
CREATE TRIGGER trg_reminders_updated_at
BEFORE UPDATE ON vehicle_management.maintenance_reminders
FOR EACH ROW EXECUTE FUNCTION trigger_set_updated_at();
SELECT create_tenant_rls_policies('vehicle_management', 'maintenance_reminders');
-- -------------------------------------------
-- REMINDER_NOTIFICATIONS - Notificaciones enviadas
-- -------------------------------------------
CREATE TABLE vehicle_management.reminder_notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
reminder_id UUID NOT NULL REFERENCES vehicle_management.maintenance_reminders(id) ON DELETE CASCADE,
notification_type VARCHAR(20) NOT NULL CHECK (notification_type IN ('email', 'sms', 'push', 'whatsapp')),
sent_to VARCHAR(200),
sent_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
status VARCHAR(20) DEFAULT 'sent' CHECK (status IN ('sent', 'delivered', 'failed')),
error_message TEXT
);
CREATE INDEX idx_reminder_notif_reminder ON vehicle_management.reminder_notifications(reminder_id);
-- -------------------------------------------
-- VEHICLE_DOCUMENTS - Documentos del vehículo
-- -------------------------------------------
CREATE TABLE vehicle_management.vehicle_documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
vehicle_id UUID NOT NULL REFERENCES vehicle_management.vehicles(id) ON DELETE CASCADE,
document_type VARCHAR(50) NOT NULL
CHECK (document_type IN ('registration', 'insurance', 'permit', 'verification', 'other')),
document_number VARCHAR(100),
issue_date DATE,
expiry_date DATE,
file_url VARCHAR(500),
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_vehicle_docs_vehicle ON vehicle_management.vehicle_documents(vehicle_id);
CREATE INDEX idx_vehicle_docs_expiry ON vehicle_management.vehicle_documents(expiry_date);
-- -------------------------------------------
-- VISTA: Vehicle Summary
-- -------------------------------------------
CREATE OR REPLACE VIEW vehicle_management.vw_vehicle_summary AS
SELECT
v.id,
v.tenant_id,
v.license_plate,
v.economic_number,
v.make,
v.model,
v.year,
v.current_odometer,
v.status,
v.customer_id,
f.name as fleet_name,
f.id as fleet_id,
ec.make as engine_make,
ec.model as engine_model,
ve.serial_number as engine_serial,
ve.horsepower,
(SELECT COUNT(*) FROM service_management.service_orders so
WHERE so.vehicle_id = v.id) as total_orders,
(SELECT MAX(so.completed_at) FROM service_management.service_orders so
WHERE so.vehicle_id = v.id AND so.status = 'completed') as last_service_date
FROM vehicle_management.vehicles v
LEFT JOIN vehicle_management.fleets f ON v.fleet_id = f.id
LEFT JOIN vehicle_management.vehicle_engines ve ON ve.vehicle_id = v.id
LEFT JOIN vehicle_management.engine_catalog ec ON ve.engine_catalog_id = ec.id
WHERE v.tenant_id = get_current_tenant_id();
COMMENT ON VIEW vehicle_management.vw_vehicle_summary IS 'Vista resumida de vehículos con filtro RLS';
-- -------------------------------------------
-- Trigger para actualizar vehicle_count en fleets
-- -------------------------------------------
CREATE OR REPLACE FUNCTION vehicle_management.update_fleet_vehicle_count()
RETURNS TRIGGER AS $$
BEGIN
-- Actualizar conteo de la flota anterior (si existe)
IF TG_OP = 'DELETE' OR (TG_OP = 'UPDATE' AND OLD.fleet_id IS DISTINCT FROM NEW.fleet_id) THEN
IF OLD.fleet_id IS NOT NULL THEN
UPDATE vehicle_management.fleets
SET vehicle_count = (
SELECT COUNT(*) FROM vehicle_management.vehicles
WHERE fleet_id = OLD.fleet_id AND status = 'active'
)
WHERE id = OLD.fleet_id;
END IF;
END IF;
-- Actualizar conteo de la nueva flota
IF TG_OP = 'INSERT' OR (TG_OP = 'UPDATE' AND OLD.fleet_id IS DISTINCT FROM NEW.fleet_id) THEN
IF NEW.fleet_id IS NOT NULL THEN
UPDATE vehicle_management.fleets
SET vehicle_count = (
SELECT COUNT(*) FROM vehicle_management.vehicles
WHERE fleet_id = NEW.fleet_id AND status = 'active'
)
WHERE id = NEW.fleet_id;
END IF;
END IF;
IF TG_OP = 'DELETE' THEN
RETURN OLD;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_update_fleet_count
AFTER INSERT OR UPDATE OR DELETE ON vehicle_management.vehicles
FOR EACH ROW EXECUTE FUNCTION vehicle_management.update_fleet_vehicle_count();