Erweiterungen

This commit is contained in:
2025-09-16 10:04:53 +02:00
parent 2444574d35
commit 5d0b59c46f
4 changed files with 159 additions and 2 deletions

View File

@@ -15,9 +15,11 @@ import de.assecutor.votianlt.repository.PhotoRepository;
import de.assecutor.votianlt.repository.TaskRepository; import de.assecutor.votianlt.repository.TaskRepository;
import de.assecutor.votianlt.repository.BarcodeRepository; import de.assecutor.votianlt.repository.BarcodeRepository;
import de.assecutor.votianlt.repository.SignatureRepository; import de.assecutor.votianlt.repository.SignatureRepository;
import de.assecutor.votianlt.repository.CommentRepository;
import de.assecutor.votianlt.model.Photo; import de.assecutor.votianlt.model.Photo;
import de.assecutor.votianlt.model.Barcode; import de.assecutor.votianlt.model.Barcode;
import de.assecutor.votianlt.model.Signature; import de.assecutor.votianlt.model.Signature;
import de.assecutor.votianlt.model.Comment;
import de.assecutor.votianlt.service.JobHistoryService; import de.assecutor.votianlt.service.JobHistoryService;
import de.assecutor.votianlt.service.EmailService; import de.assecutor.votianlt.service.EmailService;
import de.assecutor.votianlt.model.JobStatus; import de.assecutor.votianlt.model.JobStatus;
@@ -59,13 +61,14 @@ public class MessageController {
private final PhotoRepository photoRepository; private final PhotoRepository photoRepository;
private final BarcodeRepository barcodeRepository; private final BarcodeRepository barcodeRepository;
private final SignatureRepository signatureRepository; private final SignatureRepository signatureRepository;
private final CommentRepository commentRepository;
private final JobHistoryService jobHistoryService; private final JobHistoryService jobHistoryService;
private final EmailService emailService; private final EmailService emailService;
public MessageController(MqttPublisher mqttPublisher, AppUserRepository appUserRepository, public MessageController(MqttPublisher mqttPublisher, AppUserRepository appUserRepository,
AppUserService appUserService, JobRepository jobRepository, CargoItemRepository cargoItemRepository, AppUserService appUserService, JobRepository jobRepository, CargoItemRepository cargoItemRepository,
TaskRepository taskRepository, PhotoRepository photoRepository, BarcodeRepository barcodeRepository, TaskRepository taskRepository, PhotoRepository photoRepository, BarcodeRepository barcodeRepository,
SignatureRepository signatureRepository, JobHistoryService jobHistoryService, EmailService emailService) { SignatureRepository signatureRepository, CommentRepository commentRepository, JobHistoryService jobHistoryService, EmailService emailService) {
this.mqttPublisher = mqttPublisher; this.mqttPublisher = mqttPublisher;
this.appUserRepository = appUserRepository; this.appUserRepository = appUserRepository;
this.appUserService = appUserService; this.appUserService = appUserService;
@@ -75,6 +78,7 @@ public class MessageController {
this.photoRepository = photoRepository; this.photoRepository = photoRepository;
this.barcodeRepository = barcodeRepository; this.barcodeRepository = barcodeRepository;
this.signatureRepository = signatureRepository; this.signatureRepository = signatureRepository;
this.commentRepository = commentRepository;
this.jobHistoryService = jobHistoryService; this.jobHistoryService = jobHistoryService;
this.emailService = emailService; this.emailService = emailService;
} }
@@ -245,6 +249,9 @@ public class MessageController {
case "BARCODE" -> { case "BARCODE" -> {
processBarcodeTaskCompletion(payload); processBarcodeTaskCompletion(payload);
} }
case "COMMENT" -> {
processCommentTaskCompletion(payload);
}
default -> { default -> {
log.info("ERROR: handleTaskCompleted called with taskType={}, data: {}", taskType, payload); log.info("ERROR: handleTaskCompleted called with taskType={}, data: {}", taskType, payload);
} }
@@ -413,6 +420,45 @@ public class MessageController {
} }
} }
private void processCommentTaskCompletion(Map<String, Object> payload) {
Object taskId = payload.get("taskId");
try {
var opt = taskRepository.findById(new ObjectId(taskId.toString()));
if (opt.isEmpty()) {
log.warn("Task not found for comment completion. taskId={}", taskId);
return;
}
BaseTask task = opt.get();
String extraDataSummary = null;
Object extra = payload.get("extraData");
if (extra instanceof Map<?, ?> extraData) {
Object commentTextObj = extraData.get("commentText");
if (commentTextObj instanceof String commentText && !commentText.isBlank()) {
// Save comment to database
String completedBy = task.getCompletedBy() != null ? task.getCompletedBy() : "Unknown";
Comment commentEntry = new Comment(new ObjectId(taskId.toString()), commentText, completedBy);
commentRepository.save(commentEntry);
extraDataSummary = "Kommentar: " + commentText;
log.info("Comment saved for taskId={}: {}", taskId, commentText);
} else {
extraDataSummary = "Kommentar abgegeben (leer)";
}
} else {
extraDataSummary = "Kommentar abgegeben";
log.warn("extraData is not a Map for comment task completion, taskId={}", taskId);
}
// Finally, mark the task as completed with history logging
completeTaskWithHistory(taskId, extraDataSummary);
} catch (IllegalArgumentException ex) {
log.error("Invalid taskId format for comment completion: {}", taskId);
} catch (Exception ex) {
log.error("Error while processing comment task completion (taskId={}): {}", taskId, ex.getMessage(), ex);
}
}
private void completeTask(Object tid) { private void completeTask(Object tid) {
completeTaskWithHistory(tid, null); completeTaskWithHistory(tid, null);
} }

