Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

15 Commits

Folders and files

Repository files navigation

Sales Reports Service

Бэкенд-сервис для генерации аналитических XLSX-отчетов по продажам. Тяжелая работа по сбору данных и формированию файлов вынесена из HTTP-запроса в отдельного worker'а через Redis Queue.


1. Описание проекта

Сервис позволяет:

  • хранить данные о категориях, товарах, заказах и позициях заказов;
  • ставить задачи на генерацию аналитических отчетов по продажам за выбранный период;
  • асинхронно собирать данные и формировать многолистовые XLSX-отчеты;
  • отслеживать статус задачи и скачивать готовый файл.

Это коммерчески приближенный шаблон, подходящий как пример проекта на FastAPI + PostgreSQL + Redis + Worker.


2. Архитектура проекта

Пользователь / Frontend
        ↓
FastAPI Backend
        ↓
PostgreSQL — хранит заказы, товары, отчеты и статусы
        ↓
Redis Queue — хранит задачи на генерацию отчетов
        ↓
Worker — собирает данные и формирует XLSX
        ↓
File Storage — хранит готовые отчеты
  • FastAPI Backend — принимает HTTP-запросы, валидирует данные, создает задачи отчетов, отдает статус и файл.
  • PostgreSQL — основное хранилище: пользователи (имя клиента), категории, товары, заказы, позиции заказов, задачи отчетов.
  • Redis Queue — Redis List, реализующий очередь FIFO (LPUSH/BRPOP).
  • Worker — отдельный процесс, который читает задачи и формирует XLSX.
  • File Storage — каталог storage/reports, смонтированный в общий Docker-том между API и worker.

3. Почему используется Redis Queue

Генерация отчета — тяжелая операция: выборка из БД, агрегация, формирование XLSX, запись на диск. Это могут быть тысячи строк и несколько секунд работы. Делать это в HTTP-запросе нельзя:

  • запрос будет долго висеть;
  • любая ошибка сети приведет к потере результата;
  • увеличится нагрузка на API-инстансы;
  • невозможно масштабировать обработку независимо от приема запросов.

Redis Queue:

  • развязывает API и обработку (асинхронность);
  • даёт возможность поднять несколько worker'ов и масштабировать обработку горизонтально;
  • сохраняет задачи в памяти Redis даже если worker временно недоступен;
  • легче и дешевле, чем полноценный broker для нашего сценария.

4. Инструкция запуска

Требуется Docker и Docker Compose.

docker-compose up --build

Поднимутся 4 сервиса:

  • postgres — БД на порту 5432;
  • redis — на порту 6379;
  • api — FastAPI на http://localhost:8000;
  • worker — фоновая обработка задач.

Документация API: http://localhost:8000/docs


5. Описание API

Метод URL Описание
POST /seed Заполняет БД демонстрационными данными
POST /reports/sales Создает задачу на генерацию отчета
GET /reports Список всех задач отчетов
GET /reports/{report_id} Информация о задаче
GET /reports/{report_id}/download Скачать готовый XLSX
GET /health Health-check

POST /reports/sales

Тело запроса:

{
  "date_from": "2026-05-01",
  "date_to": "2026-05-31",
  "format": "xlsx"
}

Если date_from > date_to — ответ 422.

Ответ 201:

{ "id": "f8b...uuid", "status": "queued" }

GET /reports/{report_id}/download

  • 404 — отчет не найден;
  • 409 — отчет ещё не готов;
  • 404 — файл отсутствует на диске;
  • 200 — XLSX-файл.

6. Как создать тестовые данные

curl -X POST http://localhost:8000/seed

Создаются:

  • 5 категорий товаров;
  • 30 товаров;
  • 120 заказов за последние 90 дней;
  • 1–5 позиций в каждом заказе;
  • статусы распределены: ~45% completed, 25% paid, 15% created, 15% cancelled.

7. Как запустить генерацию отчета

curl -X POST http://localhost:8000/reports/sales \
  -H "Content-Type: application/json" \
  -d '{"date_from":"2026-02-01","date_to":"2026-05-31","format":"xlsx"}'

Сервис:

  1. Валидирует даты.
  2. Создаёт запись ReportTask со статусом queued.
  3. Кладёт сообщение в Redis Queue reports:queue.
  4. Возвращает id и status.

8. Как проверить статус отчета

curl http://localhost:8000/reports/{report_id}

