437 lines
11 KiB
TypeScript
437 lines
11 KiB
TypeScript
export type WorkType = "support" | "consulting";
|
|
export type BillingStatus = "billed" | "non_billable" | null;
|
|
export type PeriodType = "month" | "day";
|
|
export type TicketDetailPeriodType = PeriodType | "all";
|
|
export type UserRole = "admin" | "user";
|
|
|
|
export type AuthUser = {
|
|
id: string;
|
|
username: string;
|
|
display_name: string;
|
|
role: UserRole;
|
|
active: boolean;
|
|
zammad_user_id: string | null;
|
|
has_zammad_api_token: boolean;
|
|
};
|
|
|
|
export type DashboardWidgetType = "today" | "month" | "openRatings" | "projectBudgets" | "todos" | "teamspace" | "favorites" | "divider" | "statistic" | "notes";
|
|
export type DashboardSortDirection = "asc" | "desc";
|
|
|
|
export type DashboardFavorite = {
|
|
ticketNumber: string;
|
|
addedAt: string;
|
|
sortOrder: number;
|
|
};
|
|
|
|
export type DashboardWidget = {
|
|
id: string;
|
|
type: DashboardWidgetType;
|
|
title?: string;
|
|
x: number;
|
|
y: number;
|
|
w: number;
|
|
h: number;
|
|
config?: Record<string, unknown>;
|
|
};
|
|
|
|
export type DashboardPreference = {
|
|
version: number;
|
|
widgets: DashboardWidget[];
|
|
favorites: DashboardFavorite[];
|
|
};
|
|
|
|
export type AdminUser = AuthUser & {
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
export type Organization = {
|
|
id: string;
|
|
zammad_id: string;
|
|
name: string;
|
|
synced_at: string;
|
|
};
|
|
|
|
export type RecurringBillingSlot = {
|
|
id?: string;
|
|
weekday: number | null;
|
|
start_time: string | null;
|
|
duration_minutes: number;
|
|
};
|
|
|
|
export type RecurringBilling = {
|
|
id: string;
|
|
user_id: string;
|
|
owner_username: string;
|
|
owner_display_name: string;
|
|
ticket_number: string;
|
|
configured_ticket_number: string | null;
|
|
organization_id: string;
|
|
organization_name: string;
|
|
activity: string;
|
|
work_type: WorkType;
|
|
recurrence_type: "weekly" | "every_n_weeks";
|
|
interval_value: number;
|
|
valid_from: string;
|
|
valid_until: string | null;
|
|
start_time: string;
|
|
active: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
slots: RecurringBillingSlot[];
|
|
};
|
|
|
|
export type TicketMeta = {
|
|
id: string;
|
|
ticket_number: string;
|
|
title: string | null;
|
|
organization_id: string | null;
|
|
organization_name: string | null;
|
|
customer_name: string | null;
|
|
work_type: WorkType | null;
|
|
zammad_ticket_id?: string | null;
|
|
zammad_group_id?: string | null;
|
|
zammad_priority_id?: string | null;
|
|
zammad_state_id?: string | null;
|
|
zammad_owner_id?: string | null;
|
|
project_id?: string | null;
|
|
is_project?: boolean;
|
|
project_name?: string | null;
|
|
project_hour_budget_minutes?: number | null;
|
|
project_teamspace_entry_count?: number;
|
|
project_teamspace_entries?: ProjectTeamspaceEntry[];
|
|
project_owner_user_id?: string | null;
|
|
project_owner_display_name?: string | null;
|
|
can_edit_project?: boolean;
|
|
has_recurring_billing?: boolean;
|
|
};
|
|
|
|
export type TicketSearchResult = {
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
title: string | null;
|
|
organization_id: string | null;
|
|
organization_name: string | null;
|
|
customer_name: string | null;
|
|
work_type: WorkType | null;
|
|
project_id: string | null;
|
|
is_project: boolean;
|
|
project_name: string | null;
|
|
latest_started_at: string | null;
|
|
latest_period: string;
|
|
session_count: number;
|
|
total_minutes: number;
|
|
};
|
|
|
|
export type ProjectSummary = {
|
|
id: string;
|
|
user_id?: string;
|
|
owner_username?: string | null;
|
|
owner_display_name?: string | null;
|
|
can_edit?: boolean;
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
title: string | null;
|
|
organization_id: string | null;
|
|
organization_name: string | null;
|
|
customer_name: string | null;
|
|
work_type: WorkType | null;
|
|
teamspace_project: string | null;
|
|
description: string;
|
|
goals: string;
|
|
starts_on: string | null;
|
|
ends_on: string | null;
|
|
hour_budget_minutes: number | null;
|
|
manual_consumption_minutes: number;
|
|
teamspace_consumption_minutes?: number;
|
|
consumption_minutes?: number;
|
|
closed_at: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
session_count?: number;
|
|
recurring_session_count?: number;
|
|
manual_session_count?: number;
|
|
has_recurring_billing?: boolean;
|
|
billed_minutes?: number;
|
|
open_todos?: number;
|
|
overdue_todos?: number;
|
|
done_todos?: number;
|
|
teamspace_entry_count?: number;
|
|
teamspace_entries?: ProjectTeamspaceEntry[];
|
|
unassigned_teamspace_session_count?: number;
|
|
};
|
|
|
|
export type ProjectTeamspaceEntry = {
|
|
id: string;
|
|
project_id?: string;
|
|
teamspace_project: string | null;
|
|
is_default: boolean;
|
|
hour_budget_minutes: number | null;
|
|
manual_consumption_minutes: number;
|
|
teamspace_consumption_minutes?: number;
|
|
consumption_minutes?: number;
|
|
display_order?: number;
|
|
};
|
|
|
|
export type TodoPriority = "low" | "medium" | "high" | "urgent";
|
|
export type TodoStatus = "open" | "done";
|
|
|
|
export type TicketTodo = {
|
|
id: string;
|
|
ticket_id: string;
|
|
ticket_number?: string;
|
|
organization_name?: string | null;
|
|
project_id?: string | null;
|
|
teamspace_project?: string | null;
|
|
title: string;
|
|
description: string;
|
|
priority: TodoPriority;
|
|
status: TodoStatus;
|
|
sort_order: number;
|
|
starts_on: string | null;
|
|
ends_on: string | null;
|
|
completed_at: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
export type TicketSummary = {
|
|
id: string;
|
|
ticket_number: string;
|
|
title: string | null;
|
|
organization_id: string | null;
|
|
organization_name: string | null;
|
|
customer_name: string | null;
|
|
work_type: WorkType | null;
|
|
project_id: string | null;
|
|
session_count: number;
|
|
total_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
open_count: number;
|
|
ticket_open_count: number;
|
|
billed_count: number;
|
|
non_billable_count: number;
|
|
recurring_session_count: number;
|
|
manual_session_count: number;
|
|
requires_closure: boolean;
|
|
closed: boolean;
|
|
closed_at: string | null;
|
|
};
|
|
|
|
export type OpenSession = {
|
|
id: string;
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
organization_id: string | null;
|
|
organization_name: string | null;
|
|
customer_name: string;
|
|
activity: string;
|
|
work_type: WorkType;
|
|
project_teamspace_entry_id?: string | null;
|
|
project_teamspace_project?: string | null;
|
|
started_at: string;
|
|
rounded_minutes: number;
|
|
recurring_billing_id?: string | null;
|
|
};
|
|
|
|
export type ActivityBucket = {
|
|
bucket_key: string;
|
|
session_count: number;
|
|
total_minutes: number;
|
|
};
|
|
|
|
export type PeriodOverview = {
|
|
periodType: PeriodType;
|
|
period: string;
|
|
closed: boolean;
|
|
closedAt: string | null;
|
|
canClose: boolean;
|
|
totals: {
|
|
tickets: number;
|
|
sessions: number;
|
|
minutes: number;
|
|
crmBilledMinutes: number;
|
|
nonBillableMinutes: number;
|
|
openMinutes: number;
|
|
openSessions: number;
|
|
};
|
|
tickets: TicketSummary[];
|
|
openSessions: OpenSession[];
|
|
activitySeries: ActivityBucket[];
|
|
};
|
|
|
|
export type TicketDayBilling = {
|
|
day: string;
|
|
billed_minutes: number;
|
|
};
|
|
|
|
export type TicketAvailableMonth = {
|
|
month: string;
|
|
session_count: number;
|
|
};
|
|
|
|
export type SessionEntry = {
|
|
id: string;
|
|
organization_id: string | null;
|
|
organization_name: string | null;
|
|
customer_name: string;
|
|
activity: string;
|
|
work_type: WorkType;
|
|
project_teamspace_entry_id?: string | null;
|
|
project_teamspace_project?: string | null;
|
|
started_at: string;
|
|
ended_at: string;
|
|
duration_seconds: number;
|
|
rounded_minutes: number;
|
|
billing_status: BillingStatus;
|
|
billing_updated_at: string | null;
|
|
created_at: string;
|
|
recurring_billing_id: string | null;
|
|
recurring_billing_slot_id: string | null;
|
|
recurring_occurrence_date: string | null;
|
|
};
|
|
|
|
export type TicketPeriod = {
|
|
periodType: TicketDetailPeriodType;
|
|
period: string;
|
|
closed: boolean;
|
|
closedAt: string | null;
|
|
filters?: {
|
|
month: string;
|
|
status: "all" | "open" | "billed" | "non_billable";
|
|
source: "all" | "manual" | "recurring";
|
|
};
|
|
availableMonths?: TicketAvailableMonth[];
|
|
ticket: {
|
|
id: string;
|
|
ticket_number: string;
|
|
title: string | null;
|
|
organization_id: string | null;
|
|
organization_name: string | null;
|
|
customer_name: string | null;
|
|
work_type: WorkType | null;
|
|
closed_at: string | null;
|
|
requires_closure: boolean;
|
|
recurring_session_count: number;
|
|
manual_session_count: number;
|
|
has_recurring_billing?: boolean;
|
|
};
|
|
sessions: SessionEntry[];
|
|
dayBillings: TicketDayBilling[];
|
|
project?: ProjectSummary | null;
|
|
todos?: TicketTodo[];
|
|
canClose: boolean;
|
|
openCount: number;
|
|
ticketOpenCount: number;
|
|
};
|
|
|
|
export type MonthOverview = PeriodOverview;
|
|
export type TicketMonth = TicketPeriod;
|
|
|
|
export type StatisticsDailyBucket = {
|
|
day: string;
|
|
sessions: number;
|
|
total_minutes: number;
|
|
billed_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
billed_sessions: number;
|
|
non_billable_sessions: number;
|
|
open_sessions: number;
|
|
crm_billed_minutes: number;
|
|
};
|
|
|
|
export type StatisticsGroup = {
|
|
organization_id?: string | null;
|
|
organization_name?: string;
|
|
work_type?: WorkType;
|
|
tickets: number;
|
|
sessions: number;
|
|
total_minutes: number;
|
|
billed_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
billed_sessions: number;
|
|
non_billable_sessions: number;
|
|
open_sessions: number;
|
|
crm_billed_minutes: number;
|
|
crm_delta_minutes: number;
|
|
};
|
|
|
|
export type StatisticsTicket = {
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
organization_id: string | null;
|
|
organization_name: string;
|
|
active_days: number;
|
|
sessions: number;
|
|
total_minutes: number;
|
|
billed_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
billed_sessions: number;
|
|
non_billable_sessions: number;
|
|
open_sessions: number;
|
|
crm_billed_minutes: number;
|
|
crm_delta_minutes: number;
|
|
};
|
|
|
|
export type StatisticsOpenSession = {
|
|
id: string;
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
organization_name: string;
|
|
activity: string;
|
|
started_at: string;
|
|
rounded_minutes: number;
|
|
};
|
|
|
|
export type StatisticsCrmDay = {
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
organization_name: string;
|
|
day: string;
|
|
tracked_minutes: number;
|
|
crm_billed_minutes: number;
|
|
delta_minutes?: number;
|
|
acknowledged?: boolean;
|
|
acknowledged_at?: string | null;
|
|
};
|
|
|
|
export type StatisticsOverview = {
|
|
periodType: "month";
|
|
period: string;
|
|
closed: boolean;
|
|
closedAt: string | null;
|
|
totals: {
|
|
tickets: number;
|
|
sessions: number;
|
|
minutes: number;
|
|
billedMinutes: number;
|
|
nonBillableMinutes: number;
|
|
openMinutes: number;
|
|
billedSessions: number;
|
|
nonBillableSessions: number;
|
|
openSessions: number;
|
|
recurringMinutes: number;
|
|
manualMinutes: number;
|
|
recurringSessions: number;
|
|
manualSessions: number;
|
|
averageSessionMinutes: number;
|
|
activeDays: number;
|
|
crmBilledMinutes: number;
|
|
crmDeltaMinutes: number;
|
|
};
|
|
dailySeries: StatisticsDailyBucket[];
|
|
organizations: StatisticsGroup[];
|
|
workTypes: StatisticsGroup[];
|
|
tickets: StatisticsTicket[];
|
|
attention: {
|
|
openSessions: StatisticsOpenSession[];
|
|
missingCrmDays: StatisticsCrmDay[];
|
|
acknowledgedMissingCrmDays: StatisticsCrmDay[];
|
|
crmMismatches: StatisticsCrmDay[];
|
|
};
|
|
};
|