Backend: - Migration 015_rental.sql: rental_objects + rental_bookings tables, seed demo data - New routes: GET/POST/PATCH/DELETE rental-objects and rental-bookings per hotel - Register rentalRoutes in app.ts Frontend: - api.ts: add rental.listObjects, listBookings, createBooking, updateBooking, deleteBooking - CalendarPage: fetch rental objects + bookings from API instead of mock data - BookingCalendar: rental cell UI redesigned — colored squares + working hours + time slots (matches design spec) - BookingCalendar: remove base rate price from desktop room label column (irrelevant with dynamic pricing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
53 lines
3.0 KiB
SQL
53 lines
3.0 KiB
SQL
-- Rental objects (tennis court, sauna, conference hall, etc.)
|
|
CREATE TABLE IF NOT EXISTS rental_objects (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
hotel_id UUID NOT NULL REFERENCES hotels(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
icon TEXT NOT NULL DEFAULT '🏨',
|
|
color TEXT NOT NULL DEFAULT 'bg-slate-500',
|
|
text_color TEXT NOT NULL DEFAULT 'text-slate-700 dark:text-slate-400',
|
|
price_per_hour INTEGER NOT NULL DEFAULT 0,
|
|
price_per_day INTEGER NOT NULL DEFAULT 0,
|
|
open_hour INTEGER NOT NULL DEFAULT 8,
|
|
close_hour INTEGER NOT NULL DEFAULT 22,
|
|
max_hours_per_slot INTEGER,
|
|
buffer_minutes INTEGER NOT NULL DEFAULT 0,
|
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Rental bookings (hourly / full-day slots)
|
|
CREATE TABLE IF NOT EXISTS rental_bookings (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
hotel_id UUID NOT NULL REFERENCES hotels(id) ON DELETE CASCADE,
|
|
object_id UUID NOT NULL REFERENCES rental_objects(id) ON DELETE CASCADE,
|
|
date DATE NOT NULL,
|
|
is_full_day BOOLEAN NOT NULL DEFAULT false,
|
|
start_hour INTEGER NOT NULL DEFAULT 0,
|
|
end_hour INTEGER NOT NULL DEFAULT 0,
|
|
guest_name TEXT NOT NULL,
|
|
guest_phone TEXT NOT NULL DEFAULT '',
|
|
linked_room_id UUID REFERENCES rooms(id),
|
|
total_amount INTEGER NOT NULL DEFAULT 0,
|
|
paid_amount INTEGER NOT NULL DEFAULT 0,
|
|
status TEXT NOT NULL DEFAULT 'confirmed',
|
|
notes TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Seed demo rental objects for all existing hotels (idempotent)
|
|
INSERT INTO rental_objects (hotel_id, name, icon, color, text_color, price_per_hour, price_per_day, open_hour, close_hour, sort_order)
|
|
SELECT h.id, 'Теннисный корт', '🎾', 'bg-green-500', 'text-green-700 dark:text-green-400', 1500, 8000, 8, 22, 1
|
|
FROM hotels h
|
|
WHERE NOT EXISTS (SELECT 1 FROM rental_objects ro WHERE ro.hotel_id = h.id AND ro.name = 'Теннисный корт');
|
|
|
|
INSERT INTO rental_objects (hotel_id, name, icon, color, text_color, price_per_hour, price_per_day, open_hour, close_hour, max_hours_per_slot, sort_order)
|
|
SELECT h.id, 'Баня', '🛁', 'bg-orange-500', 'text-orange-700 dark:text-orange-400', 2500, 12000, 10, 23, 4, 2
|
|
FROM hotels h
|
|
WHERE NOT EXISTS (SELECT 1 FROM rental_objects ro WHERE ro.hotel_id = h.id AND ro.name = 'Баня');
|
|
|
|
INSERT INTO rental_objects (hotel_id, name, icon, color, text_color, price_per_hour, price_per_day, open_hour, close_hour, sort_order)
|
|
SELECT h.id, 'Конференц-зал', '🏛️', 'bg-violet-500', 'text-violet-700 dark:text-violet-400', 3000, 15000, 9, 20, 3
|
|
FROM hotels h
|
|
WHERE NOT EXISTS (SELECT 1 FROM rental_objects ro WHERE ro.hotel_id = h.id AND ro.name = 'Конференц-зал');
|