# Расчётный контракт дополнения Редакция 13.10.2026. Фактический эталон — `prototype-v2` commit `5213150`; это контракт демо и принятых формул, а серверная архитектура остаётся предложением. Все NEW-01–09 реализованы пакетами; общая QA и риск-ревью ещё не завершены. [Спецификация](spec.md), [прослеживаемость](addendum-coverage.md), [словарь](CONTEXT.md). ## Единый владелец и границы В прототипе формулы принадлежат `js/calc.js`, валидация/запись — `js/api.js`, данные — `js/seed.js`, экраны только вызывают и форматируют их. API синхронный mock `api.post(action,payload)` с localStorage и глобальной revision, а не реализованный HTTP-сервис. Ошибка 400 не записывает состояние, конфликт revision — 409, недоступное/повреждённое хранилище — 503. Сохранение reportData заменяет объект целиком; форма переносит неизменённые поля. Серверные стабильные ID, Decimal, авторизация, журналы/версии БД, 1С/Time/Сфера пока проектируются. Переключатель РМ/РП демонстрирует scope, не доступ. Дополнение имеет приоритет над противоречащими формулами v1.7. P=FTE×персональная H принят; отдельной нормы продажи нет. Новые процессы замещения, переноса работ, пересогласования денег и политика исторического пересчёта рабочего сервиса не добавлены. Исходные документы и изображения v1.7 сохранены как история. ## Календарь и доступные периоды Hкал = сумма date→hours федеральной пятидневки 40 ч. Праздники и перенесённые выходные имеют 0 ч, сокращённые рабочие дни — 7 ч, обычные — 8 ч. 20.02.2027 — рабочая суббота 7 ч; 22.02 — перенесённый выходной. Региональные исключения в демо не включены. | Год | янв | фев | мар | апр | май | июн | июл | авг | сен | окт | ноя | дек | год | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 2026 | 120 | 152 | 168 | 175 | 151 | 167 | 184 | 168 | 176 | 176 | 159 | 176 | 1972 | | 2027 | 120 | 151 | 176 | 175 | 152 | 167 | 176 | 176 | 176 | 168 | 159 | 176 | 1972 | Источники, проверенные при подготовке календаря 13.10.2026: [2026](https://www.consultant.ru/law/ref/calendar/proizvodstvennye/2026/), [2027](https://www.consultant.ru/law/ref/calendar/proizvodstvennye/2027/), [постановление №1187](https://www.consultant.ru/document/cons_doc_LAW_544706/). Это опубликованные данные, не проверка API 1С. API принимает месяцы 2026-01…2027-12; иной месяц — 400. Форма заявки предлагает до 12 месяцев и уменьшает выбор у конца календаря, API — до 24 уникальных месяцев. Первый месяц шестимесячного плана ≤2027-07; некоммерческого отчёта с периодом 3/6/12 ≤2027-01. Недельное окно — 12 недель: неделя, включающая 2025, целиком неизвестна; норму 2025 не подставляют. Январь/февраль/март 2026 имеют 8/4/0 таких недель. Календарные даты кадрового начала могут быть старше 2026; это не добавляет часы отсутствующего календаря. ## Отпуск, больничный, пересечения и полнота `reportData.vacations` и `reportData.sickLeaves` содержат уникальные записи сотрудник×месяц. Каждая запись — одно из: ```json {"employee":"e1","month":"2026-10","hours":16} ``` ```json {"employee":"e1","month":"2027-02","dates":["2027-02-20","2027-02-22"]} ``` Hours — подтверждённые рабочие часы 0…Hкал, уже без пересечений и нерабочего времени. Dates — полные дни этого месяца, не интервалы частичных часов. Повтор даты внутри записи нормализуется, неверная дата/месяц отклоняется. Объединение отпускных и больничных дат исключает повтор; праздник/выходной в dates даёт 0 ч. Пример: отпуск 20.02+22.02.2027, больничный 20.02 → исключено 7 ч, H=144. Для пересечений оба вида вводят dates. Положительную сводку hours и датированные отсутствия одного сотрудника/месяца смешивать нельзя; API просит оба вида указать датами. Сводные часы — допущение демо: доступность каждого рабочего дня уменьшается пропорционально его календарным часам. Без дат реальное положение отсутствия в месяце неизвестно; это не прогноз больничных и не доказательство точности кадровой интеграции. Для точного дневного плана нужны dates. Наличие записи каждого вида подтверждает полноту: пустое поле удаляет запись → unknown; hours=0 либо dates=[] подтверждает отсутствие. H неизвестна, если нет хотя бы одной из двух записей. Полная сумма отсутствий не может превышать Hкал; отказ атомарный. H = Hкал − объединённые рабочие часы отсутствий; N = сумма H выбранных сотрудников/месяцев. Hкал остаётся известной и показывается отдельно. Повторно отпуск/больничный из H/N не вычитаются; колонок с дополнительным вычетом нет. ## P, фактические часы и деньги Обычный месячный план: P = FTE × H. Для дневного плана: P = сумма dailyFte(date) × availableDayHours(employee,date). `days[date]` имеет приоритет, явный 0 сохраняется. Если H неизвестна и загрузка ненулевая, зависимые P, деньги и проценты неизвестны. Известная нулевая загрузка даёт 0 часов даже при неизвестной H. Известная H=0 даёт 0 плановых часов; P/H и проценты с нулевой нормой — прочерк. До выбора сотрудника строка «На подбор» использует Hкал и известную R, C неизвестна; после выбора — H сотрудника. Эта граница явно отражает отсутствие персональной нормы до назначения. Мок допускает создание заявки при неизвестной H, но требует подтверждённые обе записи отсутствий для всех назначенных месяцев при согласовании. Проверка перегрузки — сумма дневных FTE в рабочие дни с доступными часами, включая рабочую субботу; подтверждённый день с 0 доступных часов исключается. Неизвестность не снимает проверку. До решения change план неизменён; исходные месячные ставки сохраняются при дневном изменении. При выводе 0,5 FTE с 16.11.2026 и нулевых отсутствиях → 35,5 ч, месячный FTE=35,5/159. `actuals` — запись сотрудник×проект×месяц: одно из fte (0…2) или hours. Введённый FTE переводится в A через H; явные hours сохраняются напрямую и видны даже при неизвестной H. Hours ограничены 2Hкал и при известной H также 2H; это граница ручного ввода, а разрешение импорта другого факта не принято. Пусто удаляет запись, 0 сохраняется. Отсутствие записи хотя бы для одного выбранного сотрудника×проекта×месяца делает сумму A неполной; известная детализация не пропадает. Если проектов выбранного типа нет, A=0. Отпуск/больничный не являются работами. I=P×R, расход=P×C, разница=I−расход. Часы/деньги не округляются до суммы; отображление округляет. Финансы списка, формы, карточки, месячных строк и отчёта используют одни исходные часы/ставки; неизвестные значения в CSV пусты, не 0. Изменение введённых отсутствий меняет текущие P и деньги прототипа, включая уже согласованные заявки; нового процесса пересогласования нет. Legacy месячные R сохраняются, показанная средняя взвешена P. Форма/карточка: отрицательная разница красная, неотрицательная зелёная. Месячный и списочный расход красный только при отрицательной разнице; неизвестный без цвета. Пример Анны: Hкал=176,V=16,B=0 → H=160, FTE=0,5 → 80 ч, R/C=3500/2800 → 280000/224000 ₽. B=8 → H=152, P=76, 266000/212800 ₽. Пример потери при 88 ч и R/C=4000/4300 → 352000/378400/−26400 ₽. ## Σ, Итог и показатели отчётов Σ ч = сумма часов; Σ FTE·мес = сумма месячных FTE; Σ % = сумма часов / сумма персональных норм ×100. Для 0,5/1/0,75 при нормах 160/176/176: 2,25 FTE·мес, 388 ч, процент 388/512×100. Это не сумма процентов и не средняя FTE. Нижний Итог использует видимых сотрудников ровно один раз. Проекты — расшифровка, не дополнительный вклад. Свёртка не меняет его; поиск/свободный ресурс/область РП меняют состав. Поиск проекта оставляет полную загрузку найденных сотрудников: итог равен показанным сотрудникам, как существующее поведение плана. Месячный FTE группы — сумма персональных FTE, процент группы — сумма часов / сумма H. Три показателя утилизации используют один scope: P/N, Pком/N, A/N. Коммерческий числитель выбирается по категории «Коммерческий» ИЛИ типу commercial (как `utilizationIndicators`), категории таблиц выбирает `projectType` с приоритетом подробной категории. Неизвестная/нулевая N даёт прочерк с причиной, неполный A — пояснение. Категории не суммируют свой общий знаменатель. Накопительный процент — суммы часов / суммы H при одном составе людей; не среднее процентов. Нулевой знаменатель новых колец и агрегата периода — прочерк; сохранённая `planSummary` для пустой выборки показывает 0%, недельная сводка с известной нулевой нормой — 0%. Это отдельные контексты существующего отображения, не подтверждение неизвестной нормы. Четыре верхние вкладки: План, Заявки, Назначения, Отчёты. В Отчётах пять разделов: Утилизация, Финансы, Распределение, Некоммерческие проекты, Статистика. ЦФО/подразделение в Распределении и CSV берутся из введённых данных, пропуск — прочерк. ## Контрольное демо и проверка Все 24 месяца отсутствий демо подтверждены; отпуск Анны октября 16 ч, прочие 0, больничные 0. Октябрь: N=1040,P=432,Pком=256, FTE группы=2,5; факт неполный. Ноябрь: N=954,P=A=477, полный факт →50%. Норма 6 сотрудников ноября =6×159, без выдуманных отсутствий. Старое localStorage не переписывается: новые отсутствующие sickLeaves неизвестны, для контрольного демо нужен сброс. | Заявка | Доход ₽ | Расход ₽ | | --- | --- | --- | | demo-1 | 2446550 | 2388700 | | demo-2 | 1548700 | 1246200 | | demo-3 | 2176900 | неизвестен | Детальные проверки и файлы — [матрица покрытия](addendum-coverage.md). Числовая сверка документа выполняется на неизменном `5213150`; она не заменяет будущую общую QA.