FSP 1.0

FSP / Модули / pricing

stable версия 1.0

FSP Pricing 1.0

Как оператор описывает свой прайс: тарифный план, предложения, правила цены, условия, модификаторы, ступени.

Зависит от: core. Объявить этот модуль в манифесте без него нельзя (PROFILE-002).

Прайс описывается так, чтобы по нему можно было посчитать смету, а не только прочитать глазами.

Услуги, единицы начисления, материалы и габаритные профили берутся из core.

Уровни соответствия

Глубина модели цены разная у разных операторов, и требовать от всех максимума бессмысленно: прайс из Excel так и останется прайсом из Excel. Поэтому модуль определяет три уровня. Оператор объявляет достигнутый в манифесте (pricing: {versions: ["1.0"], level: "L2"}), а запрос может потребовать минимальный через quote_request.pricing_level_min.

Уровень Что добавляет Типичный источник
L1 Плоский прайс rate_cards, offers, offer_services, offer_materials, price_rules; методы flat, per_unit, per_metric, manual_quote Прайс-лист, где у строки есть услуга, единица и одна ставка
L2 Условия и модификаторы price_rule_conditions, price_adjustments, price_adjustment_conditions; метод minimum_charge Ставка зависит от габаритов, схемы, маршрута или объёма; наценка за срочность; минимальный чек
L3 Ступенчатые тарифы price_tiers, поля tier_mode/tier_variable/tier_scope; метод tiered Бесплатный период хранения, разная цена первой и последующих единиц, матрицы цены по количеству

Уровни кумулятивны. Согласованным между сторонами считается наименьший общий (PROFILE-006): запрос уровня выше не выкидывает оператора из выдачи, а возвращает код pricing_level_insufficient — понятную задачу «дописать прайс».

Из трёх реальных прайс-листов, разобранных в термины стандарта, L3 требуют ровно две конструкции: бесплатный период хранения и матрица «цена за заказ по числу хрупких товаров». Всё остальное укладывается в L1 и L2.

Валидатор следит, чтобы каждая сущность модели цены была отнесена ровно к одному уровню, а метод со ступенями не оказался на уровне без ступеней.

Реестры

Реестр Что внутри
price_model Сущности и поля: rate_cards → offers → price_rules → price_tiers / price_adjustments
price_conditions Закрытый реестр 92 типизированных полей условий
condition_operators Единая семантика операторов и поведение при null
calculation_methods Закрытый реестр значений calculation_method
conformance_levels Уровни соответствия L1/L2/L3
tier_variables, tier_scopes Шкалы и области группировки для ступенчатых тарифов
rules PRICE-*, TIME-*, STORAGE-*

Ступенчатые тарифы

Ступенчатое правило описывается calculation_method=tiered и тремя обязательными полями:

Поле Что задаёт
tier_variable шкала — код из tier_variables (storage_age_days, unit_sequence, weight_kg, …)
tier_scope группа, внутри которой шкала считается заново — код из tier_scopes (batch, order_sku, …)
tier_mode progressive — каждая часть по своей ставке; slab — весь объём по ставке итогового диапазона

Границы лежат в price_tiers: quantity_from включена, quantity_to исключена. Ставки не обязаны расти: бесплатный период это первый диапазон с явным amount=0 (PRICE-018).

Хранение по сроку. Шкала storage_age_days считается в сутках от приёмки партии, а не от начала расчётного месяца, область — batch. В progressive каждые сутки тарифицируются по ставке своего диапазона: 0–14 → 0 ₽, 14–∞ → 120 ₽ за м³·сутки. Если оператор считает иначе, весь срок по ставке итогового диапазона, это slab по storage_stay_days. При частичном списании возраст остатка определяет inventory_rotation_method; без него расчёт блокируется (STORAGE-003).

Первая и последующие единицы одного товара. Шкала unit_sequence с нумерацией от 1, область order_sku / supply_sku / batch, режим progressive: 1–2 → 25 ₽, 2–∞ → 10 ₽. Отдельная услуга под это не заводится (PRICE-020, CAT-011).

Границы модуля

Поля условий — это входы контекста расчёта, а не ссылки на объекты этого модуля. route_id, warehouse_id, marketplace приходят от вызывающей стороны, и их значения не проверяются на ссылочную целостность внутри Pricing. Сами маршруты и графики отправки описываются в FSP Capacity: цена может зависеть от маршрута, но маршрут не является частью прайса.

Пустая цена не равна нулю (PRICE-003). Индивидуальная цена — это manual_quote, который возвращает MANUAL_QUOTE_REQUIRED, а не сумму 0.

Нормативные правила

Обязательны для соответствия модулю. Префиксы объявлены в манифесте: PRICE-*, TIME-*, STORAGE-*.

Схема

JSON Schema 2020-12: /1.0/pricing/schema.json. Определения: calculation_method, tier_mode, tier_variable, tier_scope, condition_operator, condition, rate_card, offer, offer_service, offer_material, price_rule, price_tier, price_adjustment.

Манифест модуля

{
  "module": "pricing",
  "title": "FSP Pricing",
  "version": "1.0",
  "status": "stable",
  "summary": "Как оператор описывает свой прайс: тарифный план, предложения, правила цены, условия, модификаторы, ступени.",
  "depends": [
    "core"
  ],
  "registries": [
    "price_model",
    "price_conditions",
    "condition_operators",
    "calculation_methods",
    "tier_variables",
    "tier_scopes",
    "conformance_levels",
    "rules"
  ],
  "rule_prefixes": [
    "PRICE",
    "TIME",
    "STORAGE"
  ],
  "schema": "schema.json",
  "conformance": {
    "levels_registry": "conformance_levels",
    "methods_registry": "calculation_methods",
    "declared_as": "level"
  }
}