Repository: urlaubsverwaltung/urlaubsverwaltung
Pull request #5174 (2025-02-18 15:56:40)

Accepting a sick note creates a SickNoteAcceptedEvent
<!--

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/pom.xml b/pom.xml
index 9d48fa59e..3b0100b95 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
     <maven.compiler.showWarnings>true</maven.compiler.showWarnings>
     <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
     <java.version>21</java.version>
-    <uv-extension-api.version>1.3.0</uv-extension-api.version>
+    <uv-extension-api.version>1.4.0</uv-extension-api.version>
     <jollyday.version>1.5.0</jollyday.version>
 
     <!-- Remove commons-compress dependency when testcontainers ships with commons-compress >= 1.27.1, see
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/extension/sicknote/SickNoteEventHandlerExtension.java b/src/main/java/org/synyx/urlaubsverwaltung/extension/sicknote/SickNoteEventHandlerExtension.java
index afd129873..82ed8fe53 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/extension/sicknote/SickNoteEventHandlerExtension.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/extension/sicknote/SickNoteEventHandlerExtension.java
@@ -1,6 +1,7 @@
 package org.synyx.urlaubsverwaltung.extension.sicknote;
 
 import de.focus_shift.urlaubsverwaltung.extension.api.sicknote.DayLength;
+import de.focus_shift.urlaubsverwaltung.extension.api.sicknote.SickNoteAcceptedEventDTO;
 import de.focus_shift.urlaubsverwaltung.extension.api.sicknote.SickNoteCancelledEventDTO;
 import de.focus_shift.urlaubsverwaltung.extension.api.sicknote.SickNoteConvertedToApplicationEventDTO;
 import de.focus_shift.urlaubsverwaltung.extension.api.sicknote.SickNoteCreatedEventDTO;
@@ -17,6 +18,7 @@ import org.synyx.urlaubsverwaltung.absence.AbsencePeriod;
 import org.synyx.urlaubsverwaltung.absence.AbsenceService;
 import org.synyx.urlaubsverwaltung.person.Person;
 import org.synyx.urlaubsverwaltung.sicknote.sicknote.SickNote;
+import org.synyx.urlaubsverwaltung.sicknote.sicknote.SickNoteAcceptedEvent;
 import org.synyx.urlaubsverwaltung.sicknote.sicknote.SickNoteCancelledEvent;
 import org.synyx.urlaubsverwaltung.sicknote.sicknote.SickNoteCreatedEvent;
 import org.synyx.urlaubsverwaltung.sicknote.sicknote.SickNoteToApplicationConvertedEvent;
@@ -169,6 +171,30 @@ public class SickNoteEventHandlerExtension {
 
         };
     }
