{
    "status": "success",
    "count": 216,
    "tools": [
        {
            "name": "access.user.get",
            "title": "Карточка доступа пользователя",
            "description": "Роли, состояние, политика, активные области и число постоянных входов.",
            "scope": "erp100.users",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID пользователя"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp100_base"
        },
        {
            "name": "access.roles.set",
            "title": "Изменить роли пользователя",
            "description": "Заменяет набор ролей. Login сохраняется; снять роль с последнего активного администратора нельзя.",
            "scope": "erp100.roles",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "user_id": {
                        "type": "integer",
                        "description": "Пользователь"
                    },
                    "roles": {
                        "type": "array",
                        "description": "Полный новый список ролей",
                        "items": {
                            "type": "string"
                        }
                    }
                },
                "required": [
                    "user_id",
                    "roles"
                ]
            },
            "module": "erp100_base"
        },
        {
            "name": "access.status.set",
            "title": "Заблокировать или разблокировать пользователя",
            "description": "Блокировка запрещает вход и отзывает все сеансы. Последнего активного администратора блокировать нельзя.",
            "scope": "erp100.users",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "user_id": {
                        "type": "integer",
                        "description": "Пользователь"
                    },
                    "status": {
                        "type": "string",
                        "description": "Новый статус",
                        "enum": [
                            "active",
                            "blocked"
                        ]
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина блокировки"
                    }
                },
                "required": [
                    "user_id",
                    "status"
                ]
            },
            "module": "erp100_base"
        },
        {
            "name": "access.sessions.revoke",
            "title": "Завершить все сеансы пользователя",
            "description": "Увеличивает версию сеанса и удаляет remember-токены; открытые сеансы прекратятся на следующем запросе.",
            "scope": "erp100.users",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "user_id": {
                        "type": "integer",
                        "description": "Пользователь"
                    }
                },
                "required": [
                    "user_id"
                ]
            },
            "module": "erp100_base"
        },
        {
            "name": "access.policy.set",
            "title": "Изменить политику области данных",
            "description": "Restricted разрешает только явно назначенные области; пустой список означает deny-all.",
            "scope": "erp100.roles",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "user_id": {
                        "type": "integer",
                        "description": "Пользователь"
                    },
                    "access_policy": {
                        "type": "string",
                        "description": "Политика",
                        "enum": [
                            "unrestricted",
                            "restricted"
                        ]
                    }
                },
                "required": [
                    "user_id",
                    "access_policy"
                ]
            },
            "module": "erp100_base"
        },
        {
            "name": "access.scope.add",
            "title": "Добавить область данных",
            "description": "Добавляет подразделение, склад или рабочий центр. Для подразделения можно включить дочерние узлы.",
            "scope": "erp100.roles",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "user_id": {
                        "type": "integer",
                        "description": "Пользователь"
                    },
                    "resource_type": {
                        "type": "string",
                        "description": "Тип",
                        "enum": [
                            "department",
                            "warehouse",
                            "work_center"
                        ]
                    },
                    "resource_id": {
                        "type": "integer",
                        "description": "ID объекта"
                    },
                    "include_descendants": {
                        "type": "boolean",
                        "description": "Включить дочерние подразделения"
                    },
                    "valid_from": {
                        "type": "string",
                        "description": "Начало периода"
                    },
                    "valid_to": {
                        "type": "string",
                        "description": "Конец периода"
                    }
                },
                "required": [
                    "user_id",
                    "resource_type",
                    "resource_id"
                ]
            },
            "module": "erp100_base"
        },
        {
            "name": "audit.journal.search",
            "title": "Поиск по журналу действий",
            "description": "Записи журнала: кто, когда, что изменил. Фильтры по модулю, сущности, действию, важности, периоду и тексту.",
            "scope": "erp119_audit.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "module": {
                        "type": "string",
                        "description": "Модуль (erp402, erp401, erp228 …)"
                    },
                    "entity_type": {
                        "type": "string",
                        "description": "Тип сущности (order, movement, tech_card …)"
                    },
                    "entity_id": {
                        "type": "string",
                        "description": "Идентификатор сущности (id или uuid)"
                    },
                    "action": {
                        "type": "string",
                        "description": "Действие (create, update, status, delete …)"
                    },
                    "severity": {
                        "type": "string",
                        "description": "Важность",
                        "enum": [
                            "info",
                            "notice",
                            "warning",
                            "critical"
                        ]
                    },
                    "term": {
                        "type": "string",
                        "description": "Поиск по подписи, тексту и номеру"
                    },
                    "from": {
                        "type": "string",
                        "description": "Начало периода, ГГГГ-ММ-ДД"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода, ГГГГ-ММ-ДД"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько записей вернуть",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 20
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение",
                        "minimum": 0,
                        "default": 0
                    }
                },
                "required": []
            },
            "module": "erp119_audit"
        },
        {
            "name": "audit.entity.timeline",
            "title": "История объекта",
            "description": "Все изменения конкретного объекта по порядку: что было до и после. Например, история производственного заказа по его uuid.",
            "scope": "erp119_audit.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "entity_type": {
                        "type": "string",
                        "description": "Тип сущности (order, movement, tech_card …)"
                    },
                    "entity_id": {
                        "type": "string",
                        "description": "Идентификатор сущности (id или uuid)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько записей вернуть",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 30
                    }
                },
                "required": [
                    "entity_type",
                    "entity_id"
                ]
            },
            "module": "erp119_audit"
        },
        {
            "name": "audit.summary",
            "title": "Сводка журнала",
            "description": "Активность за период: сколько записей, по важности, топ действий, объектов и авторов. Ответ на вопрос «что происходило на этой неделе».",
            "scope": "erp119_audit.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "days": {
                        "type": "integer",
                        "description": "Период в днях",
                        "minimum": 1,
                        "maximum": 365,
                        "default": 7
                    }
                },
                "required": []
            },
            "module": "erp119_audit"
        },
        {
            "name": "qr.resolve",
            "title": "Что за предмет по коду наклейки",
            "description": "Расшифровывает код с QR-наклейки: состояние наклейки, цель (объект, партия, заказ, сотрудник), доступные сценарии и последние действия. Код можно передавать как есть — ссылкой из QR.",
            "scope": "erp199.scan",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "Код наклейки, UUID или ссылка из QR"
                    }
                },
                "required": [
                    "code"
                ]
            },
            "module": "erp199_sqr"
        },
        {
            "name": "qr.tokens",
            "title": "Реестр наклеек",
            "description": "Поиск наклеек по коду, подписи цели, состоянию, виду цели и партии печати. Возвращает состояние и к какой цели привязана наклейка.",
            "scope": "erp199.tokens.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "q": {
                        "type": "string",
                        "description": "Код наклейки, подпись цели или пометка"
                    },
                    "status": {
                        "type": "string",
                        "description": "Состояние наклейки",
                        "enum": [
                            "new",
                            "active",
                            "blocked",
                            "damaged",
                            "lost",
                            "archived"
                        ]
                    },
                    "kind": {
                        "type": "string",
                        "description": "Вид цели",
                        "enum": [
                            "local",
                            "registry",
                            "item",
                            "lot",
                            "order",
                            "employee"
                        ]
                    },
                    "batch": {
                        "type": "string",
                        "description": "Партия печати"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp199_sqr"
        },
        {
            "name": "qr.token",
            "title": "Карточка наклейки",
            "description": "Одна наклейка целиком: цель у владельца данных, фотографии и история действий. Нужна, когда по коду из qr.resolve требуется подробность.",
            "scope": "erp199.tokens.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "token": {
                        "type": "string",
                        "description": "Код или UUID наклейки"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько последних действий показать",
                        "minimum": 1,
                        "maximum": 100
                    }
                },
                "required": [
                    "token"
                ]
            },
            "module": "erp199_sqr"
        },
        {
            "name": "qr.objects",
            "title": "Свободные объекты модуля",
            "description": "Объекты, заведённые в поле или вручную (то, для чего нет владельца в других модулях): статус, тип, атрибуты и привязанные наклейки.",
            "scope": "erp199.objects.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "q": {
                        "type": "string",
                        "description": "Название, серийный номер или марка"
                    },
                    "status": {
                        "type": "string",
                        "description": "Статус",
                        "enum": [
                            "draft",
                            "active",
                            "rejected",
                            "archived"
                        ]
                    },
                    "type": {
                        "type": "string",
                        "description": "Код типа, например equipment"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp199_sqr"
        },
        {
            "name": "qr.inventories",
            "title": "Инвентаризации и прогресс",
            "description": "Открытые и закрытые сессии инвентаризации: область проверки, прогресс и расхождения «ожидалось − отмечено».",
            "scope": "erp199.inventories.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Сколько сессий показать",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp199_sqr"
        },
        {
            "name": "qr.journal",
            "title": "Журнал QR-маркировки",
            "description": "Кто, когда и где касался физического мира: сканирования, фото, смены статуса, отметки инвентаризации. Фильтры по коду наклейки, действию и результату.",
            "scope": "erp199.activity.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "q": {
                        "type": "string",
                        "description": "Код наклейки, комментарий или содержимое записи"
                    },
                    "action": {
                        "type": "string",
                        "description": "Вид действия",
                        "enum": [
                            "issue",
                            "bind",
                            "unbind",
                            "scan",
                            "scenario",
                            "photo",
                            "media",
                            "status",
                            "moderate",
                            "inventory",
                            "type",
                            "scenarios"
                        ]
                    },
                    "result": {
                        "type": "string",
                        "description": "Результат, например ok"
                    },
                    "code": {
                        "type": "string",
                        "description": "Код наклейки"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp199_sqr"
        },
        {
            "name": "outbox.stats",
            "title": "Состояние очереди доставки",
            "description": "Показывает ready, processing, dead-letter и возраст старейшего сообщения для диагностики интеграций.",
            "scope": "erp208_events.list_events",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp208_events"
        },
        {
            "name": "outbox.search",
            "title": "Поиск сообщений outbox",
            "description": "Ищет сообщения по состоянию, событию или correlation ID. Payload возвращается для диагностики только ключу с правом журнала событий.",
            "scope": "erp208_events.list_events",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Состояние",
                        "enum": [
                            "pending",
                            "processing",
                            "delivered",
                            "dead"
                        ]
                    },
                    "event_name": {
                        "type": "string",
                        "description": "Точное имя события"
                    },
                    "correlation_id": {
                        "type": "string",
                        "description": "Correlation UUID"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp208_events"
        },
        {
            "name": "outbox.replay",
            "title": "Повторить dead-letter",
            "description": "Возвращает одно dead-letter сообщение в очередь. Требует подтверждения; потребитель обязан использовать idempotency key.",
            "scope": "erp208_events.manage_subscriptions",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID из outbox.search"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp208_events"
        },
        {
            "name": "crm.deals",
            "title": "Сделки и воронка",
            "description": "Поиск сделок по клиенту, стадии, ответственному, сроку и сумме. Возвращает воронку по стадиям и общие цифры: сколько в работе, прогноз, выиграно и просрочено. Деньги здесь — оценка продаж, а не бухгалтерская выручка.",
            "scope": "erp221.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "q": {
                        "type": "string",
                        "description": "Номер, название сделки или клиент"
                    },
                    "stage": {
                        "type": "string",
                        "description": "Код стадии, например negotiation"
                    },
                    "kind": {
                        "type": "string",
                        "description": "Вид стадии",
                        "enum": [
                            "open",
                            "won",
                            "lost"
                        ]
                    },
                    "counterparty": {
                        "type": "integer",
                        "description": "id клиента в справочнике контрагентов"
                    },
                    "assigned_to": {
                        "type": "integer",
                        "description": "id ответственного менеджера"
                    },
                    "overdue": {
                        "type": "boolean",
                        "description": "Только сделки с прошедшим сроком"
                    },
                    "stale": {
                        "type": "integer",
                        "description": "Дней без записей в ленте (застой)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp221_crm"
        },
        {
            "name": "crm.deal",
            "title": "Карточка сделки",
            "description": "Одна сделка целиком: клиент, стадия, деньги, участники, лента работы с задачами, история разборов ИИ. Нужна, когда по списку crm.deals требуется подробность.",
            "scope": "erp221.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "deal": {
                        "type": "string",
                        "description": "Номер сделки (DEAL-…) или её id"
                    }
                },
                "required": [
                    "deal"
                ]
            },
            "module": "erp221_crm"
        },
        {
            "name": "crm.clients",
            "title": "Клиенты и профиль продаж",
            "description": "Поиск клиентов по названию, ИНН или состоянию. Клиенты — это контрагенты erp301; CRM дополняет их профилем продаж (сегмент, отрасль, источник) и уровнем ЛПР у контактов.",
            "scope": "erp221.clients.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "Название, код или ИНН"
                    },
                    "status": {
                        "type": "string",
                        "description": "Состояние",
                        "enum": [
                            "active",
                            "blocked",
                            "archived"
                        ]
                    },
                    "role": {
                        "type": "string",
                        "description": "Роль контрагента",
                        "enum": [
                            "customer",
                            "supplier",
                            "carrier",
                            "contractor"
                        ]
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp221_crm"
        },
        {
            "name": "crm.analytics",
            "title": "Аналитика продаж",
            "description": "Воронка, динамика по месяцам, работа менеджеров, источники обращений и причины отказов за период. Прогноз взвешен по вероятности стадии.",
            "scope": "erp221.analytics.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Дата начала периода, YYYY-MM-DD"
                    },
                    "to": {
                        "type": "string",
                        "description": "Дата конца периода, YYYY-MM-DD"
                    },
                    "assigned_to": {
                        "type": "integer",
                        "description": "id менеджера"
                    },
                    "months": {
                        "type": "integer",
                        "description": "Сколько месяцев динамики",
                        "minimum": 1,
                        "maximum": 24
                    }
                },
                "required": []
            },
            "module": "erp221_crm"
        },
        {
            "name": "crm.journal",
            "title": "Лента работы и задачи",
            "description": "Что происходило по сделкам и клиентам: звонки, письма, встречи, задачи и файлы. Видны незакрытые задачи с их сроком — что менеджер обещал и когда.",
            "scope": "erp221.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "deal_id": {
                        "type": "integer",
                        "description": "Записи одной сделки"
                    },
                    "counterparty": {
                        "type": "integer",
                        "description": "Записи одного клиента"
                    },
                    "type": {
                        "type": "string",
                        "description": "Вид записи",
                        "enum": [
                            "comment",
                            "call",
                            "meeting",
                            "email",
                            "task",
                            "file",
                            "note",
                            "stage",
                            "system"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "description": "Состояние",
                        "enum": [
                            "pending",
                            "completed",
                            "cancelled"
                        ]
                    },
                    "assigned_to": {
                        "type": "integer",
                        "description": "Чьи задачи показать"
                    },
                    "overdue": {
                        "type": "boolean",
                        "description": "Только просроченные задачи"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp221_crm"
        },
        {
            "name": "crm.kb",
            "title": "База знаний менеджера",
            "description": "Готовые ответы на типовые вопросы клиентов: сроки, цены, гарантия. Поиск по вопросу, ответу и категории.",
            "scope": "erp221.kb.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "q": {
                        "type": "string",
                        "description": "Вопрос или текст ответа"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 100
                    }
                },
                "required": []
            },
            "module": "erp221_crm"
        },
        {
            "name": "product_structure.search",
            "title": "Поиск EBOM\/MBOM",
            "description": "Ищет ревизии спецификаций по изделию, виду, состоянию и площадке. Сначала используйте этот инструмент вместо угадывания ID.",
            "scope": "erp231.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "Код, название или ревизия"
                    },
                    "product_item_id": {
                        "type": "integer",
                        "description": "ID изделия из реестра"
                    },
                    "kind": {
                        "type": "string",
                        "description": "Вид",
                        "enum": [
                            "ebom",
                            "mbom",
                            "service"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "description": "Статус",
                        "enum": [
                            "draft",
                            "review",
                            "approved",
                            "obsolete"
                        ]
                    },
                    "site_code": {
                        "type": "string",
                        "description": "Код площадки"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp231_product_structure"
        },
        {
            "name": "product_structure.get",
            "title": "Ревизия EBOM\/MBOM",
            "description": "Возвращает шапку и строки спецификации с человекочитаемыми кодами и названиями.",
            "scope": "erp231.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID из product_structure.search"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp231_product_structure"
        },
        {
            "name": "product_structure.validate",
            "title": "Проверить EBOM\/MBOM",
            "description": "Детерминированно проверяет ссылки и циклы перед передачей человеку на согласование.",
            "scope": "erp231.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID ревизии"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp231_product_structure"
        },
        {
            "name": "product_structure.draft.create",
            "title": "Создать черновик EBOM\/MBOM",
            "description": "Создаёт только draft. Агент не может утвердить спецификацию; product_item_id выбирается через инструменты реестра.",
            "scope": "erp231.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "product_item_id": {
                        "type": "integer",
                        "description": "ID изделия"
                    },
                    "kind": {
                        "type": "string",
                        "description": "Вид",
                        "enum": [
                            "ebom",
                            "mbom",
                            "service"
                        ]
                    },
                    "revision": {
                        "type": "string",
                        "description": "Ревизия; пусто — автоматически"
                    },
                    "site_code": {
                        "type": "string",
                        "description": "Площадка"
                    },
                    "source_system": {
                        "type": "string",
                        "description": "Источник"
                    },
                    "source_revision": {
                        "type": "string",
                        "description": "Ревизия источника"
                    }
                },
                "required": [
                    "product_item_id",
                    "kind"
                ]
            },
            "module": "erp231_product_structure"
        },
        {
            "name": "product_structure.line.add",
            "title": "Добавить строку в черновик",
            "description": "Добавляет компонент в draft\/review; проверяет номенклатуру, количество и принадлежность родителя.",
            "scope": "erp231.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "structure_id": {
                        "type": "integer",
                        "description": "ID черновика"
                    },
                    "component_item_id": {
                        "type": "integer",
                        "description": "ID компонента из реестра"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество",
                        "exclusiveMinimum": 0
                    },
                    "uom": {
                        "type": "string",
                        "description": "Единица erp227, например pcs"
                    },
                    "line_no": {
                        "type": "integer",
                        "description": "Номер строки"
                    },
                    "parent_line_id": {
                        "type": "integer",
                        "description": "Родительская строка"
                    },
                    "supply_type": {
                        "type": "string",
                        "description": "Обеспечение",
                        "enum": [
                            "make",
                            "buy",
                            "phantom",
                            "consumable"
                        ]
                    },
                    "scrap_pct": {
                        "type": "number",
                        "description": "Процент отхода"
                    },
                    "operation_no": {
                        "type": "integer",
                        "description": "Номер операции"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание"
                    }
                },
                "required": [
                    "structure_id",
                    "component_item_id",
                    "qty"
                ]
            },
            "module": "erp231_product_structure"
        },
        {
            "name": "product_structure.approve",
            "title": "Утвердить ревизию",
            "description": "Критическое действие человека: делает состав неизменяемым и замещает предыдущую утверждённую ревизию.",
            "scope": "erp231.approve",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID ревизии в статусе review"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp231_product_structure"
        },
        {
            "name": "counterparty.search",
            "title": "Поиск контрагентов",
            "description": "Клиенты, поставщики, перевозчики и подрядчики. Возвращает id для документов, закупок и продаж; фильтрует по роли без угадывания внутренних идентификаторов.",
            "scope": "erp301.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "Название, код или ИНН"
                    },
                    "role": {
                        "type": "string",
                        "description": "Роль",
                        "enum": [
                            "supplier",
                            "customer",
                            "carrier",
                            "contractor"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "description": "Статус",
                        "enum": [
                            "active",
                            "blocked",
                            "archived"
                        ]
                    },
                    "kind": {
                        "type": "string",
                        "description": "Тип лица",
                        "enum": [
                            "legal",
                            "individual",
                            "state",
                            "foreign"
                        ]
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Размер страницы",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 25
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение",
                        "minimum": 0,
                        "default": 0
                    }
                },
                "required": []
            },
            "module": "erp301_counterparty"
        },
        {
            "name": "counterparty.get",
            "title": "Карточка контрагента",
            "description": "Реквизиты одного клиента или поставщика по id из counterparty.search.",
            "scope": "erp301.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID из counterparty.search"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp301_counterparty"
        },
        {
            "name": "workforce.employees.search",
            "title": "Поиск сотрудников",
            "description": "Ищет сотрудников по ФИО, табельному номеру, телефону или e-mail с фильтром подразделения и статуса. Возвращает текущие назначения и связь с учётной записью.",
            "scope": "erp310.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "ФИО, табельный номер, телефон или e-mail"
                    },
                    "department_id": {
                        "type": "integer",
                        "description": "Подразделение"
                    },
                    "status": {
                        "type": "string",
                        "description": "Кадровый статус",
                        "enum": [
                            "active",
                            "leave",
                            "dismissed"
                        ]
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Количество строк",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение",
                        "minimum": 0
                    }
                },
                "required": []
            },
            "module": "erp310_workforce"
        },
        {
            "name": "workforce.employee.get",
            "title": "Карточка сотрудника",
            "description": "Возвращает сотрудника, текущую должность, подразделение, учётную запись и полную историю назначений.",
            "scope": "erp310.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID сотрудника"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp310_workforce"
        },
        {
            "name": "workforce.structure.list",
            "title": "Организационная структура",
            "description": "Активные организации, филиалы, подразделения, цеха, участки и бригады с parent_id.",
            "scope": "erp310.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp310_workforce"
        },
        {
            "name": "workforce.positions.list",
            "title": "Должности",
            "description": "Активные должности по подразделениям и число текущих сотрудников.",
            "scope": "erp310.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp310_workforce"
        },
        {
            "name": "workforce.staffing.list",
            "title": "Штат и вакансии",
            "description": "Плановые, занятые и вакантные ставки по подразделениям и должностям. Отрицательная вакансия означает превышение штата.",
            "scope": "erp310.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp310_workforce"
        },
        {
            "name": "workforce.staffing.save",
            "title": "Изменить штатное расписание",
            "description": "Создаёт или изменяет план ставок. Требует подтверждения человека: изменение влияет на отчёт вакансий и кадровые решения.",
            "scope": "erp310.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID строки при изменении"
                    },
                    "department_id": {
                        "type": "integer",
                        "description": "Подразделение"
                    },
                    "position_id": {
                        "type": "integer",
                        "description": "Должность"
                    },
                    "planned_fte": {
                        "type": "number",
                        "description": "Плановое число ставок"
                    },
                    "valid_from": {
                        "type": "string",
                        "description": "Начало действия ГГГГ-ММ-ДД"
                    },
                    "valid_to": {
                        "type": "string",
                        "description": "Конец действия"
                    },
                    "note": {
                        "type": "string",
                        "description": "Основание или примечание"
                    }
                },
                "required": [
                    "department_id",
                    "position_id",
                    "planned_fte"
                ]
            },
            "module": "erp310_workforce"
        },
        {
            "name": "workforce.employee.save",
            "title": "Создать или изменить сотрудника",
            "description": "Сохраняет карточку и текущее назначение. Передайте id для изменения; без id создаётся сотрудник. Требует подтверждения из-за персональных данных.",
            "scope": "erp310.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID при изменении"
                    },
                    "personnel_no": {
                        "type": "string",
                        "description": "Табельный номер"
                    },
                    "last_name": {
                        "type": "string",
                        "description": "Фамилия"
                    },
                    "first_name": {
                        "type": "string",
                        "description": "Имя"
                    },
                    "middle_name": {
                        "type": "string",
                        "description": "Отчество"
                    },
                    "email": {
                        "type": "string",
                        "description": "E-mail"
                    },
                    "phone": {
                        "type": "string",
                        "description": "Телефон"
                    },
                    "hired_at": {
                        "type": "string",
                        "description": "Дата приёма ГГГГ-ММ-ДД"
                    },
                    "status": {
                        "type": "string",
                        "description": "Статус",
                        "enum": [
                            "active",
                            "leave"
                        ]
                    },
                    "department_id": {
                        "type": "integer",
                        "description": "Подразделение"
                    },
                    "position_id": {
                        "type": "integer",
                        "description": "Должность"
                    },
                    "user_id": {
                        "type": "integer",
                        "description": "Учётная запись erp100"
                    },
                    "rate": {
                        "type": "number",
                        "description": "Ставка 0.1–2.0"
                    }
                },
                "required": [
                    "personnel_no",
                    "last_name",
                    "first_name",
                    "department_id"
                ]
            },
            "module": "erp310_workforce"
        },
        {
            "name": "workforce.employee.dismiss",
            "title": "Уволить сотрудника",
            "description": "Меняет кадровый статус и закрывает текущее назначение последним рабочим днём. Учётная запись сохраняется для аудита.",
            "scope": "erp310.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID сотрудника"
                    },
                    "dismissed_at": {
                        "type": "string",
                        "description": "Последний рабочий день ГГГГ-ММ-ДД"
                    }
                },
                "required": [
                    "id",
                    "dismissed_at"
                ]
            },
            "module": "erp310_workforce"
        },
        {
            "name": "warehouse.stock.list",
            "title": "Остатки по складам",
            "description": "Возвращает физический, зарезервированный и доступный остаток с номенклатурой и признаком ниже минимума.",
            "scope": "erp401_wms.view_stock",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "warehouse_id": {
                        "type": "integer",
                        "description": "ID склада"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "ID позиции номенклатуры"
                    },
                    "low_only": {
                        "type": "boolean",
                        "description": "Только позиции ниже минимального остатка"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Размер страницы",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 50
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение",
                        "minimum": 0,
                        "default": 0
                    }
                }
            },
            "module": "erp401_wms"
        },
        {
            "name": "warehouse.movements.list",
            "title": "Движения склада",
            "description": "Журнал приходов, расходов, перемещений и корректировок с фильтрами по складу, позиции и датам.",
            "scope": "erp401_wms.view_stock",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "type": {
                        "type": "string",
                        "description": "Тип движения",
                        "enum": [
                            "receipt",
                            "issue",
                            "transfer",
                            "adjust"
                        ]
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "ID склада"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "ID позиции"
                    },
                    "date_from": {
                        "type": "string",
                        "description": "Дата от YYYY-MM-DD"
                    },
                    "date_to": {
                        "type": "string",
                        "description": "Дата до YYYY-MM-DD"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Размер страницы",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 50
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение",
                        "minimum": 0,
                        "default": 0
                    }
                }
            },
            "module": "erp401_wms"
        },
        {
            "name": "warehouse.list",
            "title": "Список складов",
            "description": "Активные склады и точки хранения, доступные для фильтрации остатков и движений.",
            "scope": "erp401_wms.view_stock",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": []
            },
            "module": "erp401_wms"
        },
        {
            "name": "production.orders.search",
            "title": "Поиск производственных заказов",
            "description": "Список заказов с фильтрами: статус, поиск по номеру\/изделию, только просроченные. Возвращает номер, изделие, статус, план и факт выпуска.",
            "scope": "erp402_production.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Статус заказа",
                        "enum": [
                            "draft",
                            "planned",
                            "released",
                            "in_progress",
                            "done",
                            "cancelled"
                        ]
                    },
                    "term": {
                        "type": "string",
                        "description": "Поиск по номеру, изделию и примечанию (кириллица поддерживается)"
                    },
                    "overdue": {
                        "type": "boolean",
                        "description": "Только заказы с истёкшим сроком"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько записей вернуть (1–100)",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 20
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода",
                        "minimum": 0,
                        "default": 0
                    }
                },
                "required": []
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.get",
            "title": "Карточка производственного заказа",
            "description": "Заказ целиком: изделие, план и факт выпуска, состав с нормами и списанием, обеспеченность материалами и доступные действия (что можно сделать дальше).",
            "scope": "erp402_production.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Номер заказа (id) или uuid"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.requirements",
            "title": "Потребность заказа в материалах",
            "description": "По каждой строке состава: нужно, есть на складе заказа, всего по всем складам, нехватка. Помогает понять, можно ли запускать заказ.",
            "scope": "erp402_production.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Номер заказа (id) или uuid"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.materials.shortages",
            "title": "Нехватка материалов по всем заказам",
            "description": "Открытые заказы (план, резерв, в работе), по которым не хватает материалов: сколько нужно, сколько есть и сколько не хватает.",
            "scope": "erp402_production.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Сколько заказов просмотреть",
                        "minimum": 1,
                        "maximum": 200,
                        "default": 20
                    }
                },
                "required": []
            },
            "module": "erp402_production"
        },
        {
            "name": "production.orders.stats",
            "title": "Сводка производства",
            "description": "Заказы по статусам, просроченные, объём выпуска, строки без остатка и без номенклатуры.",
            "scope": "erp402_production.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp402_production"
        },
        {
            "name": "production.catalog.search",
            "title": "Поиск номенклатуры",
            "description": "Найти позицию реестра (материал или изделие) по названию или коду. Возвращает id, который нужен в аргументе item_id других инструментов.",
            "scope": "erp402_production.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "Название или код позиции"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько позиций вернуть",
                        "minimum": 1,
                        "maximum": 50,
                        "default": 15
                    }
                },
                "required": [
                    "term"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.warehouses",
            "title": "Склады",
            "description": "Активные склады: id и название. Нужны для аргументов warehouse_id и output_warehouse_id.",
            "scope": "erp402_production.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp402_production"
        },
        {
            "name": "production.tech_cards.search",
            "title": "Поиск технологических карт",
            "description": "Найти техкарту по названию. Возвращает id карты для аргумента tech_card_id.",
            "scope": "erp228.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "Часть названия техкарты"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько карт вернуть",
                        "minimum": 1,
                        "maximum": 50,
                        "default": 20
                    }
                },
                "required": []
            },
            "module": "erp402_production"
        },
        {
            "name": "production.tech_card.composition",
            "title": "Состав техкарты",
            "description": "Спецификация техкарты и маршрут операций до создания заказа: какие материалы нужны, с какими нормами и нашлась ли под них номенклатура реестра.",
            "scope": "erp228.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "tech_card_id": {
                        "type": "integer",
                        "description": "Идентификатор техкарты (erp228)"
                    }
                },
                "required": [
                    "tech_card_id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.create",
            "title": "Создать производственный заказ",
            "description": "Создаёт заказ в статусе «черновик»: изделие, план выпуска, техкарта, склады, срок. Состав заполняется отдельно (production.order.fill_from_tech_card или item_add).",
            "scope": "erp402_production.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "title": {
                        "type": "string",
                        "description": "Что производим (изделие или назначение заказа)"
                    },
                    "qty": {
                        "type": "number",
                        "description": "План выпуска",
                        "minimum": 0.001,
                        "default": 1
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения (pcs, kg, m …)",
                        "default": "pcs"
                    },
                    "tech_card_id": {
                        "type": "integer",
                        "description": "Техкарта (erp228) — источник состава"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Номенклатура изделия (реестр erp227)"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад материалов"
                    },
                    "output_warehouse_id": {
                        "type": "integer",
                        "description": "Склад готовой продукции"
                    },
                    "customer_id": {
                        "type": "integer",
                        "description": "Заказчик (erp301), если заказ под клиента"
                    },
                    "target_date": {
                        "type": "string",
                        "description": "Срок изготовления, ГГГГ-ММ-ДД"
                    },
                    "priority": {
                        "type": "integer",
                        "description": "Приоритет 1 (высший) — 9 (низший)",
                        "minimum": 1,
                        "maximum": 9,
                        "default": 5
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание"
                    }
                },
                "required": [
                    "title"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.update",
            "title": "Изменить производственный заказ",
            "description": "Меняет поля заказа, пока он не запущен (черновик, план, резерв). При смене плана выпуска потребность пересчитывается.",
            "scope": "erp402_production.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    },
                    "title": {
                        "type": "string",
                        "description": "Изделие \/ наименование"
                    },
                    "qty": {
                        "type": "number",
                        "description": "План выпуска"
                    },
                    "tech_card_id": {
                        "type": "integer",
                        "description": "Техкарта"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Номенклатура изделия"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад материалов"
                    },
                    "output_warehouse_id": {
                        "type": "integer",
                        "description": "Склад готовой продукции"
                    },
                    "customer_id": {
                        "type": "integer",
                        "description": "Заказчик"
                    },
                    "target_date": {
                        "type": "string",
                        "description": "Срок изготовления, ГГГГ-ММ-ДД"
                    },
                    "priority": {
                        "type": "integer",
                        "description": "Приоритет 1–9",
                        "minimum": 1,
                        "maximum": 9
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.fill_from_tech_card",
            "title": "Заполнить состав из техкарты",
            "description": "Читает спецификацию техкарты и добавляет строки состава в заказ (норма × план), сопоставляя материалы с номенклатурой реестра.",
            "scope": "erp402_production.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    },
                    "tech_card_id": {
                        "type": "integer",
                        "description": "Другая техкарта (по умолчанию — карта из заказа)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.item_add",
            "title": "Добавить строку состава",
            "description": "Добавляет материал в состав заказа вручную: наименование, норма на изделие, при необходимости номенклатура и склад.",
            "scope": "erp402_production.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    },
                    "name": {
                        "type": "string",
                        "description": "Наименование материала"
                    },
                    "qty_per_unit": {
                        "type": "number",
                        "description": "Норма расхода на единицу изделия",
                        "minimum": 0,
                        "default": 1
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Номенклатура (реестр erp227) — нужна для резерва со склада"
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения",
                        "default": "pcs"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад, с которого списывать"
                    },
                    "note": {
                        "type": "string",
                        "description": "Комментарий"
                    }
                },
                "required": [
                    "order_id",
                    "name"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.item_remove",
            "title": "Удалить строку состава",
            "description": "Убирает строку состава из заказа (доступно, пока заказ не запущен).",
            "scope": "erp402_production.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "item_id": {
                        "type": "integer",
                        "description": "Идентификатор строки состава (line id)"
                    }
                },
                "required": [
                    "item_id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.plan",
            "title": "Утвердить план заказа",
            "description": "Переводит заказ в статус «план»: состав должен быть заполнен, потребность пересчитывается.",
            "scope": "erp402_production.plan",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.release",
            "title": "Зарезервировать материалы",
            "description": "Пытается зарезервировать материалы под заказ. Если чего-то не хватает, заказ остаётся планом, а строки получают статус «не хватает» — об этом сообщается в ответе.",
            "scope": "erp402_production.plan",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.start",
            "title": "Начать работу по заказу",
            "description": "Переводит заказ в статус «в работе» (можно и из плана, если материалы придут позже).",
            "scope": "erp402_production.plan",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.complete",
            "title": "Выпустить продукцию",
            "description": "Списывает материалы и принимает готовую продукцию на склад. Поддерживает частичный выпуск: заказ закрывается, когда выпущено не меньше плана. Требует подтверждения человека.",
            "scope": "erp402_production.complete",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Сколько выпущено (по умолчанию — остаток плана)",
                        "minimum": 0.001
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "production.order.cancel",
            "title": "Отменить заказ",
            "description": "Отменяет заказ и снимает резервы материалов. Требует подтверждения человека.",
            "scope": "erp402_production.complete",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор заказа"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отмены (попадёт в журнал и события)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp402_production"
        },
        {
            "name": "procurement.stats",
            "title": "Сводка закупок",
            "description": "Состояние закупок одним вызовом: сколько заявок ждут решения, сколько заказов в работе и на какую сумму, сколько приёмок ждёт проведения, что заблокировано входным контролем и сколько позиций на минимуме склада.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.requests.search",
            "title": "Поиск заявок",
            "description": "Заявки на закупку с фильтрами по состоянию, источнику, складу, позиции и тексту. Заявка — это потребность: что купить и к какому сроку.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "array",
                        "description": "Состояния заявок",
                        "items": {
                            "type": "string",
                            "enum": [
                                "draft",
                                "submitted",
                                "approved",
                                "rejected",
                                "ordered",
                                "cancelled"
                            ]
                        }
                    },
                    "source": {
                        "type": "string",
                        "description": "Источник: manual, auto, erp407, import",
                        "enum": [
                            "manual",
                            "auto",
                            "erp407",
                            "import"
                        ]
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Заявки одного склада"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Заявки, в которых есть эта позиция номенклатуры"
                    },
                    "overdue": {
                        "type": "boolean",
                        "description": "Только просроченные по сроку «нужен к»"
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру, позиции и пояснению"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.request.get",
            "title": "Заявка целиком",
            "description": "Заявка, её позиции и заказ, в который она попала: видно, что уже закрыто, а что ещё ждёт решения.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заявки"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.orders.search",
            "title": "Поиск заказов",
            "description": "Заказы поставщикам с фильтрами по состоянию, поставщику и тексту. Заказ — это обязательство: что и у кого куплено и к какому сроку привезут.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "array",
                        "description": "Состояния заказов",
                        "items": {
                            "type": "string",
                            "enum": [
                                "draft",
                                "sent",
                                "confirmed",
                                "partially_received",
                                "received",
                                "cancelled"
                            ]
                        }
                    },
                    "supplier_id": {
                        "type": "integer",
                        "description": "Заказы одного поставщика"
                    },
                    "open": {
                        "type": "boolean",
                        "description": "Только незакрытые (черновик, отправлен, подтверждён, частично принят)"
                    },
                    "overdue": {
                        "type": "boolean",
                        "description": "Только просроченные по дате поставки"
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру и позициям"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.order.get",
            "title": "Заказ целиком",
            "description": "Заказ, его позиции с прогрессом приёмки, приёмки по заказу и заявка-источник. Главный инструмент, чтобы понять, что ещё не приехало.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заказа"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.receipts.search",
            "title": "Поиск приёмок",
            "description": "Приёмки с фильтрами по состоянию, поставщику, заказу и тексту. Видно, что ещё не проведено на склад и что заблокировано входным контролем.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "array",
                        "description": "Состояния приёмок",
                        "items": {
                            "type": "string",
                            "enum": [
                                "draft",
                                "posted",
                                "cancelled"
                            ]
                        }
                    },
                    "supplier_id": {
                        "type": "integer",
                        "description": "Приёмки одного поставщика"
                    },
                    "order_id": {
                        "type": "integer",
                        "description": "Приёмки по заказу"
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру, документу поставщика и позициям"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.receipt.get",
            "title": "Приёмка целиком",
            "description": "Приёмка, её позиции с результатом входного контроля и документ поставщика. Показывает, что мешает провести приход на склад.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid приёмки"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.suppliers.search",
            "title": "Поиск поставщиков",
            "description": "Поставщики — контрагенты с ролью «поставщик» (erp301) вместе с закупочными условиями: срок поставки, минимальная партия, оценка, отсрочка, метка «предпочтительный».",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "search": {
                        "type": "string",
                        "description": "Поиск по названию и ИНН"
                    },
                    "preferred": {
                        "type": "boolean",
                        "description": "Только предпочтительные поставщики"
                    },
                    "active": {
                        "type": "boolean",
                        "description": "Только действующие (false — только отключённые)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.suppliers.compare",
            "title": "Сравнить поставщиков по позиции",
            "description": "У кого брать позицию: по каждому поставщику — последняя цена, срок, исполнительность и баллы (цена до 50, срок до 30, оценка до 15, исполнительность до 15, предпочтительный +10, партия меньше минимальной −20). Первая строка — рекомендация.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "item_id": {
                        "type": "integer",
                        "description": "Позиция номенклатуры (erp227)"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество — проверка минимальной партии"
                    }
                },
                "required": [
                    "item_id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.prices.history",
            "title": "История цен",
            "description": "Как менялись цены: по позиции номенклатуры (все поставщики) или по поставщику (всё, что он поставляет). Источник записи — заказ, приёмка или ручной ввод.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "item_id": {
                        "type": "integer",
                        "description": "Цены по позиции номенклатуры"
                    },
                    "supplier_id": {
                        "type": "integer",
                        "description": "Цены одного поставщика"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько записей вернуть (по умолчанию 30)",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.shortages",
            "title": "Дефицит склада",
            "description": "Позиции, остаток по которым опустился до минимума: сколько не хватает, сколько предложено закупить (минимум с запасом 20 %) и есть ли уже открытая заявка — чтобы не заказать дважды.",
            "scope": "erp403.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Только один склад"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько позиций вернуть (по умолчанию 50)",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.request.create",
            "title": "Создать заявку",
            "description": "Заводит заявку на закупку: одна позиция (item_id\/name\/qty\/uom_code) или список строк в lines. Черновик можно править, согласование — отдельный шаг.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "item_id": {
                        "type": "integer",
                        "description": "Позиция номенклатуры (erp227)"
                    },
                    "name": {
                        "type": "string",
                        "description": "Название позиции, если номенклатура не заведена"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество",
                        "exclusiveMinimum": true,
                        "minimum": 0
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения (по умолчанию шт)"
                    },
                    "price": {
                        "type": "number",
                        "description": "Ожидаемая цена за единицу"
                    },
                    "need_date": {
                        "type": "string",
                        "description": "Нужен к дате (ГГГГ-ММ-ДД)"
                    },
                    "priority": {
                        "type": "integer",
                        "description": "Приоритет: 1 — аварийная, 2 — высокая, 3 — обычная, 4 — плановая",
                        "minimum": 1,
                        "maximum": 4
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад, для которого закупаем"
                    },
                    "source": {
                        "type": "string",
                        "description": "Источник: manual, auto, erp407, import",
                        "enum": [
                            "manual",
                            "auto",
                            "erp407",
                            "import"
                        ]
                    },
                    "source_ref": {
                        "type": "string",
                        "description": "Ссылка на источник (программа, минимум склада)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Пояснение для согласующего"
                    },
                    "lines": {
                        "type": "array",
                        "description": "Позиции заявки: item_id, name, qty, uom_code, price, supplier_id, note",
                        "items": {
                            "type": "object"
                        }
                    }
                },
                "required": [
                    "qty"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.request.line.add",
            "title": "Добавить позицию в заявку",
            "description": "Добавляет позицию в черновик заявки. Позиции без номенклатуры допустимы — их потом сопоставят вручную.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "request_id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заявки"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Позиция номенклатуры (erp227)"
                    },
                    "name": {
                        "type": "string",
                        "description": "Название позиции"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество",
                        "minimum": 0
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения"
                    },
                    "price": {
                        "type": "number",
                        "description": "Ожидаемая цена за единицу"
                    },
                    "supplier_id": {
                        "type": "integer",
                        "description": "Желаемый поставщик (erp301)"
                    },
                    "need_date": {
                        "type": "string",
                        "description": "Нужен к дате (ГГГГ-ММ-ДД)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание к позиции"
                    }
                },
                "required": [
                    "request_id",
                    "name"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.request.update",
            "title": "Изменить заявку",
            "description": "Правит шапку черновика: срок, приоритет, склад, пояснение. Заявка, ушедшая на согласование, не правится — сначала отмените её.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заявки"
                    },
                    "need_date": {
                        "type": "string",
                        "description": "Нужен к дате (ГГГГ-ММ-ДД)"
                    },
                    "priority": {
                        "type": "integer",
                        "description": "Приоритет 1–4",
                        "minimum": 1,
                        "maximum": 4
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад"
                    },
                    "note": {
                        "type": "string",
                        "description": "Пояснение"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.request.submit",
            "title": "Отправить заявку на согласование",
            "description": "Переводит заявку из черновика в «на согласовании»: с этого момента её правят только решением согласующего. Пустая заявка не уходит.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заявки"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.auto_requests",
            "title": "Создать заявки по минимуму склада",
            "description": "Проходит по позициям на минимуме (erp401) и заводит по заявке на склад: количество — до минимума с запасом 20 %, открытые заявки не задваиваются. dry_run показывает, что будет создано, ничего не записывая. Требует подтверждения человека: это пакет документов.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Только один склад"
                    },
                    "need_days": {
                        "type": "integer",
                        "description": "Через сколько дней нужен товар (по умолчанию 14)",
                        "minimum": 1,
                        "maximum": 180
                    },
                    "priority": {
                        "type": "integer",
                        "description": "Приоритет заявок 1–4 (по умолчанию 2)",
                        "minimum": 1,
                        "maximum": 4
                    },
                    "dry_run": {
                        "type": "boolean",
                        "description": "Показать план, ничего не создавая"
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.order.create",
            "title": "Создать заказ поставщику",
            "description": "Два способа: из согласованных заявок (request_ids — заказы группируются по поставщику) или вручную (supplier_id + lines). Позиции без поставщика получают рекомендованного по цене и сроку.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "request_ids": {
                        "type": "array",
                        "description": "Согласованные заявки, из которых собрать заказ(ы)",
                        "items": {
                            "type": "integer"
                        }
                    },
                    "supplier_id": {
                        "type": "integer",
                        "description": "Поставщик для ручного заказа (erp301)"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад приёмки"
                    },
                    "currency": {
                        "type": "string",
                        "description": "Валюта (по умолчанию RUB)"
                    },
                    "delivery_date": {
                        "type": "string",
                        "description": "Дата поставки (ГГГГ-ММ-ДД)"
                    },
                    "payment_terms": {
                        "type": "string",
                        "description": "Условия оплаты"
                    },
                    "note": {
                        "type": "string",
                        "description": "Пояснение к заказу"
                    },
                    "lines": {
                        "type": "array",
                        "description": "Позиции ручного заказа: item_id, name, qty, price, uom_code, delivery_date",
                        "items": {
                            "type": "object"
                        }
                    }
                },
                "required": []
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.order.line.add",
            "title": "Добавить позицию в заказ",
            "description": "Добавляет позицию в черновик заказа. Цена — за единицу; если не указана, подставится последняя известная цена позиции.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заказа"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Позиция номенклатуры (erp227)"
                    },
                    "name": {
                        "type": "string",
                        "description": "Название позиции"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество",
                        "minimum": 0
                    },
                    "price": {
                        "type": "number",
                        "description": "Цена за единицу"
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения"
                    },
                    "delivery_date": {
                        "type": "string",
                        "description": "Срок по позиции (ГГГГ-ММ-ДД)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание к позиции"
                    }
                },
                "required": [
                    "order_id",
                    "name"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.order.send",
            "title": "Отправить заказ поставщику",
            "description": "Отправляет заказ: фиксирует цены в истории цен и переводит заказ в «отправлен». Черновик после этого не правится. Требует подтверждения человека — это шаг наружу.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заказа"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.order.confirm",
            "title": "Поставщик подтвердил заказ",
            "description": "Переводит отправленный заказ в «подтверждён»: поставщик взял его в работу. Приёмку можно оформлять и без этого шага.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заказа"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.order.cancel",
            "title": "Отменить заказ",
            "description": "Отменяет заказ с причиной: позиции освобождаются, заявки возвращаются в работу по решению закупщика. Причина уходит в журнал. Требует подтверждения человека.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заказа"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отмены (попадёт в журнал)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.receipt.create",
            "title": "Оформить приёмку",
            "description": "Создаёт черновик приёмки по заказу: строки подставляются как «то, что заказ ещё не принял». Свой список строк — в lines. Приход на склад произойдёт только после проведения.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "integer",
                        "description": "Заказ, по которому принимаем"
                    },
                    "supplier_id": {
                        "type": "integer",
                        "description": "Поставщик (если приёмка без заказа)"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад-получатель"
                    },
                    "doc_number": {
                        "type": "string",
                        "description": "Номер накладной поставщика"
                    },
                    "doc_date": {
                        "type": "string",
                        "description": "Дата накладной (ГГГГ-ММ-ДД)"
                    },
                    "received_at": {
                        "type": "string",
                        "description": "Дата приёмки (по умолчанию сегодня)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Пояснение"
                    },
                    "lines": {
                        "type": "array",
                        "description": "Свой список позиций: item_id, order_line_id, name, qty, price, uom_code",
                        "items": {
                            "type": "object"
                        }
                    }
                },
                "required": [
                    "order_id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.receipt.quality",
            "title": "Записать входной контроль",
            "description": "Отмечает позицию приёмки: pending («не проверена»), passed («годна») или failed («брак»). Позиция с проваленным контролем блокирует проведение всей приёмки.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "line_id": {
                        "type": "integer",
                        "description": "Позиция приёмки"
                    },
                    "quality_status": {
                        "type": "string",
                        "description": "Результат контроля: pending, passed, failed",
                        "enum": [
                            "pending",
                            "passed",
                            "failed"
                        ]
                    },
                    "note": {
                        "type": "string",
                        "description": "Что нашли (для брака — обязательно)"
                    }
                },
                "required": [
                    "line_id",
                    "quality_status"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.receipt.post",
            "title": "Провести приёмку на склад",
            "description": "Проводит приёмку: позиции с номенклатурой уходят приходом на склад (erp401), цены попадают в историю цен, заказ получает принятое количество. Позиции с проваленным входным контролем блокируют проведение. Требует подтверждения человека: это движение денег и товара.",
            "scope": "erp403.approve",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid приёмки"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад прихода (если нужно переопределить)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.receipt.cancel",
            "title": "Отменить приёмку",
            "description": "Отменяет черновик приёмки с причиной. Проведённую приёмку отменить нельзя: приход уже на складе, обратное движение оформляется расходом в модуле склада. Требует подтверждения человека.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid приёмки"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отмены"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.request.approve",
            "title": "Согласовать заявку",
            "description": "Согласует заявку: после этого её можно проводить в заказ. Агент готовит заявку и показывает расчёт, решение по деньгам принимает человек — поэтому инструмент под подтверждением.",
            "scope": "erp403.approve",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заявки"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.request.reject",
            "title": "Отклонить заявку",
            "description": "Отклоняет заявку с причиной — она уходит в журнал и видна заявителю. Отклонённая заявка не правится: нужна новая. Требует подтверждения человека.",
            "scope": "erp403.approve",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid заявки"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отклонения"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.supplier.save",
            "title": "Сохранить условия поставщика",
            "description": "Закупочные условия: срок поставки, минимальная партия, валюта, оценка, отсрочка, метка «предпочтительный», активность. По этим условиям считается рекомендация поставщика.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "supplier_id": {
                        "type": "integer",
                        "description": "Поставщик — контрагент erp301"
                    },
                    "lead_time_days": {
                        "type": "integer",
                        "description": "Срок поставки в днях",
                        "minimum": 0
                    },
                    "currency": {
                        "type": "string",
                        "description": "Валюта расчётов"
                    },
                    "min_order": {
                        "type": "number",
                        "description": "Минимальная партия",
                        "minimum": 0
                    },
                    "payment_terms": {
                        "type": "string",
                        "description": "Условия оплаты (отсрочка, предоплата)"
                    },
                    "rating": {
                        "type": "integer",
                        "description": "Оценка закупщика 1–5",
                        "minimum": 1,
                        "maximum": 5
                    },
                    "is_preferred": {
                        "type": "boolean",
                        "description": "Предпочтительный поставщик"
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "Действующий поставщик"
                    },
                    "note": {
                        "type": "string",
                        "description": "Заметка закупщика"
                    }
                },
                "required": [
                    "supplier_id"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "procurement.price.record",
            "title": "Записать цену",
            "description": "Добавляет цену в историю: полезно, когда поставщик назвал цену по телефону, без заказа и приёмки. Цены из заказов и приёмок пишутся сами.",
            "scope": "erp403.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "supplier_id": {
                        "type": "integer",
                        "description": "Поставщик (erp301)"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Позиция номенклатуры (erp227)"
                    },
                    "name": {
                        "type": "string",
                        "description": "Название позиции (если нет номенклатуры)"
                    },
                    "price": {
                        "type": "number",
                        "description": "Цена за единицу",
                        "exclusiveMinimum": true,
                        "minimum": 0
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество, на которое названа цена",
                        "minimum": 0
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения"
                    },
                    "currency": {
                        "type": "string",
                        "description": "Валюта (по умолчанию RUB)"
                    },
                    "dated_at": {
                        "type": "string",
                        "description": "Дата цены (по умолчанию сегодня)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Откуда цена"
                    }
                },
                "required": [
                    "supplier_id",
                    "price"
                ]
            },
            "module": "erp403_procurement"
        },
        {
            "name": "documents.stats",
            "title": "Сводка по документам",
            "description": "Состояние печати одним вызовом: сколько документов ждёт выпуска, сколько выпущено, напечатано, в архиве и отменено, и какие типы объектов печатаем чаще.",
            "scope": "erp404.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД)"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД)"
                    },
                    "ref_type": {
                        "type": "string",
                        "description": "Ограничить типом объекта: erp402_order, erp403_order, erp403_receipt, erp405_inspection, erp408_operation"
                    }
                },
                "required": []
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.list",
            "title": "Документы",
            "description": "Список документов с фильтрами (состояние, тип объекта, объект, шаблон, период, поиск). Показывает номер, шаблон с версией и сколько раз печатали.",
            "scope": "erp404.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Состояние: draft, issued, printed, archived, cancelled"
                    },
                    "ref_type": {
                        "type": "string",
                        "description": "Тип объекта-источника"
                    },
                    "ref_id": {
                        "type": "string",
                        "description": "Идентификатор объекта (id или uuid)"
                    },
                    "template_code": {
                        "type": "string",
                        "description": "Код шаблона, например ORDER-SUPPLIER"
                    },
                    "term": {
                        "type": "string",
                        "description": "Поиск по номеру, названию или объекту"
                    },
                    "from": {
                        "type": "string",
                        "description": "Созданы не раньше (ГГГГ-ММ-ДД)"
                    },
                    "to": {
                        "type": "string",
                        "description": "Созданы не позже (ГГГГ-ММ-ДД)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 25)"
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Сдвиг для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.get",
            "title": "Документ целиком",
            "description": "Один документ: шапка, состояние, снимок выпуска (по флагу with_body) и журнал печати — кто, когда и сколько копий вывел.",
            "scope": "erp404.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор документа или его uuid"
                    },
                    "with_body": {
                        "type": "boolean",
                        "description": "Вернуть снимок печатной формы (HTML)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.preview",
            "title": "Предпросмотр документа",
            "description": "Что подставится в форму прямо сейчас — до выпуска. Возвращает список проблем (чего не хватает) и готовый HTML. Удобно проверить шаблон и данные до необратимого шага.",
            "scope": "erp404.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор документа или его uuid"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.templates",
            "title": "Шаблоны печатных форм",
            "description": "Список шаблонов с фильтрами: код, название, тип объекта, вид формы, версия и сколько документов по нему выпущено.",
            "scope": "erp404.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "ref_type": {
                        "type": "string",
                        "description": "Тип объекта-источника"
                    },
                    "kind": {
                        "type": "string",
                        "description": "Вид формы: print, label, act"
                    },
                    "code": {
                        "type": "string",
                        "description": "Точный код шаблона"
                    },
                    "term": {
                        "type": "string",
                        "description": "Поиск по коду и названию"
                    },
                    "active": {
                        "type": "boolean",
                        "description": "Только включённые"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 25)"
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Сдвиг для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.template",
            "title": "Шаблон формы целиком",
            "description": "Тело шаблона, список подстановок и списков ({{#rows}}), версия и тип объекта. По подстановкам видно, из какого модуля шаблон берёт данные.",
            "scope": "erp404.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор шаблона, его uuid или код"
                    },
                    "code": {
                        "type": "string",
                        "description": "Код шаблона, если нет id"
                    }
                },
                "required": []
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.template_check",
            "title": "Проверка шаблона",
            "description": "Проверяет подстановки шаблона и, если указан объект, собирает форму на его данных: видно, что подставится и чего не хватает. Ничего не сохраняет.",
            "scope": "erp404.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор шаблона, его uuid или код"
                    },
                    "ref_id": {
                        "type": "string",
                        "description": "Объект-источник (id или uuid) для проверки на реальных данных"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.create",
            "title": "Завести документ (черновик)",
            "description": "Создаёт черновик под шаблон, связанный с объектом (заказ, приёмка, контроль, операция). Номер выдаётся сразу и остаётся за документом. Печатать можно только выпущенный документ.",
            "scope": "erp404.print",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "template_code": {
                        "type": "string",
                        "description": "Код шаблона, например ORDER-SUPPLIER"
                    },
                    "template_id": {
                        "type": "integer",
                        "description": "Идентификатор шаблона (вместо кода)"
                    },
                    "ref_type": {
                        "type": "string",
                        "description": "Тип объекта, если он не задан шаблоном"
                    },
                    "ref_id": {
                        "type": "string",
                        "description": "Идентификатор объекта (id или uuid)"
                    },
                    "title": {
                        "type": "string",
                        "description": "Название документа (по умолчанию — название шаблона)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание"
                    }
                },
                "required": []
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.issue",
            "title": "Выпустить документ",
            "description": "Собирает данные у владельца (закупки, производство, качество, цех), раскрывает подстановки и фиксирует снимок вместе с версией шаблона. После выпуска документ не переписывается: нужен другой текст — новый документ.",
            "scope": "erp404.print",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор документа или его uuid"
                    },
                    "payload": {
                        "type": "object",
                        "description": "Данные для универсального шаблона (без объекта-источника): {\"ref\": {…}}"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.print",
            "title": "Отметить печать",
            "description": "Записывает вывод бумаги в журнал печати: кто, когда и сколько копий. Отметка — часть истории документа; сам вывод делает человек или внешний воркер.",
            "scope": "erp404.print",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор документа или его uuid"
                    },
                    "copies": {
                        "type": "integer",
                        "description": "Сколько копий напечатали (по умолчанию 1)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание: куда ушла копия"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.archive",
            "title": "Сдать документ в архив",
            "description": "Переводит выпущенный документ в архив: он больше не рабочий, но читаемый. Черновик в архив не уходит — его отменяют или выпускают.",
            "scope": "erp404.print",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор документа или его uuid"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.cancel",
            "title": "Отменить документ",
            "description": "Отменяет черновик или выпущенный документ с обязательной причиной. Номер остаётся занятым, запись — в журнале: отменённый документ не исчезает. Подтверждает человек: бумага с этим номером могла уже уйти контрагенту.",
            "scope": "erp404.print",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор документа или его uuid"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отмены (обязательна)"
                    }
                },
                "required": [
                    "id",
                    "reason"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "documents.template_save",
            "title": "Сохранить шаблон формы",
            "description": "Заводит или правит шаблон печатной формы. Правка тела поднимает версию: выпущенные документы помнят версию, по которой их печатали. Подстановка с опечаткой не сохраняется — форма с дырами до бумаги не доходит.",
            "scope": "erp404.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор шаблона для правки (без него шаблон заводится)"
                    },
                    "code": {
                        "type": "string",
                        "description": "Код шаблона (у существующего не меняется)"
                    },
                    "name": {
                        "type": "string",
                        "description": "Название шаблона"
                    },
                    "ref_type": {
                        "type": "string",
                        "description": "Тип объекта-источника (пусто — универсальный шаблон)"
                    },
                    "kind": {
                        "type": "string",
                        "description": "Вид формы: print, label, act"
                    },
                    "body": {
                        "type": "string",
                        "description": "Тело формы: HTML с подстановками {{ref.number}} и блоками {{#rows ref.lines}}…{{\/rows}}"
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "Включён ли шаблон"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание"
                    }
                },
                "required": [
                    "name",
                    "body"
                ]
            },
            "module": "erp404_documents"
        },
        {
            "name": "quality.stats",
            "title": "Сводка качества",
            "description": "Состояние качества одним вызовом: сколько контролей, сколько партий с браком и какова его доля, что ждёт решения, сколько стоит на карантине и где теряем качество (по причинам).",
            "scope": "erp405.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspections",
            "title": "Контроли качества",
            "description": "Список контролей с фильтрами (вид, состояние, итог, источник, ожидание решения, поиск). Возвращает партии с количеством брака и принятым решением.",
            "scope": "erp405.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "kind": {
                        "type": "string",
                        "description": "Вид контроля: incoming, operational, final"
                    },
                    "status": {
                        "type": "string",
                        "description": "Состояние: draft, registered, decided, closed, cancelled"
                    },
                    "result": {
                        "type": "string",
                        "description": "Итог: passed или failed"
                    },
                    "pending": {
                        "type": "boolean",
                        "description": "Только те, где брак без решения"
                    },
                    "term": {
                        "type": "string",
                        "description": "Поиск по номеру или позиции"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 25)"
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Сдвиг для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection",
            "title": "Контроль качества целиком",
            "description": "Одна партия: количество, брак и его доля, список несоответствий с причинами и виновником, журнал решений с ссылками на движения склада, состояние карантина.",
            "scope": "erp405.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля или его uuid"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.pending",
            "title": "Очередь решений по браку",
            "description": "Партии с браком, по которым решения ещё нет. Именно эта очередь превращается в разговор с поставщиком или в переделку — держите её пустой.",
            "scope": "erp405.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 25)"
                    }
                },
                "required": []
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.quarantine",
            "title": "Карантин",
            "description": "Что физически лежит на складе карантина: позиции, количества, склады и контроли, к которым они относятся.",
            "scope": "erp405.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.defect_codes",
            "title": "Коды дефектов",
            "description": "Справочник кодов дефектов с категорией, важностью и частотой использования. Единый словарь — условие честной статистики качества.",
            "scope": "erp405.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "Поиск по коду или названию"
                    },
                    "category": {
                        "type": "string",
                        "description": "Категория дефекта"
                    },
                    "all": {
                        "type": "boolean",
                        "description": "Показывать выключенные коды"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 200)"
                    }
                },
                "required": []
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.defects_report",
            "title": "Статистика брака",
            "description": "Где теряем качество: брак по кодам, по причинам (поставщик, цех, склад, оборудование), по поставщикам, по номенклатуре и по месяцам — за период или за всё время.",
            "scope": "erp405.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "С даты (ГГГГ-ММ-ДД)"
                    },
                    "to": {
                        "type": "string",
                        "description": "По дату (ГГГГ-ММ-ДД)"
                    },
                    "months": {
                        "type": "integer",
                        "description": "Сколько месяцев динамики показать (по умолчанию 6)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк в каждой таблице (по умолчанию 20)"
                    }
                },
                "required": []
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection.create",
            "title": "Завести контроль качества",
            "description": "Взять партию под контроль. Для складских решений (карантин, утиль) укажите номенклатуру и склад, где лежит партия: без них двигать нечего.",
            "scope": "erp405.inspect",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "kind": {
                        "type": "string",
                        "description": "Вид контроля: incoming, operational, final"
                    },
                    "source": {
                        "type": "string",
                        "description": "Откуда партия: manual, erp403_receipt, erp402_order, erp408_operation"
                    },
                    "source_ref": {
                        "type": "string",
                        "description": "Ссылка на источник (например, id позиции приёмки)"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Идентификатор номенклатуры (реестр erp227)"
                    },
                    "item_name": {
                        "type": "string",
                        "description": "Название позиции, если номенклатуры нет"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество в партии",
                        "exclusiveMinimum": true
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад, где физически лежит партия"
                    },
                    "supplier_id": {
                        "type": "integer",
                        "description": "Поставщик (для входного контроля)"
                    },
                    "order_id": {
                        "type": "integer",
                        "description": "Производственный заказ (для операционного контроля)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание"
                    }
                },
                "required": [
                    "qty"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection.from_receipt",
            "title": "Входной контроль по приёмке",
            "description": "Завести контроль по позиции приёмки закупки (erp403): партия, количество и поставщик берутся из приёмки. Повторный вызов для той же позиции не создаёт второй контроль.",
            "scope": "erp405.inspect",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "line_id": {
                        "type": "integer",
                        "description": "Идентификатор позиции приёмки"
                    }
                },
                "required": [
                    "line_id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.defect.add",
            "title": "Записать дефект",
            "description": "Записать несоответствие: код дефекта, количество и причина. Факт дефекта сам переводит итог контроля в «брак» — партия больше не может быть принята годной без решения.",
            "scope": "erp405.inspect",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "inspection_id": {
                        "type": "integer",
                        "description": "Контроль, к которому относится дефект"
                    },
                    "defect_code_id": {
                        "type": "integer",
                        "description": "Код дефекта из справочника"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Сколько единиц с этим дефектом",
                        "exclusiveMinimum": true
                    },
                    "cause": {
                        "type": "string",
                        "description": "Причина: supplier, production, warehouse, equipment, design, unknown"
                    },
                    "severity": {
                        "type": "integer",
                        "description": "Важность 1..3 (по умолчанию — из кода дефекта)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание"
                    }
                },
                "required": [
                    "inspection_id",
                    "qty"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection.start",
            "title": "Начать проверку",
            "description": "Перевести контроль из черновика в рабочий: партия проверяется, дефекты записываются.",
            "scope": "erp405.inspect",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection.pass",
            "title": "Принять партию годной",
            "description": "Итог «годная». Требует, чтобы дефектов не было: если брак записан, нужен разбор и решение. Для входного контроля закупки сразу снимает блокировку прихода.",
            "scope": "erp405.decide",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection.quarantine",
            "title": "Изолировать партию",
            "description": "Переместить брак на склад карантина — партия физически уходит из оборота. Пока она на карантине, контроль не закрывается.",
            "scope": "erp405.decide",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад карантина (по умолчанию первый склад типа quarantine)"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Сколько изолировать (по умолчанию — всё бракованное количество)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection.release",
            "title": "Выпустить из карантина",
            "description": "Вернуть партию из карантина в оборот: после сортировки, решения «использовать как есть» или прихода сопроводительных документов.",
            "scope": "erp405.decide",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Куда вернуть (по умолчанию — склад партии)"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Сколько выпустить (по умолчанию всё, что на карантине)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.inspection.close",
            "title": "Закрыть контроль",
            "description": "Закрыть разобранный контроль: решение исполнено, документ больше не правится. Партия на карантине закрытию мешает — сначала выпуск.",
            "scope": "erp405.decide",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.decision.scrap",
            "title": "Брак в утиль",
            "description": "Списать брак: перемещение на склад утиля (erp401). Необратимая потеря — поэтому решение подтверждает человек. Без склада типа scrap операция не выполняется, а не «делает вид».",
            "scope": "erp405.decide",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад утиля (по умолчанию первый склад типа scrap)"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Сколько списать (по умолчанию — всё бракованное количество)"
                    },
                    "comment": {
                        "type": "string",
                        "description": "Обоснование решения"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.decision.return",
            "title": "Вернуть брак поставщику",
            "description": "Решение «вернуть поставщику»: партия изолируется, поставщику уходит событие с количеством и позицией для рекламации. Разговор с контрагентом — решение человека.",
            "scope": "erp405.decide",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    },
                    "comment": {
                        "type": "string",
                        "description": "Обоснование и договорённости с поставщиком"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.decision.rework",
            "title": "Брак в переделку",
            "description": "Решение «переделать»: событие для производства (erp402) с количеством и заказом. Товар остаётся на складе, пока производство не возьмёт его в работу.",
            "scope": "erp405.decide",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор контроля"
                    },
                    "comment": {
                        "type": "string",
                        "description": "Что именно переделать и кто отвечает"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "quality.defect_code.save",
            "title": "Код дефекта",
            "description": "Завести или изменить код дефекта. Свободный текст в статистике не сходится: один дефект должен называться одним кодом на всём заводе.",
            "scope": "erp405.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор кода (пусто — завести новый)"
                    },
                    "code": {
                        "type": "string",
                        "description": "Обозначение, например SURF-SCRATCH"
                    },
                    "name": {
                        "type": "string",
                        "description": "Название дефекта"
                    },
                    "category": {
                        "type": "string",
                        "description": "Категория: size, surface, material, assembly, document, packaging, other"
                    },
                    "severity": {
                        "type": "integer",
                        "description": "Важность 1..3"
                    },
                    "description": {
                        "type": "string",
                        "description": "Описание: как распознать дефект"
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "Выключить код (FALSE) вместо удаления"
                    }
                },
                "required": [
                    "name"
                ]
            },
            "module": "erp405_quality"
        },
        {
            "name": "planning.stats",
            "title": "Сводка планирования",
            "description": "Состояние планирования одним вызовом: сколько программ и в каком они состоянии, когда был последний расчёт, сколько предложений ждут решения и сколько из них просрочено по дате заказа.",
            "scope": "erp407.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.programs.search",
            "title": "Поиск программ",
            "description": "Производственные программы с фильтрами по состоянию, периоду и тексту. Программа — источник спроса: изделия, количество и срок.",
            "scope": "erp407.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Состояние программы",
                        "enum": [
                            "draft",
                            "approved",
                            "closed"
                        ]
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру и названию"
                    },
                    "period_from": {
                        "type": "string",
                        "description": "Программы, начинающиеся не раньше даты (ГГГГ-ММ-ДД)"
                    },
                    "period_to": {
                        "type": "string",
                        "description": "Программы, заканчивающиеся не позже даты (ГГГГ-ММ-ДД)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.program.list",
            "title": "Список программ выпуска",
            "description": "Список производственных программ перед вызовом planning.program.get. Возвращает id и uuid, поэтому агенту не нужно угадывать идентификатор.",
            "scope": "erp407.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Состояние программы",
                        "enum": [
                            "draft",
                            "approved",
                            "closed"
                        ]
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру и названию"
                    },
                    "period_from": {
                        "type": "string",
                        "description": "Начало периода, ГГГГ-ММ-ДД"
                    },
                    "period_to": {
                        "type": "string",
                        "description": "Конец периода, ГГГГ-ММ-ДД"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть",
                        "minimum": 1,
                        "maximum": 100,
                        "default": 20
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение",
                        "minimum": 0,
                        "default": 0
                    }
                },
                "required": []
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.program.get",
            "title": "Программа целиком",
            "description": "Программа, её строки, потребность последнего расчёта и предложения — всё, что нужно, чтобы понять план и его узкие места.",
            "scope": "erp407.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid программы"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.deficits",
            "title": "Дефициты последнего расчёта",
            "description": "Чего не хватает по последнему расчёту: сколько нужно, сколько покрыто (склад, незавершёнка, заказы) и к какой дате надо разместить заказ. Просроченные по дате заказа помечены флагом late.",
            "scope": "erp407.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "program_id": {
                        "type": "integer",
                        "description": "Программа (по умолчанию — последняя с расчётом)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько позиций вернуть (по умолчанию 50)",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.proposals.search",
            "title": "Поиск предложений",
            "description": "Предложения плана: что решено закупить или выпустить, что уже передано в исполнение и куда. Фильтры по состоянию, способу, программе и позиции.",
            "scope": "erp407.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Состояние предложения",
                        "enum": [
                            "new",
                            "approved",
                            "exported",
                            "done",
                            "cancelled"
                        ]
                    },
                    "kind": {
                        "type": "string",
                        "description": "Способ обеспечения",
                        "enum": [
                            "purchase",
                            "produce"
                        ]
                    },
                    "program_id": {
                        "type": "integer",
                        "description": "Предложения одной программы"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Предложения одной позиции номенклатуры"
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по названию позиции"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.program.create",
            "title": "Создать программу",
            "description": "Заводит производственную программу на период. Дальше в неё добавляются строки и запускается расчёт потребности.",
            "scope": "erp407.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "title": {
                        "type": "string",
                        "description": "Название программы"
                    },
                    "period_from": {
                        "type": "string",
                        "description": "Начало периода, ГГГГ-ММ-ДД"
                    },
                    "period_to": {
                        "type": "string",
                        "description": "Конец периода, ГГГГ-ММ-ДД"
                    },
                    "horizon_days": {
                        "type": "integer",
                        "description": "Горизонт планирования в днях (по умолчанию 30)",
                        "minimum": 1,
                        "maximum": 365
                    },
                    "note": {
                        "type": "string",
                        "description": "Контекст плана"
                    }
                },
                "required": [
                    "title",
                    "period_from",
                    "period_to"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.program.line.add",
            "title": "Добавить строку программы",
            "description": "Добавляет изделие в программу: что и сколько нужно к сроку. Если у изделия есть техкарта, расчёт разложит его на материалы и полуфабрикаты.",
            "scope": "erp407.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "program_id": {
                        "type": "string",
                        "description": "Идентификатор или uuid программы из planning.program.list"
                    },
                    "name": {
                        "type": "string",
                        "description": "Наименование изделия"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество",
                        "minimum": 0.001
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения (по умолчанию шт)"
                    },
                    "due_date": {
                        "type": "string",
                        "description": "Нужен к дате, ГГГГ-ММ-ДД"
                    },
                    "code": {
                        "type": "string",
                        "description": "Артикул"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Идентификатор номенклатуры erp227 — включает учёт остатков"
                    },
                    "tech_card_id": {
                        "type": "integer",
                        "description": "Техкарта erp228 для разложения на материалы"
                    }
                },
                "required": [
                    "program_id",
                    "name",
                    "qty"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.program.approve",
            "title": "Утвердить программу",
            "description": "Переводит программу из черновика в утверждённую: план зафиксирован, строки больше не правятся. Требует подтверждения человека — утверждение плана это решение, а не расчёт.",
            "scope": "erp407.plan",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid программы"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.mrp.calculate",
            "title": "Рассчитать потребность",
            "description": "Главный расчёт модуля: разбирает изделия программы по техкартам (до 3 уровней), вычитает склад, незавершёнку и уже размещённые заказы, считает дефицит и дату заказа по сроку поставки. Результат сохраняется снимком и виден в планировании.",
            "scope": "erp407.plan",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid программы"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад, с которого считать покрытие (по умолчанию — все)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.proposals.create",
            "title": "Завести предложения по дефицитам",
            "description": "Превращает дефициты последнего расчёта в предложения: закупить или выпустить. По каждой позиции создаётся не больше одного открытого предложения — повторный вызов не задваивает.",
            "scope": "erp407.plan",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "program_id": {
                        "type": "integer",
                        "description": "Программа с выполненным расчётом"
                    },
                    "only_late": {
                        "type": "boolean",
                        "description": "Только позиции, у которых срок заказа уже прошёл"
                    }
                },
                "required": [
                    "program_id"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.proposal.create",
            "title": "Создать предложение вручную",
            "description": "Заводит предложение вне расчёта: аварийная закупка, замена, опытная партия. Обязательно укажите способ (закупить или выпустить).",
            "scope": "erp407.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "kind": {
                        "type": "string",
                        "description": "Способ обеспечения",
                        "enum": [
                            "purchase",
                            "produce"
                        ]
                    },
                    "name": {
                        "type": "string",
                        "description": "Наименование позиции"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Количество",
                        "minimum": 0.001
                    },
                    "program_id": {
                        "type": "integer",
                        "description": "Программа, к которой относится предложение"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Номенклатура erp227"
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица измерения (по умолчанию шт)"
                    },
                    "due_date": {
                        "type": "string",
                        "description": "Нужно к дате, ГГГГ-ММ-ДД"
                    },
                    "order_date": {
                        "type": "string",
                        "description": "Когда размещать заказ, ГГГГ-ММ-ДД"
                    },
                    "priority": {
                        "type": "integer",
                        "description": "Приоритет: 1 срочно, 3 обычный, 4 низкий",
                        "minimum": 1,
                        "maximum": 4
                    },
                    "note": {
                        "type": "string",
                        "description": "Обоснование"
                    }
                },
                "required": [
                    "kind",
                    "name",
                    "qty"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.proposal.approve",
            "title": "Утвердить предложение",
            "description": "Предложение переходит в «утверждено»: с этого момента оно учитывается как покрытие потребности, а правки по нему закрываются.",
            "scope": "erp407.plan",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid предложения"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.proposal.export",
            "title": "Передать предложение в исполнение",
            "description": "Создаёт работу для соседнего модуля: для выпуска — заказ производства (erp402), для закупки — заявку закупки (erp403), если модуль подключён. Ссылка на приёмник сохраняется в target_ref. Требует подтверждения человека: агент предлагает, заказ порождает человек.",
            "scope": "erp407.approve",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid предложения"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "planning.proposal.cancel",
            "title": "Отклонить предложение",
            "description": "Отклоняет предложение с причиной. Причина уходит в журнал — по ней потом видно, почему план не выполнен. Требует подтверждения человека.",
            "scope": "erp407.plan",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid предложения"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отклонения (попадёт в журнал)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp407_planning"
        },
        {
            "name": "shopfloor.board",
            "title": "Загрузка цеха на день",
            "description": "Доска мастера: рабочие центры с операциями на день, плановые часы, свободные часы из календаря, процент загрузки. Возвращает и операции без назначенного центра.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "day": {
                        "type": "string",
                        "description": "День в виде ГГГГ-ММ-ДД (по умолчанию — сегодня)"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Только один рабочий центр"
                    }
                },
                "required": []
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operations.search",
            "title": "Поиск операций цеха",
            "description": "Операции с фильтрами: статус, рабочий центр, день или период, поиск по названию и номеру заказа, только открытые. Основной способ найти работу по цеху.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Статус операции",
                        "enum": [
                            "planned",
                            "in_progress",
                            "paused",
                            "done",
                            "cancelled"
                        ]
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр"
                    },
                    "day": {
                        "type": "string",
                        "description": "День плана, ГГГГ-ММ-ДД"
                    },
                    "from": {
                        "type": "string",
                        "description": "Начало периода, ГГГГ-ММ-ДД"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода, ГГГГ-ММ-ДД"
                    },
                    "term": {
                        "type": "string",
                        "description": "Поиск по названию операции и номеру заказа"
                    },
                    "order_id": {
                        "type": "integer",
                        "description": "Операции одного производственного заказа"
                    },
                    "open_only": {
                        "type": "boolean",
                        "description": "Только незакрытые (к выполнению, в работе, на паузе)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.get",
            "title": "Карточка операции",
            "description": "Одна операция целиком: план и факт, время работы и простоя, назначение, а также журнал отметок — кто и когда нажимал кнопки в терминале.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "logs": {
                        "type": "integer",
                        "description": "Сколько отметок вернуть (по умолчанию 30)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.terminal.tasks",
            "title": "Задания терминала",
            "description": "Открытые операции на день и просроченные — то, что оператор видит на планшете у станка: что делать, сколько осталось, где идёт простой.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр"
                    },
                    "day": {
                        "type": "string",
                        "description": "День, ГГГГ-ММ-ДД (по умолчанию — сегодня)"
                    }
                },
                "required": []
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.stats",
            "title": "Сводка цеха",
            "description": "Итоги за период: сколько операций закрыто, в работе, просрочено, сколько годных и брака, часы работы и простоя — с разбивкой по дням и центрам.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "days": {
                        "type": "integer",
                        "description": "Сколько дней назад считать (по умолчанию 7)",
                        "minimum": 1,
                        "maximum": 365
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Только один рабочий центр"
                    }
                },
                "required": []
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.queue",
            "title": "Заказы без маршрута",
            "description": "Производственные заказы, по которым цех ещё не получил работы: заказ в плане, работе или выпуске, а операций нет. Кандидаты на раскладку маршрута.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Сколько заказов вернуть (по умолчанию 20)"
                    }
                },
                "required": []
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.centers.list",
            "title": "Рабочие центры",
            "description": "Справочник рабочих центров и участков: код, название, цех, производительность и стоимость нормо-часа, признак активности.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "term": {
                        "type": "string",
                        "description": "Поиск по коду, названию и цеху"
                    },
                    "kind": {
                        "type": "string",
                        "description": "Вид: рабочий центр или участок",
                        "enum": [
                            "center",
                            "area"
                        ]
                    },
                    "active": {
                        "type": "boolean",
                        "description": "Только включённые центры"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 50)"
                    }
                },
                "required": []
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.shifts.list",
            "title": "Смены и календарь",
            "description": "Шаблоны смен и записи календаря за период: какие дни рабочие и сколько часов доступно центру. По этим часам считается загрузка.",
            "scope": "erp408.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода, ГГГГ-ММ-ДД"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода, ГГГГ-ММ-ДД"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Календарь одного рабочего центра"
                    }
                },
                "required": []
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.start",
            "title": "Начать операцию",
            "description": "Переводит операцию в работу и открывает отсчёт времени. Доступно для статуса «к выполнению» и после паузы — используйте shopfloor.operation.resume.",
            "scope": "erp408.terminal",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.pause",
            "title": "Пауза",
            "description": "Останавливает отсчёт времени: отработанные секунды уходят в факт операции. Продолжение — shopfloor.operation.resume.",
            "scope": "erp408.terminal",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "comment": {
                        "type": "string",
                        "description": "Комментарий мастера"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.resume",
            "title": "Продолжить операцию",
            "description": "Возвращает приостановленную операцию в работу и снова открывает отсчёт времени.",
            "scope": "erp408.terminal",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.output",
            "title": "Записать выработку",
            "description": "Добавляет годные и брак по операции. В терминале это нажатие «Выработка»: журнал хранит, кто и сколько записал.",
            "scope": "erp408.terminal",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "qty_ok": {
                        "type": "number",
                        "description": "Сколько годных изготовлено",
                        "minimum": 0
                    },
                    "qty_scrap": {
                        "type": "number",
                        "description": "Сколько ушло в брак",
                        "minimum": 0
                    },
                    "comment": {
                        "type": "string",
                        "description": "Комментарий мастера"
                    }
                },
                "required": [
                    "id",
                    "qty_ok"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.downtime_start",
            "title": "Отметить простой",
            "description": "Станок встал: операция уходит в паузу, время простоя начинает считаться, причина сохраняется в журнале — потом по ним разбирают потери.",
            "scope": "erp408.terminal",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина простоя",
                        "enum": [
                            "no_material",
                            "equipment",
                            "setup",
                            "no_tool",
                            "no_staff",
                            "quality",
                            "power",
                            "other"
                        ]
                    },
                    "comment": {
                        "type": "string",
                        "description": "Уточнение (что именно случилось)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.downtime_stop",
            "title": "Закончить простой",
            "description": "Останавливает отсчёт простоя: секунды уходят в потери операции. Работа возобновляется отдельно — shopfloor.operation.resume.",
            "scope": "erp408.terminal",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "comment": {
                        "type": "string",
                        "description": "Уточнение"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.finish",
            "title": "Завершить операцию",
            "description": "Закрывает операцию: время работы фиксируется, факт уходит в производство событием erp408.operation.completed. Требует подтверждения человека — операцию в цехе закрывает мастер.",
            "scope": "erp408.terminal",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "qty_ok": {
                        "type": "number",
                        "description": "Сколько годных закрыть (по умолчанию — остаток плана)"
                    },
                    "qty_scrap": {
                        "type": "number",
                        "description": "Сколько в брак"
                    },
                    "comment": {
                        "type": "string",
                        "description": "Комментарий мастера"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.assign",
            "title": "Назначить операцию",
            "description": "Ставит операцию на рабочий центр, смену и день. Если день нерабочий по календарю, он сдвигается на ближайший рабочий — об этом сообщается в ответе.",
            "scope": "erp408.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "work_center_id": {
                        "type": "integer",
                        "description": "Рабочий центр или участок"
                    },
                    "shift_id": {
                        "type": "integer",
                        "description": "Смена (по умолчанию — текущая у операции)"
                    },
                    "day": {
                        "type": "string",
                        "description": "День, ГГГГ-ММ-ДД (по умолчанию — плановый день операции)"
                    }
                },
                "required": [
                    "id",
                    "work_center_id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.route.plan",
            "title": "Разложить маршрут заказа",
            "description": "Строит операции цеха по техкарте производственного заказа. Если техкарты нет, но есть состав — создаётся одна операция «Изготовление по заказу». Повторный вызов ничего не дублирует. Требует подтверждения человека.",
            "scope": "erp408.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "integer",
                        "description": "Идентификатор производственного заказа"
                    }
                },
                "required": [
                    "order_id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.cancel",
            "title": "Отменить операцию",
            "description": "Отменяет работу по операции с причиной. История и отметки остаются в журнале — операция не удаляется.",
            "scope": "erp408.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отмены (попадёт в журнал)"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "shopfloor.operation.delete",
            "title": "Удалить операцию",
            "description": "Удаляет операцию, по которой ещё не было отметок и которая стоит «к выполнению». Исправление ошибки мастера, а не способ спрятать факт: по работе с отметками используйте отмену.",
            "scope": "erp408.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Идентификатор или uuid операции"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp408_shopfloor"
        },
        {
            "name": "costing.orders",
            "title": "Себестоимость производственных заказов",
            "description": "Read-only список заказов и последних версий калькуляции. Нулевая ставка сопровождается предупреждением и не должна трактоваться как бесплатный ресурс.",
            "scope": "erp409.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Максимум строк, до 200"
                    }
                },
                "required": []
            },
            "module": "erp409_costing"
        },
        {
            "name": "costing.explain",
            "title": "Объяснить версию себестоимости",
            "description": "Read-only drill-down план\/факт до движения WMS, операции shopfloor и зафиксированного источника ставки. Не пересчитывает и не утверждает данные.",
            "scope": "erp409.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "calculation": {
                        "type": "string",
                        "description": "ID или UUID версии из costing.orders"
                    }
                },
                "required": [
                    "calculation"
                ]
            },
            "module": "erp409_costing"
        },
        {
            "name": "sales.stats",
            "title": "Сводка продаж",
            "description": "Состояние продаж одним вызовом: сколько заказов в работе и на какую сумму, что просрочено по сроку отгрузки, сколько отгрузок собрано и ждёт проведения, сколько отгружено и на какую сумму за месяц, сколько счетов ждёт оплаты и что просрочено, как выглядит клиентская база.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.orders.search",
            "title": "Поиск заказов клиентов",
            "description": "Заказы клиентов с фильтрами по состоянию, клиенту, тексту и сроку отгрузки. Заказ — это обещание клиенту: что, сколько и к какой дате продаём.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "array",
                        "description": "Состояния заказов",
                        "items": {
                            "type": "string",
                            "enum": [
                                "draft",
                                "confirmed",
                                "reserved",
                                "picking",
                                "shipped",
                                "closed",
                                "cancelled"
                            ]
                        }
                    },
                    "customer_id": {
                        "type": "integer",
                        "description": "Заказы одного клиента (контрагент erp301)"
                    },
                    "open": {
                        "type": "boolean",
                        "description": "Только открытые: черновики, подтверждённые, с резервом и в сборке"
                    },
                    "overdue": {
                        "type": "boolean",
                        "description": "Только просроченные по дате отгрузки"
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру, клиенту, позиции и примечанию"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.order.get",
            "title": "Заказ клиента целиком",
            "description": "Заказ с позициями (сколько заказано, зарезервировано и отгружено), его отгрузками, счетами и проверкой кредитного лимита клиента. Основной инструмент, когда нужно понять, можно ли отгружать.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "integer",
                        "description": "Идентификатор заказа",
                        "minimum": 1
                    },
                    "number": {
                        "type": "string",
                        "description": "Номер заказа (если идентификатор неизвестен)"
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.shipments.search",
            "title": "Поиск отгрузок",
            "description": "Отгрузки клиентам с фильтрами по состоянию, клиенту и заказу. Проведённая отгрузка означает, что товар списан со склада.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "array",
                        "description": "Состояния отгрузок",
                        "items": {
                            "type": "string",
                            "enum": [
                                "draft",
                                "ready",
                                "shipped",
                                "cancelled"
                            ]
                        }
                    },
                    "customer_id": {
                        "type": "integer",
                        "description": "Отгрузки одного клиента"
                    },
                    "order_id": {
                        "type": "integer",
                        "description": "Отгрузки по заказу клиента"
                    },
                    "open": {
                        "type": "boolean",
                        "description": "Только непроведённые: черновики и готовые к отправке"
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру, перевозчику и адресу"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.shipment.get",
            "title": "Отгрузка целиком",
            "description": "Отгрузка со строками (что везём и на какую сумму) и счётом, если он уже выставлен.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "shipment_id": {
                        "type": "integer",
                        "description": "Идентификатор отгрузки",
                        "minimum": 1
                    },
                    "number": {
                        "type": "string",
                        "description": "Номер отгрузки (если идентификатор неизвестен)"
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.invoices.search",
            "title": "Поиск счетов",
            "description": "Счета клиентам с фильтрами по состоянию, клиенту, неоплаченным и просроченным. Показывает, сколько денег ждёт оплаты и насколько она задержалась.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "array",
                        "description": "Состояния счетов",
                        "items": {
                            "type": "string",
                            "enum": [
                                "draft",
                                "issued",
                                "paid",
                                "cancelled"
                            ]
                        }
                    },
                    "customer_id": {
                        "type": "integer",
                        "description": "Счета одного клиента"
                    },
                    "order_id": {
                        "type": "integer",
                        "description": "Счета по заказу"
                    },
                    "unpaid": {
                        "type": "boolean",
                        "description": "Только неоплаченные (выставленные)"
                    },
                    "overdue": {
                        "type": "boolean",
                        "description": "Только просроченные по дате оплаты"
                    },
                    "search": {
                        "type": "string",
                        "description": "Поиск по номеру и примечанию"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.invoice.get",
            "title": "Счёт целиком",
            "description": "Счёт с позициями, суммой, оплаченным и остатком; показывает заказ и отгрузку, из которых он собран.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "invoice_id": {
                        "type": "integer",
                        "description": "Идентификатор счёта",
                        "minimum": 1
                    },
                    "number": {
                        "type": "string",
                        "description": "Номер счёта (если идентификатор неизвестен)"
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.customers.search",
            "title": "Поиск клиентов продажи",
            "description": "Покупатели (контрагенты erp301) с условиями продажи и открытой задолженностью. Кредитный лимит и отсрочка живут в профиле продажи.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "search": {
                        "type": "string",
                        "description": "Поиск по названию клиента"
                    },
                    "active": {
                        "type": "boolean",
                        "description": "Только действующие условия"
                    },
                    "with_profile": {
                        "type": "boolean",
                        "description": "Только клиенты с условиями продажи"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 20)",
                        "minimum": 1,
                        "maximum": 100
                    },
                    "offset": {
                        "type": "integer",
                        "description": "Смещение для постраничного вывода"
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.customer.get",
            "title": "Клиент целиком",
            "description": "Карточка клиента продажи: условия (отсрочка, лимит, скидка), открытая задолженность, свободный остаток лимита, последние заказы и неоплаченные счета.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "customer_id": {
                        "type": "integer",
                        "description": "Идентификатор контрагента-покупателя",
                        "minimum": 1
                    }
                },
                "required": [
                    "customer_id"
                ]
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.credit.check",
            "title": "Проверка кредитного лимита",
            "description": "Можно ли продать клиенту на указанную сумму: лимит отсрочки, текущая задолженность, свободный остаток и причина отказа. Вызывать перед оформлением заказа без предоплаты.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "customer_id": {
                        "type": "integer",
                        "description": "Идентификатор клиента",
                        "minimum": 1
                    },
                    "amount": {
                        "type": "number",
                        "description": "Сумма предполагаемой продажи, ₽",
                        "minimum": 0
                    }
                },
                "required": [
                    "customer_id"
                ]
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.due",
            "title": "Что отгрузить на неделе",
            "description": "Заказы со сроком отгрузки в ближайшие дни и уже просроченные — рабочий список «что везти». Возвращает заказы, сгруппированные по срочности.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "days": {
                        "type": "integer",
                        "description": "Горизонт в днях (по умолчанию 7)",
                        "minimum": 1,
                        "maximum": 60
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько заказов вернуть (по умолчанию 20, максимум 100)",
                        "minimum": 1,
                        "maximum": 100
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.price.get",
            "title": "Цена позиции для клиента",
            "description": "По какой цене продавать: договорная цена клиента, базовая цена прайса или цена последней отгрузки — с основанием, скидкой и итоговой ценой. Вызывать перед добавлением позиции в заказ.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "item_id": {
                        "type": "integer",
                        "description": "Позиция номенклатуры (erp227)",
                        "minimum": 1
                    },
                    "customer_id": {
                        "type": "integer",
                        "description": "Клиент: если не указан, вернётся базовая цена",
                        "minimum": 1
                    }
                },
                "required": [
                    "item_id"
                ]
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.price.history",
            "title": "История цен позиции",
            "description": "Все записи прайса по позиции: когда, для какого клиента, по какой цене и из какого источника (вручную, из заказа, отгрузки или счёта). Показывает, как менялась цена.",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "item_id": {
                        "type": "integer",
                        "description": "Позиция номенклатуры (erp227)",
                        "minimum": 1
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько записей вернуть (по умолчанию 25)",
                        "minimum": 1,
                        "maximum": 100
                    }
                },
                "required": [
                    "item_id"
                ]
            },
            "module": "erp410_shipment"
        },
        {
            "name": "sales.catalog.prices",
            "title": "Прайс каталога для клиента",
            "description": "Цены всех позиций каталога для выбранного клиента: договорная цена, базовый прайс или цена последней отгрузки. Показывает, по каким позициям цены вообще нет, — это риск продать «за ноль».",
            "scope": "erp410.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "customer_id": {
                        "type": "integer",
                        "description": "Клиент: если не указан, вернётся базовый прайс",
                        "minimum": 1
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько позиций вернуть (по умолчанию 50)",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp410_shipment"
        },
        {
            "name": "traceability.lots",
            "title": "Найти партии и serial",
            "description": "Поиск по номеру партии, serial, коду\/названию номенклатуры и статусу. Возвращает UUID для следующих действий.",
            "scope": "erp412.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "q": {
                        "type": "string",
                        "description": "Номер, serial, код или название"
                    },
                    "status": {
                        "type": "string",
                        "description": "Статус",
                        "enum": [
                            "available",
                            "quarantine",
                            "consumed",
                            "scrapped",
                            "recalled"
                        ]
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "ID, полученный интерактивным поиском номенклатуры"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp412_traceability"
        },
        {
            "name": "traceability.genealogy",
            "title": "Genealogy партии",
            "description": "Показывает входные и выходные партии, производственный заказ\/операцию и split\/merge\/rework связи.",
            "scope": "erp412.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "lot": {
                        "type": "string",
                        "description": "UUID или ID из traceability.lots"
                    },
                    "depth": {
                        "type": "integer",
                        "description": "Глубина",
                        "minimum": 1,
                        "maximum": 50
                    }
                },
                "required": [
                    "lot"
                ]
            },
            "module": "erp412_traceability"
        },
        {
            "name": "traceability.affected_outputs",
            "title": "Выпуски, затронутые партией",
            "description": "Обратная задача отзыва: все прямые и многоуровневые выходные партии.",
            "scope": "erp412.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "lot": {
                        "type": "string",
                        "description": "UUID партии"
                    }
                },
                "required": [
                    "lot"
                ]
            },
            "module": "erp412_traceability"
        },
        {
            "name": "traceability.create_lot",
            "title": "Создать партию или serial",
            "description": "Создание идентичности партии. AI готовит предложение; выполнение требует подтверждения. Номенклатура сначала выбирается поиском, не угадывается.",
            "scope": "erp412.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "item_id": {
                        "type": "integer",
                        "description": "ID выбранной номенклатуры"
                    },
                    "lot_number": {
                        "type": "string",
                        "description": "Номер; пустой генерируется"
                    },
                    "tracking_mode": {
                        "type": "string",
                        "description": "Режим",
                        "enum": [
                            "lot",
                            "serial"
                        ]
                    },
                    "serial_number": {
                        "type": "string",
                        "description": "Обязателен для serial"
                    },
                    "manufactured_at": {
                        "type": "string",
                        "description": "Дата изготовления"
                    },
                    "expires_at": {
                        "type": "string",
                        "description": "Срок годности"
                    }
                },
                "required": [
                    "item_id",
                    "tracking_mode"
                ]
            },
            "module": "erp412_traceability"
        },
        {
            "name": "traceability.link",
            "title": "Связать входную и выходную партии",
            "description": "Фиксирует consume\/split\/merge\/rework по заказу или операции. Циклы запрещены. Требует подтверждения.",
            "scope": "erp412.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "input_lot_id": {
                        "type": "string",
                        "description": "UUID входной партии из поиска"
                    },
                    "output_lot_id": {
                        "type": "string",
                        "description": "UUID выходной партии из поиска"
                    },
                    "relation": {
                        "type": "string",
                        "description": "Тип связи",
                        "enum": [
                            "consume",
                            "split",
                            "merge",
                            "rework",
                            "substitute"
                        ]
                    },
                    "order_id": {
                        "type": "integer",
                        "description": "Производственный заказ из поиска"
                    },
                    "operation_id": {
                        "type": "integer",
                        "description": "Операция из поиска"
                    },
                    "qty_input": {
                        "type": "number",
                        "description": "Расход входной партии"
                    },
                    "qty_output": {
                        "type": "number",
                        "description": "Связанный выпуск"
                    },
                    "uom_code": {
                        "type": "string",
                        "description": "Единица"
                    }
                },
                "required": [
                    "input_lot_id",
                    "output_lot_id",
                    "relation",
                    "qty_input"
                ]
            },
            "module": "erp412_traceability"
        },
        {
            "name": "traceability.production_record",
            "title": "Связать фактический материал с выпуском",
            "description": "По выбранным UUID партии материала и выпуска находит списание WMS производственного заказа, распределяет lot и создаёт genealogy. Не принимает неподтверждённое количество. Требует approval.",
            "scope": "erp412.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "input_lot": {
                        "type": "string",
                        "description": "UUID входной партии из traceability.lots"
                    },
                    "output_lot": {
                        "type": "string",
                        "description": "UUID партии выпуска"
                    },
                    "order_id": {
                        "type": "integer",
                        "description": "ID заказа, найденного по номеру"
                    },
                    "qty": {
                        "type": "number",
                        "description": "Фактический расход партии",
                        "exclusiveMinimum": 0
                    }
                },
                "required": [
                    "input_lot",
                    "output_lot",
                    "order_id",
                    "qty"
                ]
            },
            "module": "erp412_traceability"
        },
        {
            "name": "traceability.status",
            "title": "Изменить статус партии",
            "description": "Карантин, разрешение, расход или утиль. Требует причины и подтверждения. Отзыв выполняется отдельным инструментом.",
            "scope": "erp412.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "lot": {
                        "type": "string",
                        "description": "UUID партии"
                    },
                    "status": {
                        "type": "string",
                        "description": "Новый статус",
                        "enum": [
                            "available",
                            "quarantine",
                            "consumed",
                            "scrapped"
                        ]
                    },
                    "reason": {
                        "type": "string",
                        "description": "Обязательная причина"
                    }
                },
                "required": [
                    "lot",
                    "status",
                    "reason"
                ]
            },
            "module": "erp412_traceability"
        },
        {
            "name": "traceability.recall",
            "title": "Отозвать партию",
            "description": "Блокирует партию и формирует durable факт; перед подтверждением проверьте affected_outputs.",
            "scope": "erp412.recall",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "lot": {
                        "type": "string",
                        "description": "UUID партии"
                    },
                    "reason": {
                        "type": "string",
                        "description": "Причина отзыва"
                    }
                },
                "required": [
                    "lot",
                    "reason"
                ]
            },
            "module": "erp412_traceability"
        },
        {
            "name": "analytics.summary",
            "title": "Сводка аналитики",
            "description": "KPI завода одним вызовом: покрытие запасов, мёртвый запас, OEE, выполнение плана, доля брака, просроченные поставки — с целью и состоянием каждого показателя, плюс что требует внимания. Блок, чей источник выключен, помечен available=false, а не нулём.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД). По умолчанию: запасы — 90 дней, производство и качество — текущий месяц"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад (для витрин запасов)"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр (для витрины производства)"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.sources",
            "title": "Состояние источников",
            "description": "Какие модули-владельцы данных подключены и что каждый даёт аналитике. Первое, что нужно проверить, если витрина вернула source_missing.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.stock",
            "title": "Оборачиваемость и покрытие запасов",
            "description": "По каждой позиции: приход, расход, текущий остаток, дни покрытия, обороты за период и класс движения (быстрый\/средний\/медленный\/мёртвый\/нет запаса). Покрытие считается от текущего темпа расхода — истории остатков в системе нет.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД). По умолчанию: запасы — 90 дней, производство и качество — текущий месяц"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад (для витрин запасов)"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр (для витрины производства)"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Одна позиция номенклатуры"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 25, максимум 200)"
                    },
                    "class": {
                        "type": "string",
                        "description": "Фильтр по классу: fast, medium, slow, dead, out, idle"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.deficit",
            "title": "Чего не хватает",
            "description": "Позиции, которых не хватит до цели покрытия или которые уже ниже минимума склада, с прикидкой «сколько докупить». Это не заказ: заказ считает планирование (erp407) со сроками поставки.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД). По умолчанию: запасы — 90 дней, производство и качество — текущий месяц"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад (для витрин запасов)"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр (для витрины производства)"
                    },
                    "item_id": {
                        "type": "integer",
                        "description": "Одна позиция номенклатуры"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.abc",
            "title": "ABC\/XYZ анализ",
            "description": "Разложение расхода по позициям: ABC — по накопительной доле расхода (что двигает склад), XYZ — по вариации месячного расхода (насколько ровно). Считается по количеству, а не по деньгам: цены живут в закупках. Матрица — сколько позиций в каждой из девяти клеток.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД). По умолчанию: запасы — 90 дней, производство и качество — текущий месяц"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад (для витрин запасов)"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр (для витрины производства)"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько строк вернуть (по умолчанию 25, максимум 200)"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.production",
            "title": "OEE и простои",
            "description": "OEE за период (доступность × производительность × качество) с составляющими, план\/факт по выпуску и времени, Парето простоев по причинам и разрез по рабочим центрам. Значение OEE выше 100 % — признак заниженной нормы, о чём инструмент сообщает в notes.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД), по умолчанию — начало месяца"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр (без него — все)"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.quality",
            "title": "Качество: брак и причины",
            "description": "Доля забракованных контролей против цели, количества брака и карантина, Парето причин и кодов дефектов, разрез по поставщикам и последние месяцы. Доля считается от контролей, а не от выпуска: партии и штуки выпуска не свести без общего ключа.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД), по умолчанию — начало месяца"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько причин и кодов вернуть (по умолчанию 15)"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.purchases",
            "title": "Закупки: сроки и просрочка",
            "description": "Состояние заказов поставщикам, доля просроченных против цели, открытая сумма, списки просроченных и подходящих к сроку заказов с именами поставщиков.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Сколько заказов вернуть в каждом списке (по умолчанию 10)"
                    },
                    "due_days": {
                        "type": "integer",
                        "description": "Горизонт «ближайших сроков», дней (по умолчанию 7)"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.snapshots",
            "title": "Снимки витрин",
            "description": "Список снятых снимков: какие витрины и на какие даты зафиксированы. Снимок не пересчитывается задним числом, поэтому по нему можно спорить о цифре за прошлый период.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "Код витрины: summary, stock, abc, production, quality, purchases"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько снимков вернуть (по умолчанию 25)"
                    }
                },
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.snapshot",
            "title": "Снимок витрины",
            "description": "Снимок целиком: фильтры, результат и — по флагу compare — отличия от предыдущего снимка той же витрины (KPI и итоги, без построчных списков).",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор снимка или его uuid"
                    },
                    "compare": {
                        "type": "boolean",
                        "description": "Показать отличия от предыдущего снимка витрины"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.settings",
            "title": "Пороги витрин",
            "description": "По каким границам аналитика считает «плохо»: целевое покрытие запасов, порог мёртвого запаса, границы ABC и XYZ, цель по OEE, допустимая доля брака и просрочки. Показывает и значения, и допустимые диапазоны.",
            "scope": "erp801.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.export",
            "title": "Выгрузка витрины в CSV",
            "description": "Таблица витрины в CSV (BOM, точка с запятой) — открывается в Excel двойным щелчком. Возвращается текстом: агент сам решает, куда его положить.",
            "scope": "erp801.export",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД). По умолчанию: запасы — 90 дней, производство и качество — текущий месяц"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад (для витрин запасов)"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр (для витрины производства)"
                    },
                    "code": {
                        "type": "string",
                        "description": "Код витрины для выгрузки",
                        "enum": [
                            "summary",
                            "stock",
                            "abc",
                            "production",
                            "quality",
                            "purchases"
                        ]
                    }
                },
                "required": [
                    "code"
                ]
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.save_snapshot",
            "title": "Снять снимок витрины",
            "description": "Фиксирует витрину на дату: фильтры и результат сохраняются в базе и больше не пересчитываются. Повторный вызов создаёт второй снимок — это не «обновить», а «запомнить ещё раз».",
            "scope": "erp801.view",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "from": {
                        "type": "string",
                        "description": "Начало периода (ГГГГ-ММ-ДД). По умолчанию: запасы — 90 дней, производство и качество — текущий месяц"
                    },
                    "to": {
                        "type": "string",
                        "description": "Конец периода (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "warehouse_id": {
                        "type": "integer",
                        "description": "Склад (для витрин запасов)"
                    },
                    "center_id": {
                        "type": "integer",
                        "description": "Рабочий центр (для витрины производства)"
                    },
                    "code": {
                        "type": "string",
                        "description": "Код витрины: summary, stock, abc, production, quality, purchases"
                    },
                    "day": {
                        "type": "string",
                        "description": "День, за который снимается отчёт (ГГГГ-ММ-ДД), по умолчанию сегодня"
                    },
                    "title": {
                        "type": "string",
                        "description": "Название снимка (по умолчанию — витрина и дата)"
                    },
                    "note": {
                        "type": "string",
                        "description": "Примечание: зачем сняли"
                    }
                },
                "required": [
                    "code"
                ]
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.save_settings",
            "title": "Изменить пороги витрин",
            "description": "Меняет пороги, по которым считается «плохо». Значение вне допустимого диапазона не сохраняется: молчаливая правка порога меняет решения, а не только цифры на экране.",
            "scope": "erp801.manage",
            "mutating": true,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "values": {
                        "type": "object",
                        "description": "Пороги: {«cover_target_days»: 30, …}. Пустая строка возвращает значение по умолчанию"
                    }
                },
                "required": [
                    "values"
                ]
            },
            "module": "erp801_analytics"
        },
        {
            "name": "analytics.delete_snapshot",
            "title": "Удалить снимок витрины",
            "description": "Удаляет снимок навсегда. Подтверждает человек: снимок — это «как считалось тогда», и после удаления спор о цифре за прошлый период закрыть нечем.",
            "scope": "erp801.manage",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Идентификатор снимка или его uuid"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp801_analytics"
        },
        {
            "name": "integration.packages",
            "title": "Найти интеграционные пакеты",
            "description": "Статусы входящих пакетов, dry-run, ошибки и счётчики строк. Источник выбирается по понятному коду.",
            "scope": "erp802.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "description": "Статус пакета"
                    },
                    "source_code": {
                        "type": "string",
                        "description": "Код источника: file или 1c"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Лимит",
                        "minimum": 1,
                        "maximum": 200
                    }
                },
                "required": []
            },
            "module": "erp802_integration"
        },
        {
            "name": "integration.package",
            "title": "Протокол интеграционного пакета",
            "description": "Возвращает пакет и диагностику каждой строки по ID, полученному из поиска.",
            "scope": "erp802.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID пакета"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp802_integration"
        },
        {
            "name": "integration.validate_items",
            "title": "Проверить пакет номенклатуры",
            "description": "Без изменений номенклатуры разбирает bounded CSV\/JSON и создаёт построчный dry-run протокол.",
            "scope": "erp802.import",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "source_code": {
                        "type": "string",
                        "description": "Код источника",
                        "enum": [
                            "file",
                            "1c"
                        ]
                    },
                    "format": {
                        "type": "string",
                        "description": "Формат",
                        "enum": [
                            "json",
                            "csv"
                        ]
                    },
                    "content": {
                        "type": "string",
                        "description": "Содержимое до 10 МБ \/ 10000 строк"
                    },
                    "external_batch_id": {
                        "type": "string",
                        "description": "Номер пакета источника"
                    }
                },
                "required": [
                    "source_code",
                    "format",
                    "content"
                ]
            },
            "module": "erp802_integration"
        },
        {
            "name": "integration.import_items",
            "title": "Импортировать номенклатуру",
            "description": "После подтверждения применяет пакет. Коллизии кодов без mapping отвергаются; AI не выбирает запись автоматически.",
            "scope": "erp802.import",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "source_code": {
                        "type": "string",
                        "description": "Код источника",
                        "enum": [
                            "file",
                            "1c"
                        ]
                    },
                    "format": {
                        "type": "string",
                        "description": "Формат",
                        "enum": [
                            "json",
                            "csv"
                        ]
                    },
                    "content": {
                        "type": "string",
                        "description": "Проверенное содержимое пакета"
                    },
                    "external_batch_id": {
                        "type": "string",
                        "description": "Номер пакета источника"
                    }
                },
                "required": [
                    "source_code",
                    "format",
                    "content"
                ]
            },
            "module": "erp802_integration"
        },
        {
            "name": "integration.retry",
            "title": "Повторить ошибочные строки",
            "description": "Контролируемый повтор eligible-строк failed\/partial пакета; требует подтверждения.",
            "scope": "erp802.retry",
            "mutating": true,
            "approval": true,
            "schema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "ID пакета"
                    }
                },
                "required": [
                    "id"
                ]
            },
            "module": "erp802_integration"
        },
        {
            "name": "system.tool.search",
            "title": "Найти нужный инструмент по задаче",
            "description": "ВСЕГДА используйте этот инструмент первым. Опишите обычными словами, что нужно сделать. Он вернёт только 1–5 доступных инструментов, объяснит аргументы и даст готовый вызов system.tool.call на этом же endpoint. Не придумывайте имя инструмента самостоятельно.",
            "scope": "",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Задача обычными словами. Хорошо: «показать остатки ABS на складе». Плохо: одно общее слово «данные»."
                    },
                    "mode": {
                        "type": "string",
                        "description": "Искать чтение, изменение или оба вида. Без явного выбора безопасно ищется только чтение",
                        "enum": [
                            "any",
                            "read",
                            "write"
                        ],
                        "default": "read"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Число кандидатов; обычно достаточно 3",
                        "minimum": 1,
                        "maximum": 5,
                        "default": 3
                    }
                },
                "required": [
                    "query"
                ]
            },
            "module": "erp804_mcp"
        },
        {
            "name": "system.tools.summary",
            "title": "Краткая карта доступных инструментов",
            "description": "Компактная замена большому system.tools.list. Возвращает только общее количество и число доступных инструментов по модулям, не выгружая сотни названий в контекст. После сводки ищите конкретное действие через system.tool.search.",
            "scope": "",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp804_mcp"
        },
        {
            "name": "system.health",
            "title": "Готовность системы",
            "description": "Короткая preflight-проверка БД, MCP-реестра и демо-контура. Возвращает машинный status ready\/degraded до начала сквозного теста.",
            "scope": "",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp804_mcp"
        },
        {
            "name": "system.whoami",
            "title": "Кто я и что мне можно",
            "description": "Возвращает имя ключа агента, его права и признак «только чтение». Полезно первым вызовом, чтобы не пытаться делать запрещённое.",
            "scope": "",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": [],
                "required": []
            },
            "module": "erp804_mcp"
        },
        {
            "name": "system.tools.list",
            "title": "Список инструментов",
            "description": "Каталог инструментов с правами и признаком изменения данных. Можно ограничить одним модулем (erp402, erp119, erp804 …).",
            "scope": "",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "module": {
                        "type": "string",
                        "description": "Модуль-владелец инструментов (erp402, erp119, erp804)"
                    }
                },
                "required": []
            },
            "module": "erp804_mcp"
        },
        {
            "name": "system.call.status",
            "title": "Статус вызова",
            "description": "Что стало с вызовом: выполняется, выполнен, ошибка, ждёт подтверждения человека или отклонён. Нужен после операций, требующих согласования.",
            "scope": "",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "call_id": {
                        "type": "integer",
                        "description": "Номер вызова из ответа tools\/call"
                    }
                },
                "required": [
                    "call_id"
                ]
            },
            "module": "erp804_mcp"
        },
        {
            "name": "system.last_calls",
            "title": "Последние вызовы",
            "description": "Журнал вызовов MCP: кто (ключ), что вызывал, чем закончилось. Помогает разобраться, если агент «что-то сделал».",
            "scope": "erp804_mcp.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "tool_name": {
                        "type": "string",
                        "description": "Фильтр по имени инструмента"
                    },
                    "status": {
                        "type": "string",
                        "description": "Фильтр по статусу",
                        "enum": [
                            "ok",
                            "error",
                            "awaiting_approval",
                            "approved",
                            "rejected",
                            "pending"
                        ]
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Сколько записей вернуть",
                        "minimum": 1,
                        "maximum": 50,
                        "default": 10
                    }
                },
                "required": []
            },
            "module": "erp804_mcp"
        },
        {
            "name": "demo.status",
            "title": "Состояние демо-стенда",
            "description": "Включён ли стенд, собрана ли демо-база, когда и кем собрана, сколько чего в ней. Блок без данных отвечает available=false и причиной, а не нулём.",
            "scope": "erp811.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": []
            },
            "module": "erp811_demo"
        },
        {
            "name": "demo.scenario",
            "title": "Сценарий стенда",
            "description": "Что за производство показывает стенд: компания, детали, материалы, рабочие центры, смены, глубина истории. Нужен, чтобы объяснять цифры витрин словами производства.",
            "scope": "erp811.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": []
            },
            "module": "erp811_demo"
        },
        {
            "name": "demo.tour",
            "title": "Маршрут осмотра",
            "description": "Порядок показа системы: адрес экрана, что на нём видно и какой вопрос к нему задать. Годится и для человека, и для автономной демонстрации роботом.",
            "scope": "erp811.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": []
            },
            "module": "erp811_demo"
        },
        {
            "name": "demo.counts",
            "title": "Сколько данных на стенде",
            "description": "Журнал последней сборки: сколько заказов, операций, контролей, документов и снимков собрано в демо-базе, и какие шаги пропущены.",
            "scope": "erp811.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": []
            },
            "module": "erp811_demo"
        },
        {
            "name": "demo.runs",
            "title": "Журнал сборок стенда",
            "description": "Кто и когда собирал демо-базу, по какому сценарию и с каким составом данных. Нужен, чтобы понимать, насколько свежая демонстрация перед показом.",
            "scope": "erp811.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "limit": {
                        "type": "integer",
                        "description": "Сколько последних сборок вернуть (по умолчанию 10)"
                    }
                }
            },
            "module": "erp811_demo"
        },
        {
            "name": "docs.search",
            "title": "Поиск по документации",
            "description": "Полнотекстовый поиск по процессам, модулям, таблицам БД и инструментам PromERP.",
            "scope": "erp812.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Поисковый запрос (например: склад, mdm_unit, order_create, закупки)"
                    }
                },
                "required": [
                    "query"
                ]
            },
            "module": "erp812_docs"
        },
        {
            "name": "docs.process.get",
            "title": "Получить схему бизнес-процесса",
            "description": "Получить подробную схему и пошаговый регламент сквозного бизнес-процесса PromERP.",
            "scope": "erp812.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "process_id": {
                        "type": "string",
                        "description": "Идентификатор процесса (p2p, o2c, production, wms_flow, maintenance)"
                    }
                },
                "required": [
                    "process_id"
                ]
            },
            "module": "erp812_docs"
        },
        {
            "name": "docs.module.get",
            "title": "Получить карточку модуля",
            "description": "Получить метаданные, маршруты, таблицы БД и MCP инструменты конкретного модуля PromERP.",
            "scope": "erp812.view",
            "mutating": false,
            "approval": false,
            "schema": {
                "type": "object",
                "properties": {
                    "module": {
                        "type": "string",
                        "description": "Имя модуля (например: mdm, orders, warehouse, erp812_docs)"
                    }
                },
                "required": [
                    "module"
                ]
            },
            "module": "erp812_docs"
        }
    ]
}