Repository: urlaubsverwaltung/urlaubsverwaltung (java)

Issue:
Verlauf von Abwesenheiten, Krankmeldungen und Überstunden sind nicht korrekt Sortiert
**Describe the bug**

Der Verlauf von Abwesenheiten, Krankmeldungen und Überstunden sind nicht korrekt Sortiert. Aktuell erscheint, dass es keine Reihenfolge gibt. Wir möchten zunächst den Verlauf anhand ihrer vorlaufenden IDs absteigend sortieren, sodass der neuste Eintrag ganz oben steht.


**Screenshots**
If applicable, add screenshots to help explain your problem.

![Image](https://github.com/user-attachments/assets/7cceedd3-d6a9-4cf5-a350-61389d5ab563)

Pull request description:
Sort comments for overtime, sick notes and applications descending by id
closes #5414

<!--

Thanks for contributing to the Urlaubsverwaltung.
Please review the following notes before submitting you pull request.

Please look for other issues or pull requests which already work on this topic. Is somebody already on it? Do you need to synchronize?

# Security Vulnerabilities

🛑 STOP! 🛑 If your contribution fixes a security vulnerability, please do not submit it.
Instead, please open a report of a security vulnerability via
[Report a security vulnerability](https://github.com/urlaubsverwaltung/urlaubsverwaltung/security/advisories/new)


# Describing Your Changes

If, having reviewed the notes above, you're ready to submit your pull request, please
provide a brief description of the proposed changes.

If they:
 🐞 fix a bug, please describe the broken behaviour and how the changes fix it.
    Please label with 'type: bug' and 'status: new'
    
 🎁 make an enhancement, please describe the new functionality and why you believe it's useful.
    Please label with 'type: enhancement' and 'status: new'
 
If your pull request relates to any existing issues,
please reference them by using the issue number prefixed with #.

-->


Patch:
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepository.java b/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepository.java
index 73c625eee..73d5a70b4 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepository.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepository.java
@@ -9,7 +9,7 @@ import java.util.List;
 
 interface ApplicationCommentRepository extends CrudRepository<ApplicationCommentEntity, Long> {
 
-    List<ApplicationCommentEntity> findByApplicationId(Long applicationId);
+    List<ApplicationCommentEntity> findByApplicationIdOrderByIdDesc(Long applicationId);
 
     List<ApplicationCommentEntity> findByPerson(Person person);
 
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentServiceImpl.java b/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentServiceImpl.java
index 1cb016b14..d0c4364d1 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentServiceImpl.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentServiceImpl.java
@@ -27,17 +27,21 @@ class ApplicationCommentServiceImpl implements ApplicationCommentService {
     private final Clock clock;
 
     @Autowired
-    ApplicationCommentServiceImpl(ApplicationCommentRepository commentRepository, ApplicationService applicationService,
-                                  Clock clock) {
-
+    ApplicationCommentServiceImpl(
+        ApplicationCommentRepository commentRepository,
+        ApplicationService applicationService,
+        Clock clock
+    ) {
         this.commentRepository = commentRepository;
         this.applicationService = applicationService;
         this.clock = clock;
     }
 
     @Override
-    public ApplicationComment create(Application application, ApplicationCommentAction action, Optional<String> text,
-                                     Person author) {
+    public ApplicationComment create(
+        Application application, ApplicationCommentAction action,
+        Optional<String> text, Person author
+    ) {
 
         final ApplicationCommentEntity commentEntity = new ApplicationCommentEntity(author, clock);
         commentEntity.setAction(action);
@@ -56,7 +60,7 @@ class ApplicationCommentServiceImpl implements ApplicationCommentService {
     @Override
     public List<ApplicationComment> getCommentsByApplication(Application application) {
 
-        final List<ApplicationCommentEntity> commentEntities = commentRepository.findByApplicationId(application.getId());
+        final List<ApplicationCommentEntity> commentEntities = commentRepository.findByApplicationIdOrderByIdDesc(application.getId());
 
         final List<Long> applicationIds = commentEntities
             .stream()
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeComment.java b/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeComment.java
index 4610dde5b..bb82be45f 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeComment.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeComment.java
@@ -126,4 +126,16 @@ public class OvertimeComment extends AbstractTenantAwareEntity {
     public int hashCode() {
         return Objects.hash(id);
     }
+
+    @Override
+    public String toString() {
+        return "OvertimeComment{" +
+            "id=" + id +
+            ", overtime=" + overtime +
+            ", action=" + action +
+            ", person=" + person +
+            ", date=" + date +
+            ", text='" + text + '\'' +
+            '}';
+    }
 }
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeCommentRepository.java b/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeCommentRepository.java
index be3ec19f4..243f1bb1c 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeCommentRepository.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeCommentRepository.java
@@ -13,7 +13,7 @@ import java.util.List;
  */
 interface OvertimeCommentRepository extends CrudRepository<OvertimeComment, Long> {
 
-    List<OvertimeComment> findByOvertime(Overtime overtime);
+    List<OvertimeComment> findByOvertimeOrderByIdDesc(Overtime overtime);
 
     List<OvertimeComment> findByPerson(Person person);
 
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImpl.java b/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImpl.java
index 261927dcb..1e6e94b7d 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImpl.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImpl.java
@@ -118,7 +118,7 @@ class OvertimeServiceImpl implements OvertimeService {
 
     @Override
     public List<OvertimeComment> getCommentsForOvertime(Overtime overtime) {
-        return overtimeCommentRepository.findByOvertime(overtime);
+        return overtimeCommentRepository.findByOvertimeOrderByIdDesc(overtime);
     }
 
     @Override
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntity.java b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntity.java
index 0b2d339ae..cd5c04b00 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntity.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntity.java
@@ -119,4 +119,16 @@ public class SickNoteCommentEntity extends AbstractTenantAwareEntity {
     public int hashCode() {
         return Objects.hash(id);
     }
+
+    @Override
+    public String toString() {
+        return "SickNoteCommentEntity{" +
+            "id=" + id +
+            ", sickNoteId=" + sickNoteId +
+            ", action=" + action +
+            ", person=" + person +
+            ", date=" + date +
+            ", text='" + text + '\'' +
+            '}';
+    }
 }
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepository.java b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepository.java
index 1048ebd38..fac373c3a 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepository.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepository.java
@@ -13,7 +13,7 @@ import java.util.List;
  */
 interface SickNoteCommentEntityRepository extends CrudRepository<SickNoteCommentEntity, Long> {
 
-    List<SickNoteCommentEntity> findBySickNoteId(Long sickNoteId);
+    List<SickNoteCommentEntity> findBySickNoteIdOrderByIdDesc(Long sickNoteId);
 
     List<SickNoteCommentEntity> findByPerson(Person author);
 
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImpl.java b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImpl.java
index e370021a1..b080dbbd9 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImpl.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImpl.java
@@ -45,7 +45,7 @@ class SickNoteCommentServiceImpl implements SickNoteCommentService {
 
     @Override
     public List<SickNoteCommentEntity> getCommentsBySickNote(SickNote sickNote) {
-        return sickNoteCommentEntityRepository.findBySickNoteId(sickNote.getId());
+        return sickNoteCommentEntityRepository.findBySickNoteIdOrderByIdDesc(sickNote.getId());
     }
 
     @Override


Test patch:
diff --git a/src/test/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepositoryIT.java b/src/test/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepositoryIT.java
index cf8b0d915..c4080281a 100644
--- a/src/test/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepositoryIT.java
+++ b/src/test/java/org/synyx/urlaubsverwaltung/application/comment/ApplicationCommentRepositoryIT.java
@@ -12,11 +12,14 @@ import org.synyx.urlaubsverwaltung.application.vacationtype.VacationTypeService;
 import org.synyx.urlaubsverwaltung.person.Person;
 import org.synyx.urlaubsverwaltung.person.PersonService;
 
+import java.util.List;
 import java.util.Optional;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.synyx.urlaubsverwaltung.application.comment.ApplicationCommentAction.ALLOWED;
 import static org.synyx.urlaubsverwaltung.application.comment.ApplicationCommentAction.ALLOWED_DIRECTLY;
+import static org.synyx.urlaubsverwaltung.application.comment.ApplicationCommentAction.COMMENTED;
+
 
 @SpringBootTest
 @Transactional
@@ -37,7 +40,7 @@ class ApplicationCommentRepositoryIT extends SingleTenantTestContainersBase {
     @Test
     void ensureDeleteByApplicationPerson() {
 
-        final VacationType<?> vacationType = vacationTypeService.getActiveVacationTypes().get(0);
+        final VacationType<?> vacationType = vacationTypeService.getActiveVacationTypes().getFirst();
 
         final Person person = personService.create("batman", "Bruce", "Wayne", "batman@example.org");
         final Application application = new Application();
@@ -67,4 +70,27 @@ class ApplicationCommentRepositoryIT extends SingleTenantTestContainersBase {
             assertThat(commentEntity.getText()).isEqualTo("Whoop");
         });
     }
+
+    @Test
+    void ensureToGetApplicationCommentsInCorrectOrder() {
+
+        final VacationType<?> vacationType = vacationTypeService.getActiveVacationTypes().getFirst();
+
+        final Person person = personService.create("batman", "Bruce", "Wayne", "batman@example.org");
+
+        final Application application = new Application();
+        application.setPerson(person);
+        application.setVacationType(vacationType);
+        final Application savedApplication = applicationService.save(application);
+
+        final ApplicationComment first = applicationCommentService.create(savedApplication, COMMENTED,  Optional.of("first"), person);
+        final ApplicationComment second = applicationCommentService.create(savedApplication, COMMENTED,  Optional.of("second"), person);
+        final ApplicationComment third = applicationCommentService.create(savedApplication, COMMENTED,  Optional.of("third"), person);
+        final ApplicationComment fourth = applicationCommentService.create(savedApplication, COMMENTED,  Optional.of("fourth"), person);
+
+        final List<ApplicationCommentEntity> applicationComments = sut.findByApplicationIdOrderByIdDesc(savedApplication.getId());
+        assertThat(applicationComments)
+            .extracting(ApplicationCommentEntity::getId)
+            .containsExactly(fourth.id(), third.id(), second.id(), first.id());
+    }
 }
diff --git a/src/test/java/org/synyx/urlaubsverwaltung/overtime/OvertimeCommentRepositoryIT.java b/src/test/java/org/synyx/urlaubsverwaltung/overtime/OvertimeCommentRepositoryIT.java
new file mode 100644
index 000000000..6c19459fb
--- /dev/null
+++ b/src/test/java/org/synyx/urlaubsverwaltung/overtime/OvertimeCommentRepositoryIT.java
@@ -0,0 +1,51 @@
+package org.synyx.urlaubsverwaltung.overtime;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.transaction.annotation.Transactional;
+import org.synyx.urlaubsverwaltung.SingleTenantTestContainersBase;
+import org.synyx.urlaubsverwaltung.person.Person;
+import org.synyx.urlaubsverwaltung.person.PersonService;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+
+import static java.time.ZoneOffset.UTC;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.synyx.urlaubsverwaltung.overtime.OvertimeCommentAction.COMMENTED;
+
+@SpringBootTest
+@Transactional
+class OvertimeCommentRepositoryIT extends SingleTenantTestContainersBase {
+
+    @Autowired
+    private OvertimeCommentRepository sut;
+
+    @Autowired
+    private PersonService personService;
+    @Autowired
+    private OvertimeService overtimeService;
+
+    @Test
+    void ensureToGetOvertimeCommentsInCorrectOrder() {
+
+        final LocalDate now = LocalDate.now(UTC);
+
+        final Person person = personService.create("batman", "Bruce", "Wayne", "batman@example.org");
+
+        final Overtime overtime = new Overtime(person, now, now, Duration.ofHours(4));
+        final Overtime savedOvertime = overtimeService.save(overtime, Optional.empty(), person);
+
+        final OvertimeComment first = overtimeService.getCommentsForOvertime(savedOvertime).getFirst();
+        final OvertimeComment second = overtimeService.saveComment(savedOvertime, COMMENTED, "second", person);
+        final OvertimeComment third = overtimeService.saveComment(savedOvertime, COMMENTED, "third", person);
+        final OvertimeComment fourth = overtimeService.saveComment(savedOvertime, COMMENTED, "fourth", person);
+
+        final List<OvertimeComment> overtimeComments = sut.findByOvertimeOrderByIdDesc(savedOvertime);
+        assertThat(overtimeComments)
+            .containsExactly(fourth, third, second, first);
+    }
+}
diff --git a/src/test/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImplTest.java b/src/test/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImplTest.java
index aa2873ebd..c3783d2ca 100644
--- a/src/test/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImplTest.java
+++ b/src/test/java/org/synyx/urlaubsverwaltung/overtime/OvertimeServiceImplTest.java
@@ -230,7 +230,7 @@ class OvertimeServiceImplTest {
         final Overtime overtime = new Overtime();
         sut.getCommentsForOvertime(overtime);
 
-        verify(overtimeCommentRepository).findByOvertime(overtime);
+        verify(overtimeCommentRepository).findByOvertimeOrderByIdDesc(overtime);
     }
 
     // Get total overtime for year -------------------------------------------------------------------------------------
diff --git a/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepositoryIT.java b/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepositoryIT.java
index ad7547845..63149eef0 100644
--- a/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepositoryIT.java
+++ b/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentEntityRepositoryIT.java
@@ -16,6 +16,7 @@ import java.util.stream.StreamSupport;
 
 import static java.time.ZoneOffset.UTC;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.synyx.urlaubsverwaltung.sicknote.comment.SickNoteCommentAction.COMMENTED;
 
 @SpringBootTest
 @Transactional
@@ -46,10 +47,10 @@ class SickNoteCommentEntityRepositoryIT extends SingleTenantTestContainersBase {
         final SickNote sickNoteBatmanTwo = sickNoteService.save(SickNote.builder().person(batman).startDate(now.minusDays(5)).endDate(now.minusDays(5)).build());
         final SickNote sickNoteRobinOne = sickNoteService.save(SickNote.builder().person(robin).startDate(now.minusDays(3)).endDate(now.minusDays(3)).build());
 
-        sickNoteCommentService.create(sickNoteBatmanOne, SickNoteCommentAction.COMMENTED, robin, "miss you, not");
-        sickNoteCommentService.create(sickNoteBatmanOne, SickNoteCommentAction.COMMENTED, robin, "well... actually...");
-        sickNoteCommentService.create(sickNoteBatmanTwo, SickNoteCommentAction.COMMENTED, robin, "aaaand again");
-        sickNoteCommentService.create(sickNoteRobinOne, SickNoteCommentAction.COMMENTED, alfred, "Get well soon!");
+        sickNoteCommentService.create(sickNoteBatmanOne, COMMENTED, robin, "miss you, not");
+        sickNoteCommentService.create(sickNoteBatmanOne, COMMENTED, robin, "well... actually...");
+        sickNoteCommentService.create(sickNoteBatmanTwo, COMMENTED, robin, "aaaand again");
+        sickNoteCommentService.create(sickNoteRobinOne, COMMENTED, alfred, "Get well soon!");
 
         final List<SickNoteCommentEntity> allCommentsBeforeDelete = getAllComments();
         assertThat(allCommentsBeforeDelete).hasSize(4);
@@ -58,8 +59,26 @@ class SickNoteCommentEntityRepositoryIT extends SingleTenantTestContainersBase {
 
         final List<SickNoteCommentEntity> allComments = getAllComments();
         assertThat(allComments).hasSize(1);
-        assertThat(allComments.get(0).getSickNoteId()).isEqualTo(sickNoteRobinOne.getId());
-        assertThat(allComments.get(0).getText()).isEqualTo("Get well soon!");
+        assertThat(allComments.getFirst().getSickNoteId()).isEqualTo(sickNoteRobinOne.getId());
+        assertThat(allComments.getFirst().getText()).isEqualTo("Get well soon!");
+    }
+
+    @Test
+    void ensureToGetSickNoteCommentsInCorrectOrder() {
+
+        final LocalDate now = LocalDate.now(UTC);
+
+        final Person person = personService.create("batman", "Bruce", "Wayne", "batman@example.org");
+        final SickNote sickNote = sickNoteService.save(SickNote.builder().person(person).startDate(now).endDate(now).build());
+
+        final SickNoteCommentEntity first = sickNoteCommentService.create(sickNote, COMMENTED, person, "first");
+        final SickNoteCommentEntity second = sickNoteCommentService.create(sickNote, COMMENTED, person, "second");
+        final SickNoteCommentEntity third = sickNoteCommentService.create(sickNote, COMMENTED, person, "third");
+        final SickNoteCommentEntity fourth = sickNoteCommentService.create(sickNote, COMMENTED, person, "fourth");
+
+        final List<SickNoteCommentEntity> sickNoteComments = sut.findBySickNoteIdOrderByIdDesc(sickNote.getId());
+        assertThat(sickNoteComments)
+            .containsExactly(fourth, third, second, first);
     }
 
     private List<SickNoteCommentEntity> getAllComments() {
diff --git a/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImplTest.java b/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImplTest.java
index 66ad7b3e3..2ff5a02cf 100644
--- a/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImplTest.java
+++ b/src/test/java/org/synyx/urlaubsverwaltung/sicknote/comment/SickNoteCommentServiceImplTest.java
@@ -110,6 +110,6 @@ class SickNoteCommentServiceImplTest {
 
         final ArgumentCaptor<List<SickNoteCommentEntity>> argument = ArgumentCaptor.forClass(List.class);
         verify(sickNoteCommentEntityRepository).saveAll(argument.capture());
-        assertThat(argument.getValue().get(0).getPerson()).isNull();
+        assertThat(argument.getValue().getFirst().getPerson()).isNull();
     }
 }