L12 Zeiterfassung: Services für Nachtrag, Freigabe, Auto-Wechsel und Für heute beenden
time-entries.ts (manuelle Einträge, Korrekturvorschläge, Freigabe/Ablehnung mit Team-Scope), Sessions in inTransaction mit switchFromOther, stopForToday, Segmentwechsel und getMyActiveSession. Sync-Ops time.add_manual, time.propose_correction, session.stop_day, session.segment inkl. optimistischer Offline-Ansicht. Bericht, Zeiten-Tab, Dashboard und Lotse zählen nur freigegebene Zeiten; Abrechnungsfreigabe blockiert bei offenen Zeiten. Empfänger und Links der Zeit-Events. Notdienst-Start pausiert eine laufende Uhr automatisch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+51
-1
@@ -50,6 +50,8 @@ export const sessionStartPayload = z.object({
|
||||
longitude: lng.optional(),
|
||||
offline: z.boolean().default(false),
|
||||
deviceInfo: z.string().max(200).optional(),
|
||||
/** L12 auto switch: pause the user's running session on another order in the same transaction */
|
||||
switchFromOther: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export const sessionControlPayload = z.object({
|
||||
@@ -57,6 +59,50 @@ export const sessionControlPayload = z.object({
|
||||
at: isoDate.optional(),
|
||||
});
|
||||
|
||||
/** session.resume (L12): like session.start, may pause a running session on another order. */
|
||||
export const sessionResumePayload = sessionControlPayload.extend({ switchFromOther: z.boolean().optional() });
|
||||
|
||||
/** Segment types a technician can switch to inside a running session (L12). */
|
||||
export const SESSION_SEGMENT_TYPES = ["work", "return_travel", "material_procurement"] as const;
|
||||
export type SessionSegmentType = (typeof SESSION_SEGMENT_TYPES)[number];
|
||||
|
||||
export const sessionSegmentPayload = z.object({
|
||||
workOrderId: id,
|
||||
type: z.enum(SESSION_SEGMENT_TYPES),
|
||||
at: isoDate.optional(),
|
||||
});
|
||||
|
||||
/** Time entry types (Prisma enum TimeEntryType). */
|
||||
export const TIME_TYPES = ["travel", "work", "break", "material_procurement", "return_travel", "interruption"] as const;
|
||||
export type TimeType = (typeof TIME_TYPES)[number];
|
||||
|
||||
/**
|
||||
* time.add_manual (L12): manual time entry. Own entries become `pending` (approval by team lead /
|
||||
* back office); with `field:correct_time` for a team member (`forUserId`) they are approved directly.
|
||||
* Either `endedAt` or `durationMinutes` is required.
|
||||
*/
|
||||
export const timeAddManualPayload = z.object({
|
||||
workOrderId: id,
|
||||
clientId: clientId.optional(),
|
||||
type: z.enum(TIME_TYPES).default("work"),
|
||||
startedAt: isoDate,
|
||||
endedAt: isoDate.optional(),
|
||||
durationMinutes: z.number().int().min(1).max(16 * 60).optional(),
|
||||
reason: z.string().trim().min(3).max(500),
|
||||
note: z.string().trim().max(2000).optional(),
|
||||
forUserId: id.optional(),
|
||||
});
|
||||
|
||||
/** time.propose_correction (L12): correction proposal for an own entry; old values count until approval. */
|
||||
export const timeProposeCorrectionPayload = z.object({
|
||||
workOrderId: id,
|
||||
timeEntryId: id,
|
||||
type: z.enum(TIME_TYPES).optional(),
|
||||
startedAt: isoDate,
|
||||
endedAt: isoDate,
|
||||
reason: z.string().trim().min(3).max(500),
|
||||
});
|
||||
|
||||
export const workOrderTransitionPayload = z.object({
|
||||
workOrderId: id,
|
||||
to: z.enum(WORK_ORDER_STATUSES),
|
||||
@@ -138,7 +184,7 @@ const passthrough = z.record(z.string(), z.unknown());
|
||||
export const OP_PAYLOAD_SCHEMAS = {
|
||||
"session.start": sessionStartPayload,
|
||||
"session.pause": sessionControlPayload,
|
||||
"session.resume": sessionControlPayload,
|
||||
"session.resume": sessionResumePayload,
|
||||
"session.end": sessionControlPayload,
|
||||
"work_order.transition": workOrderTransitionPayload,
|
||||
"note.create": noteCreatePayload,
|
||||
@@ -150,6 +196,10 @@ export const OP_PAYLOAD_SCHEMAS = {
|
||||
"report.submit": reportSubmitPayload,
|
||||
"signature.capture": passthrough,
|
||||
"emergency.create": emergencyCreatePayload,
|
||||
"session.stop_day": sessionControlPayload,
|
||||
"session.segment": sessionSegmentPayload,
|
||||
"time.add_manual": timeAddManualPayload,
|
||||
"time.propose_correction": timeProposeCorrectionPayload,
|
||||
} satisfies Record<SyncOpType, z.ZodType>;
|
||||
|
||||
export type OpPayload<T extends SyncOpType> = z.input<(typeof OP_PAYLOAD_SCHEMAS)[T]>;
|
||||
|
||||
Reference in New Issue
Block a user