Corp/docs/guides/COMPANY_ANALYTICS.md

25 KiB
Raw Permalink Blame History

Аналитика компании

Аналитика встроена во вкладку «Аналитика компании» на странице /finances. Внутренние вкладки: проекты, продажи, сотрудники, производство и журнал фактов. Выбранные вкладки запоминаются для пользователя; обычный и широкий режимы используют то же переключение, что и управление зарплатой. Фильтры открываются модальным окном по кнопке в шапке финансов; под внутренними вкладками остаётся короткая строка применённых фильтров. Отмена закрывает окно без изменения отчёта. Карточки адаптируются к ширине рабочей области. В обычном режиме и при ширине рабочей области меньше 928px списки по умолчанию свёрнуты до заголовка со счётчиком и стрелкой. После открытия списка табличные строки представлены карточками с раскрывающимися подробностями. В широком режиме списки всегда открыты и показывают таблицы. Это относится к сводным отчётам, документам выплат и журналу фактов. В широком режиме при ширине рабочей области от 928px основной блок сочетает график и таблицу в двух колонках, если таблица помещается без горизонтальной прокрутки. Иначе график располагается сверху, а таблица — снизу на всю ширину. Компоновка пересчитывается при изменении размера области и данных таблицы. Дополнительные блоки располагаются попарно. Таблицы имеют собственную прокрутку и закреплённые заголовки. В обычном и узком режиме графики открываются только модальным окном по кнопке в заголовке списка, в том числе когда список свёрнут.

У каждого списка есть график с выбором показателя: разные единицы не смешиваются. Месячные данные представлены линией с разрывами на неизвестных значениях; остальные — сравнением до семи позиций. Высота области всех графиков — 280px. Для явно отмеченных суммируемых показателей при числе позиций больше семи показываются шесть крупнейших по модулю и «Прочее» — сумма остальных с учётом знака. Число объединённых позиций видно в подписи и подсказке. Неизвестные значения исключаются и отмечаются отдельно. Проценты, средние, возраст и стаж не суммируются; для них показываются семь крупнейших значений. Месячные ряды сохраняют все месяцы. Полные списки и CSV не сокращаются. Графики сводных списков учитывают поиск по всем страницам результата. Для документов и журнала используется только текущая загруженная страница, что явно подписано над графиком; аннулированные записи журнала исключены. Поиск, страницы, CSV и права на действия сохраняются в обоих режимах. Методика и инструкции открываются по вопросику в шапке, пояснения к отдельным таблицам — по вопросику рядом с названием. Предупреждения о качестве данных остаются в отчётах. Старый адрес /finances/analytics перенаправляет на /finances?tab=analytics, открывая встроенную вкладку. Используются визуальные компоненты и темы портала. Изображения из локальных материалов служат примерами; их показатели, числа и оформление не являются ТЗ.

Возможности

  • Продажи по товарам, каналам, сочетанию товара и канала, клиентам и месяцам.
  • Выручка, себестоимость, привязанные расходы, прибыль по учтённым расходам и маржа.
  • Зарплата каждого сотрудника, изменение зарплаты, дни работы, отпуска и больничного, уплаченные налоги, возраст, стаж и динамика численности команды.
  • Выпуск, продажи произведённых товаров, производственные закупки и графики с переключением между закупками, выручкой и прибылью. Прибыль по товарам и каналам повторно доступна в производственном отчёте и рассчитывается тем же сервисом.
  • Журнал подтверждённых фактов: выпуск, производственные закупки, уплаченные налоги сотрудника, общие расходы, поступления и выплаты денег.
  • Локальные проекты объединяют продажи, расходы и платежи связанных внешних объектов; подтверждённые часы получают предварительную оценку до закрытия зарплатного периода и точную оценку по его итоговому начислению после закрытия.
  • Выбор дат включительно, валюты и источника продаж. Поиск, страницы таблиц и CSV всех строк текущей группировки с учётом поиска. Диапазон ограничен 367 днями.

Источники и методика

Продажи и возвраты берутся из commerce.Sale и SaleLine, расходы — из Cost. Операции с counts_as_sale=False и связанные с ними расходы исключаются. Возвраты уменьшают количество, выручку и себестоимость. Расходы учитываются по собственной дате; их знак сохраняется, в том числе для компенсаций.

Выручка равна сумме после скидок и возвратов в денежной базе источника. Сервис не пересчитывает НДС. Прибыль по учтённым расходам равна выручке минус себестоимость минус привязанные расходы. Общие расходы и налоги не распределяются автоматически. Этот показатель не следует принимать за окончательную чистую прибыль компании. Правила распределения общехозяйственных расходов и налогов требуют согласования.

