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

projects — самостоятельный Django-модуль корпоративного портала. Проект создаётся локально и не требует подключения МойСклад. Торговые модели и действующая синхронизация остаются в commerce.

Структура

  • models/project.py: карточка проекта, история настроек и связанные материалы.
  • models/membership.py: участники, роли, даты участия и плановая загрузка.
  • models/stage.py: этапы и сроки.
  • models/external_binding.py: связь локального проекта с внешним объектом.
  • models/time_allocation.py: день сотрудника, распределение, версии и напоминания.
  • services/time_tracking.py: валидация распределения, снимок часов, напоминания.
  • permissions.py: доступ к проектам и управлению ими.
  • api/v1/projects/: API; frontend/src/app/projects/: список и карточка.

Доступ и история

Создание доступно администраторам и пользователям с projects.add_project. Руководитель управляет своей карточкой, командой, этапами, связями и видит отчёт команды. Участник видит проект и собственные строки времени. Администратор видит все проекты. ?mine=true ограничивает список собственными назначениями и для администратора. Финансовый endpoint отдельно проверяет действующие права can_access_payroll_management; руководство проектом не открывает зарплаты. Все ответы API имеют Cache-Control: private, no-store.

Проекты архивируются, API не удаляет их. Участие завершается датой окончания, чтобы сохранить контекст. API сохраняет события изменений карточки и связей; версии распределения времени хранят полный снимок процентов, часов, комментария и статуса. В админке дни и версии доступны только для чтения.

Внешние связи

Идентичность объекта — (source, object_type, external_id). Один внешний объект может принадлежать одному локальному проекту; локальный проект может объединять несколько внешних объектов. Названия не служат ключом и автоматически не объединяются. Привязка не изменяет внешнюю запись, перенос привязки требует явного удаления прежней связи. Синхронизация commerce не записывает локальные проекты.

Для проектов МойСклад есть поиск по импортированному справочнику, включая индикацию занятых привязок. Главная страница /projects отдельно показывает активные внешние проекты без связи. Из этой очереди руководитель может одной операцией создать локальную карточку вместе с привязкой либо связать внешний проект с уже существующей карточкой. Создание выполняется транзакционно и не изменяет исходную запись МойСклад. Для будущих источников можно сохранять привязки по ID и типу объекта. Это хранение соответствий, а не реализация новых адаптеров.

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

Ежедневное распределение

/projects, профиль и ежедневная «Выработка» открывают один модал. В нём есть дата, проекты сотрудника, общая деятельность (работа отдела, обучение, поддержка), проценты и комментарий. Подтверждение требует ровно 100%; черновик допускает меньшую сумму. Повторяющиеся строки и сумма больше 100% отклоняются. Повторение прошлого подтверждённого дня за 90 дней фильтрует недоступные назначения и требует ручного подтверждения нового дня. Можно редактировать дни за прошедшие 366 дней.

Доступные назначения учитывают даты участия. Новые записи не относятся к завершённым и архивным проектам. Ранее сохранённые строки можно исправлять с сохранением версии. Продолжительность берётся из успешного анализа посещаемости с положительным work_hours. Без него сохраняются проценты, часы остаются null. Это часы по данным посещаемости, не автоматически подтверждённый трудозатратный табель. Изменение посещаемости после сохранения отмечается при открытии дня; повторное сохранение создаёт новую версию с обновлёнными часами.

Часы участия = часы конкретного дня × процент / 100. В итог входят только подтверждённые дни с известными часами; черновики и дни без часов отмечены отдельно. Средние дневные проценты не используются вместо суммы часов. Часы и баллы выработки не смешиваются, зарплата от ввода процентов не изменяется.

Сохранение блокирует строку сотрудника, проверяет версию и атомарно заменяет строки дня вместе со снимком истории. Для конкурентного доступа предусмотрен PostgreSQL; SQLite в локальной разработке не реализует SELECT FOR UPDATE.

Напоминания

Общая оболочка портала проверяет напоминание после входа и раз в минуту, когда вкладка видима, другое окно не открыто и пользователь не вводит текст. Сервер выбирает последний незаполненный день за 14 дней, для которого есть успешная посещаемость с положительными часами и доступный проект. Используются только прошедшие даты, поэтому сегодняшняя/ночная смена не предлагается до завершения календарного дня. Выходные и отсутствия не выводятся из предположения о пятидневке.

Право показа резервируется на сервере один раз за день, общим для устройств. «Напомнить через 2 часа» откладывает следующую попытку; закрытие оставляет день незаполненным, доступным из «Мой день». Нужна открытая вкладка портала: отдельных email/push-рассылок эта версия не отправляет. Отключение напоминаний конкретному сотруднику доступно в админке AllocationReminder.enabled.

Связи с другими разделами и границы версии

Задачи, закупки и документы присоединяются внутренними ссылками из карточки проекта. Доступ к оригиналу проверяется его модулем. Пока это явные ссылки, а не обязательное поле проекта в формах создания каждого из этих объектов.

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

Проверка

cd backend
.venv/bin/python manage.py migrate
.venv/bin/python manage.py check
.venv/bin/python -m pytest tests/projects tests/finance/test_projects.py -q

Frontend: npm run build, npx tsc --noEmit, целевой ESLint для новых компонентов.