From bca3e8f75ac95a9911b06f7d254367f50588c4ee Mon Sep 17 00:00:00 2001 From: Laura Ketola Date: Thu, 6 Jun 2024 15:05:15 +0300 Subject: [PATCH] VKT(Backend): Provide unused free enrollment slots to frontend --- .../PublicEnrollmentInitialisationDTO.java | 3 +- .../api/dto/PublicFreeEnrollmentDetails.java | 8 ++++ .../java/fi/oph/vkt/model/Enrollment.java | 2 +- .../java/fi/oph/vkt/model/FreeEnrollment.java | 5 +++ .../repository/FreeEnrollmentRepository.java | 21 ++++++++++- .../vkt/service/PublicEnrollmentService.java | 37 +++++++++++++++++-- .../service/PublicEnrollmentServiceTest.java | 7 +++- 7 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicFreeEnrollmentDetails.java diff --git a/backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicEnrollmentInitialisationDTO.java b/backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicEnrollmentInitialisationDTO.java index 27d935b7a..7deffe47c 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicEnrollmentInitialisationDTO.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicEnrollmentInitialisationDTO.java @@ -8,5 +8,6 @@ public record PublicEnrollmentInitialisationDTO( @NonNull PublicExamEventDTO examEvent, @NonNull PublicPersonDTO person, PublicReservationDTO reservation, - PublicEnrollmentDTO enrollment + PublicEnrollmentDTO enrollment, + PublicFreeEnrollmentDetails freeEnrollmentDetails ) {} diff --git a/backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicFreeEnrollmentDetails.java b/backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicFreeEnrollmentDetails.java new file mode 100644 index 000000000..add8c605c --- /dev/null +++ b/backend/vkt/src/main/java/fi/oph/vkt/api/dto/PublicFreeEnrollmentDetails.java @@ -0,0 +1,8 @@ +package fi.oph.vkt.api.dto; + +import lombok.NonNull; + +public record PublicFreeEnrollmentDetails( + @NonNull int freeTextualSkillExamsLeft, + @NonNull int freeOralSkillExamsLeft +) {} diff --git a/backend/vkt/src/main/java/fi/oph/vkt/model/Enrollment.java b/backend/vkt/src/main/java/fi/oph/vkt/model/Enrollment.java index e7c565a34..9bf710629 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/model/Enrollment.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/model/Enrollment.java @@ -99,7 +99,7 @@ public class Enrollment extends BaseEntity { @OneToMany(mappedBy = "enrollment") private List payments = new ArrayList<>(); - @ManyToOne(fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "free_enrollment", referencedColumnName = "free_enrollment_id") private FreeEnrollment freeEnrollment; diff --git a/backend/vkt/src/main/java/fi/oph/vkt/model/FreeEnrollment.java b/backend/vkt/src/main/java/fi/oph/vkt/model/FreeEnrollment.java index e6c19c2da..9cb2fe2a2 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/model/FreeEnrollment.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/model/FreeEnrollment.java @@ -11,6 +11,8 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.Getter; import lombok.Setter; @@ -39,4 +41,7 @@ public class FreeEnrollment extends BaseEntity { @Column(name = "comment") String comment; + + @OneToOne(mappedBy = "freeEnrollment", fetch = FetchType.LAZY, optional = false) + Enrollment enrollment; } diff --git a/backend/vkt/src/main/java/fi/oph/vkt/repository/FreeEnrollmentRepository.java b/backend/vkt/src/main/java/fi/oph/vkt/repository/FreeEnrollmentRepository.java index 9f964f748..d1c516f5b 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/repository/FreeEnrollmentRepository.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/repository/FreeEnrollmentRepository.java @@ -1,7 +1,26 @@ package fi.oph.vkt.repository; import fi.oph.vkt.model.FreeEnrollment; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @Repository -public interface FreeEnrollmentRepository extends BaseRepository {} +public interface FreeEnrollmentRepository extends BaseRepository { + @Query( + "SELECT count(f)" + + " FROM FreeEnrollment f" + + " JOIN f.enrollment e" + + " WHERE f.person.id = ?1" + + " AND e.textualSkill = true" + ) + int findUsedTextualSkillFreeEnrollmentsForPerson(final long personId); + + @Query( + "SELECT count(f)" + + " FROM FreeEnrollment f" + + " JOIN f.enrollment e" + + " WHERE f.person.id = ?1" + + " AND e.oralSkill = true" + ) + int findUsedOralSkillFreeEnrollmentsForPerson(final long personId); +} diff --git a/backend/vkt/src/main/java/fi/oph/vkt/service/PublicEnrollmentService.java b/backend/vkt/src/main/java/fi/oph/vkt/service/PublicEnrollmentService.java index 8ab97be54..06a0e06c0 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/service/PublicEnrollmentService.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/service/PublicEnrollmentService.java @@ -4,10 +4,12 @@ import fi.oph.vkt.api.dto.PublicEnrollmentDTO; import fi.oph.vkt.api.dto.PublicEnrollmentInitialisationDTO; import fi.oph.vkt.api.dto.PublicExamEventDTO; +import fi.oph.vkt.api.dto.PublicFreeEnrollmentDetails; import fi.oph.vkt.api.dto.PublicPersonDTO; import fi.oph.vkt.api.dto.PublicReservationDTO; import fi.oph.vkt.model.Enrollment; import fi.oph.vkt.model.ExamEvent; +import fi.oph.vkt.model.FeatureFlag; import fi.oph.vkt.model.FreeEnrollment; import fi.oph.vkt.model.Person; import fi.oph.vkt.model.Reservation; @@ -22,6 +24,7 @@ import fi.oph.vkt.util.exception.APIException; import fi.oph.vkt.util.exception.APIExceptionType; import fi.oph.vkt.util.exception.NotFoundException; +import jakarta.annotation.Resource; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Optional; @@ -40,7 +43,7 @@ public class PublicEnrollmentService extends AbstractEnrollmentService { private final PublicReservationService publicReservationService; private final ReservationRepository reservationRepository; private final FreeEnrollmentRepository freeEnrollmentRepository; - private final Environment environment; + private final FeatureFlagService featureFlagService; @Transactional public PublicEnrollmentInitialisationDTO initialiseEnrollment(final long examEventId, final Person person) { @@ -70,6 +73,7 @@ public PublicEnrollmentInitialisationDTO initialiseEnrollment(final long examEve person, openings, Optional.of(reservationDTO), + Optional.empty(), Optional.empty() ); } @@ -95,12 +99,28 @@ public PublicEnrollmentInitialisationDTO getEnrollmentInitialisationDTO(final lo final Optional optionalEnrollmentDTO = findEnrollment(examEvent, person, enrollmentRepository) .map(this::createEnrollmentDTO); + Optional optionalPublicFreeEnrollmentDetails; + if (featureFlagService.isEnabled(FeatureFlag.FREE_ENROLLMENT_FOR_HIGHEST_LEVEL_ALLOWED)) { + final int freeTextualSkillExamsLeft = + 3 - freeEnrollmentRepository.findUsedTextualSkillFreeEnrollmentsForPerson(person.getId()); + final int freeOralSkillExamsLeft = + 3 - freeEnrollmentRepository.findUsedOralSkillFreeEnrollmentsForPerson(person.getId()); + final PublicFreeEnrollmentDetails freeEnrollmentDetails = new PublicFreeEnrollmentDetails( + freeTextualSkillExamsLeft, + freeOralSkillExamsLeft + ); + optionalPublicFreeEnrollmentDetails = Optional.of(freeEnrollmentDetails); + } else { + optionalPublicFreeEnrollmentDetails = Optional.empty(); + } + return createEnrollmentInitialisationDTO( examEvent, person, openings, optionalReservationDTO, - optionalEnrollmentDTO + optionalEnrollmentDTO, + optionalPublicFreeEnrollmentDetails ); } @@ -133,7 +153,8 @@ private PublicEnrollmentInitialisationDTO createEnrollmentInitialisationDTO( final Person person, final long openings, final Optional optionalReservationDTO, - final Optional optionalEnrollmentDTO + final Optional optionalEnrollmentDTO, + final Optional optionalPublicFreeEnrollmentDetails ) { final PublicExamEventDTO examEventDTO = PublicExamEventDTO .builder() @@ -153,6 +174,7 @@ private PublicEnrollmentInitialisationDTO createEnrollmentInitialisationDTO( .person(personDTO) .reservation(optionalReservationDTO.orElse(null)) .enrollment(optionalEnrollmentDTO.orElse(null)) + .freeEnrollmentDetails(optionalPublicFreeEnrollmentDetails.orElse(null)) .build(); } @@ -175,7 +197,14 @@ public PublicEnrollmentInitialisationDTO initialiseEnrollmentToQueue(final long throw new APIException(APIExceptionType.INITIALISE_ENROLLMENT_DUPLICATE_PERSON); } - return createEnrollmentInitialisationDTO(examEvent, person, openings, Optional.empty(), Optional.empty()); + return createEnrollmentInitialisationDTO( + examEvent, + person, + openings, + Optional.empty(), + Optional.empty(), + Optional.empty() + ); } @Transactional diff --git a/backend/vkt/src/test/java/fi/oph/vkt/service/PublicEnrollmentServiceTest.java b/backend/vkt/src/test/java/fi/oph/vkt/service/PublicEnrollmentServiceTest.java index 56e315d24..8bde99d31 100644 --- a/backend/vkt/src/test/java/fi/oph/vkt/service/PublicEnrollmentServiceTest.java +++ b/backend/vkt/src/test/java/fi/oph/vkt/service/PublicEnrollmentServiceTest.java @@ -21,6 +21,7 @@ import fi.oph.vkt.api.dto.PublicPersonDTO; import fi.oph.vkt.model.Enrollment; import fi.oph.vkt.model.ExamEvent; +import fi.oph.vkt.model.FeatureFlag; import fi.oph.vkt.model.Person; import fi.oph.vkt.model.Reservation; import fi.oph.vkt.model.type.EnrollmentStatus; @@ -72,6 +73,7 @@ public class PublicEnrollmentServiceTest { private TestEntityManager entityManager; private PublicEnrollmentService publicEnrollmentService; + private FeatureFlagService featureFlagService; @BeforeEach public void setup() throws IOException, InterruptedException { @@ -80,6 +82,9 @@ public void setup() throws IOException, InterruptedException { final Environment environment = mock(Environment.class); when(environment.getRequiredProperty("app.reservation.duration")).thenReturn(ONE_MINUTE.toString()); + final FeatureFlagService featureFlagService = mock(FeatureFlagService.class); + when(featureFlagService.isEnabled(any(FeatureFlag.class))).thenReturn(true); + final PublicReservationService publicReservationService = new PublicReservationService( reservationRepository, environment @@ -92,7 +97,7 @@ public void setup() throws IOException, InterruptedException { publicReservationService, reservationRepository, freeEnrollmentRepository, - environment + featureFlagService ); }