Skip to content

Импорт оборудования из Excel ​

Чтобы не собирать список оборудования руками, его можно загрузить из .xlsx прямо в проект. Импорт создаёт проектную заявку на оборудование из строк файла, сопоставляя каждую строку с каталогом по названию и автоматически создавая недостающие позиции.

Эндпоинты ​

МетодПутьНазначение
GET/api/v1/projects/{id}/equipment-requests/import/templateСкачать .xlsx-шаблон с примером.
POST/api/v1/projects/{id}/equipment-requests/importЗагрузить заполненный .xlsx.

Доступ — как к логистическому разделу проекта (та же проверка, что и у создания заявки на оборудование вручную).

Формат файла ​

Первая строка — заголовки, далее строки данных. Колонки (порядок свободный, заголовки сопоставляются гибко, рус/англ):

ЗаголовокОбязателенПримерПоле заявки
НазваниедаAcer Nitro 5 AN515-44-R34Jсопоставление
Цена / день / Цена в проектенет5500 или 5 500 ₽unit_price
Кол-вода1requested_qty
Днейнет1 (по умолчанию 1)rental_days

Числа терпимы к рублёвому символу, пробелам-разделителям тысяч и запятой как десятичному разделителю. Полностью пустые строки пропускаются.

Цена в проекте vs цена каталога ​

Цена из Excel — это «цена в проекте» (unit_price): она переопределяет базовую цену из каталога при расчёте сметы позиции. Если колонка пуста, в расчёте используется базовая цена каталога (equipment.cost). При авто-создании позиции цена из Excel становится и базовой ценой новой позиции каталога. То же поле unit_price можно передать при ручном добавлении позиции (POST .../equipment-requests).

Логика сопоставления ​

Для каждой строки:

  1. Поиск активной позиции каталога по названию (без учёта регистра и пробелов).
  2. Если найдено — используется существующая позиция (matched).
  3. Если не найдено — создаётся новая позиция каталога из названия и цены за день (created_equipment), категория — «Импорт».

Дубликаты (одна и та же позиция в нескольких строках) отбрасываются с ошибкой строки.

Отчёт об импорте ​

Ответ — отчёт, а не «тихая» загрузка: видно, что сопоставлено, что создано и какие строки не прошли.

json
{
  "project_id": 7,
  "matched": 1,
  "created_equipment": 1,
  "items": [
    { "row": 2, "name": "Acer Nitro 5", "equipment_id": 1, "created_equipment": false, "requested_qty": 1, "rental_days": 1 },
    { "row": 3, "name": "HDMI кабель",  "equipment_id": 42, "created_equipment": true,  "requested_qty": 5, "rental_days": 1 }
  ],
  "errors": [
    { "row": 4, "message": "quantity must be positive" }
  ],
  "request": { "id": 10, "name": "Импорт оборудования", "items": [ /* ... */ ] }
}
  • При наличии хотя бы одной валидной строки создаётся заявка (request), HTTP 201.
  • Если валидных строк нет — request отсутствует, возвращаются только errors, HTTP 200.
  • Стоимость позиций считается штатной тарифной логикой заявки (estimateRentalCost), как и при ручном добавлении.

Итоги заявки (totals) — считает сервер ​

Заявка (request, а также GET /equipment-requests/:id и список с include_items=true) несёт блок totals — готовый расчёт «Базовая сумма / Наценка / НДС / Итого» по действующему НДС проекта и наценке бюджета. Фронт ничего не пересчитывает:

json
"totals": {
  "base": 5500.00,            // Базовая сумма (Σ estimated_cost)
  "markup_percent": 0,
  "markup_amount": 0.00,      // Сумма наценки
  "vat_mode": "included",
  "vat_rate": 22,
  "vat_amount": 916.67,       // Сумма НДС
  "total_net": 4583.33,
  "total_with_vat": 5500.00   // Итоговая сумма
}

Арифметика — та же, что в сводке бюджета (money.ComputeVAT), копейка-в-копейку. Для заявок без проекта vat_mode = "none", наценка 0.

Если нужен только расчёт без полного тела заявки — есть лёгкий эндпоинт:

GET /api/v1/equipment-requests/{id}/totals   → объект totals

Где смотреть в коде ​

  • Парсер и сервис импорта: internal/modules/equipmentrequests/import.go.
  • Порт к каталогу (EquipmentCatalog) и адаптер: import.go + internal/app/equipment_catalog_adapter.go.
  • Сопоставление по названию: internal/modules/equipment/ (FindByName / FindActiveByName).
  • HTTP-обработчики: internal/modules/equipmentrequests/transport_http.go (Import, ImportTemplate).
  • Парсинг .xlsx — github.com/xuri/excelize/v2.

Загружаем документацию…