Demo_Case

0
README.md

Анализ продаж с учетом промо-активностей

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

Приложение предназначено для анализа продаж в федеральной сети с учетом промо-активностей. Оно позволяет:

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

Цели

  • Загрузить данные из федеральной сети (
    Actuals
    ), данные о клиентах (
    Customers
    ) и продуктах (
    Products
    ).
  • Проставить маркер отгрузки: "Regular" (регулярная цена) или "Promo" (промо-цена).
  • Реализовать REST API для получения аналитических данных о продажах.

Исходные таблицы

Приложение работает с тремя основными таблицами:

  1. Actuals — факт отгрузок (адрес, продукт, дата, объем отгрузки).
  2. Customers — справочник клиентов (адрес, название сети).
  3. Products — справочник продуктов (код продукта, название, категория, бренд).
  4. Price — справочник цен (название сети, код продукта, регулярная цена за единицу).

Необходимо сделать

  1. Создать таблицы и установить связи:

    • Создать таблицы для хранения данных
      Actuals
      ,
      Customers
      ,
      Products
      и
      Price
      .
    • В таблице
      Actuals
      добавить колонку
      promo_flag
      для хранения маркера отгрузки ("Regular"/"Promo").
  2. Написать REST Controller "Finance":

    • Реализовать CRUD-операции для работы с сущностью
      Price
      .
  3. Написать REST Controller "Analysis" с методами:

    • Анализ фактов продаж с учетом признака промо:
      • Возвращает данные о продажах, объемах и долях промо-продаж.
      • Параметры: сеть, месяц, факт продаж с учетом фильтра по сети/категории, факт продаж не промо, доля продаж по промо в процентах.
    • Анализ ежедневных продаж:
      • Возвращает данные о продажах по дням для указанных сетей и продуктов.

Таблицы в БД

Приложение использует PostgreSQL для хранения данных. Схема базы данных включает следующие таблицы:

  • actuals:

    • id
      — идентификатор (BIGSERIAL, PK).
    • sale_date
      — дата продажи (VARCHAR(50), NOT NULL).
    • ch3_ship_to_code
      — код клиента (VARCHAR(50), NOT NULL, FK →
      customers.ch3_ship_to_code
      ).
    • material_no
      — код продукта (VARCHAR(50), NOT NULL, FK →
      products.material_no
      ).
    • volume_units
      — объем продаж (DECIMAL(10,2), NOT NULL).
    • actual_sales_value
      — стоимость продаж (DECIMAL(10,2), NOT NULL).
    • promo_flag
      — маркер отгрузки ("Regular"/"Promo", VARCHAR(50)).
  • customers:

    • ch3_ship_to_code
      — код клиента (VARCHAR(50), PK).
    • chain_name
      — название сети (VARCHAR(255), NOT NULL).
    • ch3_ship_to_name
      — название точки продажи (VARCHAR(50), NOT NULL).
  • products:

    • material_no
      — код продукта (VARCHAR(50), PK).
    • material_desc_rus
      — название продукта (VARCHAR(255), NOT NULL).
    • l3_product_category_name
      — категория продукта (VARCHAR(255), NOT NULL).
    • l3_product_category_code
      — номер категории продуктов (VARCHAR(255), NOT NULL).
  • price:

    • id
      — идентификатор (BIGSERIAL, PK).
    • chain_name
      — название сети (VARCHAR(255), NOT NULL).
    • material_no
      — код продукта (VARCHAR(50), NOT NULL, FK →
      products.material_no
      ).
    • regular_price_per_unit
      — регулярная цена за единицу (DECIMAL(10,2), NOT NULL).

Эффективность

  • Технологии: Приложение использует Spring Boot, Spring Data JPA, PostgreSQL.
  • Оптимизация:
    • Загрузка данных реализована с использованием параллельной обработки (многопоточный ExecutorService).
    • Кэширование цен в
      ConcurrentHashMap
      для ускорения расчета
      promo_flag
      .
  • Масштабируемость:
    • Использование Spring Data JPA позволяет легко масштабировать запросы к базе данных.

Архитектура

Приложение построено по принципам многослойной архитектуры:

  • Controller:
    FinanceController
    (CRUD для
    Price
    ),
    AnalysisController
    (аналитика продаж).
  • Service:
    ActualsService
    (логика проставления
    promo_flag
    ).
  • Repository:
    ActualsRepository
    ,
    PriceRepository
    ,
    CustomerRepository
    ,
    ProductRepository
    (доступ к данным).
  • DTO:
    SalesAnalysisDTO
    ,
    DailySalesDTO
    (для передачи аналитических данных через API).
  • Entity:
    Actuals
    ,
    Customers
    ,
    Products
    ,
    Price
    (модели данных).

Логика расчета

  1. Проставление

    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
      для корректной обработки возвратов (отрицательных значений).
  2. Анализ продаж:

    • Ежемесячный анализ (
      /api/analysis/sales
      ):
      • Группировка по сети, категории и месяцу.
      • Вычисление объемов регулярных и промо-продаж.
      • Расчет доли промо-продаж в процентах:
        (promo_volume / total_volume) * 100
        .
    • Ежедневный анализ (
      /api/analysis/daily
      ):
      • Возвращает данные о продажах по дням для указанных сетей и продуктов.

Инструкции по запуску

Требования

  • Java 17+
  • Gradle
  • Docker(PostgreSQL)
  • Git

Установка и запуск

  1. Клонируйте репозиторий:

  2. Запустите Docker:

  3. Запустите приложение:

  4. Инициализация данных:

    • Приложение автоматически загружает данные из файлов
      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
        — список кодов продуктов.
    • Пример:
    • Ответ:

Тестирование

  1. Проверьте инициализацию данных:

    • После запуска проверьте, что таблицы созданы и данные загружены:
  2. Проверьте

    promo_flag
    :

    • Убедитесь, что все записи в
      actuals
      имеют
      promo_flag
      :
  3. Проверьте API:

    • Вызовите
      /api/analysis/sales
      и
      /api/analysis/daily
      с различными параметрами.
    • Проверьте корректность возвращаемых данных (объемы, доли промо, даты).

Возможные улучшения

  1. Оптимизация производительности:

    • Добавить индексы на часто используемые поля (например,
      ch3_ship_to_code
      ,
      material_no
      в
      actuals
      ).
    • Использовать пагинацию для больших наборов данных в API.
  2. Обработка ошибок:

    • Добавить валидацию входных параметров в
      AnalysisController
      .
    • Обрабатывать случаи, когда
      volume_units = 0
      или отрицательные значения (возвраты).
  3. Миграция схемы:

    • Изменить тип
      sale_date
      с
      VARCHAR(50)
      на
      DATE
      для устранения проблем с парсингом дат.
  4. Логирование:

    • Добавить более детализированные логи для отслеживания ошибок и производительности.