Продукты: то, что вы производите из материалов. Через API их можно создавать, редактировать и удалять, задавать состав продукта, получать список и данные продукта, обновлять остатки на складах.

Пути методов указаны относительно базового адреса API, а общие для всех методов правила (авторизация, формат запросов, частичное редактирование, постраничная выдача) описаны в статьях [Обзор API](https://developers.controlata.ru/hc/api-docs/articles/overview) и [Общие правила](https://developers.controlata.ru/hc/api-docs/articles/rules).

## Методы

| Метод | Что делает |
|---|---|
| [v1/products/add](https://developers.controlata.ru/hc/api-docs/articles/products-add) | Создает продукт |
| [v1/products/edit](https://developers.controlata.ru/hc/api-docs/articles/products-edit) | Изменяет продукт |
| [v1/products/delete](https://developers.controlata.ru/hc/api-docs/articles/products-delete) | Удаляет продукт |
| [v1/products/update_stock](https://developers.controlata.ru/hc/api-docs/articles/products-update-stock) | Устанавливает остаток на складе |
| [v1/products/get_list](https://developers.controlata.ru/hc/api-docs/articles/products-get-list) | Возвращает продукты склада |
| [v2/products/get_entry](https://developers.controlata.ru/hc/api-docs/articles/products-get-entry) | Возвращает данные продукта и его состав |
| [v1/products/get_stocks](https://developers.controlata.ru/hc/api-docs/articles/products-get-stocks) | Возвращает остатки продуктов по всем складам |

## Поля продукта

| Поле | Тип | Описание |
|---|---|---|
| id | int | ID продукта |
| name | string | Название |
| sku | string | Артикул |
| unit | string | Единица измерения, код из статьи [Единицы измерения](https://developers.controlata.ru/hc/api-docs/articles/units-get-list) |
| price | float | Цена продажи за единицу |
| cost | float | Себестоимость единицы. Рассчитывается Controlata, через API не задается |
| batch_size | float | Размер партии: на какое количество продукта указан состав |
| notes | string | Заметки |
| status | int | Всегда 1: удаленные продукты не возвращаются |
| archived | int | 1, если продукт в архиве |
| categories | array | Категории продукта: id и name |
| suppliers | array | Поставщики продукта: id и name |
| alternative_sku | array | Альтернативные артикулы: label и sku |

Альтернативные артикулы (в Controlata это **Альтернативные SKU**) нужны, когда один продукт продается под разными артикулами, например на разных маркетплейсах. В строках заказов, поставок и других операций продукт ищется сначала по основному артикулу, затем по альтернативным. Поле label: необязательная подпись до 100 символов, sku: артикул от 1 до 50 символов.

## Остатки на складах

Остаток, минимальный остаток и запланированное изменение хранятся отдельно для каждого склада. Поэтому методы, которые их возвращают или меняют, принимают storage_id.

| Поле | Тип | Описание |
|---|---|---|
| stock | float | Остаток на складе |
| minimum | float | Минимальный остаток на складе |
| planned | float | Изменение остатка по операциям в статусе План (производства, поставки, заказы). null, если таких операций нет |

Продукт числится на складе, если у него там есть строка остатка, в том числе с нулевым остатком. Такая строка появляется:

* на складе, указанном при создании продукта;
* на складах, где в настройках продуктов выбрано **Все**, и на складах, чьи категории совпадают с категориями продукта;
* на любом другом складе, когда туда приходит остаток (производство, поставка, перемещение, обновление остатка). Если остаток на таком складе снова становится нулевым, строка удаляется.

Методы get_list и get_entry видят продукт только на тех складах, где у него есть строка остатка.

## Состав продукта

Состав продукта задается на одну партию, то есть на batch_size единиц продукта. Он передается в методы [v1/products/add](https://developers.controlata.ru/hc/api-docs/articles/products-add) и [v1/products/edit](https://developers.controlata.ru/hc/api-docs/articles/products-edit) тремя массивами:

| Поле | Что содержит |
|---|---|
| materials | Материалы |
| products | Заготовки: другие продукты, которые входят в состав |
| resources | Ресурсы: работа, электроэнергия, оборудование, накладные расходы |

### Строки materials и products

| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
| id | int | Да | ID материала или продукта |
| amount_per_batch | float | Да | Количество на партию, больше 0 |
| unit | string | Да | Единица строки. Должна быть из той же группы, что единица материала или продукта: для материала в «кг» подойдут «кг» или «г» |
| loss_percent | float | Нет | Потери в процентах: от 0 до 100, не включая 100. По умолчанию 0 |
| position | int | Нет | Порядковый номер строки в составе |

Материалы и заготовки идут в составе общим списком, поэтому position у них общий. Строки с position сортируются по нему. Строки без position идут после них в порядке передачи: сначала materials, затем products. Controlata нумерует строки заново с 0, поэтому в ответе position может отличаться от переданного.

Продукт не может входить в состав самого себя. Повторы не проверяются: один и тот же материал можно добавить в состав дважды.

### Строки resources

| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
| id | int | Да | ID ресурса |
| amount_per_batch | float | Зависит от типа ресурса | Количество, сумма или процент на партию |
| unit | string | Зависит от типа ресурса | Единица из той же группы, что единица ресурса |

Что передавать, зависит от типа ресурса (подробнее о типах в статье [Ресурсы](https://developers.controlata.ru/hc/api-docs/articles/resources)):

| Тип ресурса | amount_per_batch | unit |
|---|---|---|
| Фиксированная ставка | Количество на партию, например часы работы | Нужна |
| Фиксированная ставка, цена указывается в составе продукта | Сумма на партию в рублях | Не нужна |
| Процент | Не нужен: процент берется из ресурса | Не нужна |
| Процент, указывается в составе продукта | Процент, больше 0 и не больше 100 | Не нужна |
| Амортизация | Количество на партию, например часы работы оборудования | Нужна |

Ресурсы идут в том порядке, в каком переданы. Поле position в строках ресурсов не учитывается.

### Как передается состав

* Количества указываются на партию. Расход на единицу продукта Controlata считает сама: amount_per_batch / batch_size. Процент процентного ресурса от размера партии не зависит.
* Массивы заменяют состав целиком. Если передан хотя бы один из массивов materials и products, материалы и заготовки заменяются полностью, а непереданный массив считается пустым. Ресурсы меняются, только если передан resources.
* Чтобы очистить состав, передайте пустой массив.
* Строки состава из ответа [v2/products/get_entry](https://developers.controlata.ru/hc/api-docs/articles/products-get-entry) можно отправить в add и edit без изменений: лишние поля (name, cost_per_batch и другие) игнорируются.

### Ошибки в строках состава

В тексте ошибки вместо 2051 будет ID позиции, а вместо 0 номер строки в массиве (с 0).

| Ошибка | Причина |
|---|---|
| Materials is not an array | materials передан не массивом (так же для products и resources) |
| Line 0 of materials must be an object | Строка не объект (так же для products и resources) |
| No id for material 0 | Не передан id материала или он не число (так же для product) |
| Material 2051 not found | Материал не найден или удален |
| Product 2051 not found | Продукт не найден или удален |
| Product cannot be a component of itself | Продукт добавлен в собственный состав |
| Amount per batch must be greater than 0 for material 2051 | Количество не передано, не число или после округления до 3 знаков равно 0 (так же для product и resource) |
| Unit not found for material 2051. Use a unit of the same group as the material unit | Единица не передана, неизвестна или из другой группы (так же для product) |
| Loss percent must be from 0 to 100 for material 2051 | Потери меньше 0, не меньше 100 или не число (так же для product) |
| Resource for line 0 not found | Ресурс не найден или удален |
| Percent must not exceed 100 for resource 2051 | Процент в составе больше 100 |
| Unit not found for resource 2051. Use a unit of the same group as the resource unit | Единица ресурса не передана, неизвестна или из другой группы |

## Себестоимость

Себестоимость единицы продукта (cost) Controlata рассчитывает по составу:

* материалы: по цене материала с учетом потерь;
* заготовки: по их себестоимости с учетом потерь;
* фиксированная ставка и амортизация: по цене ресурса за единицу;
* процентные ресурсы: процент от себестоимости без процентных ресурсов или от цены продажи, в зависимости от базы расчета ресурса.

Себестоимость пересчитывается при изменении состава, размера партии и цены продажи продукта, а также цен материалов и ресурсов и себестоимости заготовок. У продукта без состава себестоимость берется из поставок этого продукта, а до первой поставки равна 0.
