12 KiB
accruals-service
Микросервис для создания скидок и формирования цен из реализованных скидок
Branch | Pipeline | Code coverage |
---|---|---|
main | ||
staging | ||
dev |
Переменные окружения приложения
GRPC_HOST - хост прослушивания приложения (gRPC)
GPRC_PORT - порт прослушивания приложения (gRPC)
HTTP_PORT - порт прослушивания приложения (HTTP)
MONGO_HOST - хост базы данных
MONGO_PORT - порт базы данных
MONGO_USER - имя пользователя базы данных для авторизации
MONGO_PASSWORD - пароль пользователя базы данных для авторизации
MONGO_AUTH - название базы данных для авторизации
MONGO_DATABASE_NAME - название базы данных, к которой будет идти подключение
Пример переменных окружения:
GRPC_HOST=0.0.0.0
GPRC_PORT=9001
HTTP_PORT=8001
MONGO_HOST=localhost
MONGO_PORT=27017
MONGO_USER=test
MONGO_PASSWORD=test
MONGO_AUTH=admin
Команды для работы с приложением:
make help - вывести список доступных команд с описанием
make install - устанавливает все необходимые зависимости и инструменты
make generate - генерирует proto файлы gRPC сервиса
make test - запускает unit и интеграционные тесты
make test.unit - запуск unit тестов
make test.integration - запуск интеграционных тестов (поднятие и завершение окружения)
make test.integration.up - поднятие тестового окружения
make test.integration.start - запуск интеграционных тестов
make test.integration.down - завершение тестового окружения
make run - запуск приложения
Текущая логика рассчёта скидки
- Получаем на вход состояние пользователя и список тарифов
Общая логика вычисления скидки это:
- Подготовить данные для выбора скидок(Подготовка)
- Найти все подходящие скидки(Фильтрация)
- Выбор максимальных скидок(Макс)
- Применение скидок(Применение)
В вычислении скидок есть 4 слоя применения, в каждом слое есть все перечисленные пункты
Слой 1: Подготовка - если у привилегии в тарифе есть ненулевой price, то берём его в качестве цены. если нет - умножаем стоимость привилегии на amount этой привилегии в рамках тарифа. создаём map с ключем - айдишником привилегии, значением - суммарным количеством всех amount привилегий с таким же айдишником. это надо потому что в корзине может быть много тарифов с одной и той же привилегией, но разным количеством оной, а скидка применяется к общему количеству этой привилегии в корзине
Фильтрация - если userType == nko - выбираем единственную скидку за nko. Иначе - выбираем все скидки у которых layer 1 и Term <= amount привилегии
Макс - если выбрана nko, то этот пункт пропускаем. Иначе - для каждой привилегии выбираем скидку с максимальным Term
Применение - умножаем стоимость каждой привилегии на Factor соответствующей скидки. если выбрана скидка nko, то суммируем все стоимости привилегий, умножаем на Factor скидки за nko и прерываем рассчёт скидки, ибо остальные слои в случае nko не принимаются
Слой 2:
Подготовка - суммируем список привилегий с их стоимостями после применения скидок первого слоя, формируя map с ключём - serviceKey, а значением - стоимостью всех привилегий по этому сервису
Фильтрация - выбираем скидки где layer == 2, group == ключ подготовленной map, PriceFrom <= значение подготовленной map
Mакс - оставляем скидки с максимальным PriceFrom в рамках group.
Применение - умножаем значение подготовленной map на Factor соответствущей скидки
Слой 3:
Подготовка - суммируем map подготовленную на прошлом слое, после применения всех скидок. Это размер корзины
Фильтрация - выбираем скидки где layer == 3, CartPurchasesAmount <= полученное значение после суммирования
Макс - выбираем скидку с максимальным значением CartPurchasesAmount
Применение - умножаем на Factor из найденной скидки
Слой 4:
Подготовка - никакой, всё сделано на прошлом слое
Фильтрация - выбираем скидки где layer == 4, purchasesAmount <= значение после применения скидки предыдущего слоя
Макс - выбираем скидку с максимальным значением purchasesAmount
Применения - умножаем на Factor выбранной скидки
Общая формула вычисления стоимости корзины: (F1-n - множитель скидки, A1-n - количество привилегии, P1-n - стоимость кокретной привилегии, S1-n - стоимость конкретного сервиса в рамках корзины)
Cart = (S1 * F1 + S2 * F2 + ... + Sn * Fn) * Fкорзина * Fлояльность
Si = A1 * P1 * F1 + A2 * P2 * F2 + ... + An * Pn * Fn
Новая логика рассчёта скидки
- вычисляем количество привилегий во всей корзине - создаём map[Product]amount
- вычисляем стоимость каждой привилегии в корзине - создаём map[Product]price
- вычисляем стоимость каждой привилегии в корзине - создаём map[Product]serviceKey
- если в CommonConditions есть UserType == "nko", то ищем скидку за nko, суммируем ассоциативный массив цен за привилегии, умножаем на эту скидку и возвращаем
- иначе, выбираем скидки за 1 Слой. убедись, что запрос способен получать скидки с Condition.User. если не способен - можешь получить скидки на юзера отдельным запросом в самом начале расчета - это всё равно всегда одна скидка
- проходимся по ассоциативному массиву цен, ищем в списке скидок скидки за этот продукт. если есть скидка на этого юзера с layer == 1, то применяем её вместо скидки, которую нашли по getLayer. если есть скидка на этого юзера слоя 2 на этот сервис, не применяем никакой скидк(вернее применяем никакую скидку). что значит примеменить скидку - умножить стоимость этой привилегии на фактор скидки и добавить к текущему значению в ассоциативном массиве цен за сервис
- выбираем 2 Слой
- проходимся по ассоциативному массиву стоимости сервисов. если есть скидка на юзера со слоем 2 и на этот сервис - применяем её. иначе применяем скидку на этот сервис. т.е. умножаем стоимости сервиса на фактор скидки и обновляем значение в самом ассоциативном массиве
- суммируем ассоциативный массив стоимости сервисов
- выбираем 3 Слой с учетом просуммированной стоимости корзины на прошлом этапе
- применяем эту скидку ко всем стоимостям сервисов по отдельности, кроме того, на который есть скидка 2 уровня у этого юзера
- выбираем 4 Слой
- применяем эту скидку ко всем стоимостям сервисов по отдельности, кроме того, на который есть скидка 2 уровня у этого юзера
- суммируем и возвращаем