View File

@@ -0,0 +1,38 @@
package de.assecutor.votianlt.model;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@Document(collection = "comments")
public class Comment {
@Id
private ObjectId id;
@Field("task_id")
private ObjectId taskId;
@Field("comment_text")
private String commentText;
@Field("completed_by")
private String completedBy;
@Field("created_at")
private LocalDateTime createdAt;
public Comment(ObjectId taskId, String commentText, String completedBy) {
this.taskId = taskId;
this.commentText = commentText;
this.completedBy = completedBy;
this.createdAt = LocalDateTime.now();
}
}

View File

@@ -35,9 +35,11 @@ import de.assecutor.votianlt.repository.TaskRepository;
import de.assecutor.votianlt.repository.SignatureRepository; import de.assecutor.votianlt.repository.SignatureRepository;
import de.assecutor.votianlt.repository.BarcodeRepository; import de.assecutor.votianlt.repository.BarcodeRepository;
import de.assecutor.votianlt.repository.PhotoRepository; import de.assecutor.votianlt.repository.PhotoRepository;
import de.assecutor.votianlt.repository.CommentRepository;
import de.assecutor.votianlt.model.Signature; import de.assecutor.votianlt.model.Signature;
import de.assecutor.votianlt.model.Barcode; import de.assecutor.votianlt.model.Barcode;
import de.assecutor.votianlt.model.Photo; import de.assecutor.votianlt.model.Photo;
import de.assecutor.votianlt.model.Comment;
import de.assecutor.votianlt.pages.service.AppUserService; import de.assecutor.votianlt.pages.service.AppUserService;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
@@ -59,6 +61,7 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
private final SignatureRepository signatureRepository; private final SignatureRepository signatureRepository;
private final BarcodeRepository barcodeRepository; private final BarcodeRepository barcodeRepository;
private final PhotoRepository photoRepository; private final PhotoRepository photoRepository;
private final CommentRepository commentRepository;
private final AppUserService appUserService; private final AppUserService appUserService;
private final VerticalLayout content; private final VerticalLayout content;
@@ -66,13 +69,14 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
public JobSummaryView(JobRepository jobRepository, CargoItemRepository cargoItemRepository, public JobSummaryView(JobRepository jobRepository, CargoItemRepository cargoItemRepository,
TaskRepository taskRepository, SignatureRepository signatureRepository, BarcodeRepository barcodeRepository, TaskRepository taskRepository, SignatureRepository signatureRepository, BarcodeRepository barcodeRepository,
PhotoRepository photoRepository, AppUserService appUserService) { PhotoRepository photoRepository, CommentRepository commentRepository, AppUserService appUserService) {
this.jobRepository = jobRepository; this.jobRepository = jobRepository;
this.cargoItemRepository = cargoItemRepository; this.cargoItemRepository = cargoItemRepository;
this.taskRepository = taskRepository; this.taskRepository = taskRepository;
this.signatureRepository = signatureRepository; this.signatureRepository = signatureRepository;
this.barcodeRepository = barcodeRepository; this.barcodeRepository = barcodeRepository;
this.photoRepository = photoRepository; this.photoRepository = photoRepository;
this.commentRepository = commentRepository;
this.appUserService = appUserService; this.appUserService = appUserService;
setSizeFull(); setSizeFull();
@@ -590,6 +594,36 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
if (commentTask.isRequired()) { if (commentTask.isRequired()) {
content.add(new Span("Pflichtfeld")); content.add(new Span("Pflichtfeld"));
} }
// Show comments if task is completed
if (task.isCompleted()) {
try {
ObjectId taskId = new ObjectId(task.getIdAsString());
List<Comment> comments = commentRepository.findByTaskIdOrderByCreatedAtDesc(taskId);
if (!comments.isEmpty()) {
content.add(new Span("Abgegebene Kommentare (" + comments.size() + "):"));
for (Comment comment : comments) {
Div commentContainer = new Div();
commentContainer.getStyle()
.set("background-color", "#f5f5f5")
.set("border", "1px solid #ddd")
.set("border-radius", "4px")
.set("padding", "8px")
.set("margin", "4px 0")
.set("font-family", "monospace")
.set("white-space", "pre-wrap");
Span commentText = new Span(comment.getCommentText());
commentContainer.add(commentText);
content.add(commentContainer);
}
}
} catch (Exception e) {
log.debug("Failed to load comments for task {}: {}", task.getId(), e.getMessage());
}
}
} }
} }

View File

@@ -0,0 +1,39 @@
package de.assecutor.votianlt.repository;
import de.assecutor.votianlt.model.Comment;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface CommentRepository extends MongoRepository<Comment, ObjectId> {
/**
* Find all comments for a specific task, ordered by creation time descending
* (newest first)
*/
List<Comment> findByTaskIdOrderByCreatedAtDesc(ObjectId taskId);
/**
* Find all comments for a specific task, ordered by creation time ascending
* (oldest first)
*/
List<Comment> findByTaskIdOrderByCreatedAtAsc(ObjectId taskId);
/**
* Find comments by who completed them
*/
List<Comment> findByCompletedByOrderByCreatedAtDesc(String completedBy);
/**
* Count comments for a specific task
*/
long countByTaskId(ObjectId taskId);
/**
* Delete all comments for a specific task
*/
void deleteByTaskId(ObjectId taskId);
}