{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/akeda-ru/json-schema/akeda-ru-stock-settings-schema.json",
  "title": "StockSettings",
  "x-generated": "2026-11-01",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/akeda-ru-openapi.yaml#/components/schemas/StockSettings",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "block_shipment_over_free",
    "block_reservation_over_available",
    "auto_cancel_expired_reservations",
    "transfer_carries_reservation",
    "purchase_requests_enabled",
    "default_reservation_days",
    "min_shelf_life_pct",
    "min_shelf_life_days",
    "min_shelf_life_scale",
    "shelf_life_basis",
    "shelf_life_chosen_below_minimum",
    "receipt_shelf_life_dates",
    "shelf_grade_critical_pct",
    "shelf_grade_warning_pct",
    "shelf_grade_critical_days",
    "shelf_grade_warning_days",
    "updated_at",
    "pick_strictly_by_expiry",
    "priority_allocation",
    "count_expected_arrivals"
  ],
  "properties": {
    "block_shipment_over_free": {
      "type": "boolean",
      "description": "Запрещать отгрузку сверх свободного остатка"
    },
    "block_reservation_over_available": {
      "type": "boolean",
      "description": "Запрещать резерв сверх доступного остатка"
    },
    "auto_cancel_expired_reservations": {
      "type": "boolean",
      "description": "Снимать просроченные резервы автоматически"
    },
    "transfer_carries_reservation": {
      "type": "boolean",
      "description": "Перемещение зарезервированного: везти резерв на склад-получатель вместо отказа"
    },
    "purchase_requests_enabled": {
      "type": "boolean",
      "description": "Эффективный режим заявок на закупку (ERP-2533). С документооборотом всегда true; без него — сохранённый выбор кабинета (ERP-1523). Выключено — новая заявка не заводится; незавершённые, включая черновики, остаются доступны. Сохранённый выбор не меняется при включении документооборота"
    },
    "default_reservation_days": {
      "type": "integer",
      "minimum": 1,
      "maximum": 3650
    },
    "min_shelf_life_pct": {
      "type": [
        "string",
        "null"
      ],
      "description": "Порог остаточного срока годности кабинета, % срока (ERP-1821): десятичная строка больше 0 и не больше 100. Партия с меньшей долей оставшегося срока не уходит покупателю и на склад площадки. null — не задан"
    },
    "min_shelf_life_days": {
      "type": [
        "integer",
        "null"
      ],
      "minimum": 1,
      "description": "Порог остаточного срока годности кабинета в днях до «годен до». Заданы и проценты, и дни — партия обязана пройти оба. null — не задан"
    },
    "min_shelf_life_scale": {
      "allOf": [
        {
          "$ref": "#/$defs/StockShelfLifeScale"
        }
      ],
      "description": "Порог кабинета шкалой по общему сроку годности партии (ERP-2182). Всегда полный: одно значение — одна ступень без границы, порога нет — пустой массив. При шкале из двух и более ступеней min_shelf_life_pct и min_shelf_life_days — null"
    },
    "shelf_life_basis": {
      "type": "string",
      "enum": [
        "days",
        "months"
      ],
      "description": "Как считать долю остаточного срока годности (ERP-1821): days — по датам, по умолчанию; months — от первых чисел месяцев, как печатают срок на упаковке. Одна формула для отчёта «остатки по партиям» и для порога при проведении; проведённые документы не пересчитываются"
    },
    "shelf_life_chosen_below_minimum": {
      "type": "string",
      "enum": [
        "block",
        "warn"
      ],
      "description": "Партия ниже порога остаточного срока, выбранная в строке руками (ERP-2182): block — отказ проведения shelf_life_below_minimum, по умолчанию; warn — проводится, пометка в posting.shelf_life_warnings и в журнале. Просроченное не отгружается ни в одном режиме; «Авто» берёт только проходящие порог партии"
    },
    "receipt_shelf_life_dates": {
      "type": "string",
      "enum": [
        "block",
        "warn"
      ],
      "description": "Срок и серия при поступлении (ERP-3047): block — поступление, ввод остатков и оприходование товара со сроком годности без серии и «Годен до» не проводятся, по умолчанию (правило ERP-2708); warn — проводятся, недостающее по строкам видно в «Что мешает действию» предупреждением"
    },
    "shelf_grade_critical_pct": {
      "type": "string",
      "description": "Градация ОСГ (ERP-2182): ниже — красная (critical). Десятичная строка больше 0 и меньше shelf_grade_warning_pct; по умолчанию 30. Только показ отчётов и отборов"
    },
    "shelf_grade_warning_pct": {
      "type": "string",
      "description": "Градация ОСГ: ниже — жёлтая (warning), от неё — зелёная (ok). Не больше 100; по умолчанию 70"
    },
    "shelf_grade_critical_days": {
      "type": "integer",
      "minimum": 1,
      "description": "Партия без ОСГ (нет даты изготовления): дней до «годен до» не больше — красная; по умолчанию 30"
    },
    "shelf_grade_warning_days": {
      "type": "integer",
      "minimum": 2,
      "maximum": 36500,
      "description": "Партия без ОСГ: дней не больше — жёлтая; больше shelf_grade_critical_days, по умолчанию 90"
    },
    "pick_strictly_by_expiry": {
      "type": "boolean",
      "description": "Отбор строго по сроку (ERP-2144): отгрузка и перемещение между местами не берут партию с более поздним сроком, пока есть допустимая партия с более ранним. Отказ называет ячейку (или «не размещено») и срок ранней партии. По умолчанию выключено; на перекладку внутри места не действует"
    },
    "priority_allocation": {
      "type": "boolean",
      "description": "Распределять при нехватке по приоритету каналов (ERP-2874): склад забирает бронь у заказа менее важного канала, если его срок позже. Порядок каналов — в окне «Каналы продаж». По умолчанию выключено; действует с автопереносом брони"
    },
    "count_expected_arrivals": {
      "type": "boolean",
      "description": "Учитывать ожидаемый приход (ERP-2874): бронь забирается, только если подтверждённая закупка с датой поставки успевает к сроку заказа. По умолчанию выключено"
    },
    "writeoff_accounting_post": {
      "type": "boolean",
      "readOnly": true,
      "description": "Только чтение (ERP-2950): в документообороте включено «Списания и акты инвентаризации проводит учёт». Тогда у списания без заявки и актов инвентаризации склад вместо «Провести» передаёт документ в учёт. Документооборот не подключён — false"
    },
    "updated_at": {
      "type": "string",
      "format": "date-time"
    },
    "negative_stock_kinds": {
      "type": "array",
      "description": "Виды номенклатуры, расход которых может уйти в минус (ERP-2183): материал и полуфабрикат. Комплектация, списание и отгрузка берут недостающее по последней известной цене, приход гасит минус сам. Готовый товар в минус не уходит никогда. Пусто — минуса нет",
      "items": {
        "type": "string",
        "enum": [
          "material",
          "semi_product"
        ]
      }
    }
  },
  "$defs": {
    "StockShelfLifeScale": {
      "type": "array",
      "maxItems": 10,
      "description": "Шкала порога остаточного срока по общему сроку годности партии (ERP-2182): ступени по возрастанию границы up_to_months, у последней границы нет. Общий срок ровно на границе — ступень этой границы. Общий срок не определить (нет даты изготовления и срока в карточке) — партия порог не проходит: no_production_date",
      "items": {
        "$ref": "#/$defs/StockShelfLifeStep"
      }
    },
    "StockShelfLifeStep": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "up_to_months",
        "min_remaining_pct",
        "min_remaining_days"
      ],
      "description": "Ступень шкалы порога (ERP-2182): партия, у которой общий срок годности (годен до − дата изготовления; без даты изготовления — срок из карточки товара) не больше up_to_months месяцев, должна иметь остаток срока не меньше min_remaining_pct процентов и/или min_remaining_days дней. Ступень без значений — требования в этом диапазоне нет",
      "properties": {
        "up_to_months": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1,
          "maximum": 1200,
          "description": "Граница общего срока, месяцев, включительно; у последней ступени — null (всё, что длиннее предыдущей)"
        },
        "min_remaining_pct": {
          "type": [
            "string",
            "null"
          ],
          "description": "Доля оставшегося срока, %: десятичная строка больше 0 и не больше 100, не точнее сотых"
        },
        "min_remaining_days": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1,
          "description": "Дней до «годен до»"
        }
      }
    }
  }
}