This commit is contained in:
michael committed 2026-09-29 07:46:21 +02:00
1 parent 2105a0c5f7
commit c89d4825e2
30 files changed
+5435 -627

No files matched your search

+103 -5
View File
@@ -19,11 +19,13 @@ import type {
WorkType,
ZammadSessionArticleQueueItem
} from "./types";
import type { TimerEntry, TimerPhase } from "./timers";
type CreateSessionPayload = {
ticketNumber: string;
organizationId: string;
activity: string;
zammadArticleBody?: string | null;
workType: WorkType;
startedAt: string;
endedAt: string;
@@ -35,6 +37,22 @@ type CreateSessionPayload = {
zammadArticleTypeId?: number;
};
type CreateTimerPayload = Omit<TimerEntry, "id"> & {
id?: string;
};
type UpdateTimerPayload = Partial<{
organizationName: string | null;
workType: TimerEntry["workType"];
isProject: boolean;
projectName: string | null;
ticketLookupDone: boolean;
activity: string;
zammadArticleBody?: string | null;
billingStatus: TimerEntry["billingStatus"];
phase: TimerPhase;
}>;
type DeleteSessionResult = {
deleted: {
id: string;
@@ -50,7 +68,7 @@ type DeleteSessionResult = {
export type CreateSessionResult = {
zammadArticle?: {
requested: boolean;
status: "not_requested" | "sent" | "queued";
status: "not_requested" | "sent" | "failed";
error: string | null;
articleId: number | null;
};
@@ -106,6 +124,25 @@ export type ZammadSyncJob = {
finishedAt: string | null;
};
export type TicketZammadMailSessionItem = {
articleId: number;
ticketNumber: string;
subject: string | null;
activity: string;
createdAt: string;
endedAt: string;
timeUnit: number;
durationSeconds: number;
};
export type TicketZammadMailSessionResult = {
checked: number;
created: number;
skipped: number;
items: TicketZammadMailSessionItem[];
errors: Array<{ articleId: number; error: string }>;
};
export type RestoreValidationResult = {
valid: boolean;
checkedTables: number;
@@ -215,6 +252,7 @@ export function updateCurrentUser(payload: {
zammadSessionNoteDefaultEnabled?: boolean;
zammadTimeUnitRoundingEnabled?: boolean;
zammadTimeUnitRoundingMinutes?: number;
zammadAtossEmailSyncEnabled?: boolean;
zammadArticleTypeId?: number;
}) {
return request<{ user: AuthUser }>("/api/auth/me", {
@@ -479,6 +517,20 @@ export function applyOwnZammadConsultingTicketsFromPreview(previewJobId: string,
}, onJobStarted);
}
export function previewZammadMailSessions(daysBack: number, perPage: number, onJobStarted?: (job: ZammadSyncJob) => void) {
return runZammadSyncJob("/api/zammad-sync/jobs/mail-sessions", {
dryRun: true,
daysBack,
perPage
}, onJobStarted);
}
export function applyZammadMailSessionsFromPreview(previewJobId: string, articleIds: number[], onJobStarted?: (job: ZammadSyncJob) => void) {
return runZammadSyncJob(`/api/zammad-sync/jobs/${encodeURIComponent(previewJobId)}/apply-mail-sessions`, {
articleIds
}, onJobStarted);
}
export function getRecurringBillings() {
return request<{ recurringBillings: RecurringBilling[] }>("/api/recurring-billings");
}
@@ -564,6 +616,7 @@ export function createProject(payload: {
teamspaceEntries?: Array<{
id?: string | null;
teamspaceProject?: string | null;
teamspaceDescription?: string | null;
isDefault: boolean;
hourBudgetMinutes?: number | null;
budgetSyncDisabled?: boolean;
@@ -592,6 +645,7 @@ export function updateProject(
teamspaceEntries?: Array<{
id?: string | null;
teamspaceProject?: string | null;
teamspaceDescription?: string | null;
isDefault: boolean;
hourBudgetMinutes?: number | null;
budgetSyncDisabled?: boolean;
@@ -699,6 +753,37 @@ export function createSession(payload: CreateSessionPayload) {
});
}
export function resendSessionZammadArticle(sessionId: string, payload: { zammadArticleTypeId?: number } = {}) {
return request<CreateSessionResult>(`/api/sessions/${encodeURIComponent(sessionId)}/zammad-article`, {
method: "POST",
body: JSON.stringify(payload)
});
}
export function getActiveTimers() {
return request<{ timers: TimerEntry[] }>("/api/timers");
}
export function createActiveTimer(payload: CreateTimerPayload) {
return request<{ timers: TimerEntry[] }>("/api/timers", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function updateActiveTimer(timerId: string, payload: UpdateTimerPayload) {
return request<{ timers: TimerEntry[] }>(`/api/timers/${encodeURIComponent(timerId)}`, {
method: "PATCH",
body: JSON.stringify(payload)
});
}
export function deleteActiveTimer(timerId: string) {
return request<{ timers: TimerEntry[] }>(`/api/timers/${encodeURIComponent(timerId)}`, {
method: "DELETE"
});
}
export function getZammadSessionArticleQueue() {
return request<{ queue: ZammadSessionArticleQueueItem[] }>("/api/zammad/session-article-queue");
}
@@ -749,6 +834,7 @@ export function updateSessionDetails(
payload: {
organizationId: string;
activity: string;
zammadArticleBody?: string | null;
workType: WorkType;
removeProjectData?: boolean;
projectTeamspaceEntryId?: string | null;
@@ -762,10 +848,10 @@ export function updateSessionDetails(
});
}
export function updateTicketDayBilling(ticketId: string, day: string, billedMinutes: number | null) {
export function updateTicketDayBilling(ticketId: string, day: string, billedMinutes: number | null, projectTeamspaceEntryId?: string | null) {
return request(`/api/tickets/${ticketId}/day-billings/${day}`, {
method: "PATCH",
body: JSON.stringify({ billedMinutes })
body: JSON.stringify({ billedMinutes, projectTeamspaceEntryId: projectTeamspaceEntryId ?? null })
});
}
@@ -792,8 +878,8 @@ export function getPeriodOverview(type: PeriodType, period: string) {
return request<PeriodOverview>(`/api/periods/${periodPath(type)}/${period}/overview`);
}
export function getStatisticsOverview(month: string) {
return request<StatisticsOverview>(`/api/statistics/months/${month}`);
export function getStatisticsOverview(period: string, type: "month" | "week" = "month") {
return request<StatisticsOverview>(`/api/statistics/${type === "week" ? "weeks" : "months"}/${period}`);
}
export function getTicketPeriod(type: PeriodType, period: string, ticketId: string) {
@@ -825,6 +911,18 @@ export function getTicketDetails(
return request<TicketPeriod>(`/api/tickets/${ticketId}/details${params.size ? `?${params}` : ""}`);
}
export function previewTicketZammadMailSessions(ticketId: string, daysBack: number) {
const params = new URLSearchParams({ daysBack: String(daysBack) });
return request<TicketZammadMailSessionResult>(`/api/tickets/${ticketId}/zammad-mail-sessions?${params}`);
}
export function importTicketZammadMailSessions(ticketId: string, daysBack: number, articleIds: number[]) {
return request<TicketZammadMailSessionResult>(`/api/tickets/${ticketId}/zammad-mail-sessions`, {
method: "POST",
body: JSON.stringify({ daysBack, articleIds })
});
}
export function updateSessionBilling(sessionId: string, billingStatus: BillingStatus) {
return request(`/api/sessions/${sessionId}/billing`, {
method: "PATCH",