diff --git a/common/pom.xml b/common/pom.xml
index 54c68693..d881db63 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -5,7 +5,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
4.0.0
diff --git a/interfaces/pom.xml b/interfaces/pom.xml
index ecd30f0e..7509e140 100644
--- a/interfaces/pom.xml
+++ b/interfaces/pom.xml
@@ -5,7 +5,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
4.0.0
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/AbstractConnectorMagdaClient.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/AbstractConnectorMagdaClient.java
new file mode 100644
index 00000000..3fdb4f59
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/AbstractConnectorMagdaClient.java
@@ -0,0 +1,36 @@
+package be.vlaanderen.vip.magda.client;
+
+import be.vlaanderen.vip.magda.exception.ServerException;
+
+import java.util.UUID;
+
+public abstract class AbstractConnectorMagdaClient implements MagdaClient {
+
+ private final MagdaConnector connector;
+
+ protected AbstractConnectorMagdaClient(
+ MagdaConnector connector) {
+ this.connector = connector;
+ }
+
+ @Override
+ public MagdaResponseWrapper send(MagdaRequest request) throws MagdaClientException {
+ return send(request, UUID.randomUUID());
+ }
+
+ @Override
+ public MagdaResponseWrapper send(MagdaRequest request, UUID requestId) throws MagdaClientException {
+ try {
+ var response = connector.send(request, requestId);
+
+ validateMagdaResponse(response, request);
+
+ return new MagdaResponseWrapper(response);
+ }
+ catch (ServerException e) {
+ throw new MagdaClientException("Error occurred while sending magda request", e);
+ }
+ }
+
+ protected abstract void validateMagdaResponse(MagdaResponse response, MagdaRequest request) throws MagdaClientException;
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/ConnectorMagdaClient.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/ConnectorMagdaClient.java
index 8a8442cc..13460c90 100644
--- a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/ConnectorMagdaClient.java
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/ConnectorMagdaClient.java
@@ -1,41 +1,23 @@
package be.vlaanderen.vip.magda.client;
-import be.vlaanderen.vip.magda.exception.ServerException;
import be.vlaanderen.vip.magda.exception.UitzonderingenSectionInResponseException;
import be.vlaanderen.vip.magda.legallogging.model.UitzonderingEntry;
import be.vlaanderen.vip.magda.legallogging.model.UitzonderingType;
import java.util.List;
-import java.util.UUID;
-public class ConnectorMagdaClient implements MagdaClient {
- private MagdaConnector connector;
-
- public ConnectorMagdaClient(
- MagdaConnector connector) {
- this.connector = connector;
- }
+/**
+ * A MagdaConnector-based client which handles both level 2 and level 3 uitzondingen in the response.
+ * Level 3 uitzondingen are handled in an opinionated manner whereby an exception is thrown if at least one of them is of type "FOUT".
+ */
+public class ConnectorMagdaClient extends AbstractConnectorMagdaClient {
- @Override
- public MagdaResponseWrapper send(MagdaRequest request) throws MagdaClientException {
- return send(request, UUID.randomUUID());
+ public ConnectorMagdaClient(MagdaConnector connector) {
+ super(connector);
}
@Override
- public MagdaResponseWrapper send(MagdaRequest request, UUID requestId) throws MagdaClientException {
- try {
- var response = connector.send(request, requestId);
-
- validateMagdaResponse(response, request);
-
- return new MagdaResponseWrapper(response);
- }
- catch (ServerException e) {
- throw new MagdaClientException("Error occurred while sending magda request", e);
- }
- }
-
- private void validateMagdaResponse(MagdaResponse response, MagdaRequest request) throws MagdaClientException {
+ protected void validateMagdaResponse(MagdaResponse response, MagdaRequest request) throws MagdaClientException {
if(!response.getUitzonderingEntries().isEmpty()) {
throw new MagdaClientException("Level 2 exception occurred while calling magda service", new UitzonderingenSectionInResponseException(request.getSubject(), response.getUitzonderingEntries(), request.getCorrelationId(), response.getRequestId()));
}
@@ -47,5 +29,4 @@ private void validateMagdaResponse(MagdaResponse response, MagdaRequest request)
private boolean haveAtLeastOneFout(List entries) {
return entries.stream().anyMatch(uitzonderingEntry -> uitzonderingEntry.getUitzonderingType().equals(UitzonderingType.FOUT));
}
-
}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/LenientConnectorMagdaClient.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/LenientConnectorMagdaClient.java
new file mode 100644
index 00000000..8d6ac450
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/LenientConnectorMagdaClient.java
@@ -0,0 +1,20 @@
+package be.vlaanderen.vip.magda.client;
+
+import be.vlaanderen.vip.magda.exception.UitzonderingenSectionInResponseException;
+
+/**
+ * A MagdaConnector-based client which handles level 2 uitzondingen in the response.
+ */
+public class LenientConnectorMagdaClient extends AbstractConnectorMagdaClient {
+
+ public LenientConnectorMagdaClient(MagdaConnector connector) {
+ super(connector);
+ }
+
+ @Override
+ protected void validateMagdaResponse(MagdaResponse response, MagdaRequest request) throws MagdaClientException {
+ if(!response.getUitzonderingEntries().isEmpty()) {
+ throw new MagdaClientException("Level 2 exception occurred while calling magda service", new UitzonderingenSectionInResponseException(request.getSubject(), response.getUitzonderingEntries(), request.getCorrelationId(), response.getRequestId()));
+ }
+ }
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/diensten/EducationEnrollmentSource.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/diensten/EducationEnrollmentSource.java
new file mode 100644
index 00000000..4d5ecb94
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/diensten/EducationEnrollmentSource.java
@@ -0,0 +1,17 @@
+package be.vlaanderen.vip.magda.client.diensten;
+
+import lombok.Getter;
+
+@Getter
+public enum EducationEnrollmentSource {
+ HO("HO"),
+ INT("INT"),
+ LP("LP"),
+ VWO("VWO");
+
+ private final String value;
+
+ EducationEnrollmentSource(String value) {
+ this.value = value;
+ }
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/diensten/GeefHistoriekInschrijvingRequest.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/diensten/GeefHistoriekInschrijvingRequest.java
new file mode 100644
index 00000000..d05422c2
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/diensten/GeefHistoriekInschrijvingRequest.java
@@ -0,0 +1,115 @@
+package be.vlaanderen.vip.magda.client.diensten;
+
+import be.vlaanderen.vip.magda.client.MagdaDocument;
+import be.vlaanderen.vip.magda.client.MagdaServiceIdentification;
+import be.vlaanderen.vip.magda.client.diensten.subject.INSZNumber;
+import be.vlaanderen.vip.magda.client.domeinservice.MagdaRegistrationInfo;
+import jakarta.annotation.Nullable;
+import jakarta.validation.constraints.NotNull;
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.time.LocalDate;
+import java.util.Set;
+import java.util.UUID;
+
+import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE;
+
+/**
+ * A request to the "Onderwijs.GeefHistoriekInschrijving" MAGDA service, which provides education enrollment histories for a person.
+ * Adds the following fields to the {@link PersonMagdaRequest}:
+ *
+ * - startDate: the start date of the period
+ * - endDate: the end date of the period
+ * - sources: the sources to be consulted (optional)
+ *
+ *
+ * @see XML template for this request type
+ */
+@Getter
+@ToString
+@EqualsAndHashCode(callSuper = true)
+public class GeefHistoriekInschrijvingRequest extends PersonMagdaRequest {
+
+ public static class Builder extends PersonMagdaRequest.Builder {
+
+ @Getter(AccessLevel.PROTECTED)
+ private LocalDate startDate;
+ @Getter(AccessLevel.PROTECTED)
+ private LocalDate endDate;
+ @Getter(AccessLevel.PROTECTED)
+ private Set sources;
+
+ public Builder startDate(LocalDate startDate) {
+ this.startDate = startDate;
+ return this;
+ }
+
+ public Builder endDate(LocalDate endDate) {
+ this.endDate = endDate;
+ return this;
+ }
+
+ public Builder sources(Set sources) {
+ this.sources = sources;
+ return this;
+ }
+
+ public GeefHistoriekInschrijvingRequest build() {
+ if(getInsz() == null) { throw new IllegalStateException("INSZ number must be given"); }
+ if(getStartDate() == null) { throw new IllegalStateException("Start date must be given"); }
+ if(getEndDate() == null) { throw new IllegalStateException("End date must be given"); }
+
+ return new GeefHistoriekInschrijvingRequest(
+ getInsz(),
+ getRegistration(),
+ getStartDate(),
+ getEndDate(),
+ getSources()
+ );
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @NotNull
+ private final LocalDate startDate;
+ @NotNull
+ private final LocalDate endDate;
+ @Nullable
+ private final Set sources;
+
+ private GeefHistoriekInschrijvingRequest(
+ @NotNull INSZNumber insz,
+ @NotNull String registratie,
+ @NotNull LocalDate startDate,
+ @NotNull LocalDate endDate,
+ @Nullable Set sources) {
+ super(insz, registratie);
+ this.startDate = startDate;
+ this.endDate = endDate;
+ this.sources = sources;
+ }
+
+ @Override
+ public MagdaServiceIdentification magdaServiceIdentification() {
+ return new MagdaServiceIdentification("Onderwijs.GeefHistoriekInschrijving", "02.01.0000");
+ }
+
+ @Override
+ protected void fillIn(MagdaDocument request, UUID requestId, MagdaRegistrationInfo magdaRegistrationInfo) {
+ fillInCommonFields(request, requestId, magdaRegistrationInfo);
+
+ request.setValue("//Criteria/Periode/Begin", startDate.format(ISO_LOCAL_DATE));
+ request.setValue("//Criteria/Periode/Einde", endDate.format(ISO_LOCAL_DATE));
+ if(sources != null) {
+ sources.forEach(source -> request.createTextNode("//Criteria/Bronnen", "Bron", source.getValue()));
+ } else {
+ request.removeNode("//Criteria/Bronnen");
+ }
+ }
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/EnrollmentHistory.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/EnrollmentHistory.java
new file mode 100644
index 00000000..a5a7e8a5
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/EnrollmentHistory.java
@@ -0,0 +1,305 @@
+package be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.MagdaClientException;
+import be.vlaanderen.vip.magda.client.MagdaDocument;
+import be.vlaanderen.vip.magda.client.MagdaResponse;
+import be.vlaanderen.vip.magda.client.MagdaResponseWrapper;
+import be.vlaanderen.vip.magda.client.diensten.EducationEnrollmentSource;
+import jakarta.annotation.Nullable;
+
+import java.time.LocalDate;
+import java.time.Year;
+import java.util.List;
+
+/**
+ * Information on a citizen's history of enrollment in education.
+ */
+public interface EnrollmentHistory {
+
+ static EnrollmentHistory ofMagdaDocument(MagdaDocument magdaDocument) throws MagdaClientException {
+ return MagdaResponseEnrollmentHistoryAdapterJaxbImpl.getInstance().adapt(new MagdaResponseWrapper(MagdaResponse.builder()
+ .document(magdaDocument)
+ .build()));
+ }
+
+ List enrollments();
+
+ interface Enrollment {
+
+ EducationEnrollmentSource source();
+
+ String reference();
+
+ Institution institution();
+
+ @Nullable
+ EducationLocation educationLocation();
+
+ @Nullable
+ HigherEducation higherEducation();
+
+ @Nullable
+ CompulsoryEducation compulsoryEducation();
+ }
+
+ interface Institution {
+
+ String institutionNumber();
+
+ String officialName();
+
+ @Nullable
+ String agency();
+
+ @Nullable
+ Address address();
+
+ @Nullable
+ ContactInfo contactInfo();
+ }
+
+ interface EducationLocation {
+
+ Integer number();
+
+ @Nullable
+ String description();
+
+ @Nullable
+ Address address();
+
+ @Nullable
+ ContactInfo contactInfo();
+ }
+
+ interface HigherEducation {
+
+ Year academyYear();
+
+ CodeAndDescription status();
+
+ LocalDate dateOfEnrollment();
+
+ @Nullable
+ LocalDate dateOfDisenrollment();
+
+ @Nullable
+ Training training();
+
+ CodeAndDescription contractType();
+
+ CreditPoints creditPoints();
+
+ @Nullable
+ Integer studyLoad();
+
+ Boolean isAdequateStudyLoad();
+
+ Boolean isStudyCertificateAchievable();
+
+ @Nullable
+ List studyCertificates();
+
+ @Nullable
+ Training nextTraining();
+
+ @Nullable
+ Training previousTraining();
+ }
+
+ interface CompulsoryEducation {
+
+ CodeAndDescription programType();
+
+ @Nullable
+ LocalDate dateOfEnrollment();
+
+ @Nullable
+ LocalDate dateOfFirstClass();
+
+ Year schoolYear();
+
+ @Nullable
+ AdministrativeGroupRegistration administrativeGroupRegistration();
+ }
+
+ interface Training {
+
+ String code();
+
+ String fullName();
+
+ NameElements nameElements();
+
+ CodeAndDescription type();
+ }
+
+ interface NameElements {
+
+ @Nullable
+ String degreePrefix();
+
+ @Nullable
+ String degree();
+
+ @Nullable
+ String degreeSpecification();
+
+ @Nullable
+ String qualificationPrefix();
+
+ String qualification();
+ }
+
+ interface CreditPoints {
+
+ Integer amountTaken();
+
+ Integer amountAcquired();
+
+ Integer amountDeliberated();
+
+ Integer amountNoResult();
+
+ @Nullable
+ Integer amountNotParticipated();
+
+ @Nullable
+ Integer amountNotSucceeded();
+
+ Integer amountNotAcquired();
+
+ Integer amountExempted();
+
+ Integer amountOptedOut();
+ }
+
+ interface StudyCertificate {
+
+ String reference();
+
+ @Nullable
+ String ledReference();
+ }
+
+ interface AdministrativeGroupRegistration {
+
+ @Nullable
+ String reference();
+
+ Period period();
+
+ AdministrativeGroup administrativeGroup();
+
+ @Nullable
+ CodeAndDescription specialNeedsType();
+
+ @Nullable
+ Disenrollment disenrollment();
+
+ @Nullable
+ Boolean isForeignLanguageNewcomer();
+
+ @Nullable
+ Boolean isFormerForeignLanguageNewcomer();
+ }
+
+ interface AdministrativeGroup {
+
+ String number();
+
+ @Nullable
+ String name();
+
+ CodeAndDescription level();
+
+ CodeAndDescription educationType();
+
+ @Nullable
+ DualCurriculum dualCurriculum();
+ }
+
+ interface DualCurriculum {
+
+ CodeAndDescription learningPathway();
+ }
+
+ interface Disenrollment {
+
+ CodeAndDescription reason();
+
+ CodeAndDescription situationAfter();
+ }
+
+ interface Address {
+
+ @Nullable
+ Street street();
+
+ @Nullable
+ String houseNumber();
+
+ @Nullable
+ String postalBoxNumber();
+
+ @Nullable
+ Municipality municipality();
+
+ @Nullable
+ Country country();
+ }
+
+ interface Street {
+
+ @Nullable
+ String name();
+ }
+
+ interface Municipality {
+
+ @Nullable
+ String nisCode();
+
+ @Nullable
+ String postalCode();
+
+ @Nullable
+ String name();
+ }
+
+ interface Country {
+
+ @Nullable
+ String isoCode();
+
+ @Nullable
+ String name();
+ }
+
+ interface ContactInfo {
+
+ @Nullable
+ String phoneNumber();
+
+ @Nullable
+ String emailAddress();
+
+ @Nullable
+ String website();
+ }
+
+ interface Period {
+
+ LocalDate startDate();
+
+ LocalDate endDate();
+ }
+
+ interface CodeAndDescription {
+
+ String codeValue();
+
+ @Nullable
+ String codeDescription();
+ }
+}
\ No newline at end of file
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/EnrollmentHistoryJaxb.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/EnrollmentHistoryJaxb.java
new file mode 100644
index 00000000..c16c2ad2
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/EnrollmentHistoryJaxb.java
@@ -0,0 +1,503 @@
+package be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.diensten.EducationEnrollmentSource;
+import be.vlaanderen.vip.magda.client.domain.model.shared.LocalDateXmlAdapter;
+import be.vlaanderen.vip.magda.client.domain.model.shared.YearXmlAdapter;
+import jakarta.annotation.Nullable;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlElementWrapper;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import lombok.Getter;
+import lombok.experimental.Accessors;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.Year;
+import java.util.ArrayList;
+import java.util.List;
+
+@XmlRootElement(name = "Inhoud")
+@Accessors(fluent = true)
+public class EnrollmentHistoryJaxb implements EnrollmentHistory, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 7417543781799245182L;
+
+ @XmlElementWrapper(name = "Inschrijvingen")
+ @XmlElement(name = "Inschrijving")
+ ArrayList enrollments;
+
+ @Override
+ public List enrollments() {
+ return enrollments.stream()
+ .map(x -> (Enrollment) x)
+ .toList();
+ }
+
+ @Getter
+ private static class EnrollmentJaxb implements Enrollment, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 2123983013630220684L;
+
+ @XmlElement(name = "Bron")
+ EducationEnrollmentSource source;
+
+ @XmlElement(name = "Referte")
+ String reference;
+
+ @XmlElement(name = "Instelling")
+ InstitutionJaxb institution;
+
+ @XmlElement(name = "OnderwijsLocatie")
+ @Nullable
+ EducationLocationJaxb educationLocation;
+
+ @XmlElement(name = "HogerOnderwijs")
+ @Nullable
+ HigherEducationJaxb higherEducation;
+
+ @XmlElement(name = "LeerplichtOnderwijs")
+ @Nullable
+ CompulsoryEducationJaxb compulsoryEducation;
+ }
+
+ @Getter
+ private static class InstitutionJaxb implements Institution, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -1510011456863582497L;
+
+ @XmlElement(name = "Instellingsnummer")
+ String institutionNumber;
+
+ @XmlElement(name = "OfficieleNaam")
+ String officialName;
+
+ @XmlElement(name = "Instantie")
+ @Nullable
+ String agency;
+
+ @XmlElement(name = "Adres")
+ @Nullable
+ AddressJaxb address;
+
+ @XmlElement(name = "Contactgegevens")
+ @Nullable
+ ContactInfoJaxb contactInfo;
+ }
+
+ @Getter
+ private static class EducationLocationJaxb implements EducationLocation, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -6414697292027312262L;
+
+ @XmlElement(name = "Nummer")
+ Integer number;
+
+ @XmlElement(name = "Omschrijving")
+ @Nullable
+ String description;
+
+ @XmlElement(name = "Adres")
+ @Nullable
+ AddressJaxb address;
+
+ @XmlElement(name = "Contactgegevens")
+ @Nullable
+ ContactInfoJaxb contactInfo;
+ }
+
+ @Getter
+ private static class HigherEducationJaxb implements HigherEducation, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -344798218191945921L;
+
+ @XmlElement(name = "Academiejaar")
+ @XmlJavaTypeAdapter(YearXmlAdapter.class)
+ Year academyYear;
+
+ @XmlElement(name = "Status")
+ CodeAndDescriptionJaxb status;
+
+ @XmlElement(name = "DatumInschrijving")
+ @XmlJavaTypeAdapter(LocalDateXmlAdapter.class)
+ LocalDate dateOfEnrollment;
+
+ @XmlElement(name = "DatumUitschrijving")
+ @XmlJavaTypeAdapter(LocalDateXmlAdapter.class)
+ @Nullable
+ LocalDate dateOfDisenrollment;
+
+ @XmlElement(name = "Opleiding")
+ @Nullable
+ TrainingJaxb training;
+
+ @XmlElement(name = "SoortContract")
+ CodeAndDescriptionJaxb contractType;
+
+ @XmlElement(name = "Studiepunten")
+ CreditPointsJaxb creditPoints;
+
+ @XmlElement(name = "Studieomvang")
+ @Nullable
+ Integer studyLoad;
+
+ @XmlElement(name = "ToereikendeStudieomvang")
+ Boolean isAdequateStudyLoad;
+
+ @XmlElement(name = "StudiebewijsHaalbaar")
+ Boolean isStudyCertificateAchievable;
+
+ @XmlElementWrapper(name = "Studiebewijzen")
+ @XmlElement(name = "Studiebewijs")
+ @Nullable
+ ArrayList studyCertificates;
+
+ @Override
+ public List studyCertificates() {
+ if(studyCertificates == null) {
+ return null;
+ }
+
+ return studyCertificates.stream()
+ .map(x -> (StudyCertificate) x)
+ .toList();
+ }
+
+ @XmlElement(name = "VolgendeOpleiding")
+ @Nullable
+ TrainingJaxb nextTraining;
+
+ @XmlElement(name = "VorigeOpleiding")
+ @Nullable
+ TrainingJaxb previousTraining;
+ }
+
+ @Getter
+ private static class CompulsoryEducationJaxb implements CompulsoryEducation, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 394155513929130862L;
+
+ @XmlElement(name = "SoortProgramma")
+ CodeAndDescriptionJaxb programType;
+
+ @XmlElement(name = "DatumInschrijving")
+ @XmlJavaTypeAdapter(LocalDateXmlAdapter.class)
+ @Nullable
+ LocalDate dateOfEnrollment;
+
+ @XmlElement(name = "DatumEersteLes")
+ @XmlJavaTypeAdapter(LocalDateXmlAdapter.class)
+ @Nullable
+ LocalDate dateOfFirstClass;
+
+ @XmlElement(name = "Schooljaar")
+ @XmlJavaTypeAdapter(YearXmlAdapter.class)
+ Year schoolYear;
+
+ @XmlElement(name = "InschrijvingAdministratieveGroep")
+ @Nullable
+ AdministrativeGroupRegistrationJaxb administrativeGroupRegistration;
+ }
+
+ @Getter
+ private static class TrainingJaxb implements Training, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 3947632101949342933L;
+
+ @XmlElement(name = "Code")
+ String code;
+
+ @XmlElement(name = "VolledigeNaam")
+ String fullName;
+
+ @XmlElement(name = "NaamElementen")
+ NameElementsJaxb nameElements;
+
+ @XmlElement(name = "Soort")
+ CodeAndDescriptionJaxb type;
+ }
+
+ @Getter
+ private static class NameElementsJaxb implements NameElements, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -7146590833317862189L;
+
+ @XmlElement(name = "PrefixGraad")
+ @Nullable
+ String degreePrefix;
+
+ @XmlElement(name = "Graad")
+ @Nullable
+ String degree;
+
+ @XmlElement(name = "SpecificatieGraad")
+ @Nullable
+ String degreeSpecification;
+
+ @XmlElement(name = "PrefixKwalificatie")
+ @Nullable
+ String qualificationPrefix;
+
+ @XmlElement(name = "Kwalificatie")
+ String qualification;
+ }
+
+ @Getter
+ private static class CreditPointsJaxb implements CreditPoints, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 4288678212016253460L;
+
+ @XmlElement(name = "Opgenomen")
+ Integer amountTaken;
+
+ @XmlElement(name = "Verworven")
+ Integer amountAcquired;
+
+ @XmlElement(name = "Gedelibereerd")
+ Integer amountDeliberated;
+
+ @XmlElement(name = "GeenResultaat")
+ Integer amountNoResult;
+
+ @XmlElement(name = "NietDeelgenomen")
+ @Nullable
+ Integer amountNotParticipated;
+
+ @XmlElement(name = "NietGeslaagd")
+ @Nullable
+ Integer amountNotSucceeded;
+
+ @XmlElement(name = "NietVerworven")
+ Integer amountNotAcquired;
+
+ @XmlElement(name = "Vrijgesteld")
+ Integer amountExempted;
+
+ @XmlElement(name = "Uitgeschreven")
+ Integer amountOptedOut;
+ }
+
+ @Getter
+ private static class StudyCertificateJaxb implements StudyCertificate, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -7569422110911431585L;
+
+ @XmlElement(name = "Referte")
+ String reference;
+
+ @XmlElement(name = "LEDReferte")
+ @Nullable
+ String ledReference;
+ }
+
+ @Getter
+ private static class AdministrativeGroupRegistrationJaxb implements AdministrativeGroupRegistration, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -4857829255909214297L;
+
+ @XmlElement(name = "Referte")
+ @Nullable
+ String reference;
+
+ @XmlElement(name = "Periode")
+ PeriodJaxb period;
+
+ @XmlElement(name = "AdministratieveGroep")
+ AdministrativeGroupJaxb administrativeGroup;
+
+ @XmlElement(name = "TypeBuitengewoon")
+ @Nullable
+ CodeAndDescriptionJaxb specialNeedsType;
+
+ @XmlElement(name = "Uitschrijving")
+ @Nullable
+ DisenrollmentJaxb disenrollment;
+
+ @XmlElement(name = "AnderstaligeNieuwkomer")
+ @Nullable
+ Boolean isForeignLanguageNewcomer;
+
+ @XmlElement(name = "GewezenAnderstaligeNieuwkomer")
+ @Nullable
+ Boolean isFormerForeignLanguageNewcomer;
+ }
+
+ @Getter
+ private static class AdministrativeGroupJaxb implements AdministrativeGroup, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -2950123647627117385L;
+
+ @XmlElement(name = "Nummer")
+ String number;
+
+ @XmlElement(name = "Naam")
+ @Nullable
+ String name;
+
+ @XmlElement(name = "Niveau")
+ CodeAndDescriptionJaxb level;
+
+ @XmlElement(name = "SoortOnderwijs")
+ CodeAndDescriptionJaxb educationType;
+
+ @XmlElement(name = "DuaalLeren")
+ @Nullable
+ DualCurriculumJaxb dualCurriculum;
+ }
+
+ @Getter
+ private static class DualCurriculumJaxb implements DualCurriculum, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -4011341482386475604L;
+
+ @XmlElement(name = "Leerweg")
+ CodeAndDescriptionJaxb learningPathway;
+ }
+
+ @Getter
+ private static class DisenrollmentJaxb implements Disenrollment, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -990045071616004454L;
+
+ @XmlElement(name = "Aanleiding")
+ CodeAndDescriptionJaxb reason;
+
+ @XmlElement(name = "SituatieNa")
+ CodeAndDescriptionJaxb situationAfter;
+ }
+
+ @Getter
+ private static class AddressJaxb implements Address, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -2602789444589500341L;
+
+ @XmlElement(name = "Straat")
+ @Nullable
+ StreetJaxb street;
+
+ @XmlElement(name = "Huisnummer")
+ @Nullable
+ String houseNumber;
+
+ @XmlElement(name = "Busnummer")
+ @Nullable
+ String postalBoxNumber;
+
+ @XmlElement(name = "Gemeente")
+ @Nullable
+ MunicipalityJaxb municipality;
+
+ @XmlElement(name = "Land")
+ @Nullable
+ CountryJaxb country;
+ }
+
+ @Getter
+ private static class StreetJaxb implements Street, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -8500375798881388985L;
+
+ @XmlElement(name = "Naam")
+ @Nullable
+ String name;
+ }
+
+ @Getter
+ private static class MunicipalityJaxb implements Municipality, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -5732523182095981641L;
+
+ @XmlElement(name = "NISCode")
+ @Nullable
+ String nisCode;
+
+ @XmlElement(name = "PostCode")
+ @Nullable
+ String postalCode;
+
+ @XmlElement(name = "Naam")
+ @Nullable
+ String name;
+ }
+
+ @Getter
+ private static class CountryJaxb implements Country, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 3027740616814131639L;
+
+ @XmlElement(name = "ISOCode")
+ @Nullable
+ String isoCode;
+
+ @XmlElement(name = "Naam")
+ @Nullable
+ String name;
+ }
+
+ @Getter
+ private static class ContactInfoJaxb implements ContactInfo, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 4043991542075763020L;
+
+ @XmlElement(name = "Telefoonnummer")
+ @Nullable
+ String phoneNumber;
+
+ @XmlElement(name = "Email")
+ @Nullable
+ String emailAddress;
+
+ @XmlElement(name = "Website")
+ @Nullable
+ String website;
+ }
+
+ @Getter
+ private static class PeriodJaxb implements Period, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -7829462301916655547L;
+
+ @XmlElement(name = "Begin")
+ @XmlJavaTypeAdapter(LocalDateXmlAdapter.class)
+ LocalDate startDate;
+
+ @XmlElement(name = "Einde")
+ @XmlJavaTypeAdapter(LocalDateXmlAdapter.class)
+ LocalDate endDate;
+ }
+
+ @Getter
+ private static class CodeAndDescriptionJaxb implements CodeAndDescription, Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -5682187439322660274L;
+
+ @XmlElement(name = "Code")
+ String codeValue;
+
+ @XmlElement(name = "Omschrijving")
+ @Nullable
+ String codeDescription;
+ }
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/GiveEnrollmentHistoryService.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/GiveEnrollmentHistoryService.java
new file mode 100644
index 00000000..c822eb8c
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/GiveEnrollmentHistoryService.java
@@ -0,0 +1,18 @@
+package be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.MagdaClientException;
+import be.vlaanderen.vip.magda.client.diensten.GeefHistoriekInschrijvingRequest;
+
+/**
+ * A service for interfacing with MAGDA's "Onderwijs.GeefHistoriekInschrijving" services for retrieving information on a person's education enrollment history.
+ */
+public interface GiveEnrollmentHistoryService {
+
+ /**
+ * Retrieves education enrollment history information from a GeefHistoriekInschrijvingRequest request.
+ *
+ * @see EnrollmentHistory
+ * @see GeefHistoriekInschrijvingRequest
+ */
+ EnrollmentHistory getEnrollmentHistory(GeefHistoriekInschrijvingRequest request) throws MagdaClientException;
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaClientGiveEnrollmentHistoryService.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaClientGiveEnrollmentHistoryService.java
new file mode 100644
index 00000000..d28f7f30
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaClientGiveEnrollmentHistoryService.java
@@ -0,0 +1,43 @@
+package be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.MagdaClient;
+import be.vlaanderen.vip.magda.client.MagdaClientException;
+import be.vlaanderen.vip.magda.client.MagdaResponse;
+import be.vlaanderen.vip.magda.client.diensten.GeefHistoriekInschrijvingRequest;
+import be.vlaanderen.vip.magda.exception.UitzonderingenSectionInResponseException;
+import be.vlaanderen.vip.magda.legallogging.model.UitzonderingType;
+
+public class MagdaClientGiveEnrollmentHistoryService implements GiveEnrollmentHistoryService {
+
+ private final MagdaClient client;
+ private final MagdaResponseEnrollmentHistoryAdapter adapter;
+
+ public MagdaClientGiveEnrollmentHistoryService(
+ MagdaClient client,
+ MagdaResponseEnrollmentHistoryAdapter adapter) {
+ this.client = client;
+ this.adapter = adapter;
+ }
+
+ public MagdaClientGiveEnrollmentHistoryService(
+ MagdaClient service) {
+ this(service, MagdaResponseEnrollmentHistoryAdapterJaxbImpl.getInstance());
+ }
+
+ @Override
+ public EnrollmentHistory getEnrollmentHistory(GeefHistoriekInschrijvingRequest request) throws MagdaClientException {
+ var responseWrapper = client.send(request);
+
+ validateResponse(responseWrapper.getResponse(), request); // XXX test
+
+ return adapter.adapt(responseWrapper);
+ }
+
+ private void validateResponse(MagdaResponse response, GeefHistoriekInschrijvingRequest request) throws MagdaClientException {
+ if(response.getResponseUitzonderingEntries().stream().anyMatch(x ->
+ x.getUitzonderingType().equals(UitzonderingType.FOUT) &&
+ !"30101".equals(x.getIdentification()))) {
+ throw new MagdaClientException("Level 3 exception occurred while calling magda service", new UitzonderingenSectionInResponseException(request.getSubject(), response.getResponseUitzonderingEntries(), request.getCorrelationId(), response.getRequestId()));
+ }
+ }
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaResponseEnrollmentHistoryAdapter.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaResponseEnrollmentHistoryAdapter.java
new file mode 100644
index 00000000..c1d018bd
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaResponseEnrollmentHistoryAdapter.java
@@ -0,0 +1,9 @@
+package be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.MagdaClientException;
+import be.vlaanderen.vip.magda.client.MagdaResponseWrapper;
+
+public interface MagdaResponseEnrollmentHistoryAdapter {
+
+ EnrollmentHistory adapt(MagdaResponseWrapper wrapper) throws MagdaClientException;
+}
\ No newline at end of file
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaResponseEnrollmentHistoryAdapterJaxbImpl.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaResponseEnrollmentHistoryAdapterJaxbImpl.java
new file mode 100644
index 00000000..c8d5bd7c
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaResponseEnrollmentHistoryAdapterJaxbImpl.java
@@ -0,0 +1,45 @@
+package be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.MagdaClientException;
+import be.vlaanderen.vip.magda.client.MagdaResponseWrapper;
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBException;
+import lombok.SneakyThrows;
+
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+public class MagdaResponseEnrollmentHistoryAdapterJaxbImpl implements MagdaResponseEnrollmentHistoryAdapter {
+
+ private static MagdaResponseEnrollmentHistoryAdapterJaxbImpl instance;
+
+ public static MagdaResponseEnrollmentHistoryAdapterJaxbImpl getInstance() {
+ if(instance == null) {
+ instance = new MagdaResponseEnrollmentHistoryAdapterJaxbImpl();
+ }
+
+ return instance;
+ }
+
+ private final JAXBContext context;
+
+ @SneakyThrows
+ private MagdaResponseEnrollmentHistoryAdapterJaxbImpl() {
+ context = JAXBContext.newInstance(EnrollmentHistoryJaxb.class);
+ }
+
+ @Override
+ public EnrollmentHistory adapt(MagdaResponseWrapper wrapper) throws MagdaClientException {
+ try {
+ var node = Optional.ofNullable(wrapper
+ .getResponse()
+ .getDocument()
+ .xpath("//Inhoud")
+ .item(0));
+ return (EnrollmentHistory) context.createUnmarshaller()
+ .unmarshal(node.orElseThrow());
+ } catch (NoSuchElementException | JAXBException e) {
+ throw new MagdaClientException("Could not parse magda response", e);
+ }
+ }
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/model/shared/LocalDateXmlAdapter.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/model/shared/LocalDateXmlAdapter.java
new file mode 100644
index 00000000..4d9479f4
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/model/shared/LocalDateXmlAdapter.java
@@ -0,0 +1,23 @@
+package be.vlaanderen.vip.magda.client.domain.model.shared;
+
+import jakarta.xml.bind.annotation.adapters.XmlAdapter;
+
+import java.time.LocalDate;
+import java.util.Optional;
+
+public class LocalDateXmlAdapter extends XmlAdapter {
+
+ @Override
+ public LocalDate unmarshal(String stringValue) {
+ return Optional.ofNullable(stringValue)
+ .map(LocalDate::parse)
+ .orElse(null);
+ }
+
+ @Override
+ public String marshal(LocalDate localDate) {
+ return Optional.ofNullable(localDate)
+ .map(LocalDate::toString)
+ .orElse(null);
+ }
+}
diff --git a/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/model/shared/YearXmlAdapter.java b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/model/shared/YearXmlAdapter.java
new file mode 100644
index 00000000..faeb374e
--- /dev/null
+++ b/interfaces/src/main/java/be/vlaanderen/vip/magda/client/domain/model/shared/YearXmlAdapter.java
@@ -0,0 +1,23 @@
+package be.vlaanderen.vip.magda.client.domain.model.shared;
+
+import jakarta.xml.bind.annotation.adapters.XmlAdapter;
+
+import java.time.Year;
+import java.util.Optional;
+
+public class YearXmlAdapter extends XmlAdapter {
+
+ @Override
+ public Year unmarshal(String stringValue) {
+ return Optional.ofNullable(stringValue)
+ .map(Year::parse)
+ .orElse(null);
+ }
+
+ @Override
+ public String marshal(Year year) {
+ return Optional.ofNullable(year)
+ .map(Year::toString)
+ .orElse(null);
+ }
+}
diff --git a/interfaces/src/main/resources/templates/Onderwijs.GeefHistoriekInschrijving/02.01.0000/template.xml b/interfaces/src/main/resources/templates/Onderwijs.GeefHistoriekInschrijving/02.01.0000/template.xml
new file mode 100644
index 00000000..5b63520f
--- /dev/null
+++ b/interfaces/src/main/resources/templates/Onderwijs.GeefHistoriekInschrijving/02.01.0000/template.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ GeefHistoriekInschrijving
+ 02.01.0000
+
+ VRAAG
+
+ Datum
+ Tijd
+
+
+ Identificatie
+ Referte
+ Hoedanigheid
+
+
+
+
+
+ a
+
+
+ 00000000000
+
+ 2015-01-01
+ 2016-06-30
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/interfaces/src/test/java/be/vlaanderen/vip/magda/client/LenientConnectorMagdaClientTest.java b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/LenientConnectorMagdaClientTest.java
new file mode 100644
index 00000000..47889d8d
--- /dev/null
+++ b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/LenientConnectorMagdaClientTest.java
@@ -0,0 +1,84 @@
+package be.vlaanderen.vip.magda.client;
+
+import be.vlaanderen.vip.magda.exception.ServerException;
+import be.vlaanderen.vip.magda.legallogging.model.UitzonderingEntry;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class LenientConnectorMagdaClientTest {
+ @Mock private MagdaConnector connector;
+
+ @InjectMocks
+ private LenientConnectorMagdaClient service;
+
+ @Nested
+ class Send {
+ private static final UUID REQUEST_ID = UUID.fromString("64fb1939-0ca7-432b-b7f4-3b53f7fc3789");
+
+ @Mock private MagdaRequest request;
+
+ @Mock private MagdaResponse response;
+
+ private final List level2errors = new ArrayList<>();
+ private final List level3errors = new ArrayList<>();
+
+ @BeforeEach
+ void setup() {
+ lenient().when(response.getUitzonderingEntries()).thenReturn(level2errors);
+ lenient().when(response.getResponseUitzonderingEntries()).thenReturn(level3errors);
+ lenient().when(response.getRequestId()).thenReturn(REQUEST_ID);
+ }
+
+ @Test
+ void returnsMagdaResponse_whenResponseContainsNoErrors() throws MagdaClientException {
+ when(connector.send(request, REQUEST_ID)).thenReturn(response);
+
+ var result = service.send(request, REQUEST_ID);
+
+ assertThat(result.getResponse(), is(equalTo(response)));
+ }
+
+ @Test
+ void returnsMagdaResponse_whenResponseContainsLevel3Errors() throws MagdaClientException {
+ when(connector.send(request, REQUEST_ID)).thenReturn(response);
+ level3errors.add(mock(UitzonderingEntry.class));
+
+ var result = service.send(request, REQUEST_ID);
+
+ assertThat(result.getResponse(), is(equalTo(response)));
+ }
+
+ @Test
+ void throwsException_whenSendFails() {
+ when(connector.send(request, REQUEST_ID)).thenThrow(ServerException.class);
+
+ assertThrows(MagdaClientException.class,
+ () -> service.send(request, REQUEST_ID));
+ }
+
+ @Test
+ void throwsException_whenResponseContainsLevel2Errors() {
+ when(connector.send(request, REQUEST_ID)).thenReturn(response);
+ level2errors.add(mock(UitzonderingEntry.class));
+
+ assertThrows(MagdaClientException.class,
+ () -> service.send(request, REQUEST_ID));
+ }
+ }
+}
diff --git a/interfaces/src/test/java/be/vlaanderen/vip/magda/client/diensten/GeefHistoriekInschrijvingRequestTest.java b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/diensten/GeefHistoriekInschrijvingRequestTest.java
new file mode 100644
index 00000000..b591ff27
--- /dev/null
+++ b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/diensten/GeefHistoriekInschrijvingRequestTest.java
@@ -0,0 +1,123 @@
+package be.vlaanderen.vip.magda.client.diensten;
+
+import be.vlaanderen.vip.magda.client.diensten.subject.INSZNumber;
+import be.vlaanderen.vip.magda.client.domeinservice.MagdaRegistrationInfo;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+import java.util.Set;
+import java.util.UUID;
+
+import static be.vlaanderen.vip.magda.client.diensten.EducationEnrollmentSource.*;
+import static be.vlaanderen.vip.magda.client.diensten.TestBase.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.jupiter.api.Assertions.*;
+
+class GeefHistoriekInschrijvingRequestTest {
+
+ @Nested
+ class Builder {
+
+ private GeefHistoriekInschrijvingRequest.Builder builder;
+
+ @BeforeEach
+ void setup() {
+ builder = GeefHistoriekInschrijvingRequest.builder()
+ .startDate(LocalDate.of(2024, 1, 1))
+ .endDate(LocalDate.of(2024, 12, 31))
+ .sources(Set.of(LP, VWO));
+ }
+
+ @Test
+ void buildsRequest() {
+ builder.insz(TEST_INSZ);
+ var request = builder.build();
+
+ assertNotNull(request);
+ assertEquals(INSZNumber.of(TEST_INSZ), request.getInsz());
+ assertEquals(LocalDate.of(2024, 1, 1), request.getStartDate());
+ assertEquals(LocalDate.of(2024, 12, 31), request.getEndDate());
+ assertEquals(Set.of(LP, VWO), request.getSources());
+ }
+
+ @Test
+ void whenInszIsNull_throwsException() {
+ assertThrows(IllegalStateException.class, () -> builder.build());
+ }
+
+ @Test
+ void whenStartDateIsNull_throwsException() {
+ builder.insz(TEST_INSZ)
+ .startDate(null);
+
+ assertThrows(IllegalStateException.class, () -> builder.build());
+ }
+
+ @Test
+ void whenEndDateIsNull_throwsException() {
+ builder.insz(TEST_INSZ)
+ .endDate(null);
+
+ assertThrows(IllegalStateException.class, () -> builder.build());
+ }
+
+ @Test
+ void sourcesIsOptional() {
+ builder.insz(TEST_INSZ)
+ .sources(null);
+
+ var request = builder.build();
+
+ assertNotNull(request);
+ assertNull(request.getSources());
+ }
+ }
+
+ @Nested
+ class ToMagdaDocument {
+ private static final UUID REQUEST_ID = UUID.fromString("64fb1939-0ca7-432b-b7f4-3b53f7fc3789");
+
+ private MagdaRegistrationInfo magdaRegistrationInfo;
+ private GeefHistoriekInschrijvingRequest.Builder builder;
+
+ @BeforeEach
+ void setup() {
+ magdaRegistrationInfo = MagdaRegistrationInfo.builder()
+ .identification("identification")
+ .hoedanigheidscode("hoedanigheidscode")
+ .build();
+
+ builder = GeefHistoriekInschrijvingRequest.builder()
+ .insz(TEST_INSZ)
+ .startDate(LocalDate.of(2024, 1, 1))
+ .endDate(LocalDate.of(2024, 12, 31))
+ .sources(Set.of(LP, VWO));
+ }
+
+ @Test
+ void fillsInValues() {
+ var document = builder.build()
+ .toMagdaDocument(REQUEST_ID, magdaRegistrationInfo);
+
+ assertNotNull(document);
+ assertEquals(TEST_INSZ, document.getValue("//Vraag/Inhoud/Criteria/INSZ"));
+ assertEquals("2024-01-01", document.getValue("//Vraag/Inhoud/Criteria/Periode/Begin"));
+ assertEquals("2024-12-31", document.getValue("//Vraag/Inhoud/Criteria/Periode/Einde"));
+ assertThat(document.getValues("//Vraag/Inhoud/Criteria/Bronnen/Bron"), containsInAnyOrder("LP", "VWO"));
+ }
+
+ @Test
+ void whenSourcesAreNotGiven_documentDoesNotIncludeThem() {
+ var document = builder
+ .sources(null)
+ .build()
+ .toMagdaDocument(REQUEST_ID, magdaRegistrationInfo);
+
+ assertNotNull(document);
+ assertNull(document.getValue("//Vraag/Inhoud/Criteria/Bronnen"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaClientGiveEnrollmentHistoryServiceTest.java b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaClientGiveEnrollmentHistoryServiceTest.java
new file mode 100644
index 00000000..9f91f3f8
--- /dev/null
+++ b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/giveenrollmenthistory/MagdaClientGiveEnrollmentHistoryServiceTest.java
@@ -0,0 +1,106 @@
+package be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.MagdaClient;
+import be.vlaanderen.vip.magda.client.MagdaClientException;
+import be.vlaanderen.vip.magda.client.MagdaResponse;
+import be.vlaanderen.vip.magda.client.MagdaResponseWrapper;
+import be.vlaanderen.vip.magda.client.diensten.GeefHistoriekInschrijvingRequest;
+import be.vlaanderen.vip.magda.legallogging.model.UitzonderingEntry;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import static be.vlaanderen.vip.magda.client.diensten.EducationEnrollmentSource.HO;
+import static be.vlaanderen.vip.magda.client.diensten.EducationEnrollmentSource.INT;
+import static be.vlaanderen.vip.magda.legallogging.model.UitzonderingType.FOUT;
+import static be.vlaanderen.vip.magda.legallogging.model.UitzonderingType.WAARSCHUWING;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class MagdaClientGiveEnrollmentHistoryServiceTest {
+
+ @Mock
+ private MagdaClient magdaClient;
+ @Mock
+ private MagdaResponseEnrollmentHistoryAdapter adapter;
+
+ @InjectMocks
+ private MagdaClientGiveEnrollmentHistoryService service;
+
+ @Nested
+ class GetEnrollmentHistory {
+
+ private GeefHistoriekInschrijvingRequest request;
+
+ @BeforeEach
+ void setup() {
+ request = GeefHistoriekInschrijvingRequest.builder()
+ .insz("insz")
+ .startDate(LocalDate.of(2024, 1, 1))
+ .endDate(LocalDate.of(2025, 1, 1))
+ .sources(Set.of(HO, INT))
+ .build();
+
+ request.setCorrelationId(UUID.fromString("6469cd5e-e8ed-43f7-a91e-48fdfbb76e0f"));
+ }
+
+ @Test
+ void callsMagdaService() throws MagdaClientException {
+ when(magdaClient.send(request)).thenReturn(new MagdaResponseWrapper(MagdaResponse.builder()
+ .responseUitzonderingEntries(List.of())
+ .build()));
+
+ service.getEnrollmentHistory(request);
+
+ verify(magdaClient).send(request);
+ }
+
+ @Test
+ void throwsNoException_ifContainsAnyNonErrorLevel3Uitzondering() throws MagdaClientException {
+ when(magdaClient.send(request)).thenReturn(new MagdaResponseWrapper(MagdaResponse.builder()
+ .responseUitzonderingEntries(List.of(UitzonderingEntry.builder()
+ .identification("30101")
+ .uitzonderingType(WAARSCHUWING)
+ .build()))
+ .build()));
+
+ assertDoesNotThrow(() -> service.getEnrollmentHistory(request));
+ }
+
+ @Test
+ void throwsNoException_ifContainsLevel3Error30101() throws MagdaClientException {
+ when(magdaClient.send(request)).thenReturn(new MagdaResponseWrapper(MagdaResponse.builder()
+ .responseUitzonderingEntries(List.of(UitzonderingEntry.builder()
+ .identification("30101")
+ .uitzonderingType(FOUT)
+ .build()))
+ .build()));
+
+ assertDoesNotThrow(() -> service.getEnrollmentHistory(request));
+ }
+
+ @Test
+ void throwsException_ifContainsOtherLevel3Error() throws MagdaClientException {
+ when(magdaClient.send(request)).thenReturn(new MagdaResponseWrapper(MagdaResponse.builder()
+ .responseUitzonderingEntries(List.of(UitzonderingEntry.builder()
+ .identification("12345")
+ .uitzonderingType(FOUT)
+ .build()))
+ .build()));
+
+ assertThrows(MagdaClientException.class, () -> service.getEnrollmentHistory(request));
+ }
+ }
+}
\ No newline at end of file
diff --git a/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/LocalDateXmlAdapterTest.java b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/LocalDateXmlAdapterTest.java
new file mode 100644
index 00000000..8f96181f
--- /dev/null
+++ b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/LocalDateXmlAdapterTest.java
@@ -0,0 +1,36 @@
+package be.vlaanderen.vip.magda.client.domain.model.shared;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class LocalDateXmlAdapterTest {
+
+ private static final LocalDate LOCAL_DATE = LocalDate.of(2024, 1, 2);
+ private static final String LOCAL_DATE_STRING = "2024-01-02";
+
+ private final LocalDateXmlAdapter adapter = new LocalDateXmlAdapter();
+
+ @Test
+ void unmarshal_parsesValue() {
+ assertEquals(LOCAL_DATE, adapter.unmarshal(LOCAL_DATE_STRING));
+ }
+
+ @Test
+ void unmarshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.unmarshal(null));
+ }
+
+ @Test
+ void marshal_formatsValue() {
+ assertEquals(LOCAL_DATE_STRING, adapter.marshal(LOCAL_DATE));
+ }
+
+ @Test
+ void marshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.marshal(null));
+ }
+}
\ No newline at end of file
diff --git a/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/OffsetDateTimeXmlAdapterTest.java b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/OffsetDateTimeXmlAdapterTest.java
new file mode 100644
index 00000000..395304f5
--- /dev/null
+++ b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/OffsetDateTimeXmlAdapterTest.java
@@ -0,0 +1,37 @@
+package be.vlaanderen.vip.magda.client.domain.model.shared;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class OffsetDateTimeXmlAdapterTest {
+
+ private static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of(2024, 1, 2, 3, 4, 5, 0, ZoneOffset.UTC);
+ private static final String OFFSET_DATE_TIME_STRING = "2024-01-02T03:04:05.000";
+
+ private final OffsetDateTimeXmlAdapter adapter = new OffsetDateTimeXmlAdapter();
+
+ @Test
+ void unmarshal_parsesValue() {
+ assertEquals(OFFSET_DATE_TIME, adapter.unmarshal(OFFSET_DATE_TIME_STRING));
+ }
+
+ @Test
+ void unmarshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.unmarshal(null));
+ }
+
+ @Test
+ void marshal_formatsValue() {
+ assertEquals(OFFSET_DATE_TIME_STRING, adapter.marshal(OFFSET_DATE_TIME));
+ }
+
+ @Test
+ void marshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.marshal(null));
+ }
+}
\ No newline at end of file
diff --git a/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/OffsetDateXmlAdapterTest.java b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/OffsetDateXmlAdapterTest.java
new file mode 100644
index 00000000..fefd8b12
--- /dev/null
+++ b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/OffsetDateXmlAdapterTest.java
@@ -0,0 +1,37 @@
+package be.vlaanderen.vip.magda.client.domain.model.shared;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class OffsetDateXmlAdapterTest {
+
+ private static final OffsetDateTime OFFSET_DATE = OffsetDateTime.of(2024, 1, 2, 0, 0, 0, 0, ZoneOffset.UTC);
+ private static final String OFFSET_DATE_STRING = "2024-01-02";
+
+ private final OffsetDateXmlAdapter adapter = new OffsetDateXmlAdapter();
+
+ @Test
+ void unmarshal_parsesValue() {
+ assertEquals(OFFSET_DATE, adapter.unmarshal(OFFSET_DATE_STRING));
+ }
+
+ @Test
+ void unmarshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.unmarshal(null));
+ }
+
+ @Test
+ void marshal_formatsValue() {
+ assertEquals(OFFSET_DATE_STRING, adapter.marshal(OFFSET_DATE));
+ }
+
+ @Test
+ void marshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.marshal(null));
+ }
+}
\ No newline at end of file
diff --git a/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/YearXmlAdapterTest.java b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/YearXmlAdapterTest.java
new file mode 100644
index 00000000..2fd778ee
--- /dev/null
+++ b/interfaces/src/test/java/be/vlaanderen/vip/magda/client/domain/model/shared/YearXmlAdapterTest.java
@@ -0,0 +1,36 @@
+package be.vlaanderen.vip.magda.client.domain.model.shared;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.Year;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class YearXmlAdapterTest {
+
+ private static final Year YEAR = Year.of(2024);
+ private static final String YEAR_STRING = "2024";
+
+ private final YearXmlAdapter adapter = new YearXmlAdapter();
+
+ @Test
+ void unmarshal_parsesValue() {
+ assertEquals(YEAR, adapter.unmarshal(YEAR_STRING));
+ }
+
+ @Test
+ void unmarshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.unmarshal(null));
+ }
+
+ @Test
+ void marshal_formatsValue() {
+ assertEquals(YEAR_STRING, adapter.marshal(YEAR));
+ }
+
+ @Test
+ void marshal_yieldsNullWhenValueIsNull() {
+ assertNull(adapter.marshal(null));
+ }
+}
\ No newline at end of file
diff --git a/magdaconnector/pom.xml b/magdaconnector/pom.xml
index 6b29a8d1..c16e9d99 100644
--- a/magdaconnector/pom.xml
+++ b/magdaconnector/pom.xml
@@ -5,7 +5,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
4.0.0
diff --git a/magdamock-starter/pom.xml b/magdamock-starter/pom.xml
index 9eb1a313..d6ec08a9 100644
--- a/magdamock-starter/pom.xml
+++ b/magdamock-starter/pom.xml
@@ -8,7 +8,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
magdamock-starter
diff --git a/magdamock/pom.xml b/magdamock/pom.xml
index 4efd9fe7..839123d8 100644
--- a/magdamock/pom.xml
+++ b/magdamock/pom.xml
@@ -3,7 +3,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
4.0.0
diff --git a/magdamock/src/test/java/be/vlaanderen/vip/mock/magda/client/domain/giveenrollmenthistory/MagdaResponseGiveEnrollmentHistoryIntegrationTest.java b/magdamock/src/test/java/be/vlaanderen/vip/mock/magda/client/domain/giveenrollmenthistory/MagdaResponseGiveEnrollmentHistoryIntegrationTest.java
new file mode 100644
index 00000000..b04d936d
--- /dev/null
+++ b/magdamock/src/test/java/be/vlaanderen/vip/mock/magda/client/domain/giveenrollmenthistory/MagdaResponseGiveEnrollmentHistoryIntegrationTest.java
@@ -0,0 +1,40 @@
+package be.vlaanderen.vip.mock.magda.client.domain.giveenrollmenthistory;
+
+import be.vlaanderen.vip.magda.client.MagdaClientException;
+import be.vlaanderen.vip.magda.client.diensten.GeefHistoriekInschrijvingRequest;
+import be.vlaanderen.vip.magda.client.domain.giveenrollmenthistory.EnrollmentHistory;
+import be.vlaanderen.vip.mock.magda.client.domain.MagdaMock;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class MagdaResponseGiveEnrollmentHistoryIntegrationTest {
+
+ private EnrollmentHistory enrollmentHistory;
+
+ @BeforeEach
+ void setup() throws MagdaClientException {
+ enrollmentHistory = enrollmentHistory("88611099807");
+ }
+
+ @Test
+ void dataIsBoundToResponseDocument() {
+ var enrollments = enrollmentHistory.enrollments();
+ assertNotNull(enrollments);
+ assertEquals(6, enrollments.size());
+ }
+
+ private EnrollmentHistory enrollmentHistory(String insz) throws MagdaClientException {
+ var response = MagdaMock.getInstance().send(GeefHistoriekInschrijvingRequest.builder()
+ .insz(insz)
+ .startDate(LocalDate.of(2024, 1, 1))
+ .endDate(LocalDate.of(2025, 1, 1))
+ .build());
+
+ return EnrollmentHistory.ofMagdaDocument(response.getDocument());
+ }
+}
\ No newline at end of file
diff --git a/magdaservice/pom.xml b/magdaservice/pom.xml
index 48413acf..7e1cc262 100644
--- a/magdaservice/pom.xml
+++ b/magdaservice/pom.xml
@@ -5,7 +5,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
4.0.0
diff --git a/pom.xml b/pom.xml
index f1c62b59..e32ca392 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
be.vlaanderen.vip.mock
magda
- 2.35.0
+ 2.36.0
magdaservice
MAGDA diensten Mock voor afnemers
diff --git a/signing/pom.xml b/signing/pom.xml
index 94484765..6682179c 100644
--- a/signing/pom.xml
+++ b/signing/pom.xml
@@ -5,7 +5,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
4.0.0
diff --git a/tester/pom.xml b/tester/pom.xml
index 5afd1235..b2957335 100644
--- a/tester/pom.xml
+++ b/tester/pom.xml
@@ -5,7 +5,7 @@
magda
be.vlaanderen.vip.mock
- 2.35.0
+ 2.36.0
4.0.0