Files
FamilyHUB/docs/finance_module_specification.md
T

8.9 KiB
Raw Blame History

📘 Финансовый модуль

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. Потоки

Ручной ввод

User → API POST /transactions → transactions

Доход

User → API POST /transactions → transactions

Чек по номеру и дате

User → API POST /transactions → receipt provider → receipts + positions + transactions

Чек по фото

User → API POST /transactions multipart/form-data → OCR → receipt provider → receipts + positions + transactions

6. API (черновик)

Создание транзакции вручную

POST /api/v1/transactions
Content-Type: application/json
{
  "family_id": 1,
  "created_by": 2,
  "type": "expense",
  "category": "groceries",
  "amount": 1000,
  "description": "Продукты",
  "datetime": "2026-01-21T10:11:12Z"
}

Создание транзакции по номеру и дате чека

POST /api/v1/transactions
Content-Type: application/json
{
  "family_id": 1,
  "created_by": 2,
  "receipt_number": "0123456789ABCDEFGHIJKLMN",
  "receipt_date": "21.01.2026"
}

Создание транзакции по фото чека

POST /api/v1/transactions
Content-Type: multipart/form-data

Поля формы:

  • photo — файл изображения чека, обязательно
  • family_id — ID семьи, обязательно
  • created_by — ID пользователя, обязательно
  • type — тип транзакции, опционально, по умолчанию expense
  • category — категория, опционально, по умолчанию receipt
  • description — описание транзакции, опционально

Получение транзакций

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 — Транзакции

  • Endpoint создания транзакции
  • Endpoint получения списка
  • Фильтрация

Этап 4 — Доходы/расходы

  • Определение типа через категорию
  • Валидация соответствия

Этап 5 — Чеки

  • Endpoint загрузки фото чека через POST /transactions
  • Интеграция с сервисом чеков
  • Создание receipts
  • Создание транзакции по номеру и дате чека
  • Создание транзакции по фото чека
  • Создание positions

Этап 6 — Telegram интеграция

  • Команды добавления дохода/расхода
  • Обработка QR

Этап 7 — Дополнительно

  • Автокатегоризация
  • Статистика
  • Лимиты

8. Архитектурные решения

  • Transaction — основная сущность финансов
  • Receipt — дополняет транзакцию
  • Position - позиции из чека
  • Категории определяют тип операции
  • Поддержка multi-tenant через family_id

9. Открытые вопросы

  • Нужна ли мультивалютность?
  • Можно ли редактировать чек?
  • Как обрабатывать ошибки OCR?
  • Нужен ли отдельный endpoint для повторной привязки чека к существующей транзакции?
  • Нужны ли роли внутри семьи?