Update
This commit is contained in:
1 parent
040f1903e6
commit
d6c8877ed7
16 files changed
+1540
-177
No files matched your search
@@ -3,6 +3,7 @@ APP_PORT=3910
|
||||
|
||||
DATABASE_URL=postgresql://tickettracker:change-me@10.10.10.23:5432/tickettracker
|
||||
SECRET_ENCRYPTION_KEY=change-me-secret-encryption-key
|
||||
ZAMMAD_EMAIL_WEBHOOK_TOKEN=change-me-zammad-webhook-token
|
||||
DB_POOL_SIZE=10
|
||||
|
||||
COOKIE_SECURE=false
|
||||
|
||||
@@ -5,6 +5,7 @@ POSTGRES_DB=tickettracker
|
||||
POSTGRES_USER=tickettracker
|
||||
POSTGRES_PASSWORD=change-me-db-password
|
||||
SECRET_ENCRYPTION_KEY=change-me-secret-encryption-key
|
||||
ZAMMAD_EMAIL_WEBHOOK_TOKEN=change-me-zammad-webhook-token
|
||||
DB_POOL_SIZE=10
|
||||
|
||||
COOKIE_SECURE=false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
DATABASE_URL=postgresql://tickettracker:change-me@10.10.10.23:5432/tickettracker
|
||||
SECRET_ENCRYPTION_KEY=change-me-secret-encryption-key
|
||||
ZAMMAD_EMAIL_WEBHOOK_TOKEN=change-me-zammad-webhook-token
|
||||
APP_PORT=3910
|
||||
TICKETTRACKER_IMAGE=git.d-razz.de/michael/tickettracker:latest
|
||||
COOKIE_SECURE=false
|
||||
|
||||
@@ -4,3 +4,4 @@ APP_PORT=3911
|
||||
TICKETTRACKER_IMAGE=git.d-razz.de/michael/tickettracker:latest
|
||||
COOKIE_SECURE=false
|
||||
DB_POOL_SIZE=10
|
||||
ZAMMAD_EMAIL_WEBHOOK_TOKEN='sPXJc87R@ySW3uTFKjGFMrti8BcDkNv8mN2g71hRkdg='
|
||||
+5
-2
@@ -17,6 +17,7 @@ export type AuthUser = {
|
||||
active: boolean;
|
||||
zammad_user_id: string | null;
|
||||
has_zammad_api_token: boolean;
|
||||
zammad_email_session_webhook_enabled: boolean;
|
||||
};
|
||||
|
||||
declare global {
|
||||
@@ -77,7 +78,8 @@ function publicUser(user: AuthUser) {
|
||||
role: user.role,
|
||||
active: user.active,
|
||||
zammad_user_id: user.zammad_user_id ?? null,
|
||||
has_zammad_api_token: Boolean(user.has_zammad_api_token)
|
||||
has_zammad_api_token: Boolean(user.has_zammad_api_token),
|
||||
zammad_email_session_webhook_enabled: Boolean(user.zammad_email_session_webhook_enabled)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -134,7 +136,8 @@ export async function requireAuth(req: Request, res: Response, next: NextFunctio
|
||||
u.role,
|
||||
u.active,
|
||||
u.zammad_user_id::text AS zammad_user_id,
|
||||
(u.zammad_api_token IS NOT NULL) AS has_zammad_api_token
|
||||
(u.zammad_api_token IS NOT NULL) AS has_zammad_api_token,
|
||||
u.zammad_email_session_webhook_enabled
|
||||
FROM auth_sessions s
|
||||
JOIN users u ON u.id = s.user_id
|
||||
WHERE s.token_hash = $1
|
||||
|
||||
+725
-167
File diff suppressed because it is too large.
Load diff
@@ -86,6 +86,7 @@ export async function migrate() {
|
||||
`);
|
||||
await query("ALTER TABLE users ADD COLUMN IF NOT EXISTS zammad_api_token TEXT;");
|
||||
await query("ALTER TABLE users ADD COLUMN IF NOT EXISTS zammad_user_id BIGINT;");
|
||||
await query("ALTER TABLE users ADD COLUMN IF NOT EXISTS zammad_email_session_webhook_enabled BOOLEAN NOT NULL DEFAULT false;");
|
||||
|
||||
await query(`
|
||||
CREATE TABLE IF NOT EXISTS auth_sessions (
|
||||
@@ -220,6 +221,27 @@ export async function migrate() {
|
||||
await query("ALTER TABLE sessions ADD COLUMN IF NOT EXISTS recurring_occurrence_date DATE;");
|
||||
await query("ALTER TABLE sessions ADD COLUMN IF NOT EXISTS recurring_occurrence_key TEXT;");
|
||||
await query("ALTER TABLE sessions ADD COLUMN IF NOT EXISTS project_teamspace_entry_id BIGINT;");
|
||||
await query(`
|
||||
CREATE TABLE IF NOT EXISTS zammad_email_session_events (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
zammad_article_id BIGINT,
|
||||
delivery_id TEXT,
|
||||
session_id BIGINT REFERENCES sessions(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT zammad_email_session_event_source CHECK (zammad_article_id IS NOT NULL OR delivery_id IS NOT NULL)
|
||||
);
|
||||
`);
|
||||
await query(`
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_zammad_email_session_events_user_article
|
||||
ON zammad_email_session_events(user_id, zammad_article_id)
|
||||
WHERE zammad_article_id IS NOT NULL;
|
||||
`);
|
||||
await query(`
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_zammad_email_session_events_delivery
|
||||
ON zammad_email_session_events(delivery_id)
|
||||
WHERE delivery_id IS NOT NULL;
|
||||
`);
|
||||
if (adminId) {
|
||||
await query("UPDATE sessions SET user_id = $1 WHERE user_id IS NULL;", [adminId]);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ services:
|
||||
environment:
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER:-tickettracker}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-tickettracker}
|
||||
SECRET_ENCRYPTION_KEY: ${SECRET_ENCRYPTION_KEY:-}
|
||||
ZAMMAD_EMAIL_WEBHOOK_TOKEN: ${ZAMMAD_EMAIL_WEBHOOK_TOKEN:-}
|
||||
PORT: 3000
|
||||
BACKEND_PORT: 3001
|
||||
API_PROXY_TARGET: http://127.0.0.1:3001
|
||||
|
||||
@@ -8,6 +8,7 @@ services:
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
SECRET_ENCRYPTION_KEY: ${SECRET_ENCRYPTION_KEY:-}
|
||||
ZAMMAD_EMAIL_WEBHOOK_TOKEN: ${ZAMMAD_EMAIL_WEBHOOK_TOKEN:-}
|
||||
PORT: 3000
|
||||
BACKEND_PORT: 3001
|
||||
API_PROXY_TARGET: http://127.0.0.1:3001
|
||||
|
||||
@@ -528,9 +528,9 @@ function SidebarTimers({ timers, selectedTimerId, setSelectedTimerId, setTimers,
|
||||
<span className="truncate text-xs font-medium">{timer.ticketNumber}</span>
|
||||
</span>
|
||||
{timer.organizationName ? (
|
||||
<span className="block truncate text-[11px] leading-4 text-muted-foreground">
|
||||
{timer.isProject ? "Projekt · " : ""}
|
||||
{timer.projectName || timer.organizationName}
|
||||
<span className="flex min-w-0 items-center gap-1 truncate text-[11px] leading-4 text-muted-foreground">
|
||||
{timer.isProject ? <FolderGit className="size-3 shrink-0" aria-label="Projekt" /> : null}
|
||||
<span className="truncate">{timer.organizationName}</span>
|
||||
</span>
|
||||
) : null}
|
||||
<span className="block font-mono text-[11px] font-semibold leading-4 tracking-normal text-muted-foreground">
|
||||
|
||||
@@ -197,6 +197,7 @@ export function updateCurrentUser(payload: {
|
||||
currentPassword?: string;
|
||||
newPassword?: string;
|
||||
zammadApiToken?: string;
|
||||
zammadEmailSessionWebhookEnabled?: boolean;
|
||||
}) {
|
||||
return request<{ user: AuthUser }>("/api/auth/me", {
|
||||
method: "PATCH",
|
||||
|
||||
@@ -12,6 +12,7 @@ export type AuthUser = {
|
||||
active: boolean;
|
||||
zammad_user_id: string | null;
|
||||
has_zammad_api_token: boolean;
|
||||
zammad_email_session_webhook_enabled: boolean;
|
||||
};
|
||||
|
||||
export type DashboardWidgetType = "dayControl" | "today" | "month" | "openRatings" | "projectBudgets" | "todos" | "teamspace" | "favorites" | "divider" | "statistic" | "notes";
|
||||
@@ -425,6 +426,18 @@ export type StatisticsCrmDay = {
|
||||
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 StatisticsOverview = {
|
||||
periodType: "month";
|
||||
period: string;
|
||||
@@ -459,4 +472,5 @@ export type StatisticsOverview = {
|
||||
acknowledgedMissingCrmDays: StatisticsCrmDay[];
|
||||
crmMismatches: StatisticsCrmDay[];
|
||||
};
|
||||
teamspaceDays: StatisticsTeamspaceDay[];
|
||||
};
|
||||
@@ -22,7 +22,7 @@ import { CopyTicketButton } from "@/components/CopyTicketButton";
|
||||
import { HelpLink } from "@/components/HelpLink";
|
||||
import { acknowledgeMissingTicketDayBilling, closePeriod, getStatisticsOverview, reopenPeriod } from "../api";
|
||||
import { currentMonth, formatDate, formatDateTime, formatMinutes } from "../format";
|
||||
import type { StatisticsCrmDay, StatisticsOpenSession, StatisticsOverview } from "../types";
|
||||
import type { StatisticsCrmDay, StatisticsOpenSession, StatisticsOverview, StatisticsTeamspaceDay } from "../types";
|
||||
|
||||
type MonthlyClosePageProps = {
|
||||
onNavigate: (to: string) => void;
|
||||
@@ -156,6 +156,36 @@ function CrmDayItem({
|
||||
);
|
||||
}
|
||||
|
||||
function TeamspaceDayItem({ item, onNavigate }: { item: StatisticsTeamspaceDay; onNavigate: (to: string) => void }) {
|
||||
const deltaVariant = item.delta_minutes === 0 ? "outline" : item.delta_minutes > 0 ? "success" : "destructive";
|
||||
|
||||
return (
|
||||
<div className="grid gap-3 rounded-md border bg-background px-3 py-2 lg:grid-cols-[minmax(8rem,0.85fr)_minmax(0,1.45fr)_minmax(15rem,1fr)_auto] lg:items-center">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Badge variant="outline">{formatDate(`${item.day}T00:00:00`)}</Badge>
|
||||
<Badge variant="info">{item.session_count} Session(s)</Badge>
|
||||
</div>
|
||||
<div className="min-w-0 space-y-1">
|
||||
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
||||
<span className="font-medium">{item.ticket_number}</span>
|
||||
<CopyTicketButton ticketNumber={item.ticket_number} />
|
||||
{item.project_teamspace_project ? <Badge variant="secondary">{item.project_teamspace_project}</Badge> : null}
|
||||
</div>
|
||||
<p className="truncate text-sm text-muted-foreground">{item.organization_name}</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-x-3 gap-y-1 text-sm">
|
||||
<span className={`font-medium ${trackedTextClass}`}>Abgerechnet {formatMinutes(item.tracked_minutes)}</span>
|
||||
<span className={`font-medium ${teamspaceTextClass}`}>Teamspace {formatMinutes(item.crm_billed_minutes)}</span>
|
||||
<Badge variant={deltaVariant}>Diff. {formatTeamspaceDelta(item.delta_minutes)}</Badge>
|
||||
</div>
|
||||
<Button className="h-8 justify-self-start lg:justify-self-end" variant="secondary" size="sm" onClick={() => onNavigate(`/tickets/${item.ticket_id}?month=${item.day.slice(0, 7)}`)}>
|
||||
Tag öffnen
|
||||
<ExternalLink className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function MonthlyClosePage({ onNavigate }: MonthlyClosePageProps) {
|
||||
const [month, setMonth] = useState(currentMonth());
|
||||
const [stats, setStats] = useState<StatisticsOverview | null>(null);
|
||||
@@ -274,6 +304,7 @@ export function MonthlyClosePage({ onNavigate }: MonthlyClosePageProps) {
|
||||
const openSessions = stats?.attention.openSessions ?? [];
|
||||
const missingCrmDays = stats?.attention.missingCrmDays ?? [];
|
||||
const acknowledgedMissingCrmDays = stats?.attention.acknowledgedMissingCrmDays ?? [];
|
||||
const teamspaceDays = stats?.teamspaceDays ?? [];
|
||||
const openTicketGroups = useMemo(() => groupOpenSessions(openSessions), [openSessions]);
|
||||
const visibleMissingCrmDays = useMemo(() => {
|
||||
const days = showAcknowledgedMissingCrm ? [...missingCrmDays, ...acknowledgedMissingCrmDays] : [...missingCrmDays];
|
||||
@@ -379,6 +410,29 @@ export function MonthlyClosePage({ onNavigate }: MonthlyClosePageProps) {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="p-4">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<CardTitle>Vergleich abgerechnete Zeiten Teamspace</CardTitle>
|
||||
<CardDescription>Teamspace-Tageswerte je Ticket mit Datum der abgerechneten Session(s) und Projekt, sofern verfügbar.</CardDescription>
|
||||
</div>
|
||||
<Badge variant="outline">{teamspaceDays.length} Eintrag(e)</Badge>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2 px-4 pb-4">
|
||||
{teamspaceDays.length > 0 ? (
|
||||
<div className="max-h-[28rem] space-y-2 overflow-y-auto pr-1">
|
||||
{teamspaceDays.map((item) => (
|
||||
<TeamspaceDayItem key={`${item.ticket_id}-${item.day}`} item={item} onNavigate={onNavigate} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="rounded-md border bg-muted/20 p-3 text-sm text-muted-foreground">Für diesen Monat sind noch keine Teamspace-Werte zu abgerechneten Ticket-Tagen vorhanden.</p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="p-4">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { FormEvent, useEffect, useState } from "react";
|
||||
import { KeyRound, Save, Unplug, UserCircle, X } from "lucide-react";
|
||||
import { KeyRound, MailPlus, Save, Unplug, UserCircle, X } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { HelpLink } from "@/components/HelpLink";
|
||||
import { updateCurrentUser } from "../api";
|
||||
import type { AuthUser } from "../types";
|
||||
@@ -21,6 +22,7 @@ export function ProfilePage({ currentUser, onUserUpdated }: ProfilePageProps) {
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [zammadApiToken, setZammadApiToken] = useState("");
|
||||
const [zammadTokenDirty, setZammadTokenDirty] = useState(false);
|
||||
const [zammadEmailSessionWebhookEnabled, setZammadEmailSessionWebhookEnabled] = useState(currentUser.zammad_email_session_webhook_enabled);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -28,6 +30,7 @@ export function ProfilePage({ currentUser, onUserUpdated }: ProfilePageProps) {
|
||||
setDisplayName(currentUser.display_name);
|
||||
setZammadApiToken("");
|
||||
setZammadTokenDirty(false);
|
||||
setZammadEmailSessionWebhookEnabled(currentUser.zammad_email_session_webhook_enabled);
|
||||
}, [currentUser]);
|
||||
|
||||
async function submit(event: FormEvent) {
|
||||
@@ -54,7 +57,8 @@ export function ProfilePage({ currentUser, onUserUpdated }: ProfilePageProps) {
|
||||
displayName,
|
||||
currentPassword: wantsPasswordChange ? currentPassword : undefined,
|
||||
newPassword: wantsPasswordChange ? newPassword : undefined,
|
||||
...(currentUser.role === "user" && zammadTokenDirty ? { zammadApiToken } : {})
|
||||
...(currentUser.role === "user" && zammadTokenDirty ? { zammadApiToken } : {}),
|
||||
...(currentUser.role === "user" ? { zammadEmailSessionWebhookEnabled } : {})
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -206,6 +210,22 @@ export function ProfilePage({ currentUser, onUserUpdated }: ProfilePageProps) {
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex items-center justify-between gap-3 rounded-md border bg-background p-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<MailPlus className="size-4 text-muted-foreground" />
|
||||
<div>
|
||||
<label className="text-sm font-medium" htmlFor="profile-zammad-email-session-webhook">
|
||||
eMail-Sessions aus Zammad
|
||||
</label>
|
||||
<p className="text-xs text-muted-foreground">Ausgehende Zammad-eMails automatisch als Session übernehmen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
id="profile-zammad-email-session-webhook"
|
||||
checked={zammadEmailSessionWebhookEnabled}
|
||||
onCheckedChange={setZammadEmailSessionWebhookEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FormEvent, useEffect, useMemo, useState } from "react";
|
||||
import type { Dispatch, SetStateAction } from "react";
|
||||
import { Pause, Play, Plus, RotateCcw, Search, Square, Upload } from "lucide-react";
|
||||
import { FolderGit, Pause, Play, Plus, RotateCcw, Search, Square, Upload } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -610,7 +610,13 @@ export function TimerPage({ timers, setTimers, selectedTimerId, setSelectedTimer
|
||||
<CardDescription>
|
||||
{selectedTimer
|
||||
? selectedTimer.organizationName
|
||||
? `${selectedTimer.isProject ? "Projekt · " : ""}${selectedTimer.projectName || selectedTimer.organizationName}${selectedTimer.workType ? ` · ${selectedTimer.workType === "support" ? "Support" : "Consulting"}` : ""}`
|
||||
? (
|
||||
<span className="inline-flex min-w-0 items-center gap-1.5">
|
||||
{selectedTimer.isProject ? <FolderGit className="size-3.5 shrink-0" aria-label="Projekt" /> : null}
|
||||
<span>{selectedTimer.organizationName}</span>
|
||||
{selectedTimer.workType ? <span>· {selectedTimer.workType === "support" ? "Support" : "Consulting"}</span> : null}
|
||||
</span>
|
||||
)
|
||||
: "Beim Umschalten wird dieser Timer aktiviert und alle anderen werden pausiert."
|
||||
: "Starte einen Timer, um eine Session zu erfassen."}
|
||||
</CardDescription>
|
||||
|
||||
+679
@@ -0,0 +1,679 @@
|
||||
Richtung out
|
||||
URL
|
||||
http://192.168.42.169:3911/api/zammad/email-session-webhook
|
||||
Methode
|
||||
POST
|
||||
Status
|
||||
0
|
||||
Anfrage
|
||||
accept-encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
accept: */*
|
||||
user-agent: Zammad User Agent
|
||||
host: 192.168.42.169:3911
|
||||
x-zammad-trigger: Tickettracker Test
|
||||
x-zammad-delivery: ef364583-36b3-40f3-bacb-967a09e7ddae
|
||||
content-type: application/json; charset=utf-8
|
||||
Authorization: Bearer [FILTERED]@ySW3uTFKjGFMrti8BcDkNv8mN2g71...[TRUNCATED]
|
||||
|
||||
{
|
||||
"ticket": {
|
||||
"abgerechnet": "",
|
||||
"ai_agent_running": false,
|
||||
"ai_stored_result_ids": [],
|
||||
"ai_stored_results": [],
|
||||
"article_count": 13,
|
||||
"article_ids": [
|
||||
66138,
|
||||
66151,
|
||||
66152,
|
||||
66139,
|
||||
66141,
|
||||
66145,
|
||||
66144,
|
||||
66146,
|
||||
66130,
|
||||
66149,
|
||||
66131,
|
||||
66150,
|
||||
66133
|
||||
],
|
||||
"atc_version": "-",
|
||||
"bemerkung": "",
|
||||
"bestellnummer": "",
|
||||
"checklist_id": null,
|
||||
"close_at": null,
|
||||
"close_diff_in_min": null,
|
||||
"close_escalation_at": null,
|
||||
"close_in_min": null,
|
||||
"create_article_sender": "Customer",
|
||||
"create_article_sender_id": 2,
|
||||
"create_article_type": "phone",
|
||||
"create_article_type_id": 5,
|
||||
"created_at": "2026-09-22T14:56:23.929Z",
|
||||
"created_by": {
|
||||
"active": true,
|
||||
"address": "",
|
||||
"city": "",
|
||||
"country": "",
|
||||
"created_at": "2025-03-31T08:14:45.514Z",
|
||||
"created_by": "marco.christener@aikava.de",
|
||||
"created_by_id": 3,
|
||||
"department": "Senior Software Consultant",
|
||||
"email": "michael.boehmlaender@aikava.de",
|
||||
"fax": "",
|
||||
"firstname": "Michael",
|
||||
"id": 1764,
|
||||
"image": "facb8844175ddeb0a0fab286b9b68fbd",
|
||||
"image_source": null,
|
||||
"lastname": "Böhmländer",
|
||||
"login": "michael.boehmlaender@aikava.de",
|
||||
"mobile": "",
|
||||
"mobile_2": "",
|
||||
"note": "Geplante Abwesenheiten:",
|
||||
"organization": "AIKAVA GmbH",
|
||||
"organization_id": 2,
|
||||
"organization_ids": [],
|
||||
"organizations": [],
|
||||
"out_of_office": true,
|
||||
"out_of_office_end_at": "2026-08-28",
|
||||
"out_of_office_replacement": "marco.dirscherl@aikava.de",
|
||||
"out_of_office_replacement_id": 77,
|
||||
"out_of_office_start_at": "2026-08-17",
|
||||
"overview_sorting_ids": [
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
304,
|
||||
305,
|
||||
306,
|
||||
307,
|
||||
308,
|
||||
309,
|
||||
310,
|
||||
311,
|
||||
312,
|
||||
313,
|
||||
314,
|
||||
315,
|
||||
316,
|
||||
317,
|
||||
318,
|
||||
319,
|
||||
320
|
||||
],
|
||||
"phone": "",
|
||||
"role_ids": [
|
||||
2,
|
||||
1
|
||||
],
|
||||
"roles": [
|
||||
"Admin",
|
||||
"Agent"
|
||||
],
|
||||
"source": null,
|
||||
"street": "",
|
||||
"two_factor_preference_ids": [],
|
||||
"two_factor_preferences": [],
|
||||
"updated_at": "2026-09-21T05:56:12.741Z",
|
||||
"updated_by": "michael.boehmlaender@aikava.de",
|
||||
"updated_by_id": 1764,
|
||||
"verified": false,
|
||||
"vip": false,
|
||||
"web": "",
|
||||
"zip": ""
|
||||
},
|
||||
"created_by_id": 1764,
|
||||
"customer": {
|
||||
"active": true,
|
||||
"address": "testadresse",
|
||||
"city": "",
|
||||
"country": "",
|
||||
"created_at": "2023-01-10T13:07:40.366Z",
|
||||
"created_by": "thomas.roider@aikava.de",
|
||||
"created_by_id": 4,
|
||||
"department": "",
|
||||
"email": "test@test.de",
|
||||
"fax": "",
|
||||
"firstname": "Testkundenbesitzer",
|
||||
"id": 6,
|
||||
"image": null,
|
||||
"image_source": null,
|
||||
"lastname": "Testnachname",
|
||||
"login": "test@test.de",
|
||||
"mobile": "",
|
||||
"mobile_2": null,
|
||||
"note": "testkunde",
|
||||
"organization": "AIKAVA GmbH",
|
||||
"organization_id": 2,
|
||||
"organization_ids": [],
|
||||
"organizations": [],
|
||||
"out_of_office": false,
|
||||
"out_of_office_end_at": null,
|
||||
"out_of_office_replacement_id": null,
|
||||
"out_of_office_start_at": null,
|
||||
"overview_sorting_ids": [],
|
||||
"overview_sortings": [],
|
||||
"phone": "+49123456789",
|
||||
"role_ids": [],
|
||||
"roles": [],
|
||||
"source": null,
|
||||
"street": "",
|
||||
"two_factor_preference_ids": [],
|
||||
"two_factor_preferences": [],
|
||||
"updated_at": "2026-09-22T14:56:23.989Z",
|
||||
"updated_by": "thomas.roider@aikava.de",
|
||||
"updated_by_id": 4,
|
||||
"verified": false,
|
||||
"vip": false,
|
||||
"web": "",
|
||||
"zip": ""
|
||||
},
|
||||
"customer_id": 6,
|
||||
"daily_event_lock_ids": [],
|
||||
"daily_event_locks": [],
|
||||
"escalation_at": null,
|
||||
"first_response_at": "2026-09-22T15:00:35.799Z",
|
||||
"first_response_diff_in_min": null,
|
||||
"first_response_escalation_at": null,
|
||||
"first_response_in_min": null,
|
||||
"gesamtbudget": "",
|
||||
"group": {
|
||||
"active": true,
|
||||
"assignment_timeout": null,
|
||||
"created_at": "2023-01-10T12:33:22.977Z",
|
||||
"created_by": "thomas.roider@aikava.de",
|
||||
"created_by_id": 4,
|
||||
"email_address": "Zammad Helpdesk Support",
|
||||
"email_address_id": 6,
|
||||
"follow_up_assignment": true,
|
||||
"follow_up_possible": "yes",
|
||||
"id": 3,
|
||||
"name": "Support",
|
||||
"name_last": "Support",
|
||||
"note": "Support AIKAVA",
|
||||
"parent_id": null,
|
||||
"reopen_time_in_days": null,
|
||||
"shared_drafts": true,
|
||||
"signature": "AIKAVA - Abteilung als Berufsbezeichnung (Gruppe Support)",
|
||||
"signature_id": 2,
|
||||
"summary_generation": "global_default",
|
||||
"updated_at": "2026-07-30T09:34:01.249Z",
|
||||
"updated_by": "thomas.roider@aikava.de",
|
||||
"updated_by_id": 4,
|
||||
"user_ids": [
|
||||
6,
|
||||
2308,
|
||||
2309,
|
||||
251,
|
||||
77,
|
||||
4,
|
||||
3
|
||||
],
|
||||
"users": [
|
||||
"test@test.de",
|
||||
"apiuser@aikava.de",
|
||||
"hung.nguyen@aikava.de",
|
||||
"corinna.breu@aikava.de",
|
||||
"marco.dirscherl@aikava.de",
|
||||
"thomas.roider@aikava.de",
|
||||
"marco.christener@aikava.de"
|
||||
]
|
||||
},
|
||||
"group_id": 3,
|
||||
"id": 7035,
|
||||
"last_close_at": null,
|
||||
"last_contact_agent_at": "2026-09-23T06:47:38.553Z",
|
||||
"last_contact_at": "2026-09-23T06:47:38.553Z",
|
||||
"last_contact_customer_at": "2026-09-22T14:56:24.008Z",
|
||||
"last_owner_update_at": "2026-09-23T06:47:38.566Z",
|
||||
"netzwerkpfad": "",
|
||||
"note": null,
|
||||
"number": "947021",
|
||||
"organization": {
|
||||
"active": true,
|
||||
"country": "",
|
||||
"created_at": "2023-01-06T11:06:22.976Z",
|
||||
"created_by": "-",
|
||||
"created_by_id": 1,
|
||||
"customer_owner": null,
|
||||
"dauerticket_bestellnummer": "",
|
||||
"dauerticket_url": "",
|
||||
"domain": "aikava.de",
|
||||
"domain_assignment": false,
|
||||
"hardware": null,
|
||||
"hosting_adress": null,
|
||||
"hostingkunde": false,
|
||||
"hotline_contract": null,
|
||||
"id": 2,
|
||||
"member_ids": [
|
||||
297,
|
||||
295,
|
||||
251,
|
||||
301,
|
||||
6,
|
||||
2309,
|
||||
982,
|
||||
479,
|
||||
78,
|
||||
1764,
|
||||
77,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"members": [
|
||||
"auto-feb98421-3344-4f54-a650-dc54b010ba90",
|
||||
"auto-b4d24e63-db3e-44c2-9fb9-b8f3b6a1a675",
|
||||
"corinna.breu@aikava.de",
|
||||
"auto-27ce025f-f458-4a90-b320-df18812c150b",
|
||||
"test@test.de",
|
||||
"hung.nguyen@aikava.de",
|
||||
"marcel.reisch@aikava.de",
|
||||
"cristian.dimcia@aikava.de",
|
||||
"heidi.schmaderer@aikava.de",
|
||||
"michael.boehmlaender@aikava.de",
|
||||
"marco.dirscherl@aikava.de",
|
||||
"marco.christener@aikava.de",
|
||||
"thomas.roider@aikava.de"
|
||||
],
|
||||
"name": "AIKAVA GmbH",
|
||||
"note": "",
|
||||
"ort": "Cham",
|
||||
"plz": "93413",
|
||||
"rechnungsadresse": "",
|
||||
"secondary_member_ids": [],
|
||||
"shared": true,
|
||||
"stock_customer": false,
|
||||
"strasse": "Galgenfeld 7",
|
||||
"support_project": null,
|
||||
"updated_at": "2026-09-22T14:56:23.997Z",
|
||||
"updated_by": "corinna.breu@aikava.de",
|
||||
"updated_by_id": 251,
|
||||
"vertrieb_atoss": [],
|
||||
"vip": false
|
||||
},
|
||||
"organization_id": 2,
|
||||
"owner": {
|
||||
"active": true,
|
||||
"address": "",
|
||||
"city": "",
|
||||
"country": "",
|
||||
"created_at": "2025-03-31T08:14:45.514Z",
|
||||
"created_by": "marco.christener@aikava.de",
|
||||
"created_by_id": 3,
|
||||
"department": "Senior Software Consultant",
|
||||
"email": "michael.boehmlaender@aikava.de",
|
||||
"fax": "",
|
||||
"firstname": "Michael",
|
||||
"id": 1764,
|
||||
"image": "facb8844175ddeb0a0fab286b9b68fbd",
|
||||
"image_source": null,
|
||||
"lastname": "Böhmländer",
|
||||
"login": "michael.boehmlaender@aikava.de",
|
||||
"mobile": "",
|
||||
"mobile_2": "",
|
||||
"note": "Geplante Abwesenheiten:",
|
||||
"organization": "AIKAVA GmbH",
|
||||
"organization_id": 2,
|
||||
"organization_ids": [],
|
||||
"organizations": [],
|
||||
"out_of_office": true,
|
||||
"out_of_office_end_at": "2026-08-28",
|
||||
"out_of_office_replacement": "marco.dirscherl@aikava.de",
|
||||
"out_of_office_replacement_id": 77,
|
||||
"out_of_office_start_at": "2026-08-17",
|
||||
"overview_sorting_ids": [
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
304,
|
||||
305,
|
||||
306,
|
||||
307,
|
||||
308,
|
||||
309,
|
||||
310,
|
||||
311,
|
||||
312,
|
||||
313,
|
||||
314,
|
||||
315,
|
||||
316,
|
||||
317,
|
||||
318,
|
||||
319,
|
||||
320
|
||||
],
|
||||
"phone": "",
|
||||
"role_ids": [
|
||||
2,
|
||||
1
|
||||
],
|
||||
"roles": [
|
||||
"Admin",
|
||||
"Agent"
|
||||
],
|
||||
"source": null,
|
||||
"street": "",
|
||||
"two_factor_preference_ids": [],
|
||||
"two_factor_preferences": [],
|
||||
"updated_at": "2026-09-21T05:56:12.741Z",
|
||||
"updated_by": "michael.boehmlaender@aikava.de",
|
||||
"updated_by_id": 1764,
|
||||
"verified": false,
|
||||
"vip": false,
|
||||
"web": "",
|
||||
"zip": ""
|
||||
},
|
||||
"owner_id": 1764,
|
||||
"pending_time": null,
|
||||
"preferences": {},
|
||||
"priority": {
|
||||
"active": true,
|
||||
"created_at": "2023-01-06T10:59:49.163Z",
|
||||
"created_by": "-",
|
||||
"created_by_id": 1,
|
||||
"default_create": true,
|
||||
"id": 2,
|
||||
"name": "2 normal",
|
||||
"note": null,
|
||||
"ui_color": null,
|
||||
"ui_icon": null,
|
||||
"updated_at": "2023-01-06T10:59:49.163Z",
|
||||
"updated_by": "-",
|
||||
"updated_by_id": 1
|
||||
},
|
||||
"priority_id": 2,
|
||||
"project": "",
|
||||
"referencing_checklist_ids": [],
|
||||
"referencing_checklists": [],
|
||||
"state": "open",
|
||||
"state_id": 2,
|
||||
"ticket_time_accounting_ids": [
|
||||
16133,
|
||||
16135,
|
||||
16137,
|
||||
16138,
|
||||
16139,
|
||||
16140,
|
||||
16141,
|
||||
16142,
|
||||
16144,
|
||||
16145,
|
||||
16146,
|
||||
16147
|
||||
],
|
||||
"time_unit": "2.75",
|
||||
"title": "Bla",
|
||||
"type": null,
|
||||
"update_diff_in_min": null,
|
||||
"update_escalation_at": null,
|
||||
"update_in_min": null,
|
||||
"updated_at": "2026-09-23T06:47:42.937Z",
|
||||
"updated_by": {
|
||||
"active": true,
|
||||
"address": "",
|
||||
"city": "",
|
||||
"country": "",
|
||||
"created_at": "2025-03-31T08:14:45.514Z",
|
||||
"created_by": "marco.christener@aikava.de",
|
||||
"created_by_id": 3,
|
||||
"department": "Senior Software Consultant",
|
||||
"email": "michael.boehmlaender@aikava.de",
|
||||
"fax": "",
|
||||
"firstname": "Michael",
|
||||
"id": 1764,
|
||||
"image": "facb8844175ddeb0a0fab286b9b68fbd",
|
||||
"image_source": null,
|
||||
"lastname": "Böhmländer",
|
||||
"login": "michael.boehmlaender@aikava.de",
|
||||
"mobile": "",
|
||||
"mobile_2": "",
|
||||
"note": "Geplante Abwesenheiten:",
|
||||
"organization": "AIKAVA GmbH",
|
||||
"organization_id": 2,
|
||||
"organization_ids": [],
|
||||
"organizations": [],
|
||||
"out_of_office": true,
|
||||
"out_of_office_end_at": "2026-08-28",
|
||||
"out_of_office_replacement": "marco.dirscherl@aikava.de",
|
||||
"out_of_office_replacement_id": 77,
|
||||
"out_of_office_start_at": "2026-08-17",
|
||||
"overview_sorting_ids": [
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
304,
|
||||
305,
|
||||
306,
|
||||
307,
|
||||
308,
|
||||
309,
|
||||
310,
|
||||
311,
|
||||
312,
|
||||
313,
|
||||
314,
|
||||
315,
|
||||
316,
|
||||
317,
|
||||
318,
|
||||
319,
|
||||
320
|
||||
],
|
||||
"phone": "",
|
||||
"role_ids": [
|
||||
2,
|
||||
1
|
||||
],
|
||||
"roles": [
|
||||
"Admin",
|
||||
"Agent"
|
||||
],
|
||||
"source": null,
|
||||
"street": "",
|
||||
"two_factor_preference_ids": [],
|
||||
"two_factor_preferences": [],
|
||||
"updated_at": "2026-09-21T05:56:12.741Z",
|
||||
"updated_by": "michael.boehmlaender@aikava.de",
|
||||
"updated_by_id": 1764,
|
||||
"verified": false,
|
||||
"vip": false,
|
||||
"web": "",
|
||||
"zip": ""
|
||||
},
|
||||
"updated_by_id": 1764
|
||||
},
|
||||
"article": {
|
||||
"ai_stored_result_ids": [],
|
||||
"ai_stored_results": [],
|
||||
"attachments": [],
|
||||
"body": "test<br><br><div data-signature=\"true\" data-signature-id=\"2\"><div>
|
||||
<div><b>Michael Böhmländer</b></div>
|
||||
<div>Senior Software Consultant<br>Geplante Abwesenheiten:</div>
|
||||
</div><div><br></div><div><b>AIKAVA GmbH</b></div><div>Galgenfeld 7 | 93413 Cham</div><div><b><br></b></div><div>T: +49 9971 88999 40</div><div>
|
||||
<a href=\"mailto:support.atoss@aikava.de\" title=\"mailto:support.atoss@aikava.de\">support@aikava.de</a><br>
|
||||
</div><div>
|
||||
<a href=\"https://aikava.de/\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">aikava.de</a><br>
|
||||
</div><div><br></div><div><p>Amtsgericht Regensburg HRB 19554<br></p></div><div>Geschäftsführung Marco Christener</div><div><i><br></i></div><div><i>This e-mail may contain confidential and/or privileged information. If you are not the intended recipient or have received this e-mail in error please notify the sender immediately and delete this e-mail.</i></div></div>",
|
||||
"body_rendering_error": false,
|
||||
"cc": "",
|
||||
"content_type": "text/html",
|
||||
"created_at": "2026-09-23T06:47:38.553Z",
|
||||
"created_by": {
|
||||
"active": true,
|
||||
"address": "",
|
||||
"city": "",
|
||||
"country": "",
|
||||
"created_at": "2025-03-31T08:14:45.514Z",
|
||||
"created_by": "marco.christener@aikava.de",
|
||||
"created_by_id": 3,
|
||||
"department": "Senior Software Consultant",
|
||||
"email": "michael.boehmlaender@aikava.de",
|
||||
"fax": "",
|
||||
"firstname": "Michael",
|
||||
"id": 1764,
|
||||
"image": "facb8844175ddeb0a0fab286b9b68fbd",
|
||||
"image_source": null,
|
||||
"lastname": "Böhmländer",
|
||||
"login": "michael.boehmlaender@aikava.de",
|
||||
"mobile": "",
|
||||
"mobile_2": "",
|
||||
"note": "Geplante Abwesenheiten:",
|
||||
"organization": "AIKAVA GmbH",
|
||||
"organization_id": 2,
|
||||
"organization_ids": [],
|
||||
"organizations": [],
|
||||
"out_of_office": true,
|
||||
"out_of_office_end_at": "2026-08-28",
|
||||
"out_of_office_replacement": "marco.dirscherl@aikava.de",
|
||||
"out_of_office_replacement_id": 77,
|
||||
"out_of_office_start_at": "2026-08-17",
|
||||
"overview_sorting_ids": [
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
304,
|
||||
305,
|
||||
306,
|
||||
307,
|
||||
308,
|
||||
309,
|
||||
310,
|
||||
311,
|
||||
312,
|
||||
313,
|
||||
314,
|
||||
315,
|
||||
316,
|
||||
317,
|
||||
318,
|
||||
319,
|
||||
320
|
||||
],
|
||||
"phone": "",
|
||||
"role_ids": [
|
||||
2,
|
||||
1
|
||||
],
|
||||
"roles": [
|
||||
"Admin",
|
||||
"Agent"
|
||||
],
|
||||
"source": null,
|
||||
"street": "",
|
||||
"two_factor_preference_ids": [],
|
||||
"two_factor_preferences": [],
|
||||
"updated_at": "2026-09-21T05:56:12.741Z",
|
||||
"updated_by": "michael.boehmlaender@aikava.de",
|
||||
"updated_by_id": 1764,
|
||||
"verified": false,
|
||||
"vip": false,
|
||||
"web": "",
|
||||
"zip": ""
|
||||
},
|
||||
"created_by_id": 1764,
|
||||
"detected_language": null,
|
||||
"from": "\"Michael Böhmländer via Zammad Helpdesk Support\" <support@aikava.de>",
|
||||
"id": 66152,
|
||||
"in_reply_to": "",
|
||||
"internal": false,
|
||||
"message_id": "<20260923064738.7035.8a97ff10-62fc-4d7a-9d91-2d968ea53002@aikava.zammad.com>",
|
||||
"message_id_md5": "4d6a39f57fc20c1834cc2e7b8c6e94cd",
|
||||
"origin_by_id": null,
|
||||
"preferences": {
|
||||
"email_address_id": 6,
|
||||
"delivery_retry": 1,
|
||||
"delivery_channel_id": 23,
|
||||
"delivery_status_message": null,
|
||||
"delivery_status": "success",
|
||||
"delivery_status_date": "2026-09-23T06:47:42.903Z"
|
||||
},
|
||||
"reply_to": null,
|
||||
"sender": "Agent",
|
||||
"sender_id": 1,
|
||||
"subject": "test",
|
||||
"ticket_id": 7035,
|
||||
"time_unit": "0.0",
|
||||
"to": "michael.boehmlaender@aikava.de",
|
||||
"type": "email",
|
||||
"type_id": 1,
|
||||
"updated_at": "2026-09-23T06:47:42.905Z",
|
||||
"updated_by": {
|
||||
"active": true,
|
||||
"address": "",
|
||||
"city": "",
|
||||
"country": "",
|
||||
"created_at": "2025-03-31T08:14:45.514Z",
|
||||
"created_by": "marco.christener@aikava.de",
|
||||
"created_by_id": 3,
|
||||
"department": "Senior Software Consultant",
|
||||
"email": "michael.boehmlaender@aikava.de",
|
||||
"fax": "",
|
||||
"firstname": "Michael",
|
||||
"id": 1764,
|
||||
"image": "facb8844175ddeb0a0fab286b9b68fbd",
|
||||
"image_source": null,
|
||||
"lastname": "Böhmländer",
|
||||
"login": "michael.boehmlaender@aikava.de",
|
||||
"mobile": "",
|
||||
"mobile_2": "",
|
||||
"note": "Geplante Abwesenheiten:",
|
||||
"organization": "AIKAVA GmbH",
|
||||
"organization_id": 2,
|
||||
"organization_ids": [],
|
||||
"organizations": [],
|
||||
"out_of_office": true,
|
||||
"out_of_office_end_at": "2026-08-28",
|
||||
"out_of_office_replacement": "marco.dirscherl@aikava.de",
|
||||
"out_of_office_replacement_id": 77,
|
||||
"out_of_office_start_at": "2026-08-17",
|
||||
"overview_sorting_ids": [
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
304,
|
||||
305,
|
||||
306,
|
||||
307,
|
||||
308,
|
||||
309,
|
||||
310,
|
||||
311,
|
||||
312,
|
||||
313,
|
||||
314,
|
||||
315,
|
||||
316,
|
||||
317,
|
||||
318,
|
||||
319,
|
||||
320
|
||||
],
|
||||
"phone": "",
|
||||
"role_ids": [
|
||||
2,
|
||||
1
|
||||
],
|
||||
"roles": [
|
||||
"Admin",
|
||||
"Agent"
|
||||
],
|
||||
"source": null,
|
||||
"street": "",
|
||||
"two_factor_preference_ids": [],
|
||||
"two_factor_preferences": [],
|
||||
"updated_at": "2026-09-21T05:56:12.741Z",
|
||||
"updated_by": "michael.boehmlaender@aikava.de",
|
||||
"updated_by_id": 1764,
|
||||
"verified": false,
|
||||
"vip": false,
|
||||
"web": "",
|
||||
"zip": ""
|
||||
},
|
||||
"updated_by_id": 1764,
|
||||
"accounted_time": 0
|
||||
}
|
||||
}
|
||||
Antwort
|
||||
|
||||
Erstellt am 2026-09-23 08:48:13
|
||||
Reference in new issue
Block a user