feat: Umstellung auf Anthropic Claude SDK, Rechnungsgenerator-Systemtemplate und Task-Status-Sync

- LLM-Integration von LM Studio (Spring AI OpenAI) auf Anthropic Java SDK umgestellt
- Rechnungsgenerator: System-Template für Rechnungen an Nutzer, Canvas leeren, PDF-Vorschau
- Job manuell beenden sendet job_deleted an verbundene App-Clients
- MessageController: nur offene Jobs ausliefern, station_completed per jobId auflösen
- App: Task-Erledigungsstatus aus Server-Tasks auf Stations-Snapshots übernehmen, lokale Task-Status bei Offline-Pufferung erhalten
- Adressbuch-Wording in allen Sprachdateien, Version 0.9.18

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 11:16:34 +02:00
parent 31b18e1f52
commit 09db861064
21 changed files with 1087 additions and 652 deletions

View File

@@ -258,6 +258,40 @@ class Job {
return (a.taskOrder ?? 0).compareTo(b.taskOrder ?? 0);
}
// The tasks embedded in deliveryStations are snapshots from job creation
// and never reflect later completions. The top-level tasks list comes from
// the server's task collection and carries the current completion state,
// so overlay it onto the station tasks by id.
final topLevelTasksRaw = json['tasks'] ?? jobJson['tasks'];
if (deliveryStations.isNotEmpty && topLevelTasksRaw is List) {
final freshTasksById = <String, Task>{};
for (final rawTask in topLevelTasksRaw) {
if (rawTask is! Map) {
continue;
}
try {
final task = Task.fromJson(Map<String, dynamic>.from(rawTask));
if (task.id.isNotEmpty) {
freshTasksById[task.id] = task;
}
} catch (_) {
// Ignore unparseable entries; the station snapshot stays in place.
}
}
for (final station in deliveryStations) {
for (var i = 0; i < station.tasks.length; i++) {
final fresh = freshTasksById[station.tasks[i].id];
if (fresh != null && fresh.completed && !station.tasks[i].completed) {
station.tasks[i] = station.tasks[i].copyWith(
completed: true,
completedAt: fresh.completedAt,
completedBy: fresh.completedBy,
);
}
}
}
}
// Parse tasks array
List<Task> tasks = [];
if (deliveryStations.isNotEmpty) {