FSP / Правила
Нормативные правила
Всё, что обязана делать реализация. Правило принадлежит модулю, префикс объявлен в его манифесте. Ссылки на правила встречаются в схемах и в тексте спецификаций.
FSP Core
CAT-001Коды стандартных услуг неизменяемы после публикации.CAT-002Одна строка прайса ФФ может включать несколько стандартных услуг.CAT-003Материалы хранятся отдельно от операций.CAT-004Для каждой услуги в каталоге хранится полный закрытый список допустимых billing_metric v1: код и название. Значение вне списка требует новой версии стандарта.CAT-005Разделы каталога используются только для навигации и не определяют категорийную применимость услуги.CAT-006Применимость услуги к товарной категории задаётся только на реестре «Связи категорий» по кодам услуги и категории.SIZE-001Размерные классы принадлежат версионируемому профилю.SIZE-002ФФ может использовать собственный профиль размеров.SIZE-003Если товар совпал с несколькими классами профиля, выбирается класс с минимальным числовым priority. Если совпадений нет, возвращается SIZE_PROFILE_NO_MATCH.MAP-001Категории WB/Ozon сопоставляются отдельными версионируемыми строками.CAT-007Связь с категорией any распространяется на все дочерние категории; более специфичная связь не отменяет any.CAT-008Каждый параметр услуги обязан существовать на реестре «Параметры», а связь — на реестре «Параметры услуг».CAT-009Тип услуги хранится явно: base или industry. Положение строки и название раздела не являются типом.SIZE-004Отсутствие обязательного входа размерного правила возвращает SIZE_PROFILE_INPUT_MISSING; null никогда не считается совпадением.SIZE-005sum_sides_cm, max_side_cm, volume_m3, volumetric_weight_kg и chargeable_weight_kg вычисляются только по реестру «Расчётные метрики».MAP-002Для пары source_system + source_category_id периоды active-маппингов не пересекаются; результат сопоставления должен быть единственным.DATA-001Все id уникальны в пределах сущности; все ссылки обязаны существовать; публикация блокируется при любой ошибке на реестре «Проверки».CAT-010Источник истины для допустимых billing_metric — реестр «Метрики услуг»; строковые списки каталога являются только витриной.SIZE-006size_class_id всегда квалифицирован как <profile>:<version>:<class>; использование S/M/L без профиля запрещено.SIZE-007Договорный размерный профиль и фактическая логика калькулятора хранятся раздельно; расхождение блокирует публикацию тарифа.CAT-011Варианты материала, размера, маршрута и объёма не создают новую услугу: они задаются материалом, параметром, метрикой или условием цены.SCOPE-001Позиции из реестра «Исключения» не добавляются в каталог и при импорте получают статус out_of_scope.SCOPE-002Самовыкуп и стимулированный отзыв не получают код услуги и не входят в предложение оператора.PROFILE-001Манифест публикуется по адресу /.well-known/fsp и является единственным источником сведений о поддерживаемых модулях. Договорённость вне манифеста не заменяет его.PROFILE-002Объявлять модуль, чьи зависимости не объявлены, запрещено: манифест с таким набором модулей недействителен.PROFILE-003Активны только модули, объявленные обеими сторонами. Для каждого общего модуля берётся пересечение версий и выбирается наибольшая; при пустом пересечении модуль исключается.PROFILE-004Исключение модуля исключает все модули, которые от него зависят, и все расширения, чей родительский модуль исключён. Пересчёт повторяется до стабилизации.PROFILE-005Итог согласования вычисляет и фиксирует принимающая сторона, возвращая его в ответе. При расхождении сторон действует итог принимающей.PROFILE-006Для модуля с уровнями соответствия согласованным считается наименьший общий уровень. Требование уровня выше согласованного не исключает сторону из обмена, а возвращается кодом непокрытия.PROFILE-007Имя расширения имеет вид x-<vendor>:<code> и обязано указывать родительский модуль. Расширение только добавляет поля и никогда не переопределяет поля стандарта.PROFILE-008Неизвестное поле, модуль или расширение игнорируется и не является ошибкой обмена. Отсутствие у другой стороны объявленного модуля тоже не ошибка.
FSP Pricing
PRICE-001Цена может зависеть от класса размера и от сырых метрик: веса, сторон, объёма и объёмного веса.PRICE-002Условия одной группы объединяются AND, группы объединяются OR.PRICE-003Пустая цена не равна нулю.PRICE-004Индивидуальная цена возвращает MANUAL_QUOTE_REQUIRED.PRICE-005Модификаторы показываются отдельной строкой расчёта.PRICE-006price_rules.amount обязателен для flat, per_unit, per_metric и minimum_charge. Для tiered и manual_quote поле пустое.PRICE-007Каждая строка price_tiers обязана содержать собственный amount и ссылку price_rule_id.PRICE-008Каждый price_adjustments обязан содержать value и ссылку price_rule_id.PRICE-009Подходящие price_rules сортируются по priority по возрастанию. Одинаковый priority в одном offer запрещён и возвращает PRICE_RULE_PRIORITY_CONFLICT.PRICE-010Если применимого активного правила нет, возвращается PRICE_RULE_NO_MATCH; нулевая цена допустима только как явный amount=0.PRICE-011Модификаторы применяются по priority. Одинаковый priority в одном stacking_group запрещён; application_base определяет базу fixed/percent/multiplier.PRICE-012minimum_charge требует base_price_rule_id и рассчитывается как max(результат базового правила, amount). Циклические ссылки запрещены.PRICE-013Диапазоны price_tiers одного правила не пересекаются, не имеют дыр, сортируются по sequence; quantity_from включена, quantity_to исключена.PRICE-014До умножения amount количество округляется по rounding_mode и rounding_step после применения minimum_billable_quantity.PRICE-015Денежный результат округляется half_up до rate_cards.money_scale; НДС рассчитывается по vat_mode и vat_rate и показывается отдельно.TIME-001Для calculation_datetime выбирается ровно одна active-версия rate_card с effective_from <= t < effective_to; пересечение периодов запрещено.STORAGE-001Бесплатный период хранения задаётся условиями по storage_age_days; метод FIFO/FEFO/LIFO не заменяет ценовое условие.PRICE-016calculation_method=tiered требует tier_mode, tier_variable и tier_scope. Переменная берётся только из реестра «Переменные диапазонов», область — только из реестра «Области диапазонов»; иное значение возвращает TIER_VARIABLE_UNKNOWN или TIER_SCOPE_UNKNOWN.PRICE-017tier_mode=slab: вся тарифицируемая величина считается по ставке диапазона, в который попало итоговое значение переменной. tier_mode=progressive: величина делится по диапазонам, каждая часть считается по своей ставке, результат суммируется.PRICE-018Ставки диапазонов не обязаны меняться монотонно: цена может расти и убывать по шкале. Бесплатный диапазон задаётся явным amount=0 и не равен пустой цене.PRICE-019tier_scope задаёт группу, внутри которой переменная считается заново: расчёт выполняется по каждой группе отдельно, суммы групп складываются. Режим и область обязаны входить в списки, разрешённые переменной.PRICE-020Разная цена первой и последующих единиц одного товара задаётся tier_variable=unit_sequence с областью уровня товара (order_sku, supply_sku, batch) и tier_mode=progressive. Отдельная услуга для этого не создаётся.PRICE-021minimum_billable_quantity и округление по PRICE-014 применяются к тарифицируемому количеству до разбиения по диапазонам; к частям в режиме progressive повторно не применяются.STORAGE-002Зависимость цены хранения от срока задаётся диапазонами по storage_age_days в сутках от приёмки партии: в режиме progressive каждые сутки тарифицируются по ставке своего диапазона, в режиме slab по storage_stay_days весь срок считается по ставке итогового диапазона. Направление ставок любое.STORAGE-003При частичном списании возраст остатка определяется методом ротации inventory_rotation_method (FIFO/FEFO/LIFO). Без указанного метода ступени по сроку не рассчитываются и возвращается STORAGE_ROTATION_REQUIRED.
FSP Capacity
ROUTE-001График маршрута определяет доступность отправки, но не является price_rule_condition, если прайс явно не связывает цену с днём недели.CAP-001Базовая единица свободной мощности — м². Паллето-места производны от м² через коэффициент типа хранения и не могут задаваться независимо.CAP-002Свободная мощность декларативна: стандарт не требует её верификации. Актуальность выражается через updated_at, ответственность за данные лежит на операторе.CAP-003Строка свободной площади обязана указывать тип хранения и температурный режим: площадь без режима не сопоставима с запросом.CAP-004Направление отгрузки описывается маршрутом; график маршрута определяет доступность отправки и не является ценовым условием (см. ROUTE-001).
FSP Quote
QUOTE-001Запрос описывается операциями и объёмом. Требовать от заявителя площадь под хранение запрещено: если storage_need не задан, площадь выводится вызывающей стороной.QUOTE-002Формулы вывода среднего остатка, площади под хранение и нужной пропускной способности стандартом не нормируются. Каждая применённая величина обязана быть перечислена в quote_response.assumptions с кодом и значением.QUOTE-003quote_response.unmet заполняется только кодами закрытого реестра «Причины непокрытия». Свободный текст допускается лишь в поле detail рядом с кодом.QUOTE-004Код с влиянием exclude убирает оператора из выдачи; код с влиянием partial оставляет его с fit=partial. Оператор с непустым unmet никогда не имеет fit=full.QUOTE-005Пустая смета не равна нулю: если ставка не найдена или требует согласования, возвращается код service_not_priced или manual_quote_required, а не сумма 0.QUOTE-006Смета обязана указывать уровень FSP Pricing, на котором она посчитана. Расчёт на уровне ниже требуемого запросом возвращает pricing_level_insufficient.QUOTE-007Ответ на запрос в свободной форме обязан возвращать разобранную структуру запроса и перечень полей, которые не удалось определить однозначно.
Приложение (вне стандарта)
SRC-001Пустая ячейка цены в исходном прайсе импортируется как missing_price/manual_quote и никогда не считается нулём.SRC-002Источник без подтверждённых vat_mode и effective_from остаётся draft и не участвует в автоматическом расчёте.SRC-003Нормализованная строка обязана хранить source_id, файл и страницу/ячейку, canonical service_code, billing_metric, метод цены, валюту, НДС и период действия.