Skip to content

Смета проекта ​

Смета — единственный источник цены проекта для клиента: версии со статусами, разделы, строки с себестоимостью и ценой, один расчёт на сервере (модуль internal/modules/estimates, миграция 0166). ТЗ и план: estimate-budget-documents-spec.md, этап 3.

В интерфейсе: карточка проекта → «ТЗ и смета» → Смета (рядом «ТЗ» и «Бюджет»).

Версии и статусы ​

СтатусЧто значитКуда дальше
draft черновикправится: строки, разделы, наценка, скидки, налоги, «Собрать смету»sent, approved
sent отправлена клиентуитоги сохранены снимком (totals)approved, changes_requested, draft (вернуть в работу)
approved согласованадействующая смета проекта— (новая согласованная уводит её в archived)
changes_requested нужны измененияверсия закрытановая версия из неё
archived архивпрежняя согласованная—
  • Черновик у проекта один (409 estimate_draft_exists); новая версия — копия любой версии (from_id) или пустая смета со стандартными разделами.
  • Согласование: снимок итогов, прежняя согласованная → архив, плановый бюджет проекта = итог сметы для клиента (projects.planned_budget).
  • Пустую смету (итог 0) не отправляют и не согласуют (400 estimate_empty). Закрытый проект смету не меняет.
  • Действующая смета: согласованная, иначе последняя не в архиве (GET /projects/:id/estimates/current).

Расчёт ​

Множитель периода    = дни аренды со скидкой за длительность | дни | часы | 1
Себестоимость строки = кол-во × множитель × себестоимость за единицу
Цена строки          = кол-во × множитель × цена для клиента за единицу
                       (цена не задана → себестоимость × (1 + наценка сметы), до рубля)
Раздел               = Σ цен строк − скидка раздела (процент или сумма)
Сумма                = Σ разделов − скидка сметы
УСН                  = Сумма × УСН %
НДС                  = (Сумма + УСН) × ставка — сверху (on_top) или «в том числе» (included)
Итого клиенту        = Сумма + УСН + НДС сверху
Маржа                = Сумма − Σ себестоимостей

Пример заказчика: 1 000 → УСН 10 % = 1 100 → НДС 5 % от 1 100 = 1 155 (calc_test.go).

  • Скидка аренды за длительность — одна формула на всю систему (money.RentalDayMultiplier): 1-й день ×1, дни 2–5 ×0,5, 6–10 ×0,3, 11–15 ×0,15, дальше ×0,1. Ей же считают заявки на оборудование.
  • Наценка одна на смету и клиенту не видна: она внутри цен строк без своей цены. Строка с заданной ценой наценку не получает.
  • Внутренняя строка (is_internal) — только себестоимость: субаренда и закупка своего оборудования, резерв на риски. Клиент её не видит и не платит.
  • Налоги новой сметы — от продавца: переопределение НДС проекта, иначе режим юрлица-продавца (плательщик проекта, иначе основной набор «Моей компании»); УСН — у реквизитов юрлица (requisites.usn_percent), иначе из настроек бюджета; наценка — из настроек бюджета. В смете налоги и продавца можно поменять.

«Собрать смету» ​

POST /estimates/:id/collect — apply=false возвращает разницу (добавится, изменится, уберётся, исправлено вручную), apply=true применяет.

РазделИсточникСебестоимостьЦена
Оборудованиепотребность проекта (project_equipment_requirements)0 (своё)цена проекта или каталога за день × дни аренды со скидкой × кол-во
Оборудованиесубаренда и закупка — плановые статьи логистики (logistic_operation_supply)плановая стоимостьвнутренняя строка
Оборудованиеразбор ТЗ помощником — позиции каталога, которых нет в потребности; не найденные — строкой без цены0цена каталога, 1 день
Перевозкиплановые статьи операций логистикиплановая стоимостьс наценкой
Командировкиплановые статьи командировокплановая стоимостьс наценкой
Командапоследняя смета по ТЗ (часы по отделам)часы × ставка отделачасы × ставка отдела для клиента, иначе с наценкой
По категорииручные плановые статьи бюджетаплановая суммас наценкой

Строка из источника, исправленная вручную, фиксируется (is_manual) — сбор её не трогает; manual=false при правке возвращает её к данным проекта. Строка удалённого источника убирается при следующем сборе.

Загрузка из файла ​

