diff --git a/CHANGELOG.md b/CHANGELOG.md index de49d9939cd2c8ac510019b0402d7b8cea3a4a4a..a2d79a036c6b62ee21fdec238e579864fbb185cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Button added to switch to dark theme. @rgiedryte +- Add HeadTA Job Offers @toberhuber @dsavvidi ### Changed diff --git a/src/main/java/nl/tudelft/tam/dto/create/JobOfferCreateDTO.java b/src/main/java/nl/tudelft/tam/dto/create/JobOfferCreateDTO.java index 27bc543a5299c9692024d5da8d0d775a9bff7b0b..8f39f497a97993f18b0ed485b59b07370be3a608 100644 --- a/src/main/java/nl/tudelft/tam/dto/create/JobOfferCreateDTO.java +++ b/src/main/java/nl/tudelft/tam/dto/create/JobOfferCreateDTO.java @@ -25,6 +25,7 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import lombok.*; import nl.tudelft.librador.dto.create.Create; +import nl.tudelft.tam.enums.OfferType; import nl.tudelft.tam.model.JobOffer; @Data @@ -67,6 +68,9 @@ public class JobOfferCreateDTO extends Create<JobOffer> { @Builder.Default private Boolean draft = false; + @Builder.Default + private OfferType offerType = OfferType.TA_OR_HEAD_TA; + @Override public Class<JobOffer> clazz() { return JobOffer.class; diff --git a/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java b/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java index 208176bc3b7cb62c5415bf8989b52337ca03acba..e5c92040645cfa8b9c742b03c024918f7c23ed5f 100644 --- a/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java +++ b/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java @@ -24,6 +24,7 @@ import org.springframework.format.annotation.DateTimeFormat; import jakarta.validation.constraints.Positive; import lombok.*; import nl.tudelft.librador.dto.patch.Patch; +import nl.tudelft.tam.enums.OfferType; import nl.tudelft.tam.model.JobOffer; @Data @@ -51,6 +52,8 @@ public class JobOfferPatchDTO extends Patch<JobOffer> { @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate deadline; + private OfferType offerType; + @Override protected void applyOneToOne() { updateNonNull(name, data::setName); @@ -60,6 +63,7 @@ public class JobOfferPatchDTO extends Patch<JobOffer> { updateNonNull(baanCode, data::setBaanCode); data.setMaxHours(maxHours); data.setDeadline(deadline); + data.setOfferType(offerType); } @Override diff --git a/src/main/java/nl/tudelft/tam/dto/view/summary/JobOfferSummaryDTO.java b/src/main/java/nl/tudelft/tam/dto/view/summary/JobOfferSummaryDTO.java index c2664e4bb287c4b393f2efb2b2a0eb3be631dc17..8c5152956e569aa3a9e739111541b0437a32d35c 100644 --- a/src/main/java/nl/tudelft/tam/dto/view/summary/JobOfferSummaryDTO.java +++ b/src/main/java/nl/tudelft/tam/dto/view/summary/JobOfferSummaryDTO.java @@ -27,6 +27,7 @@ import com.vladsch.flexmark.util.data.MutableDataSet; import lombok.*; import lombok.experimental.SuperBuilder; import nl.tudelft.librador.dto.view.View; +import nl.tudelft.tam.enums.OfferType; import nl.tudelft.tam.model.JobOffer; @Data @@ -74,6 +75,8 @@ public class JobOfferSummaryDTO extends View<JobOffer> { private Boolean draft; + private OfferType offerType; + @Override public void postApply() { super.postApply(); diff --git a/src/main/java/nl/tudelft/tam/enums/OfferType.java b/src/main/java/nl/tudelft/tam/enums/OfferType.java new file mode 100644 index 0000000000000000000000000000000000000000..e0b4d461757bb5d1db8c2e9b9f7fe05d2de0ead1 --- /dev/null +++ b/src/main/java/nl/tudelft/tam/enums/OfferType.java @@ -0,0 +1,22 @@ +/* + * TAM + * Copyright (C) 2021 - Delft University of Technology + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package nl.tudelft.tam.enums; + +public enum OfferType { + TA_OR_HEAD_TA, TA, HEAD_TA; // OTHER; +} diff --git a/src/main/java/nl/tudelft/tam/model/JobOffer.java b/src/main/java/nl/tudelft/tam/model/JobOffer.java index 4a5cacb1c30a3fa230ca209292c406778b5b558f..05b16a1d84087ae1efe4592167daf798018e3fce 100644 --- a/src/main/java/nl/tudelft/tam/model/JobOffer.java +++ b/src/main/java/nl/tudelft/tam/model/JobOffer.java @@ -30,6 +30,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import lombok.*; +import nl.tudelft.tam.enums.OfferType; @Data @Entity @@ -123,4 +124,9 @@ public class JobOffer { @NotNull @Builder.Default private Boolean draft = true; + + @NotNull + @Enumerated(EnumType.STRING) + @Builder.Default + private OfferType offerType = OfferType.TA_OR_HEAD_TA; } diff --git a/src/main/java/nl/tudelft/tam/service/ApplicationService.java b/src/main/java/nl/tudelft/tam/service/ApplicationService.java index 52adab89362cf17a54975852c038defd7fb1942f..14907be4e9842b05e9820959756320657a6a4c4a 100644 --- a/src/main/java/nl/tudelft/tam/service/ApplicationService.java +++ b/src/main/java/nl/tudelft/tam/service/ApplicationService.java @@ -48,6 +48,7 @@ import nl.tudelft.tam.dto.view.summary.ApplicationStatusSummaryDTO; import nl.tudelft.tam.dto.view.summary.ApplicationSummaryDTO; import nl.tudelft.tam.dto.view.summary.JobOfferSummaryDTO; import nl.tudelft.tam.dto.view.summary.TrainingTypeSummaryDTO; +import nl.tudelft.tam.enums.OfferType; import nl.tudelft.tam.enums.Status; import nl.tudelft.tam.exception.ApplicationStatusException; import nl.tudelft.tam.model.*; @@ -266,8 +267,7 @@ public class ApplicationService { Application app = applicationRepository.findById(id) .orElseGet(() -> submit(personId, ApplicationCreateDTO.builder().jobOffer(new JobOfferIdDTO(offerId)).build())); - if (app.getStatus().equals(Status.OFFERED) - || app.getStatus().equals(Status.ACCEPTED)) + if (app.getStatus().equals(Status.OFFERED) || app.getStatus().equals(Status.ACCEPTED)) return; app.setHandler(profileService.findByIdOrThrow(handler)); setStatus(app, Status.OFFERED); @@ -367,7 +367,10 @@ public class ApplicationService { "Trying to change application from status:[" + app.getStatus() + "] to accepted."); setStatus(app, Status.ACCEPTED); - roleService.changeToTa(personId, offerId, false); + switch (jobOfferService.getById(offerId).getOfferType()) { + case OfferType.HEAD_TA -> roleService.changeToHeadTa(personId, offerId); + case OfferType.TA, OfferType.TA_OR_HEAD_TA -> roleService.changeToTa(personId, offerId, false); + } } /** diff --git a/src/main/java/nl/tudelft/tam/service/JobOfferService.java b/src/main/java/nl/tudelft/tam/service/JobOfferService.java index f67296287dcf75c9855f1953b6adcdee19cdc3a9..c3008b246817ecb2b19c20389a09d583d02b04cb 100644 --- a/src/main/java/nl/tudelft/tam/service/JobOfferService.java +++ b/src/main/java/nl/tudelft/tam/service/JobOfferService.java @@ -53,6 +53,7 @@ import nl.tudelft.tam.model.Application; import nl.tudelft.tam.model.JobOffer; import nl.tudelft.tam.model.TrainingType; import nl.tudelft.tam.repository.JobOfferRepository; +import nl.tudelft.tam.security.AuthorisationService; @Service public class JobOfferService { @@ -121,6 +122,8 @@ public class JobOfferService { @Value("${tam.filesys.imports-dir}") private String importDirectory; + @Autowired + private AuthorisationService authorisationService; // endregion diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 129156f53d4eae8aba7ede3a17d13d76034c53a0..cd0afe2b68525bd71085a448ebed8c017ab0d249 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -171,6 +171,11 @@ jobOffer.status = Status jobOffer.deadline = Deadline For Applying jobOffer.deadline.none = No Deadline jobOffer.deadline.closed = Closed +jobOffer.type = Offer Type +jobOffer.type.ta = TA +jobOffer.type.head_ta = Head TA +jobOffer.type.ta_or_head_ta = TA/Head TA +jobOffer.type.other = Other jobOffer.date.enter = Enter a deadline... jobOffer.name.enter = Enter a name (e.g.: TA, Mentor, ...) jobOffer.username.enter = Enter the exact username... diff --git a/src/main/resources/migrations.yaml b/src/main/resources/migrations.yaml index ee301727204387e20815234a278c8e526351427a..13512a3b1c57c95e73e67a4d1a880c4ff8bf22d3 100644 --- a/src/main/resources/migrations.yaml +++ b/src/main/resources/migrations.yaml @@ -937,4 +937,17 @@ databaseChangeLog: newColumnName: draft oldColumnName: hidden columnDataType: bit + tableName: job_offer +- changeSet: + id: 1740585090326-1 + author: dsav (generated) + changes: + - addColumn: + columns: + - column: + constraints: + nullable: false + name: offer_type + type: ENUM('HEAD_TA', 'TA', 'TA_OR_HEAD_TA') + defaultValue: 'TA_OR_HEAD_TA' tableName: job_offer \ No newline at end of file diff --git a/src/main/resources/templates/application/view_many.html b/src/main/resources/templates/application/view_many.html index 1187a999e1f89917b827a667154b7b6acb97694b..8ce631941cf6c3c973c4212cac6c5442b3beb01f 100644 --- a/src/main/resources/templates/application/view_many.html +++ b/src/main/resources/templates/application/view_many.html @@ -92,6 +92,7 @@ <th th:text="#{course}"></th> <th th:text="#{edition}"></th> <th th:text="#{jobOffer.description}"></th> + <th th:text="#{jobOffer.type}"></th> <th th:text="#{jobOffer.status}"></th> <th></th> </tr> @@ -103,6 +104,8 @@ th:text="|${app.jobOffer.edition.course.name} (${app.jobOffer.edition.course.code})|"></td> <td th:text="${app.jobOffer.edition.name}"></td> <td th:text="${app.jobOffer.name}"></td> + <td + th:text="#{|jobOffer.type.${#strings.toLowerCase(app.jobOffer.offerType)}|}"></td> <td> <th:block th:switch="${status}"> <span th:case="OFFERED" class="fa-solid fa-question"></span> diff --git a/src/main/resources/templates/job_offer/apply.html b/src/main/resources/templates/job_offer/apply.html index a5d76d06e6bc1e10d50d4561ac24fac0a387c61c..6bb62f36fe809996a637382e9b86a15523b2045f 100644 --- a/src/main/resources/templates/job_offer/apply.html +++ b/src/main/resources/templates/job_offer/apply.html @@ -35,6 +35,9 @@ class="font-500" th:text="|${offer.name} - ${edition.course.name} (${edition.course.code})|"></h1> <h4 class="font-200" th:text="${edition.program.name}"></h4> + <h4 + class="font-200" + th:text="'Offer Type: '+#{|jobOffer.type.${#strings.toLowerCase(offer.offerType.name())}|}"></h4> </div> <input type="hidden" name="jobOffer.id" th:value="${offer.id}" /> <input type="hidden" name="page" value="job-offers" /> diff --git a/src/main/resources/templates/job_offer/create.html b/src/main/resources/templates/job_offer/create.html index b95eb446f05059bc85c36df3a8a5031811924477..aee32c94c3406ac5b0df26638d4642fb3a4a0c17 100644 --- a/src/main/resources/templates/job_offer/create.html +++ b/src/main/resources/templates/job_offer/create.html @@ -167,6 +167,14 @@ th:value="${offer?.hiringMessage}" hidden /> + <label for="offerType" th:text="#{jobOffer.type}"></label> + <select class="textfield" id="offerType" th:name="offerType"> + <option + th:each="type : ${T(nl.tudelft.tam.enums.OfferType).values()}" + th:value="${type}" + th:text="#{|jobOffer.type.${#strings.toLowerCase(type.name())}|}"></option> + </select> + <div class="checkbox"> <input type="checkbox" diff --git a/src/main/resources/templates/job_offer/edit.html b/src/main/resources/templates/job_offer/edit.html index e8eeee11e55866c67ec1b5ae87d531ee3b6b49ce..b8c83d2513788a3c0aab3b597419b132a84fee8e 100644 --- a/src/main/resources/templates/job_offer/edit.html +++ b/src/main/resources/templates/job_offer/edit.html @@ -103,6 +103,15 @@ th:value="${offer.contractEndDate}" required /> + <label for="offerType" th:text="#{jobOffer.type}"></label> + <select class="textfield" id="offerType" th:name="offerType"> + <option + th:each="type : ${T(nl.tudelft.tam.enums.OfferType).values()}" + th:selected="${type.name() == offer.offerType.name()}" + th:value="${type}" + th:text="#{|jobOffer.type.${#strings.toLowerCase(type.name())}|}"></option> + </select> + <div class="checkbox"> <input type="checkbox" diff --git a/src/main/resources/templates/job_offer/view_many.html b/src/main/resources/templates/job_offer/view_many.html index 2e14a08cee3001ad047f29ec1930ac6ae4fc2580..3cbb7e8fef91cca330b016fd63ee3f250bfcfdd4 100644 --- a/src/main/resources/templates/job_offer/view_many.html +++ b/src/main/resources/templates/job_offer/view_many.html @@ -151,7 +151,8 @@ data-type="error" th:text="#{application.status.rejected}"></span> </td> - <td th:text="${offer.name}"></td> + <td + th:text="'(' + #{|jobOffer.type.${#strings.toLowerCase(offer.offerType.name())}|} + ') ' + ${offer.name}"></td> <td> <div class="flex gap-3 justify-end wrap | md:gap-2"> <button diff --git a/src/main/resources/templates/job_offer/view_one.html b/src/main/resources/templates/job_offer/view_one.html index 0f55911eea2f8ef009322c346bd72dfc913256fc..3f025af6ded2aa28c7e49c7e0e8c63f6f918d53e 100644 --- a/src/main/resources/templates/job_offer/view_one.html +++ b/src/main/resources/templates/job_offer/view_one.html @@ -145,6 +145,11 @@ th:if="${offer.deadline != null && !deadlineClosed}" th:text="${#temporals.format(offer.deadline, 'dd / MM / yyyy')}"></span> </li> + <li class="flex space-between underlined pbl-1 pil-2"> + <span th:text="#{jobOffer.type}"></span> + <span + th:text="#{|jobOffer.type.${#strings.toLowerCase(offer.offerType.name())}|}"></span> + </li> </ul> <ul class="list pil-2" role="list"> <li class="flex space-between underlined pbl-1 pil-2"> @@ -747,7 +752,7 @@ <div th:replace="~{job_offer/confirm_offer_app :: overlay}"></div> </div> <div - th:unless="${status != 'ACCEPTED' || headTA}" + th:unless="${status != 'ACCEPTED' || headTA || offer.offerType == 'TA_OR_HEAD_TA'}" data-scroll-to="true"> <button type="submit" @@ -758,7 +763,9 @@ th:data-dialog="|confirm-promote-app-${app.personId}-overlay|"></button> <div th:replace="~{job_offer/confirm_promote_app :: overlay}"></div> </div> - <div th:unless="${!headTA}" data-scroll-to="true"> + <div + th:unless="${!headTA || offer.offerType == 'TA_OR_HEAD_TA'}" + data-scroll-to="true"> <button class="button p-min" data-type="error" diff --git a/src/test/java/nl/tudelft/tam/controller/JobOfferControllerTest.java b/src/test/java/nl/tudelft/tam/controller/JobOfferControllerTest.java index 4438577969fe471c2ef810172459a5d6b53bfe68..34abd8432e1621b25a06f98bab989dcd4d378d17 100644 --- a/src/test/java/nl/tudelft/tam/controller/JobOfferControllerTest.java +++ b/src/test/java/nl/tudelft/tam/controller/JobOfferControllerTest.java @@ -53,6 +53,7 @@ import nl.tudelft.tam.dto.view.summary.ApplicationStatusSummaryDTO; import nl.tudelft.tam.dto.view.summary.ApplicationSummaryDTO; import nl.tudelft.tam.dto.view.summary.ExtraWorkSummaryDTO; import nl.tudelft.tam.dto.view.summary.JobOfferSummaryDTO; +import nl.tudelft.tam.enums.OfferType; import nl.tudelft.tam.enums.Status; import nl.tudelft.tam.model.CoordinatorDefault; import nl.tudelft.tam.model.JobOffer; @@ -137,10 +138,12 @@ class JobOfferControllerTest { offer1 = JobOfferDetailsDTO.builder().name("offer-1").id(JOFFER_ID_1).editionId(EDITION_ID) .edition(edition) .draft(false) + .offerType(OfferType.TA_OR_HEAD_TA) .deadline(LocalDate.now().plusDays(1)).build(); offer2 = JobOfferDetailsDTO.builder().name("offer-2").id(JOFFER_ID_2).editionId(EDITION_ID) .edition(edition) .draft(false) + .offerType(OfferType.TA_OR_HEAD_TA) .deadline(LocalDate.now().plusDays(2)).build(); offer1Job = JobOffer.builder().name("offer-1").id(JOFFER_ID_1).editionId(EDITION_ID) .deadline(LocalDate.now().plusDays(1)).draft(false).build(); diff --git a/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java b/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java index f2e579322357ca3d1fb91696e257e063865a66b3..0c0ece8663081c86e84d391173be1d81d9f6ce16 100644 --- a/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java +++ b/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java @@ -48,6 +48,7 @@ import nl.tudelft.tam.dto.view.details.ApplicationDetailsPersonDTO; import nl.tudelft.tam.dto.view.details.JobOfferDetailsDTO; import nl.tudelft.tam.dto.view.summary.ApplicationSummaryDTO; import nl.tudelft.tam.enums.NotificationFrequency; +import nl.tudelft.tam.enums.OfferType; import nl.tudelft.tam.enums.PayScale; import nl.tudelft.tam.enums.Status; import nl.tudelft.tam.model.*; @@ -437,6 +438,37 @@ class ApplicationServiceMockTest { @Test void accept() { when(repository.findByIdOrThrow(app1b.getId())).thenReturn(app1b); + when(jobOfferService.getById(app1b.getJobOffer().getId())).thenReturn(JobOfferDetailsDTO.builder().offerType(OfferType.TA_OR_HEAD_TA).build()); + assertThat(app1b.getStatus()).isEqualTo(Status.OFFERED); + + doNothing().when(roleService).changeToTa(anyLong(), anyLong(), anyBoolean()); + + service.accept(PERSON_ID_2, JOFFER_ID_1); + + assertThat(app1b.getStatus()).isEqualTo(Status.ACCEPTED); + + verify(roleService).changeToTa(PERSON_ID_2, JOFFER_ID_1, false); + } + + @Test + void accept_headTAOffer() { + when(repository.findByIdOrThrow(app1b.getId())).thenReturn(app1b); + when(jobOfferService.getById(app1b.getJobOffer().getId())).thenReturn(JobOfferDetailsDTO.builder().offerType(OfferType.HEAD_TA).build()); + assertThat(app1b.getStatus()).isEqualTo(Status.OFFERED); + + doNothing().when(roleService).changeToTa(anyLong(), anyLong(), anyBoolean()); + + service.accept(PERSON_ID_2, JOFFER_ID_1); + + assertThat(app1b.getStatus()).isEqualTo(Status.ACCEPTED); + + verify(roleService).changeToHeadTa(PERSON_ID_2, JOFFER_ID_1); + } + + @Test + void accept_TAOffer() { + when(repository.findByIdOrThrow(app1b.getId())).thenReturn(app1b); + when(jobOfferService.getById(app1b.getJobOffer().getId())).thenReturn(JobOfferDetailsDTO.builder().offerType(OfferType.TA).build()); assertThat(app1b.getStatus()).isEqualTo(Status.OFFERED); doNothing().when(roleService).changeToTa(anyLong(), anyLong(), anyBoolean()); diff --git a/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java b/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java index c89b26fcb183d0633898ea9dc2209f4b5ef9e8e4..a7dba6ed3abf7f6a6764dec5376dfa86b031fd10 100644 --- a/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java +++ b/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java @@ -44,8 +44,10 @@ import nl.tudelft.labracore.api.dto.*; import nl.tudelft.librador.dto.DTOConverter; import nl.tudelft.tam.dto.create.JobOfferCreateDTO; import nl.tudelft.tam.dto.patch.JobOfferPatchDTO; +import nl.tudelft.tam.dto.view.details.ApplicationDetailsPersonDTO; import nl.tudelft.tam.dto.view.details.JobOfferDetailsDTO; import nl.tudelft.tam.dto.view.summary.JobOfferSummaryDTO; +import nl.tudelft.tam.enums.OfferType; import nl.tudelft.tam.enums.Status; import nl.tudelft.tam.exception.WrongDataCallException; import nl.tudelft.tam.io.ImportHandler; @@ -101,10 +103,21 @@ class JobOfferServiceTest { @Autowired private DTOConverter dtoMapper; + final long JOFFER_ID_1 = 1001; + final long JOFFER_ID_2 = 1002; + final long PERSON_ID_1 = 5001; + final long PERSON_ID_2 = 5002; + + Application app1a, app1b; + + private ApplicationDetailsPersonDTO ap1, ap2; + @Autowired + private AuthorisationService authorisationService; + @BeforeEach void setUp() { jobOffer1 = JobOffer.builder() - .id(4889L) + .id(JOFFER_ID_1) .editionId(87956L) .name("Test-Job-open") .contractName("idkk") @@ -114,6 +127,7 @@ class JobOfferServiceTest { .requireApplicationText(false) .deadline(LocalDate.now().plusDays(7)) .editionId(1L) + .offerType(OfferType.TA) .maxHours(100) .createdDate(LocalDate.of(2020, 4, 5)) .build(); @@ -121,10 +135,23 @@ class JobOfferServiceTest { jobOffer2 = JobOffer.builder() .id(7894165L) .editionId(8946513L) + .offerType(OfferType.HEAD_TA) .name("Test-Job-closed") .deadline(LocalDate.now().minusDays(7)) .maxHours(100) .build(); + + app1a = Application.builder().id(new Application.AppId(PERSON_ID_1, JOFFER_ID_1)).jobOffer(jobOffer1) + .status(Status.ACCEPTED).build(); + app1b = Application.builder().id(new Application.AppId(PERSON_ID_2, JOFFER_ID_1)).jobOffer(jobOffer1) + .status(Status.OFFERED).build(); + ap1 = mapper.map(app1a, ApplicationDetailsPersonDTO.class); + ap1.setPerson(new PersonSummaryDTO().id(PERSON_ID_1).username("user1").displayName("name1") + .externalId("exid1").number(4201).email("1@poo")); + ap2 = mapper.map(app1b, ApplicationDetailsPersonDTO.class); + ap2.setPerson(new PersonSummaryDTO().id(PERSON_ID_2).username("user2").displayName("name2") + .externalId("exid2").number(4202).email("2@poo")); + jobOffer1.setApplications(List.of(app1a, app1b)); } @Test