{
  "standard": "FSP",
  "module": "pricing",
  "version": "1.0",
  "registry": "rules",
  "title": "Нормативные правила FSP Pricing 1.0",
  "description": "Правила расчёта цены: выбор правила, условия, модификаторы, ступени, округление, версии прайса. Обязательны для соответствия модулю.",
  "in_standard": true,
  "columns": [
    "ID",
    "Правило"
  ],
  "rows": [
    {
      "ID": "PRICE-001",
      "Правило": "Цена может зависеть от класса размера и от сырых метрик: веса, сторон, объёма и объёмного веса."
    },
    {
      "ID": "PRICE-002",
      "Правило": "Условия одной группы объединяются AND, группы объединяются OR."
    },
    {
      "ID": "PRICE-003",
      "Правило": "Пустая цена не равна нулю."
    },
    {
      "ID": "PRICE-004",
      "Правило": "Индивидуальная цена возвращает MANUAL_QUOTE_REQUIRED."
    },
    {
      "ID": "PRICE-005",
      "Правило": "Модификаторы показываются отдельной строкой расчёта."
    },
    {
      "ID": "PRICE-006",
      "Правило": "price_rules.amount обязателен для flat, per_unit, per_metric и minimum_charge. Для tiered и manual_quote поле пустое."
    },
    {
      "ID": "PRICE-007",
      "Правило": "Каждая строка price_tiers обязана содержать собственный amount и ссылку price_rule_id."
    },
    {
      "ID": "PRICE-008",
      "Правило": "Каждый price_adjustments обязан содержать value и ссылку price_rule_id."
    },
    {
      "ID": "PRICE-009",
      "Правило": "Подходящие price_rules сортируются по priority по возрастанию. Одинаковый priority в одном offer запрещён и возвращает PRICE_RULE_PRIORITY_CONFLICT."
    },
    {
      "ID": "PRICE-010",
      "Правило": "Если применимого активного правила нет, возвращается PRICE_RULE_NO_MATCH; нулевая цена допустима только как явный amount=0."
    },
    {
      "ID": "PRICE-011",
      "Правило": "Модификаторы применяются по priority. Одинаковый priority в одном stacking_group запрещён; application_base определяет базу fixed/percent/multiplier."
    },
    {
      "ID": "PRICE-012",
      "Правило": "minimum_charge требует base_price_rule_id и рассчитывается как max(результат базового правила, amount). Циклические ссылки запрещены."
    },
    {
      "ID": "PRICE-013",
      "Правило": "Диапазоны price_tiers одного правила не пересекаются, не имеют дыр, сортируются по sequence; quantity_from включена, quantity_to исключена."
    },
    {
      "ID": "PRICE-014",
      "Правило": "До умножения amount количество округляется по rounding_mode и rounding_step после применения minimum_billable_quantity."
    },
    {
      "ID": "PRICE-015",
      "Правило": "Денежный результат округляется half_up до rate_cards.money_scale; НДС рассчитывается по vat_mode и vat_rate и показывается отдельно."
    },
    {
      "ID": "TIME-001",
      "Правило": "Для calculation_datetime выбирается ровно одна active-версия rate_card с effective_from <= t < effective_to; пересечение периодов запрещено."
    },
    {
      "ID": "STORAGE-001",
      "Правило": "Бесплатный период хранения задаётся условиями по storage_age_days; метод FIFO/FEFO/LIFO не заменяет ценовое условие."
    },
    {
      "ID": "PRICE-016",
      "Правило": "calculation_method=tiered требует tier_mode, tier_variable и tier_scope. Переменная берётся только из реестра «Переменные диапазонов», область — только из реестра «Области диапазонов»; иное значение возвращает TIER_VARIABLE_UNKNOWN или TIER_SCOPE_UNKNOWN."
    },
    {
      "ID": "PRICE-017",
      "Правило": "tier_mode=slab: вся тарифицируемая величина считается по ставке диапазона, в который попало итоговое значение переменной. tier_mode=progressive: величина делится по диапазонам, каждая часть считается по своей ставке, результат суммируется."
    },
    {
      "ID": "PRICE-018",
      "Правило": "Ставки диапазонов не обязаны меняться монотонно: цена может расти и убывать по шкале. Бесплатный диапазон задаётся явным amount=0 и не равен пустой цене."
    },
    {
      "ID": "PRICE-019",
      "Правило": "tier_scope задаёт группу, внутри которой переменная считается заново: расчёт выполняется по каждой группе отдельно, суммы групп складываются. Режим и область обязаны входить в списки, разрешённые переменной."
    },
    {
      "ID": "PRICE-020",
      "Правило": "Разная цена первой и последующих единиц одного товара задаётся tier_variable=unit_sequence с областью уровня товара (order_sku, supply_sku, batch) и tier_mode=progressive. Отдельная услуга для этого не создаётся."
    },
    {
      "ID": "PRICE-021",
      "Правило": "minimum_billable_quantity и округление по PRICE-014 применяются к тарифицируемому количеству до разбиения по диапазонам; к частям в режиме progressive повторно не применяются."
    },
    {
      "ID": "STORAGE-002",
      "Правило": "Зависимость цены хранения от срока задаётся диапазонами по storage_age_days в сутках от приёмки партии: в режиме progressive каждые сутки тарифицируются по ставке своего диапазона, в режиме slab по storage_stay_days весь срок считается по ставке итогового диапазона. Направление ставок любое."
    },
    {
      "ID": "STORAGE-003",
      "Правило": "При частичном списании возраст остатка определяется методом ротации inventory_rotation_method (FIFO/FEFO/LIFO). Без указанного метода ступени по сроку не рассчитываются и возвращается STORAGE_ROTATION_REQUIRED."
    }
  ]
}