+    private static Function<AbsencePeriod, SickNoteAcceptedEventDTO> toSickNoteAcceptedEventDTO(String tenantId, SickNoteAcceptedEvent event) {
+        return absencePeriod -> {
+            final SickNotePersonDTO person = toSickNotePersonDTO(event.sickNote().getPerson());
+            final SickNotePersonDTO applier = event.sickNote().getApplier() != null ? toSickNotePersonDTO(event.sickNote().getApplier()) : null;
+            final SickNotePeriodDTO period = toPeriod(event.sickNote());
+            final SickNotePeriodDTO medicalCertificatePeriod = toMedicalCertificatePeriod(event.sickNote());
+            final Set<LocalDate> absentWorkingDays = toAbsentWorkingDays(absencePeriod);
+
+            return SickNoteAcceptedEventDTO.builder()
+                .id(event.id())
+                .sourceId(event.sickNote().getId())
+                .createdAt(event.createdAt())
+                .tenantId(tenantId)
+                .person(person)
+                .applier(applier)
+                .type(toSickNoteType(event.sickNote()))
+                .status(toStatus(event.sickNote()))
+                .period(period)
+                .medicalCertificatePeriod(medicalCertificatePeriod)
+                .absentWorkingDays(absentWorkingDays)
+                .build();
+
+        };
+    }
 
     private static Function<AbsencePeriod, SickNoteConvertedToApplicationEventDTO> toSickNoteConvertedEventDTO(String tenantId, SickNoteToApplicationConvertedEvent event) {
         return absencePeriod -> {
@@ -218,6 +244,14 @@ public class SickNoteEventHandlerExtension {
             .ifPresent(applicationEventPublisher::publishEvent);
     }
 
+    @EventListener
+    @Async
+    void on(SickNoteAcceptedEvent event) {
+        getAbsencePeriods(event.sickNote())
+            .map(toSickNoteAcceptedEventDTO(tenantSupplier.get(), event))
+            .ifPresent(applicationEventPublisher::publishEvent);
+    }
+
     @EventListener
     @Async
     void on(SickNoteToApplicationConvertedEvent event) {
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteAcceptedEvent.java b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteAcceptedEvent.java
new file mode 100644
index 000000000..73f0f3d8f
--- /dev/null
+++ b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteAcceptedEvent.java
@@ -0,0 +1,11 @@
+package org.synyx.urlaubsverwaltung.sicknote.sicknote;
+
+import java.time.Instant;
+import java.util.UUID;
+
+public record SickNoteAcceptedEvent(UUID id, Instant createdAt, SickNote sickNote) {
+
+    public static SickNoteAcceptedEvent of(SickNote sickNote) {
+        return new SickNoteAcceptedEvent(UUID.randomUUID(), Instant.now(), sickNote);
+    }
+}
diff --git a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImpl.java b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImpl.java
index 0c3af2015..1fb23fb7d 100644
--- a/src/main/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImpl.java
+++ b/src/main/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImpl.java
@@ -40,13 +40,14 @@ class SickNoteInteractionServiceImpl implements SickNoteInteractionService {
     private final ApplicationEventPublisher applicationEventPublisher;
 
     @Autowired
-    SickNoteInteractionServiceImpl(SickNoteService sickNoteService,
-                                   SickNoteExtensionService sicknoteExtensionService,
-                                   SickNoteCommentService commentService,
-                                   ApplicationInteractionService applicationInteractionService,
-                                   SickNoteMailService sickNoteMailService,
-                                   ApplicationEventPublisher applicationEventPublisher) {
-
+    SickNoteInteractionServiceImpl(
+        SickNoteService sickNoteService,
+        SickNoteExtensionService sicknoteExtensionService,
+        SickNoteCommentService commentService,
+        ApplicationInteractionService applicationInteractionService,
+        SickNoteMailService sickNoteMailService,
+        ApplicationEventPublisher applicationEventPublisher
+    ) {
         this.sickNoteService = sickNoteService;
         this.sicknoteExtensionService = sicknoteExtensionService;
         this.commentService = commentService;
@@ -79,7 +80,7 @@ class SickNoteInteractionServiceImpl implements SickNoteInteractionService {
         sickNoteMailService.sendSickNoteAcceptedNotificationToOfficeAndResponsibleManagement(acceptedSickNote, maintainer);
         sickNoteMailService.sendCreatedOrAcceptedToColleagues(acceptedSickNote);
 
-        applicationEventPublisher.publishEvent(SickNoteUpdatedEvent.of(acceptedSickNote));
+        applicationEventPublisher.publishEvent(SickNoteAcceptedEvent.of(acceptedSickNote));
 
         return acceptedSickNote;
     }


Test patch:
diff --git a/src/test/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImplTest.java b/src/test/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImplTest.java
index 635c7af08..2dacc8f80 100644
--- a/src/test/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImplTest.java
+++ b/src/test/java/org/synyx/urlaubsverwaltung/sicknote/sicknote/SickNoteInteractionServiceImplTest.java
@@ -50,7 +50,6 @@ class SickNoteInteractionServiceImplTest {
     @Mock
     private ApplicationEventPublisher applicationEventPublisher;
 
-
     @Test
     void ensureCreatedSickNoteIsPersisted() {
 
@@ -166,12 +165,12 @@ class SickNoteInteractionServiceImplTest {
         final Person creator = new Person("creator", "Senior", "Creator", "creator@example.org");
 
         final SickNote sickNote = SickNote.builder()
-                .id(42L)
-                .startDate(LocalDate.now(UTC))
-                .endDate(LocalDate.now(UTC))
-                .dayLength(DayLength.FULL)
-                .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
-                .build();
+            .id(42L)
+            .startDate(LocalDate.now(UTC))
+            .endDate(LocalDate.now(UTC))
+            .dayLength(DayLength.FULL)
+            .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
+            .build();
 
         sut.update(sickNote, creator, comment);
 
@@ -197,13 +196,13 @@ class SickNoteInteractionServiceImplTest {
         final Person creator = new Person("creator", "Senior", "Creator", "creator@example.org");
 
         final SickNote sickNote = SickNote.builder()
-                .id(42L)
-                .startDate(LocalDate.now(UTC))
-                .endDate(LocalDate.now(UTC))
-                .dayLength(DayLength.FULL)
-                .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
-                .status(SickNoteStatus.SUBMITTED)
-                .build();
+            .id(42L)
+            .startDate(LocalDate.now(UTC))
+            .endDate(LocalDate.now(UTC))
+            .dayLength(DayLength.FULL)
+            .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
+            .status(SickNoteStatus.SUBMITTED)
+            .build();
 
         sut.update(sickNote, creator, comment);
 
@@ -376,12 +375,12 @@ class SickNoteInteractionServiceImplTest {
         when(sickNoteService.save(any(SickNote.class))).then(returnsFirstArg());
 
         final SickNote sickNote = SickNote.builder()
-                .id(42L)
-                .startDate(LocalDate.now(UTC))
-                .endDate(LocalDate.now(UTC))
-                .dayLength(DayLength.FULL)
-                .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
-                .build();
+            .id(42L)
+            .startDate(LocalDate.now(UTC))
+            .endDate(LocalDate.now(UTC))
+            .dayLength(DayLength.FULL)
+            .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
+            .build();
 
         final Person creator = new Person("creator", "Senior", "Creator", "creator@example.org");
         final String comment = "comment";
@@ -405,13 +404,13 @@ class SickNoteInteractionServiceImplTest {
         when(sickNoteService.save(any(SickNote.class))).then(returnsFirstArg());
 
         final SickNote sickNote = SickNote.builder()
-                .id(42L)
-                .startDate(LocalDate.now(UTC))
-                .endDate(LocalDate.now(UTC))
-                .dayLength(DayLength.FULL)
-                .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
-                .status(SickNoteStatus.ACTIVE)
-                .build();
+            .id(42L)
+            .startDate(LocalDate.now(UTC))
+            .endDate(LocalDate.now(UTC))
+            .dayLength(DayLength.FULL)
+            .person(new Person("muster", "Muster", "Marlene", "muster@example.org"))
+            .status(SickNoteStatus.ACTIVE)
+            .build();
 
         final Person maintainer = new Person("maintainer", "Senior", "Maintainer", "maintainer@example.org");
 
@@ -428,9 +427,9 @@ class SickNoteInteractionServiceImplTest {
         verify(sickNoteMailService).sendSickNoteAcceptedNotificationToSickPerson(sickNote, maintainer);
         verify(sickNoteMailService).sendSickNoteAcceptedNotificationToOfficeAndResponsibleManagement(sickNote, maintainer);
 
-        final ArgumentCaptor<SickNoteUpdatedEvent> eventCaptor = ArgumentCaptor.forClass(SickNoteUpdatedEvent.class);
+        final ArgumentCaptor<SickNoteAcceptedEvent> eventCaptor = ArgumentCaptor.forClass(SickNoteAcceptedEvent.class);
         verify(applicationEventPublisher).publishEvent(eventCaptor.capture());
-        final SickNoteUpdatedEvent sickNoteCreatedEvent = eventCaptor.getValue();
+        final SickNoteAcceptedEvent sickNoteCreatedEvent = eventCaptor.getValue();
         assertThat(sickNoteCreatedEvent.sickNote()).isEqualTo(acceptedSickNote);
         assertThat(sickNoteCreatedEvent.createdAt()).isBeforeOrEqualTo(Instant.now());
         assertThat(sickNoteCreatedEvent.id()).isNotNull();