Возможные статусы:

  • queued — задача создана, ждёт worker'а;
  • processing — worker взял задачу;
  • done — отчёт сформирован, файл доступен для скачивания;
  • failed — обработка завершилась ошибкой (error_message содержит детали).

9. Как скачать готовый XLSX-файл

curl -OJ http://localhost:8000/reports/{report_id}/download

Полученный файл — стандартный .xlsx, открывается в Excel / LibreOffice / Numbers.


10. Структура XLSX-отчёта

Файл содержит 5 листов.

Лист 1 — «Сводка»

Аккуратная таблица ключевых показателей:

  • название отчёта;
  • период;
  • дата генерации;
  • общее количество заказов;
  • оплаченных заказов;
  • отменённых заказов;
  • общая выручка (денежный формат);
  • средний чек (денежный формат);
  • продано товаров (шт.);
  • самая прибыльная категория;
  • самый продаваемый товар.

Лист 2 — «Продажи по дням»

| Дата | Заказов | Товаров продано | Выручка | Средний чек |

Лист 3 — «Категории»

| Категория | Заказов | Товаров продано | Выручка | Доля от выручки |

Доля форматируется как процент.

Лист 4 — «Топ товаров»

| Место | Товар | Категория | Количество продаж | Выручка |

Лист 5 — «Детализация заказов»

| ID заказа | Дата | Клиент | Статус | Товар | Категория | Кол-во | Цена за единицу | Сумма позиции |

Оформление:

  • жирные белые заголовки на тёмно-синей заливке;
  • зафиксированная строка заголовков (freeze panes);
  • автофильтры на табличных листах;
  • денежный и процентный форматы;
  • настроенная ширина колонок.

Выручка считается только по заказам со статусами paid и completed — это коммерчески корректная логика «реализованной выручки».


11. Работа worker'а

Worker — отдельный процесс (python -m app.workers.report_worker). Алгоритм:

  1. Слушает очередь Redis reports:queue командой BLPOP с таймаутом.
  2. Получив задачу, парсит JSON-сообщение:
    {
      "report_id": "uuid",
      "report_type": "sales",
      "params": { "date_from": "...", "date_to": "...", "format": "xlsx" },
      "attempt": 1
    }
  3. Находит ReportTask в БД, меняет статус на processing, ставит started_at.
  4. Выбирает заказы за указанный период из PostgreSQL.
  5. Считает аналитику: суммарные показатели, разбивку по дням, по категориям, топ товаров, детализацию.
  6. Генерирует XLSX через openpyxl.
  7. Сохраняет файл в storage/reports/report_{uuid}.xlsx.
  8. Записывает путь в file_path, меняет статус на done, ставит finished_at.
  9. При ошибке — перекладывает задачу обратно в очередь с инкрементом attempt. После исчерпания attempt >= 3 — статус задачи становится failed, текст ошибки сохраняется в error_message.
  10. Если в периоде нет заказов — отчёт всё равно формируется с нулевыми показателями.

12. Полный сценарий через curl

# 1. Создаём демонстрационные данные
curl -X POST http://localhost:8000/seed

# 2. Создаём задачу отчёта
curl -X POST http://localhost:8000/reports/sales \
  -H "Content-Type: application/json" \
  -d '{"date_from":"2026-02-20","date_to":"2026-05-20","format":"xlsx"}'
# → {"id":"<REPORT_ID>","status":"queued"}

# 3. Смотрим статус (повторяем, пока не будет done)
curl http://localhost:8000/reports/<REPORT_ID>

# 4. Скачиваем готовый отчёт
curl -OJ http://localhost:8000/reports/<REPORT_ID>/download

# 5. (опционально) список всех задач
curl http://localhost:8000/reports

Структура проекта

app/
 ├── main.py
 ├── config.py
 ├── database.py
 ├── redis_client.py
 ├── models/
 │   ├── product.py
 │   ├── order.py
 │   └── report.py
 ├── schemas/
 │   ├── report.py
 │   └── seed.py
 ├── routes/
 │   ├── reports.py
 │   └── seed.py
 ├── services/
 │   ├── report_service.py
 │   ├── queue_service.py
 │   ├── sales_analytics_service.py
 │   └── file_service.py
 ├── workers/
 │   └── report_worker.py
 ├── utils/
 │   ├── report_generator.py
 │   └── seed_generator.py
 └── repositories/
     ├── report_repository.py
     ├── order_repository.py
     └── product_repository.py

storage/
 └── reports/

docker-compose.yml
Dockerfile
requirements.txt
README.md

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages