366 lines
13 KiB
PL/PgSQL
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();
|