Себестоимость с metadata.cost_source="unavailable" считается неизвестной. Нулевая себестоимость без подтверждения manual или known_zero также считается неизвестной. Для затронутых групп прибыль и маржа возвращаются null, в UI — «—». API дополнительно возвращает арифметический результат по известным расходам contribution_profit, но интерфейс не показывает его как подтверждённую прибыль.

Клиенты имеют внешний ID и имя на продаже. Миграция восстанавливает их из сохранённого SourceRecord.payload.agent, если информация присутствует. Новая синхронизация МойСклад запрашивает контрагента вместе с документом. ID клиента дополняется ID источника, поэтому одинаковые внешние ID разных систем не объединяются. Когда имеется только имя, используется имя внутри источника; для надёжного сопоставления необходимо заполнить внешний ID. Расходы без привязки к продаже остаются в группе неизвестного клиента.

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

Зарплата берётся из опубликованного расчёта каждого периода. Новая черновая ревизия не заменяет опубликованную. Учитываются только периоды, целиком входящие в выбранные даты. Начисления нескольких периодов одного месяца складываются по месяцу окончания расчётного периода. Средняя зарплата сотрудника — начисленная сумма до удержаний, делённая на число месяцев с расчётами. Среднее компании — по парам «сотрудник / месяц» с расчётами. Неопубликованные и отсутствующие расчёты не заменяются нулями. Рост сравнивает первый и последний месяц с опубликованными расчётами внутри диапазона. Границы сравнения едины для всех сотрудников и показаны в интерфейсе. Сотрудник включается в сравнение только при наличии обоих расчётов и ненулевой начальной зарплате.

Рабочие дни — записи успешного анализа посещаемости с положительными часами и без признака отсутствия. Отпуска и больничные — календарные дни по кадровым событиям с существующим приоритетом пересекающихся событий. Стаж учитывает увольнения и повторный приём, а не дату создания учётной записи. При отсутствии кадровой истории текущая численность использует активность учётной записи; историческая динамика включает только известную кадровую историю. Неизвестные даты рождения и найма исключаются из средних и учитываются в счётчиках пропусков.

Налоги берутся только из фактически оплаченных записей журнала. Удержания расчётного листка не означают уплаты налога. Производственный отчёт включает продажи товаров с неаннулированным фактом выпуска не позже конца периода. Количество выпуска вводится в единицах соответствующего товара и не зависит от выбранной валюты. Закупка может относиться к конкретному конечному товару либо оставаться общей. Производственные закупки не вычитаются повторно из прибыли поверх себестоимости продаж.

Фильтр проекта использует локальную карточку и применяется к продажам через её внешние привязки, а к ручному журналу и трудозатратам — напрямую. Фильтр источника влияет на продажи и связанные расходы; журнал остаётся общим. Денежный поток считается только по поступлениям и выплатам из журнала. Нулевое число записей не подтверждает отсутствие фактических выплат, налогов или выпуска.

Доступ и журнал

Все endpoints требуют авторизации и существующего доступа к управлению финансами, включая allow-list FinanceSettings.management_users. Ответы имеют private, no-store; фронтовое скрытие ссылки не подменяет серверную проверку.

Для добавления фактов нужно finance.add_reportingentry, для аннулирования — finance.change_reportingentry. Действует существующий временный административный доступ SIMPLE_ADMIN_ACCESS. Права на просмотр финансов сами по себе не дают права изменять журнал.

Номер документа уникален внутри вида записи. Записи не редактируются и не удаляются: исправление выполняется аннулированием и новой записью с новым номером. Автор и дата создания, автор и дата аннулирования сохраняются. Повторное аннулирование идемпотентно. Будущие факты, отрицательные суммы и несовместимые с видом записи поля отклоняются.

API

  • GET /api/v1/finance/analytics/report/?section=sales|people|production|projects
  • GET /api/v1/finance/analytics/options/?search=...
  • GET|POST /api/v1/finance/analytics/entries/
  • POST /api/v1/finance/analytics/entries/{id}/void/

Параметры отчёта и списка фактов: date_from, date_to, currency, локальный project либо unassigned; параметр source применяется к продажам и внешним привязкам. Список фактов использует стандартную пагинацию API. options возвращает локальные проекты и первые 100 товаров и сотрудников по строке поиска. CSV экранирует кавычки, переносы строк и потенциальные формулы в текстовых полях.

Подключение и проверка

