598 lines
16 KiB
TypeScript
598 lines
16 KiB
TypeScript
export type WorkType = "support" | "consulting";
|
|
export type BillingStatus = "billable" | "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;
|
|
teamspace_user_id: string | null;
|
|
has_teamspace_credentials: boolean;
|
|
zammad_email_session_webhook_enabled: boolean;
|
|
session_billing_prompt_enabled: boolean;
|
|
teamspace_time_tracking_enabled: boolean;
|
|
zammad_session_note_default_enabled: boolean;
|
|
zammad_time_unit_rounding_enabled: boolean;
|
|
zammad_time_unit_rounding_minutes: number;
|
|
zammad_atoss_email_sync_enabled: boolean;
|
|
zammad_article_type_id: number;
|
|
project_followup_enabled: boolean;
|
|
project_followup_weeks: number;
|
|
project_followup_second_enabled: boolean;
|
|
project_followup_second_weeks: number;
|
|
project_followup_complete_on_session: boolean;
|
|
};
|
|
|
|
export type DashboardWidgetType = "dayControl" | "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 DashboardDayTicket = {
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
title: string | null;
|
|
organization_name: string | null;
|
|
work_type: WorkType | null;
|
|
zammad_priority_id: string | null;
|
|
zammad_state_id: string | null;
|
|
zammad_pending_time: string | null;
|
|
latest_started_at: string | null;
|
|
has_project: boolean;
|
|
own_session_count: number;
|
|
open_session_count: number;
|
|
open_todo_count: number;
|
|
due_todo_count: number;
|
|
};
|
|
|
|
export type AdminUser = AuthUser & {
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
export type ZammadSessionArticleQueueItem = {
|
|
id: string;
|
|
session_id: string;
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
zammad_ticket_id: string | null;
|
|
activity: string;
|
|
time_unit: number;
|
|
zammad_article_type_id: number;
|
|
attempt_count: number;
|
|
last_error: string | null;
|
|
last_attempt_at: string | null;
|
|
created_at: string;
|
|
started_at: string;
|
|
rounded_minutes: number;
|
|
};
|
|
|
|
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;
|
|
zammad_owner_user_id?: string | null;
|
|
zammad_owner_display_name?: string | null;
|
|
zammad_owner_username?: string | null;
|
|
is_foreign_zammad_owner?: boolean;
|
|
can_edit_ticket_data?: boolean;
|
|
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;
|
|
zammad_priority_id?: string | null;
|
|
zammad_state_id?: string | null;
|
|
zammad_ticket_id?: string | null;
|
|
zammad_owner_id?: string | null;
|
|
ticket_zammad_owner_id?: string | null;
|
|
zammad_pending_time?: string | null;
|
|
zammad_merged_from_ticket_id?: string | null;
|
|
zammad_merged_from_ticket_number?: string | 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;
|
|
unassigned_teamspace_subentry_count?: number;
|
|
close_review_required?: boolean;
|
|
hidden_for_user?: boolean;
|
|
};
|
|
|
|
export type ProjectTeamspaceEntry = {
|
|
id: string;
|
|
project_id?: string;
|
|
teamspace_project: string | null;
|
|
teamspace_api_project_id?: string | null;
|
|
teamspace_api_project_url?: string | null;
|
|
teamspace_description?: string | null;
|
|
subentries?: ProjectTeamspaceSubentry[];
|
|
is_default: boolean;
|
|
hour_budget_minutes: number | null;
|
|
budget_sync_disabled?: boolean;
|
|
manual_consumption_minutes: number;
|
|
teamspace_consumption_minutes?: number;
|
|
consumption_minutes?: number;
|
|
display_order?: number;
|
|
};
|
|
|
|
export type ProjectTeamspaceSubentry = {
|
|
id: string;
|
|
project_teamspace_entry_id?: string;
|
|
teamspace_api_project_id: string;
|
|
teamspace_api_project_url: string | null;
|
|
teamspace_project_id: string | null;
|
|
billing_type: string | null;
|
|
name: string | null;
|
|
alias: string;
|
|
description: string;
|
|
progress: number | null;
|
|
planned_minutes: number | null;
|
|
sum_minutes: number | null;
|
|
planned_minutes_billable: number | null;
|
|
sum_minutes_billable: number | null;
|
|
planned_income: number | string | null;
|
|
sum_income: number | string | null;
|
|
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;
|
|
crm_billed_minutes: number;
|
|
billable_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
open_count: number;
|
|
ticket_open_count: number;
|
|
billable_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;
|
|
billableMinutes: number;
|
|
nonBillableMinutes: number;
|
|
openMinutes: number;
|
|
openSessions: number;
|
|
};
|
|
tickets: TicketSummary[];
|
|
openSessions: OpenSession[];
|
|
activitySeries: ActivityBucket[];
|
|
};
|
|
|
|
export type TicketDayBilling = {
|
|
day: string;
|
|
project_teamspace_entry_id?: string | null;
|
|
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;
|
|
zammad_article_body?: string | null;
|
|
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;
|
|
zammad_source_article_id?: string | null;
|
|
zammad_article_status?: "pending" | "sent" | null;
|
|
zammad_article_id?: string | null;
|
|
zammad_article_type_id?: number;
|
|
};
|
|
|
|
export type TicketPeriod = {
|
|
periodType: TicketDetailPeriodType;
|
|
period: string;
|
|
closed: boolean;
|
|
closedAt: string | null;
|
|
filters?: {
|
|
month: string;
|
|
status: "all" | "open" | "billable" | "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;
|
|
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;
|
|
zammad_owner_user_id?: string | null;
|
|
zammad_owner_display_name?: string | null;
|
|
zammad_owner_username?: string | null;
|
|
is_foreign_zammad_owner?: boolean;
|
|
can_edit_ticket_data?: boolean;
|
|
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;
|
|
billable_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
billed_sessions: number;
|
|
billable_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;
|
|
billable_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
billed_sessions: number;
|
|
billable_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;
|
|
billable_minutes: number;
|
|
non_billable_minutes: number;
|
|
open_minutes: number;
|
|
billed_sessions: number;
|
|
billable_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 StatisticsTeamspaceDay = {
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
organization_name: string;
|
|
day: string;
|
|
tracked_minutes: number;
|
|
crm_billed_minutes: number;
|
|
delta_minutes: number;
|
|
session_count: number;
|
|
project_teamspace_project: string | null;
|
|
};
|
|
|
|
export type StatisticsProjectFollowup = {
|
|
project_id: string;
|
|
ticket_id: string;
|
|
ticket_number: string;
|
|
title: string | null;
|
|
organization_name: string | null;
|
|
teamspace_project: string | null;
|
|
hour_budget_minutes: number | null;
|
|
consumption_minutes: number;
|
|
remaining_minutes: number | null;
|
|
latest_tt_update: string;
|
|
last_session_at: string | null;
|
|
project_updated_at: string;
|
|
open_followup_todo_id: string | null;
|
|
followup_state: "open" | "done" | "dismissed" | null;
|
|
open_todos: number;
|
|
overdue_todos: number;
|
|
};
|
|
|
|
export type StatisticsProjectFollowupOverview = {
|
|
enabled: boolean;
|
|
weeks: number;
|
|
secondEnabled: boolean;
|
|
secondWeeks: number;
|
|
createdTodos: number;
|
|
updatedTodos: number;
|
|
projects: StatisticsProjectFollowup[];
|
|
};
|
|
|
|
export type StatisticsOverview = {
|
|
periodType: "month" | "week";
|
|
period: string;
|
|
closed: boolean;
|
|
closedAt: string | null;
|
|
totals: {
|
|
tickets: number;
|
|
sessions: number;
|
|
minutes: number;
|
|
billedMinutes: number;
|
|
billableMinutes: number;
|
|
nonBillableMinutes: number;
|
|
openMinutes: number;
|
|
billedSessions: number;
|
|
billableSessions: 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[];
|
|
};
|
|
teamspaceDays: StatisticsTeamspaceDay[];
|
|
};
|