Time Changes
Some checks failed
Build and Push Docker Images / verify-docs-sync (push) Failing after 9s
Build and Push Docker Images / build-backend (push) Has been skipped
Build and Push Docker Images / build-frontend (push) Has been skipped
Build and Push Docker Images / build-docs (push) Has been skipped
Some checks failed
Build and Push Docker Images / verify-docs-sync (push) Failing after 9s
Build and Push Docker Images / build-backend (push) Has been skipped
Build and Push Docker Images / build-frontend (push) Has been skipped
Build and Push Docker Images / build-docs (push) Has been skipped
This commit is contained in:
@@ -9,12 +9,15 @@ export type DerivedSpan = {
|
||||
sourceEventIds: string[];
|
||||
status: SpanStatus;
|
||||
statusActorId?: string;
|
||||
payload?: Record<string, any> | null;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
type TimeEvent = {
|
||||
id: string;
|
||||
eventtype: string;
|
||||
eventtime: Date;
|
||||
payload?: Record<string, any> | null;
|
||||
};
|
||||
|
||||
// Liste aller faktischen Event-Typen, die die Zustandsmaschine beeinflussen
|
||||
@@ -45,9 +48,17 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
let currentStart: Date | null = null;
|
||||
let currentType: DerivedSpan["type"] | null = null;
|
||||
let sourceEventIds: string[] = [];
|
||||
let currentPayload: Record<string, any> | null = null;
|
||||
|
||||
const closeSpan = (end: Date) => {
|
||||
if (!currentStart || !currentType) return;
|
||||
if (end.getTime() <= currentStart.getTime()) {
|
||||
currentStart = null;
|
||||
currentType = null;
|
||||
sourceEventIds = [];
|
||||
currentPayload = null;
|
||||
return;
|
||||
}
|
||||
|
||||
spans.push({
|
||||
type: currentType,
|
||||
@@ -55,12 +66,15 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
endedAt: end,
|
||||
sourceEventIds: [...sourceEventIds],
|
||||
// Standardstatus ist "factual", wird später angereichert
|
||||
status: "factual"
|
||||
status: "factual",
|
||||
payload: currentPayload,
|
||||
description: currentPayload?.description || ""
|
||||
});
|
||||
|
||||
currentStart = null;
|
||||
currentType = null;
|
||||
sourceEventIds = [];
|
||||
currentPayload = null;
|
||||
};
|
||||
|
||||
const closeOpenSpanAsRunning = () => {
|
||||
@@ -72,12 +86,15 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
endedAt: null,
|
||||
sourceEventIds: [...sourceEventIds],
|
||||
// Standardstatus ist "factual", wird später angereichert
|
||||
status: "factual"
|
||||
status: "factual",
|
||||
payload: currentPayload,
|
||||
description: currentPayload?.description || ""
|
||||
});
|
||||
|
||||
currentStart = null;
|
||||
currentType = null;
|
||||
sourceEventIds = [];
|
||||
currentPayload = null;
|
||||
};
|
||||
|
||||
for (const event of events) {
|
||||
@@ -96,6 +113,7 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
state = "WORKING";
|
||||
currentStart = event.eventtime;
|
||||
currentType = "work";
|
||||
currentPayload = event.payload || null;
|
||||
break;
|
||||
|
||||
case "pause_start":
|
||||
@@ -104,6 +122,7 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
state = "PAUSED";
|
||||
currentStart = event.eventtime;
|
||||
currentType = "pause";
|
||||
currentPayload = event.payload || null;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -113,6 +132,7 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
state = "WORKING";
|
||||
currentStart = event.eventtime;
|
||||
currentType = "work";
|
||||
currentPayload = event.payload || null;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -140,6 +160,7 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
state = "ABSENT";
|
||||
currentStart = event.eventtime;
|
||||
currentType = newType;
|
||||
currentPayload = event.payload || null;
|
||||
break;
|
||||
|
||||
case "vacation_end":
|
||||
@@ -162,4 +183,4 @@ export function deriveTimeSpans(allValidEvents: TimeEvent[]): DerivedSpan[] {
|
||||
}
|
||||
|
||||
return spans;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/services/loadValidEvents.ts
|
||||
|
||||
import { stafftimeevents } from "../../../db/schema";
|
||||
import {sql, and, eq, gte, lte, inArray} from "drizzle-orm";
|
||||
import {sql, and, eq, gte, lte, inArray, asc} from "drizzle-orm";
|
||||
import { FastifyInstance } from "fastify";
|
||||
|
||||
export type TimeType = "work_start" | "work_end" | "pause_start" | "pause_end" | "sick_start" | "sick_end" | "vacation_start" | "vacation_end" | "ovetime_compensation_start" | "overtime_compensation_end";
|
||||
@@ -12,11 +12,43 @@ export type TimeEvent = {
|
||||
id: string;
|
||||
eventtype: string;
|
||||
eventtime: Date;
|
||||
actoruser_id: string;
|
||||
actoruser_id?: string;
|
||||
related_event_id: string | null;
|
||||
// Fügen Sie hier alle weiteren Felder hinzu, die Sie benötigen
|
||||
payload?: Record<string, any> | null;
|
||||
created_at?: Date | null;
|
||||
};
|
||||
|
||||
const EVENT_TYPE_ORDER: Record<string, number> = {
|
||||
auto_stop: 10,
|
||||
work_end: 10,
|
||||
pause_end: 10,
|
||||
vacation_end: 10,
|
||||
sick_end: 10,
|
||||
overtime_compensation_end: 10,
|
||||
work_start: 20,
|
||||
pause_start: 20,
|
||||
vacation_start: 20,
|
||||
sick_start: 20,
|
||||
overtime_compensation_start: 20,
|
||||
submitted: 30,
|
||||
approved: 30,
|
||||
rejected: 30,
|
||||
invalidated: 40,
|
||||
};
|
||||
|
||||
export function compareTimeEvents(a: TimeEvent, b: TimeEvent) {
|
||||
const eventTimeDiff = a.eventtime.getTime() - b.eventtime.getTime();
|
||||
if (eventTimeDiff !== 0) return eventTimeDiff;
|
||||
|
||||
const typeOrderDiff = (EVENT_TYPE_ORDER[a.eventtype] ?? 999) - (EVENT_TYPE_ORDER[b.eventtype] ?? 999);
|
||||
if (typeOrderDiff !== 0) return typeOrderDiff;
|
||||
|
||||
const createdAtDiff = (a.created_at?.getTime() ?? 0) - (b.created_at?.getTime() ?? 0);
|
||||
if (createdAtDiff !== 0) return createdAtDiff;
|
||||
|
||||
return a.id.localeCompare(b.id);
|
||||
}
|
||||
|
||||
export async function loadValidEvents(
|
||||
server: FastifyInstance,
|
||||
tenantId: number,
|
||||
@@ -62,10 +94,9 @@ export async function loadValidEvents(
|
||||
)
|
||||
)
|
||||
.orderBy(
|
||||
// Wichtig für die deriveTimeSpans Logik: Event-Zeit muss primär sein
|
||||
baseEvents.eventtime,
|
||||
baseEvents.created_at, // Wenn Eventtime identisch ist, das später erstellte zuerst
|
||||
baseEvents.id
|
||||
asc(baseEvents.eventtime),
|
||||
asc(baseEvents.created_at),
|
||||
asc(baseEvents.id)
|
||||
);
|
||||
|
||||
// Mapping auf den sauberen TimeEvent Typ
|
||||
@@ -73,8 +104,10 @@ export async function loadValidEvents(
|
||||
id: e.id,
|
||||
eventtype: e.eventtype,
|
||||
eventtime: e.eventtime,
|
||||
// Fügen Sie hier alle weiteren benötigten Felder hinzu (z.B. metadata, actoruser_id)
|
||||
// ...
|
||||
actoruser_id: e.actoruser_id,
|
||||
related_event_id: e.related_event_id,
|
||||
payload: e.payload,
|
||||
created_at: e.created_at,
|
||||
})) as TimeEvent[];
|
||||
}
|
||||
|
||||
@@ -99,7 +132,11 @@ export async function loadRelatedAdminEvents(server, eventIds) {
|
||||
)
|
||||
)
|
||||
// Muss nach Zeit sortiert sein, um den Status korrekt zu bestimmen!
|
||||
.orderBy(stafftimeevents.eventtime);
|
||||
.orderBy(
|
||||
asc(stafftimeevents.eventtime),
|
||||
asc(stafftimeevents.created_at),
|
||||
asc(stafftimeevents.id)
|
||||
);
|
||||
|
||||
return adminEvents;
|
||||
}
|
||||
return adminEvents as TimeEvent[];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
desc
|
||||
} from "drizzle-orm"
|
||||
import {stafftimeevents} from "../../../db/schema/staff_time_events";
|
||||
import {loadRelatedAdminEvents, loadValidEvents} from "../../modules/time/loadvalidevents.service";
|
||||
import {compareTimeEvents, loadRelatedAdminEvents, loadValidEvents} from "../../modules/time/loadvalidevents.service";
|
||||
import {deriveTimeSpans} from "../../modules/time/derivetimespans.service";
|
||||
import {buildTimeEvaluationFromSpans} from "../../modules/time/buildtimeevaluation.service";
|
||||
import {z} from "zod";
|
||||
@@ -102,7 +102,7 @@ export default async function staffTimeRoutesInternal(server: FastifyInstance) {
|
||||
const combinedEvents = [
|
||||
...factualEvents,
|
||||
...relatedAdminEvents,
|
||||
].sort((a, b) => a.eventtime.getTime() - b.eventtime.getTime());
|
||||
].sort(compareTimeEvents);
|
||||
|
||||
// SCHRITT 5: Spans ableiten
|
||||
const derivedSpans = deriveTimeSpans(combinedEvents);
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
desc
|
||||
} from "drizzle-orm"
|
||||
import {stafftimeevents} from "../../../db/schema/staff_time_events";
|
||||
import {loadRelatedAdminEvents, loadValidEvents} from "../../modules/time/loadvalidevents.service";
|
||||
import {compareTimeEvents, loadRelatedAdminEvents, loadValidEvents} from "../../modules/time/loadvalidevents.service";
|
||||
import {deriveTimeSpans} from "../../modules/time/derivetimespans.service";
|
||||
import {buildTimeEvaluationFromSpans} from "../../modules/time/buildtimeevaluation.service";
|
||||
import {z} from "zod";
|
||||
@@ -354,7 +354,7 @@ export default async function staffTimeRoutes(server: FastifyInstance) {
|
||||
const combinedEvents = [
|
||||
...factualEvents,
|
||||
...relatedAdminEvents,
|
||||
].sort((a, b) => a.eventtime.getTime() - b.eventtime.getTime());
|
||||
].sort(compareTimeEvents);
|
||||
|
||||
// SCHRITT 5: Spans ableiten
|
||||
const derivedSpans = deriveTimeSpans(combinedEvents);
|
||||
@@ -424,7 +424,7 @@ export default async function staffTimeRoutes(server: FastifyInstance) {
|
||||
const combinedEvents = [
|
||||
...factualEvents,
|
||||
...relatedAdminEvents,
|
||||
].sort((a, b) => a.eventtime.getTime() - b.eventtime.getTime());
|
||||
].sort(compareTimeEvents);
|
||||
|
||||
// SCHRITT 4: Ableiten und Anreichern
|
||||
const derivedSpans = deriveTimeSpans(combinedEvents);
|
||||
@@ -453,4 +453,4 @@ export default async function staffTimeRoutes(server: FastifyInstance) {
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user