# 📘 Финансовый модуль ## 1. Общее описание Финансовый модуль предназначен для учёта: - доходов - расходов - категорий Поддерживает три способа ввода расходов: 1. Ручной ввод 2. Ввод номера и даты чека 3. Загрузка фото чека --- ## 2. Глоссарий **Доход (Income)** Денежное поступление (зарплата, перевод, подарок и т.д.) **Расход (Expense)** Факт траты денег **Категория (Category)** Классификация доходов и расходов (например: еда, транспорт, зарплата) **Чек (Receipt)** Документ, содержащий информацию о покупке (дата, позиции, сумма) **Позиция (Position)** Отдельная строка в чеке (товар или услуга) --- ## 3. Доменная модель ### 3.1 Positions ``` positions ( id, receipt_number, operation_date, gtin_code, product_name, product_count, amount, discount, name_spd, category_id, family_id, family_member_id, created_at, updated_at ) ``` **Описание полей:** - `receipt_number` — номер чека (nullable для ручного ввода) - `operation_date` — дата операции - `gtin_code` — код товара - `product_name` — название товара - `product_count` — количество - `amount` — сумма позиции - `discount` — скидка - `name_spd` — продавец - `category_id` — категория - `family_id` — семья - `family_member_id` — участник --- ### 3.2 Receipts ``` receipts ( id, receipt_number, ui, status, issued_at, total_amount, payment_amount, cash_amount, another_amount, clearing_amount, margin, currency, payment_type, cashbox_number, cashier, name_spd, name_to, name_np, type_np, street_to, house_to, kod_soato, oblast_soato, rayon_soato, selsovet_soato, doc_num, skno_number, unp, success, family_id, family_member_id, created_at ) ``` **Описание:** - хранит агрегированную информацию о чеке - используется при сканировании QR - связывается с positions через `receipt_number` --- ### 3.3 Categories ``` categories ( id, name, type, family_id, family_member_id, created_at ) ``` **Описание полей:** - `type` — income | expense - категория принадлежит семье --- ## 4. Бизнес-логика ### 4.1 Добавление расхода вручную - пользователь вводит: - сумму - описание - категорию - создаётся запись в `positions` - `receipt_number = NULL` --- ### 4.2 Добавление дохода - аналогично расходу - используется категория типа `income` --- ### 4.3 Добавление расхода по номеру и дате чека #### Поток: 1. Пользователь вводит номер и дату чека 2. Backend получает данные чека через внешний сервис 3. Создаётся запись в `receipts` 4. Создаётся связанная транзакция в `transactions` 5. Для каждой позиции создаётся запись в `positions` --- ### 4.4 Добавление расхода по фото чека #### Поток: 1. Пользователь загружает фото чека 2. Backend извлекает текст через OCR 3. Backend извлекает из текста номер и дату чека 4. Backend получает данные чека через внешний сервис 5. Создаётся запись в `receipts` 6. Создаётся связанная транзакция в `transactions` 7. Для каждой позиции создаётся запись в `positions` --- ## 5. Потоки ### Ручной ввод ```text User → API POST /transactions → transactions ``` ### Доход ```text User → API POST /transactions → transactions ``` ### Чек по номеру и дате ```text User → API POST /transactions → receipt provider → receipts + positions + transactions ``` ### Чек по фото ```text User → API POST /transactions multipart/form-data → OCR → receipt provider → receipts + positions + transactions ``` --- ## 6. API (черновик) ### Создание транзакции вручную ```http POST /api/v1/transactions Content-Type: application/json ``` ```json { "family_id": 1, "created_by": 2, "type": "expense", "category": "groceries", "amount": 1000, "description": "Продукты", "datetime": "2026-01-21T10:11:12Z" } ``` --- ### Создание транзакции по номеру и дате чека ```http POST /api/v1/transactions Content-Type: application/json ``` ```json { "family_id": 1, "created_by": 2, "receipt_number": "0123456789ABCDEFGHIJKLMN", "receipt_date": "21.01.2026" } ``` --- ### Создание транзакции по фото чека ```http POST /api/v1/transactions Content-Type: multipart/form-data ``` Поля формы: - `photo` — файл изображения чека, обязательно - `family_id` — ID семьи, обязательно - `created_by` — ID пользователя, обязательно - `type` — тип транзакции, опционально, по умолчанию `expense` - `category` — категория, опционально, по умолчанию `receipt` - `description` — описание транзакции, опционально --- ### Получение транзакций ```http GET /api/v1/transactions ``` Фильтры: - дата - категория - тип - family_id --- ### Правила для `POST /api/v1/transactions` Используется ровно один сценарий создания: 1. Ручная транзакция: обязательны `family_id`, `created_by`, `type`, `category`, `amount`, `datetime` 2. Транзакция по чеку: обязательны `family_id`, `created_by`, `receipt_number`, `receipt_date` 3. Транзакция по фото: обязательны `photo`, `family_id`, `created_by` Нельзя смешивать ручные поля транзакции (`amount`, `datetime`, `receipt_id`) с полями чека (`receipt_number`, `receipt_date`) в одном JSON-запросе. --- ## 7. Задачи для разработки ### Этап 1 — База - [ ] Переписать SQL-миграции (positions, receipts, categories) --- ### Этап 2 — Категории - [ ] CRUD категорий - [ ] Валидация типа (income/expense) --- ### Этап 3 — Транзакции - [x] Endpoint создания транзакции - [x] Endpoint получения списка - [ ] Фильтрация --- ### Этап 4 — Доходы/расходы - [ ] Определение типа через категорию - [ ] Валидация соответствия --- ### Этап 5 — Чеки - [x] Endpoint загрузки фото чека через `POST /transactions` - [ ] Интеграция с сервисом чеков - [x] Создание receipts - [x] Создание транзакции по номеру и дате чека - [x] Создание транзакции по фото чека - [ ] Создание positions --- ### Этап 6 — Telegram интеграция - [ ] Команды добавления дохода/расхода - [ ] Обработка QR --- ### Этап 7 — Дополнительно - [ ] Автокатегоризация - [ ] Статистика - [ ] Лимиты --- ## 8. Архитектурные решения - Transaction — основная сущность финансов - Receipt — дополняет транзакцию - Position - позиции из чека - Категории определяют тип операции - Поддержка multi-tenant через family_id --- ## 9. Открытые вопросы - [ ] Нужна ли мультивалютность? - [ ] Можно ли редактировать чек? - [ ] Как обрабатывать ошибки OCR? - [ ] Нужен ли отдельный endpoint для повторной привязки чека к существующей транзакции? - [ ] Нужны ли роли внутри семьи?