Запрос на слияние 'feature/change_services' (#12) из feature/change_services в sber_mobile

This commit is contained in:
DmitrievMS
2025-06-08 19:26:25 +00:00
2 changed files with 41 additions and 59 deletions

View File

@@ -143,40 +143,30 @@ CREATE TABLE cameras (
updated_at TIMESTAMPTZ DEFAULT NOW() updated_at TIMESTAMPTZ DEFAULT NOW()
); );
-- 15. Агрегаторы платежных сервисов (ЖКХ, Интернет и т.д.) -- 15. Платежки по квартире (ЖКХ, Интернет и т.д.)
CREATE TABLE payment_services ( CREATE TABLE payment_services (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
apartment_id UUID NOT NULL REFERENCES apartments(id),
name TEXT NOT NULL, -- Например, "ЖКХ", "Интернет" name TEXT NOT NULL, -- Например, "ЖКХ", "Интернет"
icon TEXT, -- Можно хранить название иконки или url icon TEXT, -- Можно хранить название иконки или url
created_at TIMESTAMPTZ DEFAULT NOW(), amount DECIMAL(10, 2) NOT NULL, -- Общая сумма по платежке
updated_at TIMESTAMPTZ DEFAULT NOW() is_paid BOOLEAN DEFAULT FALSE, -- Оплачен ли весь агрегатор
);
-- 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')),
payment_method TEXT CHECK (payment_method IN ('card', 'sber')), payment_method TEXT CHECK (payment_method IN ('card', 'sber')),
created_at TIMESTAMPTZ DEFAULT NOW(), created_at TIMESTAMPTZ DEFAULT NOW(),
updated_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 ( CREATE TABLE tickets (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth.users(id), 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_apartments_building ON apartments(building_id);
CREATE INDEX idx_apartment_residents_apartment ON apartment_residents(apartment_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_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 -- Триггеры для обновления updated_at
CREATE OR REPLACE FUNCTION update_updated_at() CREATE OR REPLACE FUNCTION update_updated_at()

View File

@@ -1,52 +1,46 @@
const router = require('express').Router(); const router = require('express').Router();
const { getSupabaseClient } = require('./supabaseClient'); const { getSupabaseClient } = require('./supabaseClient');
// Получить агрегированные сервисы с деталями и статусами оплаты для квартиры // Получить платежки с деталями для квартиры
router.get('/payment-services', async (req, res) => { router.get('/payment-services', async (req, res) => {
const supabase = getSupabaseClient(); const supabase = getSupabaseClient();
const { apartment_id, user_id } = req.query; const { apartment_id } = req.query;
if (!apartment_id || !user_id) return res.status(400).json({ error: 'apartment_id и user_id обязательны' }); if (!apartment_id) return res.status(400).json({ error: 'apartment_id обязателен' });
// Получаем все агрегаторы // Получаем все платежки по квартире
const { data: services, error: servicesError } = await supabase const { data: services, error: servicesError } = await supabase
.from('payment_services') .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 }); if (servicesError) return res.status(400).json({ error: servicesError.message });
// Получаем детали по агрегаторам // Получаем детализацию по всем платежкам
const { data: details, error: detailsError } = await supabase const serviceIds = services.map(s => s.id);
.from('payment_service_details') let details = [];
.select('id, service_id, name, description'); if (serviceIds.length > 0) {
if (detailsError) return res.status(400).json({ error: detailsError.message }); const { data: detailsData, error: detailsError } = await supabase
.from('payment_service_details')
// Получаем платежи пользователя по деталям .select('id, payment_service_id, name, amount')
const { data: payments, error: paymentsError } = await supabase .in('payment_service_id', serviceIds);
.from('payments') if (detailsError) return res.status(400).json({ error: detailsError.message });
.select('id, detail_id, amount, period, status, payment_method') details = detailsData;
.eq('apartment_id', apartment_id) }
.eq('user_id', user_id);
if (paymentsError) return res.status(400).json({ error: paymentsError.message });
// Формируем структуру для фронта // Формируем структуру для фронта
const result = services.map(service => { const result = services.map(service => {
const serviceDetails = details.filter(d => d.service_id === service.id).map(detail => { const serviceDetails = details.filter(d => d.payment_service_id === service.id).map(detail => ({
const payment = payments.find(p => p.detail_id === detail.id) || {}; id: detail.id,
return { name: detail.name,
id: detail.id, amount: detail.amount
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,
};
});
return { return {
id: service.id, id: service.id,
name: service.name, name: service.name,
icon: service.icon, icon: service.icon,
details: serviceDetails, amount: service.amount,
isPaid: service.is_paid,
paymentMethod: service.payment_method,
details: serviceDetails
}; };
}); });