feat(generator): торговые события — корзина, покупка, сырой ecommerce
- Зачем:
- клиентская сторона мира становится целой: без add_to_cart и purchase
в данных нет ни таксономии событий, ни вложенного JSON, ни денег,
а метка «покупатель» из плана состава ни на что не влияла (#40).
- Что:
- добавлен модуль commerce: корзина шире заказа, номер заказа вида
ГГГГММДД-NNNN, промокод без скидки в сумме, сырой ecommerce через orjson;
- метка покупателя получила два рычага — долгую жизнь куки в плане и
свою воронку в дне; CART_PERCENT опущен с 8 до 6, чтобы конверсия
мира осталась около 2%;
- часть цен каталога получила копейки: productPrice округляется форматом,
purchaseRevenue несёт точную сумму — расхождение живёт внутри события;
- граница суток забирает страницу подтверждения вместе с её покупкой:
потерь на клиентской стороне этот этап не заводит;
- решения и перемеренные числа мира записаны в спеку генератора, §9.
- Проверка:
- make lint && make typecheck && make test — 383 passed (было 353).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
"""Идентификаторы событий: неповторяющиеся и переживающие JSON.
|
||||
|
||||
Обещание одно, но держит его дедупликация при переигровке дня: два
|
||||
одинаковых `WatchID` склеили бы разные события (спека, раздел 4).
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from clickstream_generator import ids
|
||||
from clickstream_generator.seeds import CANONICAL_SEED
|
||||
|
||||
|
||||
def stream(offset: int = 0) -> np.random.Generator:
|
||||
return np.random.Generator(np.random.PCG64(CANONICAL_SEED + offset))
|
||||
|
||||
|
||||
def test_ids_do_not_repeat_and_survive_json():
|
||||
numbers = ids.unique(stream(), 10_000)
|
||||
assert numbers.dtype == np.uint64
|
||||
assert len(set(numbers.tolist())) == numbers.size
|
||||
assert numbers.max() < ids.LIMIT
|
||||
assert numbers.min() > 0
|
||||
|
||||
|
||||
def test_ids_do_not_give_away_the_order_of_the_rows():
|
||||
"""Иначе номер события рассказывал бы, каким по счёту оно родилось."""
|
||||
numbers = ids.unique(stream(), 1_000)
|
||||
assert not np.all(np.diff(numbers.astype(np.int64)) > 0)
|
||||
|
||||
|
||||
def test_ids_of_another_stream_are_other_ids():
|
||||
assert not np.array_equal(ids.unique(stream(), 100), ids.unique(stream(1), 100))
|
||||
|
||||
|
||||
def test_ids_can_be_drawn_beside_the_ones_already_taken():
|
||||
"""Торговые строки берут номера из своего подпотока и не задевают чужие."""
|
||||
taken = ids.unique(stream(), 5_000)
|
||||
numbers = ids.unique_apart_from(stream(1), 500, taken)
|
||||
assert len(set(numbers.tolist())) == numbers.size
|
||||
assert not set(numbers.tolist()) & set(taken.tolist())
|
||||
assert numbers.max() < ids.LIMIT
|
||||
Reference in New Issue
Block a user