Demo_Case
Анализ продаж с учетом промо-активностей
Описание проекта
Приложение предназначено для анализа продаж в федеральной сети с учетом промо-активностей. Оно позволяет:
- Производить отгрузки с учетом скидок и без скидок.
- Анализировать продажи по регулярным ценам и промо-ценам, определяя долю промо-продаж в процентах.
Цели
- Загрузить данные из федеральной сети (
), данные о клиентах (Actuals) и продуктах (Customers).Products - Проставить маркер отгрузки: "Regular" (регулярная цена) или "Promo" (промо-цена).
- Реализовать REST API для получения аналитических данных о продажах.
Исходные таблицы
Приложение работает с тремя основными таблицами:
- Actuals — факт отгрузок (адрес, продукт, дата, объем отгрузки).
- Customers — справочник клиентов (адрес, название сети).
- Products — справочник продуктов (код продукта, название, категория, бренд).
- Price — справочник цен (название сети, код продукта, регулярная цена за единицу).
Необходимо сделать
-
Создать таблицы и установить связи:
- Создать таблицы для хранения данных
,Actuals,CustomersиProducts.Price - В таблице
добавить колонкуActualsдля хранения маркера отгрузки ("Regular"/"Promo").promo_flag
- Создать таблицы для хранения данных
-
Написать REST Controller "Finance":
- Реализовать CRUD-операции для работы с сущностью
.Price
- Реализовать CRUD-операции для работы с сущностью
-
Написать REST Controller "Analysis" с методами:
- Анализ фактов продаж с учетом признака промо:
- Возвращает данные о продажах, объемах и долях промо-продаж.
- Параметры: сеть, месяц, факт продаж с учетом фильтра по сети/категории, факт продаж не промо, доля продаж по промо в процентах.
- Анализ ежедневных продаж:
- Возвращает данные о продажах по дням для указанных сетей и продуктов.
- Анализ фактов продаж с учетом признака промо:
Таблицы в БД
Приложение использует PostgreSQL для хранения данных. Схема базы данных включает следующие таблицы:
-
actuals:
— идентификатор (BIGSERIAL, PK).id— дата продажи (VARCHAR(50), NOT NULL).sale_date— код клиента (VARCHAR(50), NOT NULL, FK →ch3_ship_to_code).customers.ch3_ship_to_code— код продукта (VARCHAR(50), NOT NULL, FK →material_no).products.material_no— объем продаж (DECIMAL(10,2), NOT NULL).volume_units— стоимость продаж (DECIMAL(10,2), NOT NULL).actual_sales_value— маркер отгрузки ("Regular"/"Promo", VARCHAR(50)).promo_flag
-
customers:
— код клиента (VARCHAR(50), PK).ch3_ship_to_code— название сети (VARCHAR(255), NOT NULL).chain_name— название точки продажи (VARCHAR(50), NOT NULL).ch3_ship_to_name
-
products:
— код продукта (VARCHAR(50), PK).material_no— название продукта (VARCHAR(255), NOT NULL).material_desc_rus— категория продукта (VARCHAR(255), NOT NULL).l3_product_category_name— номер категории продуктов (VARCHAR(255), NOT NULL).l3_product_category_code
-
price:
— идентификатор (BIGSERIAL, PK).id— название сети (VARCHAR(255), NOT NULL).chain_name— код продукта (VARCHAR(50), NOT NULL, FK →material_no).products.material_no— регулярная цена за единицу (DECIMAL(10,2), NOT NULL).regular_price_per_unit
Эффективность
- Технологии: Приложение использует Spring Boot, Spring Data JPA, PostgreSQL.
- Оптимизация:
- Загрузка данных реализована с использованием параллельной обработки (многопоточный ExecutorService).
- Кэширование цен в
для ускорения расчетаConcurrentHashMap.promo_flag
- Масштабируемость:
- Использование Spring Data JPA позволяет легко масштабировать запросы к базе данных.
Архитектура
Приложение построено по принципам многослойной архитектуры:
- Controller:
(CRUD дляFinanceController),Price(аналитика продаж).AnalysisController - Service:
(логика проставленияActualsService).promo_flag - Repository:
,ActualsRepository,PriceRepository,CustomerRepository(доступ к данным).ProductRepository - DTO:
,SalesAnalysisDTO(для передачи аналитических данных через API).DailySalesDTO - Entity:
,Actuals,Customers,Products(модели данных).Price
Логика расчета
-
Проставление
:promo_flag- Для каждой записи в
рассчитывается цена за единицу:Actuals.actual_sales_value / volume_units - Если цена меньше регулярной (
изregular_price_per_unit), устанавливаетсяPrice, иначеpromo_flag = "Promo".promo_flag = "Regular" - Расчет использует абсолютные значения (
) дляabsиactual_sales_valueдля корректной обработки возвратов (отрицательных значений).volume_units
- Для каждой записи в
-
Анализ продаж:
- Ежемесячный анализ (
):/api/analysis/sales- Группировка по сети, категории и месяцу.
- Вычисление объемов регулярных и промо-продаж.
- Расчет доли промо-продаж в процентах:
.(promo_volume / total_volume) * 100
- Ежедневный анализ (
):/api/analysis/daily- Возвращает данные о продажах по дням для указанных сетей и продуктов.
- Ежемесячный анализ (
Инструкции по запуску
Требования
- Java 17+
- Gradle
- Docker(PostgreSQL)
- Git
Установка и запуск
-
Клонируйте репозиторий:
-
Запустите Docker:
-
Запустите приложение:
-
Инициализация данных:
- Приложение автоматически загружает данные из файлов
,Actuals.json,Customers.jsonиProducts.jsonпри старте.Price.json - После загрузки вызывается метод
для проставленияActualsService.updatePromoFlags().promo_flag
- Приложение автоматически загружает данные из файлов
Использование API
Приложение предоставляет REST API для анализа продаж.
1. Finance Controller (CRUD для Price)
- GET /api/finance/prices — получить все цены.
- GET /api/finance/prices/{id} — получить конкретную цену.
- POST /api/finance/prices — создать новую цену.
- PUT /api/finance/prices/{id} — обновить цену.
- DELETE /api/finance/prices/{id} — удалить цену.
2. Analysis Controller
-
GET /api/analysis/sales — получить ежемесячный анализ продаж.
- Параметры:
(опционально) — название сети.chainName(опционально) — категория продукта.category
- Пример:
- Ответ:
- Параметры:
-
GET /api/analysis/daily — получить ежедневные продажи.
- Параметры:
— список сетей.chainNames— список кодов продуктов.materialNos
- Пример:
- Ответ:
- Параметры:
Тестирование
-
Проверьте инициализацию данных:
- После запуска проверьте, что таблицы созданы и данные загружены:
- После запуска проверьте, что таблицы созданы и данные загружены:
-
Проверьте
:promo_flag- Убедитесь, что все записи в
имеютactuals:promo_flag
- Убедитесь, что все записи в
-
Проверьте API:
- Вызовите
и/api/analysis/salesс различными параметрами./api/analysis/daily - Проверьте корректность возвращаемых данных (объемы, доли промо, даты).
- Вызовите
Возможные улучшения
-
Оптимизация производительности:
- Добавить индексы на часто используемые поля (например,
,ch3_ship_to_codeвmaterial_no).actuals - Использовать пагинацию для больших наборов данных в API.
- Добавить индексы на часто используемые поля (например,
-
Обработка ошибок:
- Добавить валидацию входных параметров в
.AnalysisController - Обрабатывать случаи, когда
или отрицательные значения (возвраты).volume_units = 0
- Добавить валидацию входных параметров в
-
Миграция схемы:
- Изменить тип
сsale_dateнаVARCHAR(50)для устранения проблем с парсингом дат.DATE
- Изменить тип
-
Логирование:
- Добавить более детализированные логи для отслеживания ошибок и производительности.