feat(generator): заказы дня — проекция покупок с деньгами магазина

- Зачем:
  - тикет #90: второй источник должен смотреть на торговую половину дня
    глазами бэкенда — заказ есть проекция покупки, а не второе порождение;
    учебный результат — два источника согласованы по построению, а не
    сверкой.
- Что:
  - `commerce` отдаёт вторым выходом покупки дня: номер заказа, корзину,
    выручку клиента, промокод и человека за кукой; новых бросков в
    подпоток `COMMERCE` не добавилось, события дня не сдвинулись.
  - заведена заказная сторона: подпоток `ORDERS` на позиции 2 дерева зерна
    (прежнее мёртвое имя `DISCREPANCIES`), ветвление — по дню рождения
    заказа; `LATECOMERS` не тронут, его наполнит этап 6.
  - новый модуль `orders.py`: деньги заказа целыми копейками —
    `items_total` из корзины, `discount` по таблице «код → скидка»
    (округление вниз), `delivery` броском по таблице весов на полную длину
    дня, `total` = `items_total` − `discount` + `delivery`.
  - план состава завёл `person_id` — последним броском когорты, после
    паспортов: вторая кука пары повторяет ID своего человека, заказ
    показывает его как `user_id`, в событие Метрики он не попадает.
  - `world`: окно изменяемости `ORDER_WINDOW_DAYS` = 7 рядом с D0 и поясом,
    черновая таблица стоимости доставки.
  - слепок дня в тестах сторожит обе половины: заказы сравниваются наравне
    с потоком событий.
  - доки: имя подпотока заказной стороны и состав денег заказа записаны в
    `docs/architecture/orders`, README генератора знает про новый модуль.
- Проверка:
  - из `generator/`: make lint, make typecheck, make test (417 тестов);
    в корне — make lint.
  - опись мира не покраснела: байты восьми дней те же, заказная сторона
    события не сдвинула.

Closes #90

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 12:30:13 +03:00
co-authored by Claude Opus 5
parent 716eafe865
commit b2fcc7e593
14 changed files with 650 additions and 52 deletions
@@ -31,6 +31,13 @@ COUNTER_TIMEZONE_MINUTES = 240 # Europe/Samara
# зависит — иначе опись перестала бы быть воспроизводимой.
ORIGIN = date(2026, 6, 1)
# Окно изменяемости заказа, модельные дни: слепок бэкенда несёт заказы,
# рождённые в последние K дней, а за окном заказ неизменяем — выручка дня
# «дышит» K дней и потом замерзает (мастер-спека, раздел 2). Стоит рядом с
# D0 и поясом: это такое же свойство модельного времени, и собирает по нему
# окно команда слепка (#92).
ORDER_WINDOW_DAYS = 7
# Приток: сколько новых людей приходит в мир в средний день. Каждый приводит
# свою куку, поэтому число это же — приток кук; вторые куки двухкуковых пар
# добавляют к нему меньше процента.
@@ -224,3 +231,17 @@ COUPONS = (
# так и бывает (мастер-спека, раздел 1.2).
GOAL_CART_ID = 42150001
GOAL_PURCHASE_ID = 42150002
# --- Числа заказов бэкенда: деньги магазина -------------------------------
# Стоимость доставки: пары «копейки — вес». Бесплатно (самовывоз или акция),
# обычная курьерская, срочная. Это единственные деньги заказа, которых нет
# ни в одном событии: выручка клиента — сумма позиций, скидку по промокоду
# считает бэкенд по таблице `COUPONS`, а доставку решает свой бросок
# заказной стороны. Числа черновые: калибровка — пересборка эталонного
# мира, этап 7.
DELIVERY_KOPECKS_WEIGHTS = (
(0, 35),
(29_900, 50),
(59_000, 15),
)