Files

213 lines
9.6 KiB
PL/PgSQL

-- Создаем таблицу для отслеживания отправленных уведомлений об окончании подписки
CREATE TABLE IF NOT EXISTS subscription_notifications (
id SERIAL PRIMARY KEY,
parent_id BIGINT NOT NULL REFERENCES parents(user_id) ON DELETE CASCADE,
notified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
days_left INTEGER NOT NULL,
UNIQUE(parent_id, days_left) -- Чтобы не дублировать уведомления для одного количества дней
);
-- Создаем таблицу справочника школ
CREATE TABLE IF NOT EXISTS schools (
id SERIAL PRIMARY KEY,
school_number VARCHAR(50) NOT NULL UNIQUE,
school_name VARCHAR(255) NOT NULL,
address TEXT,
city VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Создаем таблицу родителей (пользователей)
CREATE TABLE IF NOT EXISTS parents (
user_id BIGINT PRIMARY KEY,
username VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Создаем таблицу детей
CREATE TABLE IF NOT EXISTS children (
id SERIAL PRIMARY KEY,
parent_id BIGINT NOT NULL REFERENCES parents(user_id) ON DELETE CASCADE,
card_number VARCHAR(16) NOT NULL,
student_name VARCHAR(255) NOT NULL,
school_id INTEGER NOT NULL REFERENCES schools(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(parent_id, card_number)
);
-- Индексы для детей
CREATE INDEX IF NOT EXISTS idx_children_parent_id ON children(parent_id);
CREATE INDEX IF NOT EXISTS idx_children_card_number ON children(card_number);
CREATE INDEX IF NOT EXISTS idx_children_school_id ON children(school_id);
CREATE INDEX IF NOT EXISTS idx_subscription_notifications_parent_id ON subscription_notifications(parent_id);
-- Создаем таблицу для истории проходов через турникет
CREATE TABLE IF NOT EXISTS access_events (
id SERIAL PRIMARY KEY,
event_id VARCHAR(100) UNIQUE,
user_id VARCHAR(100) NOT NULL,
device_id VARCHAR(100),
resource_number INTEGER NOT NULL,
access_zone_id1 VARCHAR(100),
access_zone_id2 VARCHAR(100),
school_id INTEGER REFERENCES schools(id) ON DELETE CASCADE,
event_time TIMESTAMP NOT NULL,
processed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Индексы для access_events
CREATE INDEX IF NOT EXISTS idx_access_events_user_id ON access_events(user_id);
CREATE INDEX IF NOT EXISTS idx_access_events_time ON access_events(event_time);
CREATE INDEX IF NOT EXISTS idx_access_events_processed ON access_events(processed);
-- Создаем таблицу уведомлений
CREATE TABLE IF NOT EXISTS notifications (
id SERIAL PRIMARY KEY,
parent_id BIGINT NOT NULL REFERENCES parents(user_id) ON DELETE CASCADE,
child_id INTEGER REFERENCES children(id) ON DELETE CASCADE,
message TEXT NOT NULL,
event_type VARCHAR(50),
is_read BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Индексы для уведомлений
CREATE INDEX IF NOT EXISTS idx_notifications_parent_id ON notifications(parent_id);
CREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications(is_read);
-- ============================================
-- ПОДПИСОЧНАЯ СИСТЕМА
-- ============================================
-- Создаем таблицу подписок
CREATE TABLE IF NOT EXISTS subscriptions (
id SERIAL PRIMARY KEY,
parent_id BIGINT NOT NULL UNIQUE REFERENCES parents(user_id) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL DEFAULT 'trial', -- 'trial', 'active', 'expired', 'cancelled'
trial_start TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
trial_end TIMESTAMP,
paid_until TIMESTAMP,
last_payment_date TIMESTAMP,
payment_amount DECIMAL(10, 2) DEFAULT 50.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Индексы для подписок
CREATE INDEX IF NOT EXISTS idx_subscriptions_parent_id ON subscriptions(parent_id);
CREATE INDEX IF NOT EXISTS idx_subscriptions_status ON subscriptions(status);
-- Создаем таблицу истории платежей
CREATE TABLE IF NOT EXISTS payments (
id SERIAL PRIMARY KEY,
parent_id BIGINT NOT NULL REFERENCES parents(user_id) ON DELETE CASCADE,
amount DECIMAL(10, 2) NOT NULL,
payment_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
payment_method VARCHAR(50),
transaction_id VARCHAR(255) UNIQUE,
status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'success', 'failed'
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Индексы для платежей
CREATE INDEX IF NOT EXISTS idx_payments_parent_id ON payments(parent_id);
CREATE INDEX IF NOT EXISTS idx_payments_transaction_id ON payments(transaction_id);
CREATE INDEX IF NOT EXISTS idx_payments_status ON payments(status);
-- ============================================
-- ФУНКЦИИ И ТРИГГЕРЫ
-- ============================================
-- Функция для автоматического обновления updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ language 'plpgsql';
-- Триггер для обновления updated_at в parents
DROP TRIGGER IF EXISTS update_parents_updated_at ON parents;
CREATE TRIGGER update_parents_updated_at
BEFORE UPDATE ON parents
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Триггер для обновления updated_at в children
DROP TRIGGER IF EXISTS update_children_updated_at ON children;
CREATE TRIGGER update_children_updated_at
BEFORE UPDATE ON children
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Триггер для обновления updated_at в subscriptions
DROP TRIGGER IF EXISTS update_subscriptions_updated_at ON subscriptions;
CREATE TRIGGER update_subscriptions_updated_at
BEFORE UPDATE ON subscriptions
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- ============================================
-- НАЧАЛЬНЫЕ ДАННЫЕ
-- ============================================
-- Добавляем школы
INSERT INTO schools (school_number, school_name, address, city) VALUES
('101', 'Средняя общеобразовательная школа №101', 'ул. Ленина, 15', 'Москва'),
('102', 'Средняя общеобразовательная школа №102', 'ул. Гагарина, 10', 'Москва'),
('103', 'Средняя общеобразовательная школа №103', 'ул. Мира, 25', 'Москва'),
('104', 'Гимназия №104', 'ул. Садовая, 8', 'Москва'),
('105', 'Лицей №105', 'ул. Тверская, 12', 'Москва'),
('201', 'Гимназия №201', 'ул. Пушкина, 5', 'Санкт-Петербург'),
('202', 'Средняя школа №202', 'ул. Невский проспект, 20', 'Санкт-Петербург'),
('203', 'Средняя школа №203', 'ул. Московская, 15', 'Санкт-Петербург'),
('301', 'Лицей №301', 'ул. Советская, 8', 'Казань'),
('302', 'Средняя школа №302', 'ул. Ленина, 42', 'Казань'),
('401', 'Средняя школа №401', 'ул. Мира, 12', 'Новосибирск'),
('402', 'Гимназия №402', 'ул. Кирова, 7', 'Новосибирск'),
('501', 'Школа №501 с углубленным изучением математики', 'ул. Лермонтова, 3', 'Екатеринбург'),
('502', 'Гимназия №502', 'ул. Свердлова, 10', 'Екатеринбург'),
('601', 'Средняя общеобразовательная школа №601', 'ул. Садовая, 25', 'Нижний Новгород'),
('602', 'Лицей №602', 'ул. Горького, 8', 'Нижний Новгород'),
('701', 'Гимназия №701', 'ул. Чехова, 10', 'Ростов-на-Дону'),
('702', 'Средняя школа №702', 'ул. Пушкинская, 15', 'Ростов-на-Дону')
ON CONFLICT (school_number) DO NOTHING;
-- Добавляем тестового пользователя (для разработки)
-- INSERT INTO parents (user_id, username) VALUES (15649081, 'Алексей Халецкий')
-- ON CONFLICT (user_id) DO NOTHING;
-- Добавляем тестовую подписку для разработчика (активная на год)
-- INSERT INTO subscriptions (parent_id, status, paid_until, payment_amount)
-- VALUES (15649081, 'active', CURRENT_TIMESTAMP + INTERVAL '365 days', 50.00)
-- ON CONFLICT (parent_id) DO NOTHING;
-- ============================================
-- ПРОВЕРОЧНЫЕ ЗАПРОСЫ
-- ============================================
-- Проверка количества школ
-- SELECT COUNT(*) as total_schools FROM schools;
-- Проверка подписок
-- SELECT
-- p.username,
-- s.status,
-- s.trial_end,
-- s.paid_until,
-- s.payment_amount
-- FROM subscriptions s
-- JOIN parents p ON s.parent_id = p.user_id;
-- Проверка детей
-- SELECT
-- p.username,
-- c.student_name,
-- c.card_number,
-- sc.school_name
-- FROM children c
-- JOIN parents p ON c.parent_id = p.user_id
-- JOIN schools sc ON c.school_id = sc.id;