mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 10:42:57 +00:00
293 lines
12 KiB
SQL
293 lines
12 KiB
SQL
-- Create facility management tables
|
|
-- Migration: 20260109000001_create_facility_management_tables.up.sql
|
|
|
|
-- Facilities table
|
|
CREATE TABLE IF NOT EXISTS facilities (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
type VARCHAR(20) NOT NULL CHECK (type IN ('field', 'gym', 'locker', 'classroom', 'storage', 'other')),
|
|
status VARCHAR(20) NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'maintenance', 'closed')),
|
|
capacity INTEGER,
|
|
area DECIMAL(10,2),
|
|
location VARCHAR(255),
|
|
is_indoor BOOLEAN DEFAULT true,
|
|
is_outdoor BOOLEAN DEFAULT false,
|
|
image_url VARCHAR(500),
|
|
|
|
-- Booking settings
|
|
requires_approval BOOLEAN DEFAULT false,
|
|
min_booking_duration INTEGER DEFAULT 30,
|
|
max_booking_duration INTEGER DEFAULT 240,
|
|
booking_advance_days INTEGER DEFAULT 30,
|
|
|
|
-- Pricing
|
|
price_per_hour DECIMAL(10,2) DEFAULT 0.00,
|
|
|
|
CONSTRAINT facilities_name_unique UNIQUE (name, deleted_at)
|
|
);
|
|
|
|
-- Facility availability rules
|
|
CREATE TABLE IF NOT EXISTS facility_availability_rules (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
facility_id INTEGER NOT NULL REFERENCES facilities(id) ON DELETE CASCADE,
|
|
day_of_week INTEGER NOT NULL CHECK (day_of_week BETWEEN 0 AND 6),
|
|
start_time VARCHAR(5) NOT NULL CHECK (start_time ~ '^[0-2][0-9]:[0-5][0-9]$'),
|
|
end_time VARCHAR(5) NOT NULL CHECK (end_time ~ '^[0-2][0-9]:[0-5][0-9]$'),
|
|
is_available BOOLEAN DEFAULT true,
|
|
start_date DATE,
|
|
end_date DATE
|
|
);
|
|
|
|
-- Facility bookings
|
|
CREATE TABLE IF NOT EXISTS facility_bookings (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
facility_id INTEGER NOT NULL REFERENCES facilities(id) ON DELETE CASCADE,
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
end_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'confirmed', 'cancelled', 'completed', 'noshow')),
|
|
|
|
-- Pricing
|
|
total_price DECIMAL(10,2) DEFAULT 0.00,
|
|
payment_status VARCHAR(20) DEFAULT 'pending',
|
|
|
|
-- Attendance tracking
|
|
actual_start_time TIMESTAMP WITH TIME ZONE,
|
|
actual_end_time TIMESTAMP WITH TIME ZONE,
|
|
attendees_count INTEGER DEFAULT 0,
|
|
|
|
-- Notes
|
|
internal_notes TEXT,
|
|
public_notes TEXT,
|
|
|
|
-- Cancellation
|
|
cancelled_at TIMESTAMP WITH TIME ZONE,
|
|
cancelled_by INTEGER REFERENCES users(id),
|
|
cancel_reason TEXT,
|
|
|
|
CONSTRAINT bookings_no_overlap EXCLUDE (facility_id WITH =, tsrange(start_time, end_time) WITH &&) WHERE (deleted_at IS NULL AND status NOT IN ('cancelled', 'noshow'))
|
|
);
|
|
|
|
-- Facility equipment
|
|
CREATE TABLE IF NOT EXISTS facility_equipment (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
facility_id INTEGER NOT NULL REFERENCES facilities(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
category VARCHAR(100),
|
|
status VARCHAR(20) NOT NULL DEFAULT 'available' CHECK (status IN ('available', 'in_use', 'maintenance', 'damaged', 'lost', 'retired')),
|
|
quantity INTEGER NOT NULL DEFAULT 1,
|
|
available INTEGER NOT NULL DEFAULT 1,
|
|
|
|
-- Purchase info
|
|
purchase_date DATE,
|
|
purchase_price DECIMAL(10,2),
|
|
supplier VARCHAR(255),
|
|
serial_number VARCHAR(255),
|
|
warranty_expiry DATE,
|
|
|
|
-- Maintenance
|
|
last_maintenance_date DATE,
|
|
next_maintenance_date DATE,
|
|
|
|
-- Location tracking
|
|
current_location VARCHAR(255),
|
|
|
|
image_url VARCHAR(500),
|
|
|
|
-- Usage tracking
|
|
usage_count INTEGER DEFAULT 0,
|
|
last_used_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
CONSTRAINT equipment_name_facility_unique UNIQUE (name, facility_id, deleted_at)
|
|
);
|
|
|
|
-- Facility maintenance
|
|
CREATE TABLE IF NOT EXISTS facility_maintenance (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
facility_id INTEGER NOT NULL REFERENCES facilities(id) ON DELETE CASCADE,
|
|
|
|
type VARCHAR(20) NOT NULL CHECK (type IN ('routine', 'repair', 'inspection', 'upgrade')),
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Scheduling
|
|
scheduled_date TIMESTAMP WITH TIME ZONE,
|
|
estimated_duration INTEGER, -- minutes
|
|
actual_duration INTEGER, -- minutes
|
|
|
|
-- Status
|
|
status VARCHAR(20) DEFAULT 'scheduled',
|
|
started_at TIMESTAMP WITH TIME ZONE,
|
|
completed_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
-- Cost
|
|
estimated_cost DECIMAL(10,2),
|
|
actual_cost DECIMAL(10,2),
|
|
|
|
-- Personnel
|
|
assigned_to VARCHAR(255),
|
|
performed_by VARCHAR(255),
|
|
|
|
-- Impact
|
|
is_facility_unavailable BOOLEAN DEFAULT true,
|
|
|
|
-- Notes
|
|
internal_notes TEXT,
|
|
public_notes TEXT,
|
|
|
|
-- Related equipment (JSON array)
|
|
equipment_affected TEXT
|
|
);
|
|
|
|
-- Weather conditions for outdoor facilities
|
|
CREATE TABLE IF NOT EXISTS weather_conditions (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
facility_id INTEGER NOT NULL REFERENCES facilities(id) ON DELETE CASCADE,
|
|
|
|
date_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
temperature DECIMAL(5,2), -- Celsius
|
|
humidity DECIMAL(5,2), -- Percentage
|
|
precipitation DECIMAL(8,2), -- mm
|
|
wind_speed DECIMAL(5,2), -- km/h
|
|
wind_direction INTEGER, -- Degrees
|
|
weather_code VARCHAR(10), -- OpenWeatherMap condition code
|
|
description VARCHAR(255),
|
|
is_suitable BOOLEAN DEFAULT false,
|
|
recommendations TEXT,
|
|
|
|
CONSTRAINT weather_facility_datetime_unique UNIQUE (facility_id, date_time)
|
|
);
|
|
|
|
-- Facility booking templates
|
|
CREATE TABLE IF NOT EXISTS facility_booking_templates (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
facility_id INTEGER NOT NULL REFERENCES facilities(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Default booking settings
|
|
duration INTEGER, -- minutes
|
|
price_per_hour DECIMAL(10,2),
|
|
requires_approval BOOLEAN DEFAULT false,
|
|
|
|
-- Recurrence pattern
|
|
is_recurring BOOLEAN DEFAULT false,
|
|
recurrence_pattern TEXT, -- JSON
|
|
|
|
-- Default settings
|
|
default_title VARCHAR(255),
|
|
default_description TEXT,
|
|
default_attendees INTEGER DEFAULT 1,
|
|
|
|
is_active BOOLEAN DEFAULT true,
|
|
|
|
CONSTRAINT template_name_facility_unique UNIQUE (name, facility_id, deleted_at)
|
|
);
|
|
|
|
-- Indexes for performance
|
|
CREATE INDEX IF NOT EXISTS idx_facilities_type ON facilities(type);
|
|
CREATE INDEX IF NOT EXISTS idx_facilities_status ON facilities(status);
|
|
CREATE INDEX IF NOT EXISTS idx_facilities_is_outdoor ON facilities(is_outdoor);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_facility_bookings_facility_id ON facility_bookings(facility_id);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_bookings_user_id ON facility_bookings(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_bookings_start_time ON facility_bookings(start_time);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_bookings_end_time ON facility_bookings(end_time);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_bookings_status ON facility_bookings(status);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_bookings_time_range ON facility_bookings USING gist (tsrange(start_time, end_time));
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_facility_equipment_facility_id ON facility_equipment(facility_id);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_equipment_status ON facility_equipment(status);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_equipment_category ON facility_equipment(category);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_facility_maintenance_facility_id ON facility_maintenance(facility_id);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_maintenance_scheduled_date ON facility_maintenance(scheduled_date);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_maintenance_status ON facility_maintenance(status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_weather_conditions_facility_id ON weather_conditions(facility_id);
|
|
CREATE INDEX IF NOT EXISTS idx_weather_conditions_date_time ON weather_conditions(date_time);
|
|
CREATE INDEX IF NOT EXISTS idx_weather_conditions_is_suitable ON weather_conditions(is_suitable);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_facility_booking_templates_facility_id ON facility_booking_templates(facility_id);
|
|
CREATE INDEX IF NOT EXISTS idx_facility_booking_templates_is_active ON facility_booking_templates(is_active);
|
|
|
|
-- Insert sample data
|
|
INSERT INTO facilities (name, description, type, status, capacity, area, location, is_indoor, is_outdoor, price_per_hour, min_booking_duration, max_booking_duration, booking_advance_days) VALUES
|
|
('Hlavní hřiště', 'Plnoformátové fotbalové hřiště s přírodním trávníkem', 'field', 'active', 22, 7200.00, 'Hlavní sportovní areál', false, true, 500.00, 60, 180, 14),
|
|
('Tréninkové hřiště č. 1', 'Menší tréninkové hřiště s umělým trávníkem', 'field', 'active', 16, 4800.00, 'Tréninkový areál - sever', false, true, 300.00, 30, 120, 7),
|
|
('Posilovna', 'Plně vybavená posilovna pro hráče', 'gym', 'active', 20, 150.00, 'Hlavní budova - 1. patro', true, false, 100.00, 30, 90, 3),
|
|
('Šatna A', 'Šatna pro domácí tým', 'locker', 'active', 25, 80.00, 'Hlavní budova - přízemí', true, false, 0.00, 15, 60, 1),
|
|
('Zasedací místnost', 'Místnost pro týmové porady a prezentace', 'classroom', 'active', 30, 60.00, 'Hlavní budova - 2. patro', true, false, 50.00, 30, 120, 7),
|
|
('Sklad vybavení', 'Sklad pro tréninkové vybavení', 'storage', 'active', 5, 40.00, 'Hlavní budova - suterén', true, false, 0.00, 15, 30, 1);
|
|
|
|
-- Insert availability rules for main field (available Mon-Fri 16:00-22:00, Sat-Sun 08:00-22:00)
|
|
INSERT INTO facility_availability_rules (facility_id, day_of_week, start_time, end_time, is_available)
|
|
SELECT f.id, d.day_of_week, d.start_time, d.end_time, true
|
|
FROM facilities f,
|
|
(VALUES
|
|
(1, 1, '16:00', '22:00'), -- Monday
|
|
(1, 2, '16:00', '22:00'), -- Tuesday
|
|
(1, 3, '16:00', '22:00'), -- Wednesday
|
|
(1, 4, '16:00', '22:00'), -- Thursday
|
|
(1, 5, '16:00', '22:00'), -- Friday
|
|
(1, 6, '08:00', '22:00'), -- Saturday
|
|
(1, 0, '08:00', '22:00') -- Sunday
|
|
) AS d(day_of_week, start_time, end_time)
|
|
WHERE f.name = 'Hlavní hřiště';
|
|
|
|
-- Insert sample equipment
|
|
INSERT INTO facility_equipment (facility_id, name, description, category, quantity, available, purchase_date, purchase_price)
|
|
SELECT f.id, e.name, e.description, e.category, e.quantity, e.quantity, e.purchase_date, e.purchase_price
|
|
FROM facilities f,
|
|
(VALUES
|
|
(1, 'Míče velikosti 5', 'Plnoformátové fotbalové míče', 'balls', 20, 20, '2024-01-15', 800.00),
|
|
(1, 'Tréninkové kužely', 'Plastové kužele pro cvičení', 'cones', 50, 50, '2024-01-15', 500.00),
|
|
(1, 'Branky', 'Přenosné branky pro trénink', 'goals', 4, 4, '2024-02-01', 2000.00),
|
|
(3, 'Činky', 'Sada činek různých vah', 'weights', 10, 10, '2024-01-20', 5000.00),
|
|
(3, 'Posilovací lavice', 'Profesionální lavice na bench press', 'benches', 3, 3, '2024-01-20', 3000.00)
|
|
) AS e(name, description, category, quantity, available, purchase_date, purchase_price)
|
|
WHERE f.name = 'Hlavní hřiště' AND e.category IN ('balls', 'cones', 'goals')
|
|
UNION ALL
|
|
SELECT f.id, e.name, e.description, e.category, e.quantity, e.quantity, e.purchase_date, e.purchase_price
|
|
FROM facilities f,
|
|
(VALUES
|
|
('Činky', 'Sada činek různých vah', 'weights', 10, 10, '2024-01-20', 5000.00),
|
|
('Posilovací lavice', 'Profesionální lavice na bench press', 'benches', 3, 3, '2024-01-20', 3000.00)
|
|
) AS e(name, description, category, quantity, available, purchase_date, purchase_price)
|
|
WHERE f.name = 'Posilovna' AND e.category IN ('weights', 'benches');
|