From 7748a8d726c0d05a0a2e06c58dad71c111a97a05 Mon Sep 17 00:00:00 2001 From: Laura Ketola Date: Mon, 3 Jun 2024 20:00:48 +0300 Subject: [PATCH] VKT(Backend): WIP support for free enrollment in API --- .../java/fi/oph/vkt/api/PublicController.java | 10 +++ .../repository/FreeEnrollmentRepository.java | 7 ++ .../vkt/service/PublicEnrollmentService.java | 89 ++++++++++++++++++- .../service/PublicEnrollmentServiceTest.java | 8 +- 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 backend/vkt/src/main/java/fi/oph/vkt/repository/FreeEnrollmentRepository.java diff --git a/backend/vkt/src/main/java/fi/oph/vkt/api/PublicController.java b/backend/vkt/src/main/java/fi/oph/vkt/api/PublicController.java index 64078d5ba..1d0b5795a 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/api/PublicController.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/api/PublicController.java @@ -98,6 +98,11 @@ public PublicEnrollmentDTO createEnrollment( ) { final Person person = publicAuthService.getPersonFromSession(session); + // TODO this might need separate endpoint? + if (dto.isFree() && featureFlagService.isEnabled(FeatureFlag.FREE_ENROLLMENT_FOR_HIGHEST_LEVEL_ALLOWED)) { + return publicEnrollmentService.createFreeEnrollment(dto, reservationId, person); + } + return publicEnrollmentService.createEnrollment(dto, reservationId, person); } @@ -110,6 +115,11 @@ public PublicEnrollmentDTO updateEnrollment( ) { final Person person = publicAuthService.getPersonFromSession(session); + // TODO this might need separate endpoint? + if (dto.isFree() && featureFlagService.isEnabled(FeatureFlag.FREE_ENROLLMENT_FOR_HIGHEST_LEVEL_ALLOWED)) { + return publicEnrollmentService.updateEnrollmentForFree(dto, examEventId, person); + } + return publicEnrollmentService.updateEnrollmentForPayment(dto, examEventId, person); } 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 new file mode 100644 index 000000000..9f964f748 --- /dev/null +++ b/backend/vkt/src/main/java/fi/oph/vkt/repository/FreeEnrollmentRepository.java @@ -0,0 +1,7 @@ +package fi.oph.vkt.repository; + +import fi.oph.vkt.model.FreeEnrollment; +import org.springframework.stereotype.Repository; + +@Repository +public interface FreeEnrollmentRepository extends BaseRepository {} 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 1809796d5..8ab97be54 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 @@ -8,11 +8,14 @@ import fi.oph.vkt.api.dto.PublicReservationDTO; import fi.oph.vkt.model.Enrollment; import fi.oph.vkt.model.ExamEvent; +import fi.oph.vkt.model.FreeEnrollment; import fi.oph.vkt.model.Person; import fi.oph.vkt.model.Reservation; import fi.oph.vkt.model.type.EnrollmentStatus; +import fi.oph.vkt.model.type.FreeEnrollmentSource; import fi.oph.vkt.repository.EnrollmentRepository; import fi.oph.vkt.repository.ExamEventRepository; +import fi.oph.vkt.repository.FreeEnrollmentRepository; import fi.oph.vkt.repository.ReservationRepository; import fi.oph.vkt.util.ExamEventUtil; import fi.oph.vkt.util.PersonUtil; @@ -23,6 +26,7 @@ import java.time.LocalDateTime; import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -35,6 +39,8 @@ public class PublicEnrollmentService extends AbstractEnrollmentService { private final PublicEnrollmentEmailService publicEnrollmentEmailService; private final PublicReservationService publicReservationService; private final ReservationRepository reservationRepository; + private final FreeEnrollmentRepository freeEnrollmentRepository; + private final Environment environment; @Transactional public PublicEnrollmentInitialisationDTO initialiseEnrollment(final long examEventId, final Person person) { @@ -189,23 +195,65 @@ public PublicEnrollmentDTO createEnrollment( dto, examEvent, person, - EnrollmentStatus.EXPECTING_PAYMENT_UNFINISHED_ENROLLMENT + EnrollmentStatus.EXPECTING_PAYMENT_UNFINISHED_ENROLLMENT, + null ); reservationRepository.deleteById(reservationId); return createEnrollmentDTO(enrollment); } + @Transactional + public PublicEnrollmentDTO createFreeEnrollment( + final PublicEnrollmentCreateDTO dto, + final long reservationId, + final Person person + ) { + final Reservation reservation = reservationRepository.getReferenceById(reservationId); + final ExamEvent examEvent = reservation.getExamEvent(); + + if (person.getId() != reservation.getPerson().getId()) { + throw new APIException(APIExceptionType.RESERVATION_PERSON_SESSION_MISMATCH); + } + + // TODO validate that enrollment is actually free + // Either: check Koski/user-provided certificate + // Or: seperate API-endpoint for creating FreeEnrollment entity, that is checked here + + // Validate that there are unused free enrollments + + FreeEnrollment freeEnrollment = new FreeEnrollment(); + freeEnrollment.setApproved(false); + freeEnrollment.setPerson(person); + freeEnrollment.setSource(FreeEnrollmentSource.KOSKI_COMPLETED_DEGREE); + freeEnrollmentRepository.saveAndFlush(freeEnrollment); + + final Enrollment enrollment = createOrUpdateExistingEnrollment( + dto, + examEvent, + person, + EnrollmentStatus.AWAITING_APPROVAL, + freeEnrollment + ); + reservationRepository.deleteById(reservationId); + + // TODO send confirmation email + + return createEnrollmentDTO(enrollment); + } + private Enrollment createOrUpdateExistingEnrollment( final PublicEnrollmentCreateDTO dto, final ExamEvent examEvent, final Person person, - final EnrollmentStatus enrollmentStatus + final EnrollmentStatus enrollmentStatus, + final FreeEnrollment freeEnrollment ) { final Enrollment enrollment = findEnrollment(examEvent, person, enrollmentRepository).orElse(new Enrollment()); enrollment.setExamEvent(examEvent); enrollment.setPerson(person); enrollment.setStatus(enrollmentStatus); + enrollment.setFreeEnrollment(freeEnrollment != null ? freeEnrollment : enrollment.getFreeEnrollment()); copyDtoFieldsToEnrollment(enrollment, dto); if (dto.digitalCertificateConsent()) { @@ -229,7 +277,13 @@ public PublicEnrollmentDTO createEnrollmentToQueue( final Person person ) { final ExamEvent examEvent = examEventRepository.getReferenceById(examEventId); - final Enrollment enrollment = createOrUpdateExistingEnrollment(dto, examEvent, person, EnrollmentStatus.QUEUED); + final Enrollment enrollment = createOrUpdateExistingEnrollment( + dto, + examEvent, + person, + EnrollmentStatus.QUEUED, + null + ); publicEnrollmentEmailService.sendEnrollmentToQueueConfirmationEmail(enrollment, person); @@ -267,9 +321,36 @@ public PublicEnrollmentDTO updateEnrollmentForPayment( dto, examEvent, person, - EnrollmentStatus.EXPECTING_PAYMENT_UNFINISHED_ENROLLMENT + EnrollmentStatus.EXPECTING_PAYMENT_UNFINISHED_ENROLLMENT, + null ); return createEnrollmentDTO(enrollment); } + + @Transactional + public PublicEnrollmentDTO updateEnrollmentForFree( + final PublicEnrollmentCreateDTO dto, + final long examEventId, + final Person person + ) { + final ExamEvent examEvent = examEventRepository.getReferenceById(examEventId); + + // TODO check that validations from creation are still valid? + + final Enrollment enrollment = createOrUpdateExistingEnrollment( + dto, + examEvent, + person, + EnrollmentStatus.AWAITING_APPROVAL, + null + ); + + // TODO This needs proper handling + if (enrollment.getFreeEnrollment() == null) { + throw new APIException(APIExceptionType.PAYMENT_VALIDATION_FAIL); + } + + return createEnrollmentDTO(enrollment); + } } 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 62813b948..56e315d24 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 @@ -26,6 +26,7 @@ import fi.oph.vkt.model.type.EnrollmentStatus; import fi.oph.vkt.repository.EnrollmentRepository; import fi.oph.vkt.repository.ExamEventRepository; +import fi.oph.vkt.repository.FreeEnrollmentRepository; import fi.oph.vkt.repository.ReservationRepository; import fi.oph.vkt.util.exception.APIException; import fi.oph.vkt.util.exception.APIExceptionType; @@ -64,6 +65,9 @@ public class PublicEnrollmentServiceTest { @Resource private ReservationRepository reservationRepository; + @Resource + private FreeEnrollmentRepository freeEnrollmentRepository; + @Resource private TestEntityManager entityManager; @@ -86,7 +90,9 @@ public void setup() throws IOException, InterruptedException { examEventRepository, publicEnrollmentEmailServiceMock, publicReservationService, - reservationRepository + reservationRepository, + freeEnrollmentRepository, + environment ); }