Товары и запчасти в акте
Все операции. Авторизация. Запросы и повторы.
Все пути в этом файле дополняют /api/v1 на домене организации.
Описание и ограничения
Назначение
Товары и запчасти в акте, включая материалы конкретной единицы ТО, их резервирование и списание.
Доступные возможности и ограничения
При завершении акта строки с equipment_id и типом товара component, license или certificate добавляют соответствующее оснащение на оборудование. Для выданных серийных экземпляров создаются отдельные записи, для остальных — общая запись по строке. Материал, который не учитывается как оснащение, только участвует в выполнении ТО. Возврат акта в работу снимает созданное им оснащение и согласует складские изменения. В meta.affected_resources перечисляются фактически изменённые записи; для удалённых записей передаётся признак удаления. Повтор запроса не создаёт оснащение или события повторно.
Переход с привязкой проверяет текущие товар, оборудование, клиента и объект оборудования; для заявки также проверяются её акт, оборудование и мастерская. Нужны products:read, equipment:read/write и текущие права этих ресурсов; создание или снятие оснащения дополнительно требует equipment_assignments:read/write. Привязка заявки требует maintenance_schedules:read; эффекты самого ТО имеют дополнительные права по контракту перехода акта. Эти зависимости сохраняются и повторно проверяются при повторе запроса. Изменение исходного оборудования/товара назначения или клиента/объекта оборудования после операции закрывает доступ к старой записи об операции.
История продления лицензии и документальной выдачи сохраняется: если назначение уже связано с такой историей, переход, который должен его переписать или удалить, возвращает 409 ASSIGNMENT_HISTORY_LOCKED с полным откатом. Актуальный товар, у которого после добавления строки отключили допустимый тип назначения, возвращает 409 ACT_PRODUCT_ASSIGNMENT_INVALID при завершении. Правила переходов с финансовыми документами, проектом и гарантийной цепочкой описаны отдельно в актах.
inventory_effect и reservation_state показывают подтверждённые факты строки. Чтение строки прежнего режима учёта без построчного доказательства списания возвращает mode=legacy, reservation_state=unknown, written_off_quantity="0" и requires_reconciliation=true. Ноль означает отсутствие подтверждённого количества, а физическое списание остаётся неизвестным. Успешный HTTP и текущее количество строки сами по себе не доказывают складское движение.
Запись об операции новой команды прежнего режима учёта сохраняет фактически выполненное этой командой списание; повтор возвращает исходный результат и не меняет складские остатки. Для изменения количества в прежнем режиме учёта это фактически списанная положительная разница, а не восстановленная история всей строки. Последующее GET не угадывает историю из записи об операции с ограниченным сроком хранения. При изменении описательных полей без нового складского эффекта неизвестное состояние прежнего режима учёта сопровождается STOCK_RECONCILIATION_REQUIRED.
Ручная цена и скидка используют обычное право «Акты приёма оборудования → Изменение». Внутренние price, measure_id, stock_id, reserved и параметры обхода складской политики не входят во список разрешённых полей.
Поля и назначение
| Публичное поле | Формат и смысл | Доступ |
|---|---|---|
id |
id строки |
только чтение |
product_id |
обязательный id товара |
чтение и запись |
quantity |
положительная десятичная строка | чтение и запись |
unit_id |
код единицы | чтение и запись |
unit_price, discount, markup_id |
денежная цена за единицу, денежная скидка на всю строку и ID наценки/null | чтение и запись |
serial_number, note |
строки/null | чтение и запись |
maintenance_schedule_id, equipment_id |
связи с заявкой и единицей | чтение и запись |
reservation_state |
вычисляемое состояние | только чтение |
inventory_effect |
mode, reserved_quantity, written_off_quantity, shortage_quantity, requires_reconciliation |
только чтение |
Обязательность и null указаны в схемах каждой операции ниже.
Доступ и выборка
acts:read/write и право работы с актом/выбранным складом; изменение цены и скидки требует обычного права изменения акта.
Запрос и складской результат
Для создания требуются product_id и quantity (положительная десятичная строка). Отсутствующие unit_price/discount рассчитываются штатным ценообразованием строки акта от продажной цены каталога с учётом договора/клиентской скидки; markup_id=null по умолчанию. Итоговые цена и скидка фиксируются при принятии и возвращаются в ответе. Ручные значения требуют обычного права изменения акта. unit_id согласуется с товаром/позицией выбранного склада, не меняет её единицу измерения. discount — сумма на всю строку после умножения quantity на unit_price, не процент. Недопустимая точность, отрицательная скидка или превышение стоимости строки — 422. Склад берётся из акта, подмена через дополнительный stock_id запрещена.
Для создания нужен If-Resource-Version акта; для изменения и удаления — версия самой строки. Создание возвращает 201, изменение — 200 с карточкой и inventory_effect, удаление — 200 с признаком удаления. reservation_state и inventory_effect показывают подтверждённые резервы и движения; успешного HTTP-ответа для вывода о списании недостаточно. Количества передаются десятичными строками. Допустимые значения mode: soft_hold, immediate_write_off, legacy, none. Поле requires_reconciliation — логическое значение.
| Штатный режим | Нехватка | Результат API |
|---|---|---|
| Складской учёт выключен или у акта нет активного склада | Складская операция не выполняется | mode=none, количества эффекта "0", requires_reconciliation=false; сохранение строки не выдаётся за движение |
| Открытый акт, отложенное списание: hold | Мягкая бронь полного запрошенного количества разрешена | Строка сохранена; 201/200 и предупреждение STOCK_SHORTAGE; физического списания пока нет |
| Строгое резервирование | Доступного количества недостаточно | 409 INSUFFICIENT_STOCK; все изменения команды отменяются |
| Немедленное списание по партионному учёту | negative_policy=allow_warn разрешает минус; block запрещает | Allow_warn: движение и предупреждение STOCK_NEGATIVE; block: 409 INSUFFICIENT_STOCK с откатом |
| Завершение акта с учётом партий | Применяются действующие правила нехватки | Если акт завершён с проблемой списания, ответ содержит 200, STOCK_RECONCILIATION_REQUIRED, requires_reconciliation=true и фактические количества. Недоступный серийный номер или код маркировки отклоняет весь переход |
| Учёт без партий | Физического остатка недостаточно | 409 INSUFFICIENT_STOCK; отрицательный остаток не допускается. Если копирование не выполняет повторное движение, строка сохраняется с STOCK_MOVEMENT_NOT_APPLIED |
| Уникальный серийный номер/маркировка | Выбранный экземпляр недоступен/занят | 409 SERIAL_UNAVAILABLE / MARKING_UNAVAILABLE; это не мягкое предупреждение |
API не позволяет переопределять правила склада. Предупреждение содержит code, message и resource_refs. В data.inventory_effect отдельно возвращаются reserved_quantity, written_off_quantity и shortage_quantity. При повторе запроса сохраняются исходные предупреждения. Эти правила действуют также для товаров, добавленных комплектом, копированием акта или монтажом.
Правила и связи
- Добавление и изменение товара согласует его количество, резервирование и списание по действующим правилам склада.
- Нельзя зарезервировать один серийный номер для двух конкурирующих операций.
- Удаление строки учитывает связанные резервы и установленное оснащение.
- Физический остаток, резерв и фактическое списание отражаются раздельно.
Операции
| Метод | Путь | Назначение |
|---|---|---|
| GET | /acts/{act_id}/products |
Список с фильтрами и пагинацией |
| POST | /acts/{act_id}/products |
Создание |
| GET | /acts/{act_id}/products/{id} |
Карточка |
| POST | /acts/{act_id}/products/{id}/update |
Изменение разрешённых полей |
| POST | /acts/{act_id}/products/{id}/delete |
Удаление с проверкой зависимостей |
GET /acts/{act_id}/products
Список с фильтрами и пагинацией.
Доступ. Разрешения подключения: acts:read. Права сотрудника: «Акты приёма оборудования → Просмотр». Дополнительно действуют доступ к записям, мастерским, модулям и условия полей из описания ресурса выше.
Параметры
| Имя | Где | Тип | Обязательно | null | Ограничения |
|---|---|---|---|---|---|
Authorization |
заголовок | строка | да | нет | Bearer <SERVICEAPP_TOKEN> |
act_id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
sort |
параметр запроса | строка | нет | нет | Допустимо: "id", "-id", "updated_at,id", "-updated_at,-id" |
page[size] |
параметр запроса | целое число | нет | нет | ≥ 1; ≤ 100 |
page[cursor] |
параметр запроса | строка | нет | нет | не более 8192 символов |
Ответы
| HTTP | Назначение и схема |
|---|---|
| 200 | Успех. Полная схема и пример |
| 401 | Требуется действующий Bearer. Коды и формат ошибки |
| 403 | Недостаточно допуска. Коды и формат ошибки |
| 404 | Не найдено или недоступно. Коды и формат ошибки |
| 409 | Конфликт состояния или повтора. Коды и формат ошибки |
| 422 | Ошибка входных данных. Коды и формат ошибки |
| 429 | Лимит запросов, Retry-After. Коды и формат ошибки |
| 503 | Временно недоступно. Коды и формат ошибки |
Каждый ответ содержит новый X-Request-Id в заголовке. Общие транспортные отказы и правила повтора действуют также при отказе до контроллера; см. ошибки.
Пример запроса
Запускается из каталога комплекта после настройки переменных в быстром старте. Замените демонстрационные идентификаторы 101 и UUID идентификаторами доступных записей. $RESOURCE_VERSION берётся из GET владельца версии, описанного выше. Для нового действия сохраните новый ключ; для повтора используйте прежний.
curl --silent --show-error --globoff \
"$API/acts/101/products" \
--header "Authorization: Bearer $SERVICEAPP_TOKEN" \
--header "Accept: application/json"
POST /acts/{act_id}/products
Создание.
Доступ. Разрешения подключения: acts:write. Права сотрудника: «Акты приёма оборудования → Изменение», «Акты приёма оборудования → Просмотр». Дополнительно действуют доступ к записям, мастерским, модулям и условия полей из описания ресурса выше.
Параметры
| Имя | Где | Тип | Обязательно | null | Ограничения |
|---|---|---|---|---|---|
Authorization |
заголовок | строка | да | нет | Bearer <SERVICEAPP_TOKEN> |
act_id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
Idempotency-Key |
заголовок | строка | да | нет | не менее 1 символов; не более 128 символов; Шаблон: ^[A-Za-z0-9._:-]+$ |
If-Resource-Version |
заголовок | строка | да | нет | не менее 1 символов; не более 128 символов; Шаблон: ^[A-Za-z0-9._~-]+$ |
Тело запроса
Content-Type: application/json. Тело обязательно.
| Поле | Тип | Обязательно | null | Ограничения и смысл |
|---|---|---|---|---|
product_id |
целое число | да | нет | ≥ 1 |
quantity |
строка | да | нет | Шаблон: ^(?:0|[1-9][0-9]{0,8})(?:\.[0-9]{1,3})?$ |
unit_id |
целое число | нет | нет | Допустимо: 0, 12, 1, 11, 10, 2, 3, 4, 5, 6, 7, 8, 9 |
note |
строка / null | нет | да | не более 10000 символов |
serial_number |
строка / null | нет | да | не более 10000 символов |
markup_id |
целое число / null | нет | да | ≥ 1 |
maintenance_schedule_id |
целое число / null | нет | да | ≥ 1 |
equipment_id |
целое число / null | нет | да | ≥ 1 |
unit_price |
объект | нет | нет | Только перечисленные ключи |
unit_price.amount |
строка | да | нет | Шаблон: ^(?:0|[1-9][0-9]{0,15})(?:\.[0-9]{1,4})?$; Условие: required_with:unit_price |
unit_price.currency |
строка | да | нет | не менее 3 символов; не более 3 символов; Условие: required_with:unit_price |
discount |
объект | нет | нет | Только перечисленные ключи |
discount.amount |
строка | да | нет | Шаблон: ^(?:0|[1-9][0-9]{0,15})(?:\.[0-9]{1,4})?$; Условие: required_with:discount |
discount.currency |
строка | да | нет | не менее 3 символов; не более 3 символов; Условие: required_with:discount |
Ответы
| HTTP | Назначение и схема |
|---|---|
| 201 | Создано. Полная схема и пример |
| 400 | Некорректный запрос. Коды и формат ошибки |
| 401 | Требуется действующий Bearer. Коды и формат ошибки |
| 403 | Недостаточно допуска. Коды и формат ошибки |
| 404 | Не найдено или недоступно. Коды и формат ошибки |
| 409 | Конфликт состояния или повтора. Коды и формат ошибки |
| 412 | Версия устарела. Коды и формат ошибки |
| 413 | Превышен размер. Коды и формат ошибки |
| 415 | Неподдерживаемый Content-Type. Коды и формат ошибки |
| 422 | Ошибка входных данных. Коды и формат ошибки |
| 428 | Нужно предусловие версии. Коды и формат ошибки |
| 429 | Лимит запросов, Retry-After. Коды и формат ошибки |
| 500 | Внутренняя ошибка, исход нужно уточнить. Коды и формат ошибки |
| 503 | Временно недоступно. Коды и формат ошибки |
| HTTP | Заголовок ответа | Тип | Описание |
|---|---|---|---|
| 201 | Location |
строка |
Каждый ответ содержит новый X-Request-Id в заголовке. Общие транспортные отказы и правила повтора действуют также при отказе до контроллера; см. ошибки.
У принятого POST Location и meta.operation_id указывают на журнал операции; ETag отсутствует. При повторе запроса сохраняются исходные data/meta, добавляется Idempotency-Replayed: true. Версии передавайте по назначению, указанному в описании ресурса.
Пример запроса
Запускается из каталога комплекта после настройки переменных в быстром старте. Замените демонстрационные идентификаторы 101 и UUID идентификаторами доступных записей. $RESOURCE_VERSION берётся из GET владельца версии, описанного выше. Для нового действия сохраните новый ключ; для повтора используйте прежний.
curl --silent --show-error --globoff --request POST \
"$API/acts/101/products" \
--header "Authorization: Bearer $SERVICEAPP_TOKEN" \
--header "Accept: application/json" \
--header "Idempotency-Key: example:v1-act-products-store:001" \
--header "If-Resource-Version: $RESOURCE_VERSION" \
--header "Content-Type: application/json" \
--data-binary '@examples/requests/v1.act-products.store.json'
GET /acts/{act_id}/products/{id}
Карточка.
Доступ. Разрешения подключения: acts:read. Права сотрудника: «Акты приёма оборудования → Просмотр». Дополнительно действуют доступ к записям, мастерским, модулям и условия полей из описания ресурса выше.
Параметры
| Имя | Где | Тип | Обязательно | null | Ограничения |
|---|---|---|---|---|---|
Authorization |
заголовок | строка | да | нет | Bearer <SERVICEAPP_TOKEN> |
act_id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
If-None-Match |
заголовок | строка | нет | нет | — |
Ответы
| HTTP | Назначение и схема |
|---|---|
| 200 | Успех. Полная схема и пример |
| 304 | Представление не изменилось, без тела. Условный GET |
| 401 | Требуется действующий Bearer. Коды и формат ошибки |
| 403 | Недостаточно допуска. Коды и формат ошибки |
| 404 | Не найдено или недоступно. Коды и формат ошибки |
| 422 | Ошибка входных данных. Коды и формат ошибки |
| 429 | Лимит запросов, Retry-After. Коды и формат ошибки |
| 503 | Временно недоступно. Коды и формат ошибки |
| HTTP | Заголовок ответа | Тип | Описание |
|---|---|---|---|
| 200 | ETag |
строка | |
| 304 | ETag |
строка |
Каждый ответ содержит новый X-Request-Id в заголовке. Общие транспортные отказы и правила повтора действуют также при отказе до контроллера; см. ошибки.
Пример запроса
Запускается из каталога комплекта после настройки переменных в быстром старте. Замените демонстрационные идентификаторы 101 и UUID идентификаторами доступных записей. $RESOURCE_VERSION берётся из GET владельца версии, описанного выше. Для нового действия сохраните новый ключ; для повтора используйте прежний.
curl --silent --show-error --globoff \
"$API/acts/101/products/101" \
--header "Authorization: Bearer $SERVICEAPP_TOKEN" \
--header "Accept: application/json"
POST /acts/{act_id}/products/{id}/update
Изменение разрешённых полей.
Доступ. Разрешения подключения: acts:write. Права сотрудника: «Акты приёма оборудования → Изменение», «Акты приёма оборудования → Просмотр». Дополнительно действуют доступ к записям, мастерским, модулям и условия полей из описания ресурса выше.
Параметры
| Имя | Где | Тип | Обязательно | null | Ограничения |
|---|---|---|---|---|---|
Authorization |
заголовок | строка | да | нет | Bearer <SERVICEAPP_TOKEN> |
act_id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
Idempotency-Key |
заголовок | строка | да | нет | не менее 1 символов; не более 128 символов; Шаблон: ^[A-Za-z0-9._:-]+$ |
If-Resource-Version |
заголовок | строка | да | нет | не менее 1 символов; не более 128 символов; Шаблон: ^[A-Za-z0-9._~-]+$ |
Тело запроса
Content-Type: application/json. Тело обязательно.
| Поле | Тип | Обязательно | null | Ограничения и смысл |
|---|---|---|---|---|
product_id |
целое число | нет | нет | ≥ 1 |
quantity |
строка | нет | нет | Шаблон: ^(?:0|[1-9][0-9]{0,8})(?:\.[0-9]{1,3})?$ |
unit_id |
целое число | нет | нет | Допустимо: 0, 12, 1, 11, 10, 2, 3, 4, 5, 6, 7, 8, 9 |
note |
строка / null | нет | да | не более 10000 символов |
serial_number |
строка / null | нет | да | не более 10000 символов |
markup_id |
целое число / null | нет | да | ≥ 1 |
maintenance_schedule_id |
целое число / null | нет | да | ≥ 1 |
equipment_id |
целое число / null | нет | да | ≥ 1 |
unit_price |
объект | нет | нет | Только перечисленные ключи |
unit_price.amount |
строка | да | нет | Шаблон: ^(?:0|[1-9][0-9]{0,15})(?:\.[0-9]{1,4})?$; Условие: required_with:unit_price |
unit_price.currency |
строка | да | нет | не менее 3 символов; не более 3 символов; Условие: required_with:unit_price |
discount |
объект | нет | нет | Только перечисленные ключи |
discount.amount |
строка | да | нет | Шаблон: ^(?:0|[1-9][0-9]{0,15})(?:\.[0-9]{1,4})?$; Условие: required_with:discount |
discount.currency |
строка | да | нет | не менее 3 символов; не более 3 символов; Условие: required_with:discount |
Ответы
| HTTP | Назначение и схема |
|---|---|
| 200 | Успех. Полная схема и пример |
| 400 | Некорректный запрос. Коды и формат ошибки |
| 401 | Требуется действующий Bearer. Коды и формат ошибки |
| 403 | Недостаточно допуска. Коды и формат ошибки |
| 404 | Не найдено или недоступно. Коды и формат ошибки |
| 409 | Конфликт состояния или повтора. Коды и формат ошибки |
| 412 | Версия устарела. Коды и формат ошибки |
| 413 | Превышен размер. Коды и формат ошибки |
| 415 | Неподдерживаемый Content-Type. Коды и формат ошибки |
| 422 | Ошибка входных данных. Коды и формат ошибки |
| 428 | Нужно предусловие версии. Коды и формат ошибки |
| 429 | Лимит запросов, Retry-After. Коды и формат ошибки |
| 500 | Внутренняя ошибка, исход нужно уточнить. Коды и формат ошибки |
| 503 | Временно недоступно. Коды и формат ошибки |
| HTTP | Заголовок ответа | Тип | Описание |
|---|---|---|---|
| 200 | Location |
строка |
Каждый ответ содержит новый X-Request-Id в заголовке. Общие транспортные отказы и правила повтора действуют также при отказе до контроллера; см. ошибки.
У принятого POST Location и meta.operation_id указывают на журнал операции; ETag отсутствует. При повторе запроса сохраняются исходные data/meta, добавляется Idempotency-Replayed: true. Версии передавайте по назначению, указанному в описании ресурса.
Пример запроса
Запускается из каталога комплекта после настройки переменных в быстром старте. Замените демонстрационные идентификаторы 101 и UUID идентификаторами доступных записей. $RESOURCE_VERSION берётся из GET владельца версии, описанного выше. Для нового действия сохраните новый ключ; для повтора используйте прежний.
curl --silent --show-error --globoff --request POST \
"$API/acts/101/products/101/update" \
--header "Authorization: Bearer $SERVICEAPP_TOKEN" \
--header "Accept: application/json" \
--header "Idempotency-Key: example:v1-act-products-update:001" \
--header "If-Resource-Version: $RESOURCE_VERSION" \
--header "Content-Type: application/json" \
--data-binary '@examples/requests/v1.act-products.update.json'
POST /acts/{act_id}/products/{id}/delete
Удаление с проверкой зависимостей.
Доступ. Разрешения подключения: acts:write. Права сотрудника: «Акты приёма оборудования → Изменение». Дополнительно действуют доступ к записям, мастерским, модулям и условия полей из описания ресурса выше.
Параметры
| Имя | Где | Тип | Обязательно | null | Ограничения |
|---|---|---|---|---|---|
Authorization |
заголовок | строка | да | нет | Bearer <SERVICEAPP_TOKEN> |
act_id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
id |
путь | строка | да | нет | Шаблон: ^(?:[0-9]+)$ |
Idempotency-Key |
заголовок | строка | да | нет | не менее 1 символов; не более 128 символов; Шаблон: ^[A-Za-z0-9._:-]+$ |
If-Resource-Version |
заголовок | строка | да | нет | не менее 1 символов; не более 128 символов; Шаблон: ^[A-Za-z0-9._~-]+$ |
Тело запроса
Content-Type: application/json. Тело обязательно.
Тело — пустой JSON-объект {}. Другие ключи не принимаются.
Ответы
| HTTP | Назначение и схема |
|---|---|
| 200 | Успех. Полная схема и пример |
| 400 | Некорректный запрос. Коды и формат ошибки |
| 401 | Требуется действующий Bearer. Коды и формат ошибки |
| 403 | Недостаточно допуска. Коды и формат ошибки |
| 404 | Не найдено или недоступно. Коды и формат ошибки |
| 409 | Конфликт состояния или повтора. Коды и формат ошибки |
| 412 | Версия устарела. Коды и формат ошибки |
| 413 | Превышен размер. Коды и формат ошибки |
| 415 | Неподдерживаемый Content-Type. Коды и формат ошибки |
| 422 | Ошибка входных данных. Коды и формат ошибки |
| 428 | Нужно предусловие версии. Коды и формат ошибки |
| 429 | Лимит запросов, Retry-After. Коды и формат ошибки |
| 500 | Внутренняя ошибка, исход нужно уточнить. Коды и формат ошибки |
| 503 | Временно недоступно. Коды и формат ошибки |
| HTTP | Заголовок ответа | Тип | Описание |
|---|---|---|---|
| 200 | Location |
строка |
Каждый ответ содержит новый X-Request-Id в заголовке. Общие транспортные отказы и правила повтора действуют также при отказе до контроллера; см. ошибки.
У принятого POST Location и meta.operation_id указывают на журнал операции; ETag отсутствует. При повторе запроса сохраняются исходные data/meta, добавляется Idempotency-Replayed: true. Версии передавайте по назначению, указанному в описании ресурса.
Пример запроса
Запускается из каталога комплекта после настройки переменных в быстром старте. Замените демонстрационные идентификаторы 101 и UUID идентификаторами доступных записей. $RESOURCE_VERSION берётся из GET владельца версии, описанного выше. Для нового действия сохраните новый ключ; для повтора используйте прежний.
curl --silent --show-error --globoff --request POST \
"$API/acts/101/products/101/delete" \
--header "Authorization: Bearer $SERVICEAPP_TOKEN" \
--header "Accept: application/json" \
--header "Idempotency-Key: example:v1-act-products-delete:001" \
--header "If-Resource-Version: $RESOURCE_VERSION" \
--header "Content-Type: application/json" \
--data-binary '@examples/requests/v1.act-products.delete.json'