Перед запуском обновлённого backend выполните python manage.py migrate: миграции Commerce 0012–0014, Projects 0001 и Finance 0032–0034 добавляют клиента продажи, внешний справочник, локальные проекты и журнал фактов. Для старых документов без имени клиента может потребоваться повторная синхронизация.

cd backend
pytest tests/finance/test_analytics.py tests/finance/test_projects.py tests/commerce -q
python manage.py makemigrations --check --dry-run
python manage.py check
cd frontend
node --import tsx --test src/lib/analytics.test.js
npx tsc --noEmit

Исходная книга учёта оплат автоматически не импортируется: в ней есть внешние ссылки с ошибками и лист с учётными данными. Импорт этой книги требует отдельного сопоставления колонок, подтверждения исходных сумм и подготовки безопасной копии. Фраза «всё из годового финансового отчёта» требует отдельного перечня показателей или самого годового отчёта: книга оплат не задаёт полный состав такого отчёта. Индекс здоровья, планы и прогнозы из примерных изображений не включены в объём реализации текстового ТЗ.

Локальные проекты и внешние источники

Раздел «Проекты» использует локальную карточку портала как основную строку. В неё по точным внешним привязкам собираются оплаченные расходы, документы платежей, продажи и прямые расходы всех подключённых сервисов. Ручные выплаты, закупки и общие расходы журнала ссылаются на локальную карточку напрямую. Подтверждённые распределения сотрудников добавляют трудозатраты в часах, число дней учёта и участников. Пока расчётный период открыт, стоимость часа предварительная: система использует текущий расчёт зарплаты, а до его появления — действующую утверждённую базовую ставку, разделённую на норму часов периода. После закрытия периода стоимость становится точной: итоговое начисление из опубликованного расчётного листка, включая премии, доплаты и корректировки, распределяется по фактически отработанным часам. Полученная стоимость часа умножается только на подтверждённые часы проекта. Черновые ставки не используются. Закрытый период без итогового листка, а также часы без периода, нормы или фактических часов сохраняются как неоценённые и не превращаются в ноль.

Фильтр локального проекта работает в продажах, производстве, проектах и журнале. Вариант «Без привязки» объединяет внешние документы, для которых ещё не выбрана локальная карточка, а также документы без проекта источника. В списке платежей сохраняются и локальное имя, и исходное имя проекта для проверки происхождения.

Синхронизация получает /entity/project (включая архив), /entity/paymentout и /entity/cashout с проектом, статьёй расходов, получателем и валютой. Продажи получают связь project из отгрузки или возврата. Для старых продаж связь восстанавливается из сохранённого исходного документа, если поле присутствует. Проекты идентифицируются сочетанием источника и внешнего ID, а не названием.

«Оплачено по источникам» — сумма проведённых исходящих платежей и расходных ордеров за период в выбранной валюте. Проект определяется по явному полю документа; из связанных заказов и приёмок он не угадывается. Непроведённые документы и документы, исчезнувшие после полностью успешного обхода источника, исключаются. Повторный импорт обновляет ту же запись. Последние полученные исходные документы сохраняются; отсутствующие платежи помечаются флагом и не удаляются. Импортированные платежи доступны только для чтения. При ошибке обхода оставшиеся документы не помечаются отсутствующими.

Платёж может быть переводом между счетами, авансом, погашением долга, закупкой или возвратом: его нельзя автоматически вычитать из прибыли поверх себестоимости. Поэтому оплаченные суммы, ручные выплаты, закупки и общие расходы показаны отдельными колонками. Ручные записи не следует создавать повторно для уже импортированных платежей. При фильтре источника ручные факты относятся к нему через выбранный проект; ручные факты без проекта не включаются в конкретный источник.

Дополнительный API: GET /api/v1/finance/analytics/project-payments/ с обычной пагинацией. section=projects возвращает сводку, строки проектов, статьи и месяцы. Параметр project — локальный ID проекта либо unassigned. Поле project доступно в ручной записи, продаже и прямом расходе. Справочник проектов возвращается в analytics/options/. Права и no-store совпадают с остальной аналитикой.

Миграции: Commerce 0014, Projects 0001 и Finance 0033–0034. Миграция 0034 сохраняет прежнюю внешнюю связь ручной записи для аудита и заполняет локальный проект там, где уже существовала точная привязка. Обычная синхронизация включает проекты и исходящие платежи. Для отдельной загрузки без товаров и изображений:

python manage.py sync_moysklad_projects <UUID-подключения>

Контракты API: проекты, исходящие платежи, расходные ордера.