L4 Einsatz mobil: Field-Services, Sync-API, Uploads und Tests
- services/field: Einsatz-Sessions (Anfahrt/Arbeit/Pause als TimeEntry-Segmente, eine aktive Session je User+Auftrag), Zeitkorrektur mit Recht + Grund + Audit, Checkliste, Material (Abweichung nur mit Begründung, Zusatzmaterial), Notizen, Fotos, Sprachnotizen (ohne Transkriptions-Processor Status disabled), Uploads (idempotent je Mandant), autorisierte Dokument-Auslieferung, Lesemodelle + Bundle - services/sync: applyOperations mit Idempotenz, baseVersion-Konfliktprüfung, Registry für Ops anderer Lanes, lane-lokaler requireApiContext - /api/v1/sync, /api/v1/uploads, /api/v1/field/bundle, /api/v1/field/documents/[id] - lib/sync/ops.ts (Zod-Payloads je opType), lib/field/material-rules.ts - Stubs mit Vertragssignatur: transitionWorkOrder (L2), storeFile (§4.3), getSiteHistory (L1) - Processor image-derivatives + Registrierung, Audit-Entity-Labels - Tests: test-einsatz-field (48 Prüfungen), test-einsatz-sync (38 Prüfungen) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { moduleGuard } from "@/server/action-guard";
|
||||
import { ctxFromGuard, ServiceError } from "@/server/services/context";
|
||||
import { correctTimeEntry } from "@/server/services/field/time-correction";
|
||||
|
||||
const guard = moduleGuard("field");
|
||||
|
||||
export type TimeCorrectionResult = { ok: true } | { ok: false; error: "invalid" | "forbidden" | "not_found" | "failed" };
|
||||
|
||||
/** Manual time correction (Spec §12.2) — thin adapter over services/field/time-correction. */
|
||||
export async function correctTime(input: {
|
||||
workOrderId: string;
|
||||
timeEntryId: string;
|
||||
startedAt: string;
|
||||
endedAt: string | null;
|
||||
reason: string;
|
||||
}): Promise<TimeCorrectionResult> {
|
||||
const g = await guard("field:correct_time");
|
||||
try {
|
||||
await correctTimeEntry(ctxFromGuard(g), {
|
||||
timeEntryId: input.timeEntryId,
|
||||
startedAt: input.startedAt,
|
||||
endedAt: input.endedAt,
|
||||
reason: input.reason,
|
||||
});
|
||||
} catch (err) {
|
||||
if (err instanceof ServiceError && (err.code === "invalid" || err.code === "forbidden" || err.code === "not_found")) return { ok: false, error: err.code };
|
||||
console.error("[field] time correction failed:", err);
|
||||
return { ok: false, error: "failed" };
|
||||
}
|
||||
revalidatePath(`/m/orders/${input.workOrderId}/time`);
|
||||
return { ok: true };
|
||||
}
|
||||
Reference in New Issue
Block a user