diff --git a/src/main/java/de/assecutor/votianlt/controller/MessageController.java b/src/main/java/de/assecutor/votianlt/controller/MessageController.java index 76751a0..0fc799f 100644 --- a/src/main/java/de/assecutor/votianlt/controller/MessageController.java +++ b/src/main/java/de/assecutor/votianlt/controller/MessageController.java @@ -15,9 +15,11 @@ import de.assecutor.votianlt.repository.PhotoRepository; import de.assecutor.votianlt.repository.TaskRepository; import de.assecutor.votianlt.repository.BarcodeRepository; import de.assecutor.votianlt.repository.SignatureRepository; +import de.assecutor.votianlt.repository.CommentRepository; import de.assecutor.votianlt.model.Photo; import de.assecutor.votianlt.model.Barcode; import de.assecutor.votianlt.model.Signature; +import de.assecutor.votianlt.model.Comment; import de.assecutor.votianlt.service.JobHistoryService; import de.assecutor.votianlt.service.EmailService; import de.assecutor.votianlt.model.JobStatus; @@ -59,13 +61,14 @@ public class MessageController { private final PhotoRepository photoRepository; private final BarcodeRepository barcodeRepository; private final SignatureRepository signatureRepository; + private final CommentRepository commentRepository; private final JobHistoryService jobHistoryService; private final EmailService emailService; public MessageController(MqttPublisher mqttPublisher, AppUserRepository appUserRepository, AppUserService appUserService, JobRepository jobRepository, CargoItemRepository cargoItemRepository, TaskRepository taskRepository, PhotoRepository photoRepository, BarcodeRepository barcodeRepository, - SignatureRepository signatureRepository, JobHistoryService jobHistoryService, EmailService emailService) { + SignatureRepository signatureRepository, CommentRepository commentRepository, JobHistoryService jobHistoryService, EmailService emailService) { this.mqttPublisher = mqttPublisher; this.appUserRepository = appUserRepository; this.appUserService = appUserService; @@ -75,6 +78,7 @@ public class MessageController { this.photoRepository = photoRepository; this.barcodeRepository = barcodeRepository; this.signatureRepository = signatureRepository; + this.commentRepository = commentRepository; this.jobHistoryService = jobHistoryService; this.emailService = emailService; } @@ -245,6 +249,9 @@ public class MessageController { case "BARCODE" -> { processBarcodeTaskCompletion(payload); } + case "COMMENT" -> { + processCommentTaskCompletion(payload); + } default -> { log.info("ERROR: handleTaskCompleted called with taskType={}, data: {}", taskType, payload); } @@ -413,6 +420,45 @@ public class MessageController { } } + private void processCommentTaskCompletion(Map 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) { completeTaskWithHistory(tid, null); } diff --git a/src/main/java/de/assecutor/votianlt/model/Comment.java b/src/main/java/de/assecutor/votianlt/model/Comment.java new file mode 100644 index 0000000..5cff59a --- /dev/null +++ b/src/main/java/de/assecutor/votianlt/model/Comment.java @@ -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(); + } +} \ No newline at end of file diff --git a/src/main/java/de/assecutor/votianlt/pages/view/JobSummaryView.java b/src/main/java/de/assecutor/votianlt/pages/view/JobSummaryView.java index 7ee1caf..b385f52 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/JobSummaryView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/JobSummaryView.java @@ -35,9 +35,11 @@ import de.assecutor.votianlt.repository.TaskRepository; import de.assecutor.votianlt.repository.SignatureRepository; import de.assecutor.votianlt.repository.BarcodeRepository; import de.assecutor.votianlt.repository.PhotoRepository; +import de.assecutor.votianlt.repository.CommentRepository; import de.assecutor.votianlt.model.Signature; import de.assecutor.votianlt.model.Barcode; import de.assecutor.votianlt.model.Photo; +import de.assecutor.votianlt.model.Comment; import de.assecutor.votianlt.pages.service.AppUserService; import jakarta.annotation.security.RolesAllowed; import org.bson.types.ObjectId; @@ -59,6 +61,7 @@ public class JobSummaryView extends Main implements HasUrlParameter { private final SignatureRepository signatureRepository; private final BarcodeRepository barcodeRepository; private final PhotoRepository photoRepository; + private final CommentRepository commentRepository; private final AppUserService appUserService; private final VerticalLayout content; @@ -66,13 +69,14 @@ public class JobSummaryView extends Main implements HasUrlParameter { public JobSummaryView(JobRepository jobRepository, CargoItemRepository cargoItemRepository, TaskRepository taskRepository, SignatureRepository signatureRepository, BarcodeRepository barcodeRepository, - PhotoRepository photoRepository, AppUserService appUserService) { + PhotoRepository photoRepository, CommentRepository commentRepository, AppUserService appUserService) { this.jobRepository = jobRepository; this.cargoItemRepository = cargoItemRepository; this.taskRepository = taskRepository; this.signatureRepository = signatureRepository; this.barcodeRepository = barcodeRepository; this.photoRepository = photoRepository; + this.commentRepository = commentRepository; this.appUserService = appUserService; setSizeFull(); @@ -590,6 +594,36 @@ public class JobSummaryView extends Main implements HasUrlParameter { if (commentTask.isRequired()) { content.add(new Span("Pflichtfeld")); } + + // Show comments if task is completed + if (task.isCompleted()) { + try { + ObjectId taskId = new ObjectId(task.getIdAsString()); + List 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()); + } + } } } diff --git a/src/main/java/de/assecutor/votianlt/repository/CommentRepository.java b/src/main/java/de/assecutor/votianlt/repository/CommentRepository.java new file mode 100644 index 0000000..fba39b4 --- /dev/null +++ b/src/main/java/de/assecutor/votianlt/repository/CommentRepository.java @@ -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 { + + /** + * Find all comments for a specific task, ordered by creation time descending + * (newest first) + */ + List findByTaskIdOrderByCreatedAtDesc(ObjectId taskId); + + /** + * Find all comments for a specific task, ordered by creation time ascending + * (oldest first) + */ + List findByTaskIdOrderByCreatedAtAsc(ObjectId taskId); + + /** + * Find comments by who completed them + */ + List findByCompletedByOrderByCreatedAtDesc(String completedBy); + + /** + * Count comments for a specific task + */ + long countByTaskId(ObjectId taskId); + + /** + * Delete all comments for a specific task + */ + void deleteByTaskId(ObjectId taskId); +} \ No newline at end of file