feat(dm): добавлена сверка покупок с заказами

- Зачем:
  - показать расхождения трекера и бэкенда на зерне заказа
  - сохранить отложенные покупки наблюдаемыми до следующего слепка
- Что:
  - добавлены таблицы, представление и пересборка purchase_vs_orders
  - сумма покупки нормализована в Decimal на границе ODS
  - обновлены договоры и указатели на механику пересборки
- Проверка:
  - `make config-test`, `make lint`
  - `cd generator && make docs lint typecheck test`
  - `make rebuild-storage`, явные `dds_transform` и `dm_transform`
  - `make smoke`, `make check-clickhouse`, `make check-services`
This commit is contained in:
ddadmin committed 2026-08-27 04:21:15 -04:00
1 parent fb00bbe4c3
commit 20071c565f
15 files changed
+391 -38

No files matched your search

+20 -6
View File
@@ -221,6 +221,13 @@ ODS и в таблицу ошибок. Нужен ли он выше ODS, реш
`dds.event_v` отвечает за другое: даёт событию язык бизнес-модели, в том
числе snake_case-имена и расшифровку кодов.
Типы ODS обычно повторяют контракт выгрузки. Денежный `purchaseRevenue` —
исключение: источник объявляет `Array(Float64)`, а материализованное
представление ODS разбирает числа сырого JSON сразу в
`Array(Decimal(18, 2))`. DDS наследует этот тип без нового преобразования.
Прямой разбор подтвержден документацией ClickHouse через Context7 и запросом
к ClickHouse 26.3; сравнение с сырьем подтвердило: копейки всех покупок целы.
## Версии заказов
`ods.order_rep` хранит принятые версии в
@@ -483,9 +490,9 @@ kafka_offset)`: смотрят такую таблицу от класса, а
административная операция, роль `etl` права на неё не получает.
Деньги каталога живут в трёх единицах: в CSV — целые копейки, словарь отдаёт
`Decimal(18, 2)`, `productPrice` события — целые рубли. Разрыв намеренный, на
нём стоит урок про `Float64` ([описание
выгрузки](../formats/clickstream-event.md)).
`Decimal(18, 2)`, `productPrice` события — целые рубли. Поэтому точную сумму
заказа берут из `purchaseRevenue`, а не складывают округленные цены товаров
([описание выгрузки](../formats/clickstream-event.md)).
Устройство обоих объектов — почему такой движок, такая форма пути, такой
пользователь и такое окно — расписано в
@@ -523,7 +530,7 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
| `40-stg-views.sql` | матвью приёма: чтец в сырьё |
| `45-dds-tables.sql` | физические модели заказа, сессии и карты идентичностей, доноры партиций |
| `50-dds-views.sql` | публичные договоры сущностей DDS |
| `55-dm-tables.sql` | физические витрины выручки и трафика, донор партиций выручки |
| `55-dm-tables.sql` | физические витрины выручки, сверки и трафика, доноры дневных партиций |
| `60-dm-views.sql` | публичные договоры витрин DM |
Справочники идут сразу за базами: зона `dic` не зависит ни от одного слоя, и
@@ -594,6 +601,9 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
| `dm` | `dm.revenue_daily_rep` / `_dist` | дневная выручка по категориям |
| `dm` | `dm.revenue_daily_stage_rep` / `_dist` | таблица-двойник, донор дневных партиций выручки |
| `dm` | `dm.revenue_daily_v` | публичный договор дневной выручки |
| `dm` | `dm.purchase_vs_orders_rep` / `_dist` | сверка покупок с заказами, партиция — день заказа |
| `dm` | `dm.purchase_vs_orders_stage_rep` / `_dist` | донор дневных партиций сверки |
| `dm` | `dm.purchase_vs_orders_v` | публичный договор сверки с `NULL` для отсутствующей стороны |
| `dm` | `dm.daily_traffic_rep` / `_dist` | версии дневных счетчиков трафика |
| `dm` | `dm.daily_traffic_v` | точные текущие счетчики трафика с `FINAL` |
| `dic` | `dic.products_file` | чтец CSV-каталога, общего с генератором |
@@ -605,8 +615,8 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
В слое DDS построены событие, заказ, сессия и карта идентичностей. Событие
остаётся представлением над ODS; заказ и сессия гасят повтор заменой партиции;
карта пишет полный набор пар в версионную таблицу. В DM выручка заменяет
партиции изменяемых дней, а трафик пишет полную историю новой версией.
карта пишет полный набор пар в версионную таблицу. В DM выручка и сверка
заменяют партиции изменяемых дней, а трафик пишет полную историю новой версией.
## Что проверено
@@ -849,6 +859,10 @@ Kafka с пустым значением (ноль байт) и запись-н
промежуточного `toDecimal64`. Проверено на живом слепке; честность разбора
сторожит инвариант бэкенда — сумма «цена × количество» совпала с `items_total`
у всех 1662 заказов.
- **`JSONExtract` читает `Decimal` и из числа JSON.** Массив
`purchaseRevenue`, объявленный источником как `Array(Float64)`, разбирается
сразу в `Array(Decimal(18, 2))`. Синтаксис подтвержден через Context7 и на
ClickHouse 26.3; все суммы после ODS совпали с сырьем до копейки.
**Сказано по памяти, проверки нет.** Группа пуста: оба утверждения, ждавшие
матвью разбора, закрыты опытами при исполнении #43 и переехали выше.