Мультивалютные каталоги
(Раздел: Операции и Управление)
1) Задача и область применения
Мультивалютный каталог — это единый источник правды о ценах/комиссиях/налогах для разных валют, регионов и каналов. Он обеспечивает:- корректную витрину цен (UX, доверие),
- воспроизводимость расчетов (аудит, возвраты),
- экономическую предсказуемость (маржа/налоги),
- комплаенс (налогообложение, санкции, ограничения валют).
2) Модель данных (референс)
Сущности:- Product/SKU: `{sku_id, title, attributes, region_policies[]}`
- PriceList: `{pricelist_id, base_currency, effective_from, effective_to, version}`
- PriceItem: `{sku_id, base_price, base_currency, tax_class, pricing_model, promo_refs[]}`
- FXRate: `{pair: EUR→USD, rate, source, method, precision, effective_from, version}`
- `minor_units` (ISO 4217; напр. JPY=0, USD/EUR=2, KWD=3; для crypto — до 8)
- `rounding_mode`: `HALF_UP` (розница), `BANKERS` (финансы), `FLOOR`/`CEIL` (налоги/регуляторы)
3) Источники и политика FX (курсов валют)
Источники: провайдеры курсов (коммерческие/центробанки), собственный TWAP/медиана.
Политика обновления: частота (1–15 мин для волатильных, 1 раз/день для стабильных), задержка публикации.
Маркапы: `rate (1 + fx_markup_bps)` на сторону клиента; прозрачные правила per-канал/регион.
Гарантированное окно котировки (rate lock): 5–30 мин с `fx_version` в заказе.
Анти-скачок: кап изменения за тик, circuit-breakers, fallback на последнюю валидную котировку.
Версионирование: каждая публикация курсов имеет `version`, `effective_from`; храните историю для возвратов/споров.
4) Стратегии ценообразования
Base + FX: хранить базовую цену в «ядре» (например, EUR), конвертировать на витрине.
Per-currency листы: заранее рассчитанные цены для ключевых валют (лучший UX, предсказуемость).
Mixed: топ-10 валют — предрасчет, «длинный хвост» — on-the-fly.
Charm-pricing: `X.99/95/90` по региону, контролируйте накопление ошибок округления.
Комиссии/сборы: payment fee, cross-border fee, network fee (crypto) — в каталоге или на этапе «Checkout Pricing».
5) Налоги и «включенность»
VAT/GST включен/исключен: EU — чаще VAT-inclusive; B2B может быть без НДС.
Слои налогов: федеральный/штат/местный; для онлайн-игр — специфические сборы.
Пороговые ставки: налог меняется от оборота/категории/региона (threshold).
Округление налогов: per-item vs per-basket; режимы округления и порядок вычислений должны быть детерминированы.
Юр.отчетность: храните `tax_rule_version` в чеке/квитанции.
6) Округления и точность
Округляйте на последнем шаге показа; в расчетах храните «высокую точность» (до 8–9 знаков).
Для crypto используйте decimal-библиотеки (без двоичной плавающей).
Анти-дрифт корзины: «bankers rounding» для сумм, но UX-округление для отображения; фиксируйте `rounding_scope`.
Правило суммы: сумма построчных после округлений должна совпадать с total — используйте распределение последних копеек/центов (penny distribution).
7) Каталоги, промо и бандлы
Promo-правила: `if region=A and currency in [EUR,USD] then discount=10% cap=50`.
Порядок применения: (1) базовая цена → (2) скидки → (3) налоги → (4) сборы → (5) округления.
Bundle-распределение: пропорционально вкладке позиций до скидки; враппер для возвратов.
Threshold-промо: бесплатная доставка/бонус при total≥X в валюте корзины; храните эквивалент в базовой валюте, но фиксируйте версию FX.
8) Интеграция с платежами и комплаенсом
Валютная доступность: не каждая валюта доступна каждому игроку/региону/провайдеру платежей.
Guaranteed FX: префикс-авторизация по зафиксированному `fx_version`; при экспирации — запрос подтверждения новой цены.
KYC/санкции: блок-листы валют/банков/токенов, ограничения на конвертацию.
Возвраты/chargeback: пересчет по историческому `fx_version` заказа; комиссия возврата — по каталогу на дату транзакции.
9) Архитектура и контракт API
Чтение каталога:- `GET /catalog/prices?sku=…¤cy=…®ion=…&pricelist=…`
- Ответ: `{unit_price, currency, fx_version, pricelist_version, tax_breakdown[], fees[], display_price, rounding_mode}`
- `POST /pricing/quote { items[], region, currency, buyer_type }`
- Ответ: `{items_priced[], subtotal, discounts, taxes[], fees[], total, fx_version, lock_ttl, signature}`
- `POST /pricing/commit { quote_id, signature }` → квитанция с хешем и подписями.
- `PriceListUpdated`, `FXRatePublished`, `TaxRuleChanged`, `PromoChanged` — с `version/effective_from`.
10) Кэширование и производительность
Edge-кэш: ключ `pricelist:region:currency:sku:version`; TTL для стабильных валют выше.
Warmup: прогрев топ-категорий по запуску кампании.
SWR (stale-while-revalidate): для витрин; checkout — только fresh.
Partial invalidation: инвалидация по тегам `sku`, `category`, `pricelist_version`.
SLO: p95 ≤ 120 мс для витрины, p95 ≤ 250 мс для quote, ≥99.95% доступности.
11) Наблюдаемость и аудит
Трассировка: `trace_id`, `pricelist_version`, `fx_version`, `tax_rule_version` во всех событиях.
Иммутабельность: WORM-журналы публикаций прайс-листов/курсов; Merkle-срезы, подписи релизов (DSSE).
Receipts: чек/квитанция с полным раскладом и хешем полезной нагрузки; хранить 7–10 лет (по регулятору).
Дашборды: расхождение витрина↔checkout, частота округлений «вверх/вниз», ошибки FX, время блокировки курса (lock TTL), ROI промо.
12) Локализация отображения
Формат валюты: символ/код (₴, €, $, AED), позиция символа, разделители, пробел.
Локальные правила: «₴ 1 234,56» vs “$1,234.56”.
Психология: магические ценники (`.99`) не всегда уместны в финтех/играх; тестируйте per-регион.
Юридические подписи: «Цена включает НДС», «Комиссия сети взимается отдельно».
13) Особые случаи
Валюты без дробной части: JPY/ISK — minor_units=0.
Трехзнаковые minor units: KWD/BHD=3.
Крипто: BTC/ETH/USDT — до 8 знаков, network fee отдельно; stablecoins ≠ «курс 1:1» при кросс-бордере.
Двойная цена: «валюта каталога» ≠ «валюта списания» (банковский курс мерчанта). Документируйте spread.
Спорт/игры: лимиты на максимальные выигрыши в валюте каталога — хранить эквиваленты по `fx_version` раунда.
14) SLO/SLI и метрики успеха
Корректность: доля заказов, где total_checkout = total_quote (±1 minor unit при правилах распределения) ≥ 99.99%.
Стабильность FX: доля операций в окне rate lock ≥ 99%.
Экономика: маржа/единицу vs план; отклонения из-за FX/округлений (bps).
UX: скорость quote p95, доля отвалов на пересчете цены, NPS витрины.
Аудит: 100% чеков с сохраненными `_version` и подписью.
15) Плейбуки инцидентов
«Цена на витрине ≠ в корзине»:1. freeze кэш-инвалидаторы, 2) принудительный refresh прайс-листа, 3) сравнить `pricelist_version`/`fx_version`, 4) компенсация по политике.
«Скачок FX разрушает маржу»:1. включить повышенный markup/кап скидок, 2) сократить lock TTL, 3) переключиться на fallback-источник.
«Налог не сходится»:1. проверить `tax_rule_version`, 2) валидация rounding_scope, 3) hotfix правил и репрайс корзин.
«Промо дает отрицательную цену»:1. защитные правила (min_price), 2) отключить стекование, 3) recalculation и аудит.
16) Безопасность и комплаенс
Policy-as-code: контроль изменений прайс-листов/FX/налогов через PR + подписи релизов.
Роли/доступы: 4-глазный принцип на публикации цен/FX.
Логи/квитанции: подписанные события публикаций и checkout.
Региональные ограничения: запрет отдельных валют/токенов; гео-политики.
17) Эксперименты и оптимизация
A/B: charm-pricing, предрасчитанные цены vs on-the-fly, формат отображения.
Динамический markup: зависимость от волатильности пары/времени суток.
Когортный анализ: возвраты/chargeback по валютам, чувствительность к округлению.
Кэш-стратегии: влияние SWR/TTL на конверсию и точность.
18) Чек-лист внедрения
- Определить базовую валюту и политику per-currency листов.
- Настроить сбор/публикацию FX с версионированием, маркапами и lock TTL.
- Формализовать TaxRule и порядок вычислений/округлений (per-item или per-basket).
- Реализовать API каталога/quote/commit + подписанные квитанции.
- Включить edge-кэш и гранулярную инвалидацию; SWR для витрин.
- Завести дашборды (витрина↔checkout, FX ошибки, налоги, маржа bps).
- Ввести роли/подписи на публикации цен/курсoв, WORM-журналы.
- Подготовить плейбуки: несход цены, скачок FX, налоговые рассогласования.
- Провести «GameDay каталога»: отключение источника FX, промо-бурст, смена налога.
- Регулярно ревизировать minor_units/отображение по регионам.
19) FAQ
Нужно ли хранить цены в каждой валюте?
Не обязательно. Комбинируйте предрасчет для топ-валют и конверсию для «хвоста» — так балансируются UX и издержки.
Почему total после округлений «не бьется»?
Из-за различий per-item vs per-basket. Зафиксируйте один подход и используйте «penny distribution».
Как делать возврат через месяц?
По историческим `pricelist_version`, `fx_version` и `tax_rule_version`, сохраненным в квитанции.
Что с crypto?
Используйте decimal-точность, network fee отдельно, не обещайте 1:1 к фиату; фиксируйте курс и окно действия.
Резюме: Мультивалютный каталог — это сочетание точной математики, строгих политик и разумного кэширования. Версионируйте все (цены/курсы/налоги), фиксируйте окно котировки, детерминируйте порядок вычислений и округлений, подписывайте чек-артефакты и держите дашборды видимыми. Так вы получите честную витрину, воспроизводимые расчеты и управляемую экономику во всех валютах и регионах.