+ {error} +
+ ) : null; + return ( ++ Локальный проект +
++ {projectStatuses[project.status]} · {project.manager_name} +
++ {project.description || "Описание пока не заполнено."} +
++ {s.name} +
++ {s.due_on || "Без срока"} +
++ Добавьте этапы, чтобы отслеживать результат работы. +
+ )} +{m.role}
++ Плановая загрузка: {number(m.planned_percent)}% +
++ {m.starts_on || "Без ограничения"} —{" "} + {m.ends_on || "Без окончания"} +
+ {project.can_manage && ( + + )} ++ Для завершения участия укажите дату окончания. Плановая + загрузка не заменяет фактическое распределение дня. +
++ Подтверждено часов участия +
+ + {number(time.confirmed_hours)} + ++ Подтверждённых дней без часов +
+ {time.unknown_days} +Черновиков
+ {time.draft_days} ++ {time.scope === "team" ? "Участие команды" : "Ваше участие"}. + Часы — доля продолжительности дня по посещаемости. Неизвестные + часы не включаются в итог. +
++ Оплачено по источникам +
+ + {number(finance.paid)} {finance.currency} + ++ {finance.payment_count} документов ·{" "} + {finance.external_project_count} внешних проектов +
+Стоимость труда
+ + {number(finance.labor_cost)} {finance.currency} + ++ {laborStatusLabel(finance.labor_cost_status)} +
++ {finance.labor_hour_cost === null + ? "Нет полной оценки стоимости часа" + : `В среднем ${number(finance.labor_hour_cost)} ${finance.currency} / ч`} +
++ Подтверждённое время +
+ + {number(finance.labor_hours)} ч + ++ {finance.unknown_hours_days} дней без достоверных часов +
++ Денежная оценка неполная:{" "} + {number(finance.unpriced_labor_hours)} ч без предварительной + базы или точного расчёта закрытого периода; дней без + достоверных часов — {finance.unknown_hours_days}. +
+ )} ++ До закрытия зарплатного периода сумма предварительная: по + текущему расчёту или утверждённой ставке. После закрытия + используется итоговое начисление сотруднику, включая премии, + доплаты и корректировки. Выплаты источников включают движения + денег, поэтому не складываются со стоимостью труда как + итоговые расходы. +
++ Выбирайте существующие задачи и доски из доступных объектов + портала. Название и адрес формируются автоматически. +
++ Связанных досок нет +
++ {b.external_name || b.external_id} +
++ {b.source_name} · {b.object_type} +
++ Проект работает локально. Связи с сервисами необязательны. +
+ )} ++ До 200 результатов. Привязка добавляет данные в этот + локальный проект и не изменяет источник. +
++ {e.external_name} +
++ {e.source_name} +
+{e.action}
++ {e.actor} ·{" "} + {new Date(e.created_at).toLocaleString("ru-RU")} +
++ Версии распределения времени хранятся отдельно от настроек + проекта. +
+Загрузка проекта…
+ )} + {!project && modalError} + {edit && project && ( ++ Это самостоятельный локальный проект. Команда, этапы и + распределение времени сохраняются независимо от МойСклад и других + сервисов. +
++ Руководитель управляет участием и привязками. Укажите даты + участия, чтобы сотрудник видел подходящие проекты в своём рабочем + дне. +
++ Исходящие платежи показывают движение денег по привязанным + проектам. Они не равны расходам или прибыли. Финансовые права + проверяются отдельно. +
++ Для завершения проекта измените статус. История участия + сохраняется; записи времени не удаляются при завершении проекта + или участия сотрудника. +
+Проект
+{project?.name}
++ Все доступные доски уже связаны с проектом. +
+ )} + {modalError} ++ {error} +
+ )} ++ Проекты +
+ + {loading ? "…" : count} + ++ {search + ? "Проекты не найдены" + : "Пока нет доступных проектов. Создайте локальный проект или дождитесь приглашения в команду."} +
++ Выберите, какие записи являются рабочими проектами компании. +
++ Учётные категории вроде перемещений и кредитов не создаются как + локальные проекты автоматически. +
+ {externalLoading ? ( +Загрузка из МойСклад…
+ ) : ( + <> ++ {externalSearch + ? "Непривязанные проекты не найдены." + : "Все активные внешние проекты сопоставлены."} +
+ )} ++ Распределите первый день через кнопку «Мой день». +
+ )} +Загрузка проекта…
++ {externalDetail.source_name} + {externalDetail.code + ? ` · Код ${externalDetail.code}` + : " · Код не задан"} +
++ {externalDetail.payment_count} +
++ {externalDetail.sale_count} +
++ {externalDetail.description || + "Описание в МойСклад не заполнено."} +
++ Создавайте проекты внутри портала, добавляйте команду и этапы. + Непривязанные проекты МойСклад показаны в очереди на главной + странице: из записи можно создать локальный проект или привязать + её к существующему. Руководитель также может связать объекты + других подключённых сервисов. Совпадение названий не объединяет + записи автоматически. +
++ В «Мой день» распределите время между проектами и общей + деятельностью. Для подтверждения нужно 100%. Часы берутся из + успешного анализа посещаемости; без него часы неизвестны. Проценты + не изменяют зарплату или баллы выработки. +
++ Напоминание появляется один раз в день при входе после + отработанной смены, если за последние 14 дней есть незаполненный + день и участие в проекте. Оно не перекрывает другое модальное + окно. Можно отложить на два часа. +
++ Участник видит свои часы, руководитель — часы команды. Финансовые + суммы доступны только с правами финансовой аналитики. Завершённые + проекты сохраняют историю. +
+Оплачено — проведённые исходящие платежи и расходные ордера МойСклад. Выплаты и закупки показаны отдельно и не вычитаются повторно из прибыли продаж.
-Проект платежа берётся из поля «Проект» в МойСклад. Платежи без этой - связи остаются в группе «Без проекта». Изменяйте импортированные +
Стоимость труда = подтверждённые часы участия × стоимость часа. Пока зарплатный период открыт, сумма предварительная: используется текущий расчёт, а до его появления — утверждённая ставка и норма часов. После закрытия периода сумма становится точной и рассчитывается из итогового начисления сотруднику с премиями, доплатами и корректировками. Если расчётного периода, нормы или итоговых данных нет, соответствующая часть помечается как неоценённая и не считается нулём.
+Проектом отчёта служит локальная карточка портала. Платежи, продажи и + расходы подключённых сервисов объединяются по точным внешним привязкам. + Записи без локальной связи остаются в группе «Без привязки». Изменяйте импортированные документы в МойСклад. Синхронизацией управляет администратор в админке, в разделе «Подключения интеграций». В журнал добавляйте только отсутствующие в МойСклад факты. - Архивные проекты сохраняются в отчётах. Отсутствие загруженных + Подтверждённое распределение рабочего времени показывается в часах и + денежной стоимости. Архивные проекты сохраняются в отчётах. Отсутствие загруженных документов не подтверждает отсутствие реальных расходов.
>} diff --git a/frontend/src/components/analytics/AnalyticsWorkspace.tsx b/frontend/src/components/analytics/AnalyticsWorkspace.tsx index ffe4ff75..1e6ad775 100644 --- a/frontend/src/components/analytics/AnalyticsWorkspace.tsx +++ b/frontend/src/components/analytics/AnalyticsWorkspace.tsx @@ -125,7 +125,7 @@ export function AnalyticsWorkspace({ actionsTargetId, desktopWideMode, onDesktop `${params.date_from.split("-").reverse().join(".")} — ${params.date_to.split("-").reverse().join(".")}`, params.currency, query.source ? options?.sources.find((source) => String(source.id) === query.source)?.name : null, - query.project === "unassigned" ? "Без проекта" : query.project + query.project === "unassigned" ? "Без привязки" : query.project ? options?.projects.find((project) => String(project.id) === query.project)?.name : null, ].filter(Boolean).join(" · "); const actionsTarget = typeof document !== "undefined" ? document.getElementById(actionsTargetId) : null; @@ -247,11 +247,12 @@ export function AnalyticsWorkspace({ actionsTargetId, desktopWideMode, onDesktop } > - + {options?.projects .filter( (p) => - !draft.source || String(p.source_id) === draft.source, + !draft.source || + p.source_ids.includes(Number(draft.source)), ) .map((p) => (