«Загрузить из файла» — в пустой смете (создаёт черновик) и в меню «⋯» черновика. Строки из файла добавляются новыми разделами в конец; в смету ничего не пишется до «Добавить в смету».

  1. POST /estimates/:id/import/parse (multipart file, .xlsx или .csv, до 10 МБ) — разбор таблиц по заголовкам колонок: «Наименование», «Кол-во», «Ед.», «Цена», «Коэфф» / «Дней» / «Смен» (день) или «Часов» (час), «Стоимость» / «Сумма», «Себестоимость цена» / «Себестоимость сумма», «Примечание». Две таблицы рядом на листе (шаблон RMS: «Аренда оборудования» и «Работы») разделяются пустой колонкой; заголовок таблицы — строка над шапкой; строка только с названием внутри таблицы — подраздел; «Итого», скидки и налоги пропускаются. Коэффициент переносится периодом без скидки аренды за дни, поэтому сумма строки совпадает с файлом; коэффициент 1 — без периода. Цены нет — считается из суммы. Себестоимость берётся и с внутренних листов «(ВНУТР) …» по названию строки; одинаковые таблицы с разных листов берутся один раз. В файле есть «Скидка» — предупреждение: скидка задаётся у раздела или сметы руками.
  2. Таблица не нашлась (estimate_import_nothing) или файл — PDF, Word, скан — фронт отдаёт его помощнику: POST /ai/extract/estimate, ответ того же вида.
  3. Предпросмотр: разделы и строки с галочками, итог по выбранному и по файлу; «Цены в файле — это»: «Цены для клиента» (цена строки; себестоимость — если видна) или «Себестоимость» (цену даёт наценка; только с доступом к затратам).
  4. POST /estimates/:id/import — отмеченное одной транзакцией, строки ручные (is_manual): «Собрать смету» их не трогает.

Ставки сотрудников ​

  • user_rates — история ставок: себестоимость часа и ставка для клиента с даты (GET/POST/DELETE /users/:id/rates; правят финансы и администратор).
  • Действующая ставка в проекте: команда проекта (hourly_rate / client_hourly_rate) → ставка сотрудника на сегодня → отдел (hourly_rate / client_hourly_rate).
  • Строка «Сотрудник» (user_id в POST /estimates/:id/lines) берёт эти ставки, если в строке не заданы свои.

Права ​

ДействиеКто
Смотреть сметудоступ к бюджету клиента или затратам (client_budget / costs чтение) и к разделу финансов проекта
Себестоимость, маржа, внутренние строкичтение затрат (costs), администратор, finance.manage
Править, собирать, менять статускто ведёт бюджет клиента этого проекта (client_budget запись + деньги проекта), финансы (client_budget «все»), администратор, finance.manage, documents.manage
Ставка для клиента отдела и в командевидна с client_budget, себестоимость — с costs

Ссылка клиенту ​

Смета → «Отправить клиенту» (POST /estimates/:id/link): ссылка {FRONTEND_BASE_URL}/estimate/<token>. Черновик при этом становится «отправлена клиенту» (снимок итогов). Клиент без входа в RMS:

  • видит смету: наша компания и заказчик, разделы и строки с ценами, скидки, УСН и НДС, итог — без себестоимости, наценки, внутренних строк и комментариев;
  • скачивает PDF («СМЕТА (версия N)», без номера — номер получает только выпущенный документ, место для подписей сторон);
  • «Согласовать» (ФИО обязательно, комментарий) или «Нужны изменения» (комментарий обязательно). Решение одно на ссылку и только по отправленной версии: согласование — как менеджером (плановый бюджет проекта, архив прежней версии), «нужны изменения» закрывает версию — дальше новая.

Токен — 32 случайных байта; в estimate_links — sha256 для поиска и зашифрованная копия (APP_SECRETS_KEY), чтобы менеджер мог снова скопировать ссылку (без ключа — только сразу после создания). Активная ссылка у версии одна: новая отзывает прежнюю; «Отозвать» и новая версия сметы делают ссылку недействительной (404 estimate_link_not_found), как и возврат версии в черновик.

Менеджер (руководитель проекта и автор ссылки) получает уведомления: клиент открыл ссылку (первый раз), согласовал, просит изменения — и экран сметы обновляется сам (часть estimate). В окне ссылки — сколько раз и когда открыта, решение клиента. Ссылку можно отправить письмом (POST /estimates/:id/link/send), если на сервере включена почта (EMAIL_ENABLED), иначе 409 estimate_mail_disabled.

Публичные маршруты — GET /public/estimates/:token, GET …/pdf, POST …/decision — без авторизации, с лимитом по адресу: 60 просмотров и 10 решений в минуту (429). В журнале — создание ссылки и решение клиента (ФИО, комментарий, IP, браузер).

Документы и перенос ​

  • Смета PDF и счёт на всю смету (аванс, остаток) берут строки и итоги из действующей сметы; без сметы — из бюджета, как раньше. См. Систему документов.
  • Перенос при запуске: проекту без сметы с плановыми статьями или потребностью в оборудовании собирается смета v1 (если по проекту выставлены счета — сразу «согласована», плановый бюджет не трогается). Закрытые и архивные проекты не переносятся.
  • Журнал: создание версии, смена статуса, удаление черновика (entity_type = estimate). Живые обновления — часть estimate проекта.

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