Update
This commit is contained in:
1 parent
e1456ed4ca
commit
fc0dfd0556
3 files changed
+82
-20
No files matched your search
+71
-17
@@ -4230,6 +4230,16 @@ function addSyncChange(changes: ZammadSyncChange[], field: string, from: unknown
|
||||
}
|
||||
}
|
||||
|
||||
const informationalZammadSyncChangeFields = new Set([
|
||||
"Fremdes Ticket",
|
||||
"Fremder Zammad-Owner",
|
||||
"Hinweis"
|
||||
]);
|
||||
|
||||
function zammadSyncResultChanges(changes: ZammadSyncChange[]) {
|
||||
return changes.some((change) => !informationalZammadSyncChangeFields.has(change.field)) ? changes : [];
|
||||
}
|
||||
|
||||
function zammadSyncSnapshot(zammadTicket: ZammadTicketImport) {
|
||||
return {
|
||||
ticketId: zammadTicket.zammadTicketId,
|
||||
@@ -5161,7 +5171,9 @@ async function planExistingZammadTicketSync(
|
||||
}
|
||||
|
||||
if (zammadTicket.workType === "support" && zammadTicket.zammadStateId === 4) {
|
||||
return changes.length > 0
|
||||
const resultChanges = zammadSyncResultChanges(changes);
|
||||
|
||||
return resultChanges.length > 0
|
||||
? {
|
||||
ticketNumber: localTicket.ticket_number,
|
||||
action: "update",
|
||||
@@ -5172,7 +5184,7 @@ async function planExistingZammadTicketSync(
|
||||
: "Zammad-Metadaten werden aktualisiert.",
|
||||
local: localSyncSnapshot(localTicket, null, { zammadPendingTodoExists: pendingTodoExists }),
|
||||
zammad: zammadSyncSnapshot(zammadTicket),
|
||||
changes
|
||||
changes: resultChanges
|
||||
}
|
||||
: null;
|
||||
}
|
||||
@@ -5208,17 +5220,19 @@ async function planExistingZammadTicketSync(
|
||||
changes.push({ field: "Projekt/Teamspace-Daten", from: "vorhanden", to: "werden gelöscht" });
|
||||
}
|
||||
|
||||
const resultChanges = zammadSyncResultChanges(changes);
|
||||
|
||||
return {
|
||||
ticketNumber: localTicket.ticket_number,
|
||||
action: changes.length > 0 ? "update" : "skip",
|
||||
action: resultChanges.length > 0 ? "update" : "skip",
|
||||
reason: zammadTicket.ticketNumber !== localTicket.ticket_number
|
||||
? mergedTargetTicket
|
||||
? "Zammad-Merge wird lokal nachvollzogen; vorhandenes Ziel-Ticket wird verwendet."
|
||||
: "Zammad-Merge wird lokal nachvollzogen; Ziel-Ticket wird synchronisiert und die Quelle umgehängt."
|
||||
: changes.length > 0 ? "Ticket wird als Support synchronisiert." : "Keine Änderung nach aktueller Auswahl.",
|
||||
: resultChanges.length > 0 ? "Ticket wird als Support synchronisiert." : "Keine Änderung nach aktueller Auswahl.",
|
||||
local: localSyncSnapshot(localTicket, null, { zammadPendingTodoExists: pendingTodoExists }),
|
||||
zammad: zammadSyncSnapshot(zammadTicket),
|
||||
changes
|
||||
changes: resultChanges
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5263,13 +5277,15 @@ async function planExistingZammadTicketSync(
|
||||
|
||||
}
|
||||
|
||||
const resultChanges = zammadSyncResultChanges(changes);
|
||||
|
||||
return {
|
||||
ticketNumber: localTicket.ticket_number,
|
||||
action: changes.length > 0 ? "update" : "skip",
|
||||
reason: changes.length > 0 ? "Ticket wird aktualisiert; Projektdaten bleiben wegen offener TS/TT-Prüfung lokal geschützt." : "Keine Änderung nach aktueller Auswahl.",
|
||||
action: resultChanges.length > 0 ? "update" : "skip",
|
||||
reason: resultChanges.length > 0 ? "Ticket wird aktualisiert; Projektdaten bleiben wegen offener TS/TT-Prüfung lokal geschützt." : "Keine Änderung nach aktueller Auswahl.",
|
||||
local: localSyncSnapshot(localTicket, project, { zammadPendingTodoExists: pendingTodoExists }),
|
||||
zammad: zammadSyncSnapshot(zammadTicket),
|
||||
changes
|
||||
changes: resultChanges
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5277,7 +5293,7 @@ async function planExistingZammadTicketSync(
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!project) {
|
||||
if (!project && fields.type && localTicket.work_type !== "consulting") {
|
||||
changes.push({ field: "Projekt", from: null, to: "wird angelegt" });
|
||||
}
|
||||
|
||||
@@ -5327,17 +5343,19 @@ async function planExistingZammadTicketSync(
|
||||
}
|
||||
}
|
||||
|
||||
const resultChanges = zammadSyncResultChanges(changes);
|
||||
|
||||
return {
|
||||
ticketNumber: localTicket.ticket_number,
|
||||
action: changes.length > 0 ? "update" : "skip",
|
||||
action: resultChanges.length > 0 ? "update" : "skip",
|
||||
reason: zammadTicket.ticketNumber !== localTicket.ticket_number
|
||||
? mergedTargetTicket
|
||||
? "Zammad-Merge wird lokal nachvollzogen; vorhandenes Ziel-Ticket wird verwendet."
|
||||
: "Zammad-Merge wird lokal nachvollzogen; Ziel-Ticket wird synchronisiert und die Quelle umgehängt."
|
||||
: changes.length > 0 ? "Ticket wird aktualisiert." : "Keine Änderung nach aktueller Auswahl.",
|
||||
: resultChanges.length > 0 ? "Ticket wird aktualisiert." : "Keine Änderung nach aktueller Auswahl.",
|
||||
local: localSyncSnapshot(localTicket, project, { zammadPendingTodoExists: pendingTodoExists }),
|
||||
zammad: zammadSyncSnapshot(zammadTicket),
|
||||
changes
|
||||
changes: resultChanges
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6669,6 +6687,7 @@ async function applyZammadTicketSync(
|
||||
const organization = shouldResolveOrganization ? await getOrganizationByZammadId(client, zammadTicket.organizationId) : null;
|
||||
const ownerMapping = await zammadOwnerUserMapping(client, zammadTicket.zammadOwnerId);
|
||||
const zammadOwnerUserId = ownerMapping.status === "ambiguous" ? localTicket.user_id : ownerMapping.userId;
|
||||
const zammadStateChanged = numberOrNull(localTicket.zammad_state_id) !== zammadTicket.zammadStateId;
|
||||
|
||||
if (shouldResolveOrganization && !organization) {
|
||||
return "organization-missing" as const;
|
||||
@@ -6754,6 +6773,12 @@ async function applyZammadTicketSync(
|
||||
);
|
||||
}
|
||||
|
||||
if (zammadStateChanged) {
|
||||
const completedAt = new Date();
|
||||
await restartProjectFollowupPeriodForTicket(client, localTicket.id, completedAt);
|
||||
await completeAutomaticProjectFollowupsForTicketStatusChange(client, localTicket.id, completedAt);
|
||||
}
|
||||
|
||||
if (fields.pendingTodo) {
|
||||
await ensureZammadPendingTodo(client, localTicket.id, userId, zammadTicket);
|
||||
}
|
||||
@@ -7778,6 +7803,35 @@ async function completeAutomaticProjectFollowupsForSession(client: QueryClient,
|
||||
);
|
||||
}
|
||||
|
||||
async function completeAutomaticProjectFollowupsForTicketStatusChange(client: QueryClient, ticketId: string, completedAt: Date) {
|
||||
await client.query(
|
||||
`
|
||||
UPDATE ticket_todos tt
|
||||
SET status = 'done',
|
||||
completed_at = COALESCE(tt.completed_at, $2::timestamptz),
|
||||
updated_at = now()
|
||||
FROM project_followup_reminders pfr
|
||||
WHERE pfr.todo_id = tt.id
|
||||
AND pfr.ticket_id = $1
|
||||
AND tt.ticket_id = $1
|
||||
AND tt.status = 'open';
|
||||
`,
|
||||
[ticketId, completedAt.toISOString()]
|
||||
);
|
||||
}
|
||||
|
||||
async function restartProjectFollowupPeriodForTicket(client: QueryClient, ticketId: string, restartedAt: Date) {
|
||||
await client.query(
|
||||
`
|
||||
UPDATE projects
|
||||
SET updated_at = GREATEST(updated_at, $2::timestamptz)
|
||||
WHERE ticket_id = $1
|
||||
AND closed_at IS NULL;
|
||||
`,
|
||||
[ticketId, restartedAt.toISOString()]
|
||||
);
|
||||
}
|
||||
|
||||
async function getPeriodTicket(config: PeriodConfig, period: ParsedPeriod, ticketId: number, userId: string) {
|
||||
await ensureRecurringSessionsForUserPeriod(userId, period.startIso, period.endIso);
|
||||
|
||||
@@ -12442,12 +12496,12 @@ app.patch("/api/projects/:projectId/review", requireUser, async (req, res) => {
|
||||
const updateResult = await client.query<{ id: string; ticket_id: string; close_review_required: boolean }>(
|
||||
`
|
||||
UPDATE projects
|
||||
SET close_review_required = NOT $3::boolean,
|
||||
SET close_review_required = NOT $2::boolean,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id::text, ticket_id::text, close_review_required;
|
||||
`,
|
||||
[projectId, userId, acknowledged]
|
||||
[projectId, acknowledged]
|
||||
);
|
||||
|
||||
return updateResult.rows[0] ?? null;
|
||||
@@ -12493,13 +12547,13 @@ app.patch("/api/projects/:projectId/status", requireUser, async (req, res) => {
|
||||
const updateResult = await client.query<{ id: string; ticket_id: string; closed_at: string | null }>(
|
||||
`
|
||||
UPDATE projects
|
||||
SET closed_at = CASE WHEN $3::boolean THEN now() ELSE NULL END,
|
||||
close_review_required = CASE WHEN $3::boolean THEN false ELSE close_review_required END,
|
||||
SET closed_at = CASE WHEN $2::boolean THEN now() ELSE NULL END,
|
||||
close_review_required = CASE WHEN $2::boolean THEN false ELSE close_review_required END,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id::text, ticket_id::text, closed_at;
|
||||
`,
|
||||
[projectId, userId, closed]
|
||||
[projectId, closed]
|
||||
);
|
||||
|
||||
return updateResult.rows[0] ?? null;
|
||||
|
||||
@@ -1315,7 +1315,7 @@ export function App() {
|
||||
|
||||
setOpenTickets((items) => items.filter((item) => item.key !== ticket.key));
|
||||
|
||||
if (pathWithoutSearch(path) === pathWithoutSearch(ticket.path)) {
|
||||
if (route.page === "ticket" && route.ticketId === ticket.ticketId) {
|
||||
const returnPath = current.returnPath && pathWithoutSearch(current.returnPath) !== pathWithoutSearch(ticket.path) ? current.returnPath : "/analysis";
|
||||
routerNavigate(returnPath);
|
||||
}
|
||||
|
||||
@@ -669,13 +669,21 @@ const preservedExistingPreviewChangeFields = new Set([
|
||||
"TicketTracker-Zusammenführung"
|
||||
]);
|
||||
|
||||
const informationalExistingPreviewChangeFields = new Set([
|
||||
"Fremdes Ticket",
|
||||
"Fremder Zammad-Owner",
|
||||
"Hinweis"
|
||||
]);
|
||||
|
||||
function preserveExistingPreviewChanges(item: ZammadSyncItem, changes: ZammadSyncChange[], fields: ZammadSyncExistingFields) {
|
||||
const existingFields = new Set(changes.map((change) => change.field));
|
||||
|
||||
return [
|
||||
const resultChanges = [
|
||||
...item.changes.filter((change) => preservedExistingPreviewChangeFields.has(change.field) && !existingFields.has(change.field) && changeAllowedByFields(item, change, fields)),
|
||||
...changes
|
||||
];
|
||||
|
||||
return resultChanges.some((change) => !informationalExistingPreviewChangeFields.has(change.field)) ? resultChanges : [];
|
||||
}
|
||||
|
||||
function changesFromExistingPreviewCache(item: ZammadSyncItem, fields: ZammadSyncExistingFields) {
|
||||
@@ -737,7 +745,7 @@ function changesFromExistingPreviewCache(item: ZammadSyncItem, fields: ZammadSyn
|
||||
const consultingProjectCanBeTouched = !mergeProtected && zammadWorkType === "consulting" && (fields.type || localWorkType === "consulting");
|
||||
|
||||
if (consultingProjectCanBeTouched) {
|
||||
if (fields.type && !project) {
|
||||
if (fields.type && localWorkType !== "consulting" && !project) {
|
||||
changes.push({ field: "Projekt", from: null, to: "wird angelegt" });
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user