import { can, ServiceError, type ServiceCtx } from "@/server/services/context"; import { assertPlanFeature } from "@/server/plan"; /** * Who may use the planning views (L13): * - `work_order:read_all` (backoffice, admin): all teams; scheduling needs `work_order:assign` + `work_order:write`. * - `work_order:read_team` + leader of at least one active team (Teamleiter): read-only, own teams only. * - everyone else (Monteur): forbidden. * L17 Pakete: planning is a PROFI feature — Basis → `forbidden` (reason `not_in_plan`) for board, live * situation, recommendations, freed capacity, dashboard tiles and the planning API. */ export type PlanningAccess = { all: boolean; /** null = all teams of the tenant */ teamIds: string[] | null; canSchedule: boolean; canManageTeams: boolean; }; export async function planningAccess(ctx: ServiceCtx): Promise { await assertPlanFeature(ctx.tenantId, "planning"); if (can(ctx, "work_order:read_all")) { return { all: true, teamIds: null, canSchedule: can(ctx, "work_order:assign") && can(ctx, "work_order:write"), canManageTeams: can(ctx, "team:manage"), }; } if (can(ctx, "work_order:read_team")) { const led = await ctx.db.team.findMany({ where: { leaderUserId: ctx.userId, status: "active", deletedAt: null }, select: { id: true } }); if (led.length > 0) return { all: false, teamIds: led.map((t) => t.id), canSchedule: false, canManageTeams: false }; } throw new ServiceError("forbidden", "planning not allowed"); } /** Recommendations and scheduling are backoffice functions (all teams + assign right). */ export async function assertCanPlanAll(ctx: ServiceCtx): Promise { const access = await planningAccess(ctx); if (!access.all || !can(ctx, "work_order:assign")) throw new ServiceError("forbidden", "missing permission work_order:assign"); return access; }