diff --git a/server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt b/server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt index ef5844a..fa55eb6 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt +++ b/server/routers/kfu-m-24-1/sber_mobile/DB_Scheme.txt @@ -143,40 +143,30 @@ CREATE TABLE cameras ( updated_at TIMESTAMPTZ DEFAULT NOW() ); --- 15. Агрегаторы платежных сервисов (ЖКХ, Интернет и т.д.) +-- 15. Платежки по квартире (ЖКХ, Интернет и т.д.) CREATE TABLE payment_services ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + apartment_id UUID NOT NULL REFERENCES apartments(id), name TEXT NOT NULL, -- Например, "ЖКХ", "Интернет" icon TEXT, -- Можно хранить название иконки или url - created_at TIMESTAMPTZ DEFAULT NOW(), - updated_at TIMESTAMPTZ DEFAULT NOW() -); - --- 16. Детализация услуг внутри агрегатора (отопление, вода и т.д.) -CREATE TABLE payment_service_details ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - service_id UUID NOT NULL REFERENCES payment_services(id), - name TEXT NOT NULL, -- Например, "Отопление" - description TEXT, -- Описание услуги - created_at TIMESTAMPTZ DEFAULT NOW(), - updated_at TIMESTAMPTZ DEFAULT NOW() -); - --- 17. Платежи пользователя по деталям услуг -CREATE TABLE payments ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - user_id UUID NOT NULL REFERENCES auth.users(id), - apartment_id UUID REFERENCES apartments(id), - detail_id UUID NOT NULL REFERENCES payment_service_details(id), - amount DECIMAL(10, 2) NOT NULL, - period DATE NOT NULL, - status TEXT NOT NULL CHECK (status IN ('paid', 'pending', 'overdue')), + amount DECIMAL(10, 2) NOT NULL, -- Общая сумма по платежке + is_paid BOOLEAN DEFAULT FALSE, -- Оплачен ли весь агрегатор payment_method TEXT CHECK (payment_method IN ('card', 'sber')), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); --- 18. Заявки +-- 16. Детализация по платежке (например, отопление, вода и т.д.) +CREATE TABLE payment_service_details ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + payment_service_id UUID NOT NULL REFERENCES payment_services(id) ON DELETE CASCADE, + name TEXT NOT NULL, -- Например, "Отопление" + amount DECIMAL(10, 2) NOT NULL, -- Сумма по детализации + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 17. Заявки CREATE TABLE tickets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES auth.users(id), @@ -201,8 +191,6 @@ CREATE INDEX idx_tickets_user ON tickets(user_id); CREATE INDEX idx_apartments_building ON apartments(building_id); CREATE INDEX idx_apartment_residents_apartment ON apartment_residents(apartment_id); CREATE INDEX idx_apartment_residents_user ON apartment_residents(user_id); -CREATE INDEX idx_payments_apartment ON utility_payments(apartment_id); -CREATE INDEX idx_payments_service ON utility_payments(service_id); -- Триггеры для обновления updated_at CREATE OR REPLACE FUNCTION update_updated_at() diff --git a/server/routers/kfu-m-24-1/sber_mobile/utility_payments.js b/server/routers/kfu-m-24-1/sber_mobile/utility_payments.js index 2675059..61b2ae4 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/utility_payments.js +++ b/server/routers/kfu-m-24-1/sber_mobile/utility_payments.js @@ -1,52 +1,46 @@ const router = require('express').Router(); const { getSupabaseClient } = require('./supabaseClient'); -// Получить агрегированные сервисы с деталями и статусами оплаты для квартиры +// Получить платежки с деталями для квартиры router.get('/payment-services', async (req, res) => { const supabase = getSupabaseClient(); - const { apartment_id, user_id } = req.query; - if (!apartment_id || !user_id) return res.status(400).json({ error: 'apartment_id и user_id обязательны' }); + const { apartment_id } = req.query; + if (!apartment_id) return res.status(400).json({ error: 'apartment_id обязателен' }); - // Получаем все агрегаторы + // Получаем все платежки по квартире const { data: services, error: servicesError } = await supabase .from('payment_services') - .select('id, name, icon'); + .select('id, name, icon, amount, is_paid, payment_method') + .eq('apartment_id', apartment_id); if (servicesError) return res.status(400).json({ error: servicesError.message }); - // Получаем детали по агрегаторам - const { data: details, error: detailsError } = await supabase - .from('payment_service_details') - .select('id, service_id, name, description'); - if (detailsError) return res.status(400).json({ error: detailsError.message }); - - // Получаем платежи пользователя по деталям - const { data: payments, error: paymentsError } = await supabase - .from('payments') - .select('id, detail_id, amount, period, status, payment_method') - .eq('apartment_id', apartment_id) - .eq('user_id', user_id); - if (paymentsError) return res.status(400).json({ error: paymentsError.message }); + // Получаем детализацию по всем платежкам + const serviceIds = services.map(s => s.id); + let details = []; + if (serviceIds.length > 0) { + const { data: detailsData, error: detailsError } = await supabase + .from('payment_service_details') + .select('id, payment_service_id, name, amount') + .in('payment_service_id', serviceIds); + if (detailsError) return res.status(400).json({ error: detailsError.message }); + details = detailsData; + } // Формируем структуру для фронта const result = services.map(service => { - const serviceDetails = details.filter(d => d.service_id === service.id).map(detail => { - const payment = payments.find(p => p.detail_id === detail.id) || {}; - return { - id: detail.id, - name: detail.name, - description: detail.description, - amount: payment.amount || null, - period: payment.period || null, - status: payment.status || 'pending', - paymentMethod: payment.payment_method || null, - paymentId: payment.id || null, - }; - }); + const serviceDetails = details.filter(d => d.payment_service_id === service.id).map(detail => ({ + id: detail.id, + name: detail.name, + amount: detail.amount + })); return { id: service.id, name: service.name, icon: service.icon, - details: serviceDetails, + amount: service.amount, + isPaid: service.is_paid, + paymentMethod: service.payment_method, + details: serviceDetails }; });