All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.svws_nrw.data.gost.DBUtilsGost Maven / Gradle / Ivy

Go to download

Diese Bibliothek unterstützt bei dem Zugriff auf Datenbanken für die Schulverwaltungssoftware in NRW

There is a newer version: 1.0.1
Show newest version
package de.svws_nrw.data.gost;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import de.svws_nrw.core.data.gost.GostFach;
import de.svws_nrw.core.data.gost.GostLeistungen;
import de.svws_nrw.core.data.gost.GostLeistungenFachbelegung;
import de.svws_nrw.core.data.gost.GostLeistungenFachwahl;
import de.svws_nrw.core.data.schueler.Sprachendaten;
import de.svws_nrw.core.types.Note;
import de.svws_nrw.core.types.SchuelerStatus;
import de.svws_nrw.core.types.gost.GostAbiturFach;
import de.svws_nrw.core.types.gost.GostHalbjahr;
import de.svws_nrw.core.types.gost.GostKursart;
import de.svws_nrw.core.types.jahrgang.Jahrgaenge;
import de.svws_nrw.core.types.schule.Schulform;
import de.svws_nrw.core.types.schule.Schulgliederung;
import de.svws_nrw.core.utils.DateUtils;
import de.svws_nrw.core.utils.gost.GostAbiturjahrUtils;
import de.svws_nrw.core.utils.gost.GostFachUtils;
import de.svws_nrw.core.utils.gost.GostFaecherManager;
import de.svws_nrw.core.utils.jahrgang.JahrgangsUtils;
import de.svws_nrw.core.utils.schueler.SprachendatenUtils;
import de.svws_nrw.data.faecher.DBUtilsFaecherGost;
import de.svws_nrw.data.schueler.DBUtilsSchueler;
import de.svws_nrw.data.schule.SchulUtils;
import de.svws_nrw.db.DBEntityManager;
import de.svws_nrw.db.dto.current.schild.kurse.DTOKurs;
import de.svws_nrw.db.dto.current.schild.schueler.DTOSchueler;
import de.svws_nrw.db.dto.current.schild.schueler.DTOSchuelerLeistungsdaten;
import de.svws_nrw.db.dto.current.schild.schueler.DTOSchuelerLernabschnittsdaten;
import de.svws_nrw.db.dto.current.schild.schule.DTOEigeneSchule;
import de.svws_nrw.db.dto.current.schild.schule.DTOJahrgang;
import de.svws_nrw.db.dto.current.schild.schule.DTOSchuljahresabschnitte;
import de.svws_nrw.db.utils.ApiOperationException;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.core.Response.Status;

/**
 * Dies Klassen stellt Hilfmethoden für den Datenbankzugriff
 * zur Verfügung, welche in den Data-Klassen an mehreren Stellen
 * verwendet werden.
 */
public final class DBUtilsGost {

	private DBUtilsGost() {
		throw new IllegalStateException("Instantiation of " + DBUtilsGost.class.getName() + " not allowed");
	}

	/**
	 * Prüft, ob es die Schule eine Schulform mit einer Gymnasiale Oberstufe (GOSt) hat.
	 *
	 * @param conn   die aktuelle Datenbankverbindung
	 *
	 * @return das Datenbank-DTO der Schule, falls eine Schule mit Gymnasialer Oberstufe vorliegt
	 *
	 * @throws ApiOperationException    falls keine Schule definiert ist oder die Schulform keine Gymnasiale Oberstufe hat
	 */
	public static DTOEigeneSchule pruefeSchuleMitGOSt(final DBEntityManager conn) throws ApiOperationException {
		final DTOEigeneSchule schule = conn.querySingle(DTOEigeneSchule.class);
		if (schule == null)
			throw new ApiOperationException(Status.NOT_FOUND);
		final Schulform schulform = schule.Schulform;
		if ((schulform == null) || (schulform.daten == null) || (!schulform.daten.hatGymOb))
			throw new ApiOperationException(Status.NOT_FOUND);
		return schule;
	}


	/**
	 * Prüft, ob in dem angebenen Schuljahresabschnitt für das angebene Halbjahr der gymnasialen Oberstufe
	 * bereits Kurse der gymnasialen Oberstufe vorhanden sind oder nicht.
	 *
	 * @param conn       die aktuelle Datenbankverbindung
	 * @param halbjahr   das Halbjahr
	 * @param abschnitt  der Schuljahresabschnitt
	 *
	 * @return true, wenn bereits Kurse vorhanden sind und ansonsten false
	 */
	public static boolean pruefeHatOberstufenKurseInAbschnitt(final DBEntityManager conn,
			final GostHalbjahr halbjahr, final DTOSchuljahresabschnitte abschnitt) {
		final List kurse = conn.queryList("SELECT e FROM DTOKurs e WHERE e.ASDJahrgang = ?1 AND e.Schuljahresabschnitts_ID = ?2",
				DTOKurs.class, halbjahr.jahrgang, abschnitt.ID);
		for (final DTOKurs kurs : kurse) {
			final GostKursart kursart = GostKursart.fromKuerzel(kurs.KursartAllg);
			if (kursart != null)
				return true;
		}
		return false;
	}


	/**
	 * Ermittelt in dem angebenen Schuljahresabschnitt für das angebene Halbjahr der gymnasialen Oberstufe
	 * die Menge der Kurse (DB-DTOs) der gymnasialen Oberstufe.
	 *
	 * @param conn       die aktuelle Datenbankverbindung
	 * @param halbjahr   das Halbjahr
	 * @param abschnitt  der Schuljahresabschnitt
	 *
	 * @return die Menge der Kurse (DB-DTOs)
	 */
	public static Set getOberstufenKurseInAbschnitt(final DBEntityManager conn, final GostHalbjahr halbjahr,
			final DTOSchuljahresabschnitte abschnitt) {
		final List kurse = conn.queryList("SELECT e FROM DTOKurs e WHERE e.ASDJahrgang = ?1 AND e.Schuljahresabschnitts_ID = ?2",
				DTOKurs.class, halbjahr.jahrgang, abschnitt.ID);
		final Set result = new HashSet<>();
		for (final DTOKurs kurs : kurse) {
			final GostKursart kursart = GostKursart.fromKuerzel(kurs.KursartAllg);
			if (kursart != null)
				result.add(kurs);
		}
		return result;
	}


	/**
	 * Prüft, ob in dem angebenen Schuljahresabschnitt für das angebene Halbjahr der gymnasialen Oberstufe
	 * bereits Kurse der gymnasialen Oberstufe vorhanden sind und Schülern in diesem Abschnitt bei diesen
	 * Kursen bereits Quartalsnoten oder Noten zugewiesen wurden oder nicht.
	 *
	 * @param conn       die aktuelle Datenbankverbindung
	 * @param halbjahr   das Halbjahr
	 * @param abschnitt  der Schuljahresabschnitt
	 *
	 * @return true, wenn bereits Kurse vorhanden sind und Schüler dort Quartalsnoten oder Noten zugewiesen
	 *     wurden, ansonsten false
	 */
	public static List getLernabschnitteFuerGostHalbjahrInAbschnitt(final DBEntityManager conn,
			final GostHalbjahr halbjahr, final DTOSchuljahresabschnitte abschnitt) {
		// Bestimme alle Jahrgänge der Schule, welche den passenden ASD-Jahrgang haben
		final List listJahrgaengeGost = conn.queryList(DTOJahrgang.QUERY_BY_ASDJAHRGANG, DTOJahrgang.class, halbjahr.jahrgang);
		final List listJahrgaengeGostIDs = listJahrgaengeGost.stream().map(j -> j.ID).toList();
		// Bestimme die SchuelerLernabschnitte von Schülern der Stufe
		return (listJahrgaengeGostIDs.isEmpty()) ? new ArrayList<>()
				: conn.queryList(
						"SELECT sla FROM DTOSchuelerLernabschnittsdaten sla JOIN DTOSchueler s ON s.Geloescht <> true AND sla.Schueler_ID = s.ID AND sla.Schuljahresabschnitts_ID = ?1 AND sla.Jahrgang_ID IN ?2",
						DTOSchuelerLernabschnittsdaten.class, abschnitt.ID, listJahrgaengeGostIDs);
	}



	/**
	 * Prüft, ob in dem angebenen Schuljahresabschnitt für das angebene Halbjahr der gymnasialen Oberstufe
	 * bereits Kurse der gymnasialen Oberstufe vorhanden sind und Schülern in diesem Abschnitt bei diesen
	 * Kursen bereits Quartalsnoten oder Noten zugewiesen wurden oder nicht.
	 *
	 * @param conn       die aktuelle Datenbankverbindung
	 * @param halbjahr   das Halbjahr
	 * @param abschnitt  der Schuljahresabschnitt
	 *
	 * @return true, wenn bereits Kurse vorhanden sind und Schüler dort Quartalsnoten oder Noten zugewiesen
	 *     wurden, ansonsten false
	 */
	public static boolean pruefeHatNotenFuerOberstufeInAbschnitt(final DBEntityManager conn, final GostHalbjahr halbjahr,
			final DTOSchuljahresabschnitte abschnitt) {
		// Bestimme die SchuelerLernabschnitte von Schülern der Stufe
		final List schuelerLernabschnittsdaten = getLernabschnitteFuerGostHalbjahrInAbschnitt(conn, halbjahr, abschnitt);
		final List idsSchuelerLernabschnittsdaten = schuelerLernabschnittsdaten.stream().map(l -> l.ID).toList();
		if (idsSchuelerLernabschnittsdaten.isEmpty())
			return false;
		// Bestimme die Schueler-Leistungsdaten zu den Lernabschnitten, welche einen (Quartals-)Noteneintrag aufweisen
		final List leistungsdaten = conn.queryList(
				"SELECT e FROM DTOSchuelerLeistungsdaten e WHERE e.Abschnitt_ID IN ?1 AND NOT (e.NotenKrz IS NULL AND e.NotenKrzQuartal IS NULL)",
				DTOSchuelerLeistungsdaten.class,
				idsSchuelerLernabschnittsdaten);
		// ... und prüfe diese Lernabschnitte, ob sie Einträge für die gymnasiale Oberstufe beinhalten
		for (final DTOSchuelerLeistungsdaten l : leistungsdaten) {
			if (GostKursart.fromKuerzel(l.KursartAllg) == null)
				continue;
			return true;
		}
		return false;
	}


	/**
	 * Entfernt die Leistungsdaten für das angegeben Halbjahr der gymnasialen Oberstufe bei den Schülern des Abiturjahrgangs,
	 * welcher durch den Schuljahresabschnitt und das Halbjahr der gymnasialen Oberstufe gegeben ist.
	 * Dies wird nur durchgeführt, wenn Kurse für die gymnasiale Oberstufe angelegt sind und es keine Leistungsdaten
	 * für Oberstufenkursen bei den Schüler gibt, welche bereits Noten beinhalten.
	 *
	 * @param conn       die aktuelle Datenbankverbindung
	 * @param halbjahr   das Halbjahr
	 * @param abschnitt  der Schuljahresabschnitt
	 *
	 * @throws ApiOperationException im Fehlerfall
	 */
	public static void deleteOberstufenKurseUndLeistungsdaten(final DBEntityManager conn, final GostHalbjahr halbjahr,
			final DTOSchuljahresabschnitte abschnitt) throws ApiOperationException {
		// Bestimme zunächst die Kurse der gymnasialen Oberstufe für diesen Fall
		final Set kurse = getOberstufenKurseInAbschnitt(conn, halbjahr, abschnitt);
		if (kurse.isEmpty())
			throw new ApiOperationException(Status.NOT_FOUND,
					"Es konnten keine Kurse für die Gymnasiale Oberstufe gefunden werden, so dass auch keine Leistungsdaten entfernt werden können.");
		// Bestimme nun die Lernabschnitte von Schülern des zugehörigen Abiturjahrgangs und die Leistungsdaten, die ggf. entfernt werden müssen
		final List lernabschnitte = getLernabschnitteFuerGostHalbjahrInAbschnitt(conn, halbjahr, abschnitt);
		final List listRemove = new ArrayList<>();
		if (!lernabschnitte.isEmpty()) {
			final Map mapLernabschnittsdaten = lernabschnitte.stream().collect(Collectors.toMap(l -> l.ID, l -> l));
			// Bestimme die Schueler-Leistungsdaten zu den Lernabschnitten
			final List leistungsdaten = conn.queryList(DTOSchuelerLeistungsdaten.QUERY_LIST_BY_ABSCHNITT_ID,
					DTOSchuelerLeistungsdaten.class, mapLernabschnittsdaten.keySet());
			// ... und prüfe diese Lernabschnitte, ob sie Einträge für die gymnasiale Oberstufe beinhalten
			for (final DTOSchuelerLeistungsdaten leistung : leistungsdaten) {
				// Prüfe, ob es sich bei den Leistungsdaten um einen Kurs der gymnasialen Oberstufe handelt oder nicht ...
				final GostKursart kursart = GostKursart.fromKuerzel(leistung.KursartAllg);
				if (kursart == null)
					continue;
				// ... es handelt sich um einen Kurs der gymnasialen Oberstufe, also prüfe zunächst, ob Noten vorliegen, wenn ja, dann darf diese Operation nicht beendet werden
				final DTOSchuelerLernabschnittsdaten lernabschnitt = mapLernabschnittsdaten.get(leistung.Abschnitt_ID);
				if ((!((leistung.NotenKrzQuartal == Note.KEINE) || (leistung.NotenKrzQuartal == Note.ATTEST)))
						|| (!((leistung.NotenKrz == Note.KEINE) || (leistung.NotenKrz == Note.ATTEST))))
					throw new ApiOperationException(Status.BAD_GATEWAY,
							"Es liegen bereits Noten für Leistungsdaten bei mindestens einem Schüler (ID=%d) vor, so dass die Leistungsdaten nicht entfernt werden dürfen."
									.formatted(lernabschnitt.Schueler_ID));
				// ... die Leistungsdaten können entfernt werden
				listRemove.add(leistung);
			}
		}
		// Entfernen der Leistungsdaten
		if (!listRemove.isEmpty()) {
			conn.transactionRemoveAll(listRemove);
			conn.transactionFlush();
		}
		// Entferne die Menge der Kurse der gymnasialen Oberstufe für das Halbjahr dieses Abiturjahrgangs
		conn.transactionRemoveAll(kurse);
		conn.transactionFlush();
	}


	/**
	 * Prüft, ob der Schüler bei dem angegebehen GOSt-Halbjahr des angegeben Halbjahres an der Schule gewesen ist.
	 *
	 * @param dto                        der Schüler
	 * @param halbjahr                   das GOSt-Halbjahr
	 * @param abijahrgang                der Abiturjahrgang
	 * @param mapSchuljahresabschnitte   die Schuljahresabschnitte, welche ihrer ID zugeordnet sind
	 *
	 * @return true, wenn der Schüler an der Schule ist, und ansonsten false
	 */
	public static boolean pruefeIstAnSchule(final DTOSchueler dto, final GostHalbjahr halbjahr, final int abijahrgang,
			final Map mapSchuljahresabschnitte) {
		// Ist ein aktueller Schuljahresabschnitt zugewiesen? Das ist notwendig, wenn der Schüler an der Schule ist oder war
		if (dto.Schuljahresabschnitts_ID == null)
			return false;
		// Dieser Schuljahresabschnitt muss auch gültig sein
		final DTOSchuljahresabschnitte schuljahresabschnitt = mapSchuljahresabschnitte.get(dto.Schuljahresabschnitts_ID);
		if (schuljahresabschnitt == null)
			return false;
		// In dem Fall, dass der Schüler bereits abgegangen ist, wird das Entlassdatum und der Schuljahresabschnitt mit dem Schuljahresabschnitt des GOSt-Halbjahres abgegleichen
		if ((dto.Status == SchuelerStatus.ABGANG) || (dto.Status == SchuelerStatus.ABSCHLUSS)) {
			final int blockungSchuljahr = halbjahr.getSchuljahrFromAbiturjahr(abijahrgang);
			final int[] entlassung = (dto.Entlassdatum == null) ? null : DateUtils.getSchuljahrUndHalbjahrFromDateISO8601(dto.Entlassdatum);
			if (entlassung == null) {
				// Prüfe, ob der aktuelle Schuljahresabschnitt des Schülers < dem Schuljahresabschnitt des GOSt-Halbjahres / der Blockung ist -> dann muss der Schüler ignoriert werden
				if ((schuljahresabschnitt.Jahr < blockungSchuljahr)
						|| ((schuljahresabschnitt.Jahr == blockungSchuljahr) && (schuljahresabschnitt.Abschnitt < halbjahr.halbjahr)))
					return false;
			} else {
				// Prüfe, ob der Schuljahresabschnitt der Entlassung des Schülers < dem Schuljahresabschnitt des GOSt-Halbjahres / der Blockung ist -> dann muss der Schüler ignoriert werden
				if ((entlassung[0] < blockungSchuljahr) || ((entlassung[0] == blockungSchuljahr) && (entlassung[1] < halbjahr.halbjahr)))
					return false;
			}
		}
		return true;
	}


	/**
	 * Bestimmt für den übergegebenen Lernabschnitt eines Schülers das zugehörige Abiturjahr.
	 *
	 * @param schulform         die Schulform der Schule des Schülers
	 * @param schulgliederung   die Schulgliederung des Schülers
	 * @param schuljahr         das aktuelle Schuljahr, in welchem sich der Schüler befindet
	 * @param jahrgang          der Jahrgang des Schülers
	 *
	 * @return das voraussichtliche Jahr des Abiturs
	 */
	public static Integer getAbiturjahr(final Schulform schulform, final Schulgliederung schulgliederung, final int schuljahr, final Jahrgaenge jahrgang) {
		if ((schulgliederung == null) || (jahrgang == null))
			return null;
		return GostAbiturjahrUtils.getGostAbiturjahr(schulform, schulgliederung, schuljahr, jahrgang.daten.kuerzel);
	}


	private static void getLeistung(final GostLeistungen daten, final DTOSchuelerLernabschnittsdaten lernabschnitt,
			final DTOSchuelerLeistungsdaten leistung, final DTOSchuljahresabschnitte abschnittLeistungsdaten,
			final Jahrgaenge jahrgang, final GostHalbjahr halbjahr, final Sprachendaten sprachendaten,
			final GostFaecherManager gostFaecher, final Map faecher) {
		// Prüfe, ob die Kursart eine Kursart der Oberstufe ist.
		final GostKursart kursart = GostKursart.fromKuerzel(leistung.KursartAllg);
		if (kursart == null)
			return;
		// Prüfe, ob das Fach ein Fach der Oberstufe ist
		final GostFach gostFach = gostFaecher.get(leistung.Fach_ID);
		if (gostFach == null)
			return;
		// Füge die Fächer aus den Leistungsdaten zunächst in die HashMap ein...
		GostLeistungenFachwahl fach = faecher.get(gostFach.kuerzelAnzeige);
		if (fach == null) {
			fach = new GostLeistungenFachwahl();
			fach.fach = gostFach;
			faecher.put(gostFach.kuerzelAnzeige, fach);
		}
		// Prüfe ggf., ob eine Sprache fortgeführt wurde oder nicht
		final String fremdsprache = GostFachUtils.getFremdsprache(gostFach);
		if (fremdsprache != null)
			fach.istFSNeu = (SprachendatenUtils.istNeueinsetzbareSpracheInGOSt(sprachendaten, fremdsprache));

		final GostAbiturFach tmpAbiFach = GostAbiturFach.fromIDString(leistung.AbiFach);
		fach.abiturfach = (tmpAbiFach == null) ? null : tmpAbiFach.id;

		// Füge eine Belegung der Kurse für die einzelnen Fächer in dem Halbjahr ein
		final GostLeistungenFachbelegung belegung = new GostLeistungenFachbelegung();
		belegung.id = leistung.ID;
		belegung.schuljahr = abschnittLeistungsdaten.Jahr;
		belegung.halbjahrKuerzel = halbjahr.kuerzel;
		belegung.abschnitt = abschnittLeistungsdaten.Abschnitt;
		belegung.abschnittGewertet = lernabschnitt.SemesterWertung;
		belegung.jahrgang = jahrgang.daten.kuerzel;
		belegung.lehrer = leistung.Fachlehrer_ID;
		belegung.notenKuerzel = leistung.NotenKrz.kuerzel;
		belegung.kursartKuerzel = kursart.kuerzel;
		belegung.istSchriftlich = (kursart == GostKursart.LK)
				|| ((kursart == GostKursart.GK) && (("GKS".equals(leistung.Kursart))
						|| ("AB3".equals(leistung.Kursart))
						|| ("AB4".equals(leistung.Kursart) && (halbjahr != GostHalbjahr.Q22))));
		belegung.bilingualeSprache = gostFach.biliSprache;
		belegung.wochenstunden = (leistung.Wochenstunden == null)
				? kursart.getWochenstunden(fach.istFSNeu)
				: leistung.Wochenstunden;
		belegung.fehlstundenGesamt = (leistung.FehlStd == null) ? 0 : leistung.FehlStd;
		belegung.fehlstundenUnentschuldigt = (leistung.uFehlStd == null) ? 0 : leistung.uFehlStd;
		fach.belegungen.add(belegung);

		// Ermittle ggf. das Projektkursthema und die zughörigen Leitfächer
		if (kursart == GostKursart.PJK) {
			daten.projektkursLeitfach1Kuerzel = gostFach.projektKursLeitfach1Kuerzel;
			daten.projektkursLeitfach2Kuerzel = gostFach.projektKursLeitfach2Kuerzel;
			if ((leistung.Lernentw != null) && (!"".equals(leistung.Lernentw)))
				daten.projektkursThema = leistung.Lernentw;
		}
	}


	/**
	 * Ermittelt die Leistungsdaten der gymnasialen Oberstufe für den Schüler mit der
	 * angegebenen ID aus der Datenbank.
	 *
	 * @param conn   die Datenbank-Verbindung
	 * @param id     die ID des Schülers
	 *
	 * @return die Leistungsdaten der gymnasialen Oberstufe für den Schüler mit der
	 *         angegebenen ID
	 *
	 * @throws ApiOperationException   im Fehlerfall
	 */
	public static GostLeistungen getLeistungsdaten(final DBEntityManager conn, final long id) throws ApiOperationException {
		final @NotNull DTOEigeneSchule schule = SchulUtils.getDTOSchule(conn);
		final Map mapJahrgaenge = conn.queryAll(DTOJahrgang.class).stream().collect(Collectors.toMap(j -> j.ID, j -> j));

		final DTOSchueler schueler = conn.queryByKey(DTOSchueler.class, id);
		if (schueler == null)
			throw new ApiOperationException(Status.NOT_FOUND);

		final Map schuljahresabschnitte =
				conn.queryAll(DTOSchuljahresabschnitte.class).stream().collect(Collectors.toMap(a -> a.ID, a -> a));
		final DTOSchuljahresabschnitte abschnittSchueler = schuljahresabschnitte.get(schueler.Schuljahresabschnitts_ID);
		if (abschnittSchueler == null)
			throw new ApiOperationException(Status.NOT_FOUND);

		final Sprachendaten sprachendaten = DBUtilsSchueler.getSchuelerSprachendaten(conn, id);

		// Bestimme alle Lernabschnitte der Oberstufe des Schülers, sortiert nach dem Schuljahr und dem Abschnitt
		final List lernabschnitte = conn.queryList(DTOSchuelerLernabschnittsdaten.QUERY_BY_SCHUELER_ID,
				DTOSchuelerLernabschnittsdaten.class, id).stream()
				.sorted((l1, l2) -> {
					final DTOSchuljahresabschnitte a1 = schuljahresabschnitte.get(l1.Schuljahresabschnitts_ID);
					final DTOSchuljahresabschnitte a2 = schuljahresabschnitte.get(l2.Schuljahresabschnitts_ID);
					return (a1.Jahr != a2.Jahr) ? Integer.compare(a1.Jahr, a2.Jahr) : Integer.compare(a1.Abschnitt, a2.Abschnitt);
				})
				.toList();

		// Bestimme den neuesten Lernabschnitt des Schülers. Aus diesem kann das voraussichliche Abiturjahr ermittelt werden.
		final DTOSchuelerLernabschnittsdaten aktLernabschnitt = lernabschnitte.get(lernabschnitte.size() - 1);
		final Schulgliederung schulgliederung = (aktLernabschnitt.Schulgliederung == null)
				? Schulgliederung.getDefault(schule.Schulform)
				: aktLernabschnitt.Schulgliederung;
		final DTOJahrgang dtoAktJahrgang = mapJahrgaenge.get(aktLernabschnitt.Jahrgang_ID);
		final Jahrgaenge aktJahrgang =
				((dtoAktJahrgang == null) || (dtoAktJahrgang.ASDJahrgang == null)) ? null : Jahrgaenge.getByKuerzel(dtoAktJahrgang.ASDJahrgang);
		final Integer abiturjahr = getAbiturjahr(schule.Schulform, schulgliederung, abschnittSchueler.Jahr, aktJahrgang);
		final GostFaecherManager gostFaecher = DBUtilsFaecherGost.getFaecherManager(conn, abiturjahr);

		// Ermittle nun die Leistungsdaten aus den Lernabschnitten
		final GostLeistungen daten = new GostLeistungen();
		daten.id = schueler.ID;
		daten.aktuellesSchuljahr = abschnittSchueler.Jahr;
		daten.aktuellerJahrgang = (aktJahrgang == null) ? null : aktJahrgang.daten.kuerzel;
		daten.sprachendaten = sprachendaten;
		final String biliZweig = aktLernabschnitt.BilingualerZweig;
		if ((biliZweig != null) && (!"".equals(biliZweig)))
			daten.bilingualeSprache = biliZweig.toUpperCase().substring(0, 1);
		// eine Map zur temporären Speicherung der Fächer -> muss später noch sortiert werden
		final Map faecher = new HashMap<>();
		for (final DTOSchuelerLernabschnittsdaten lernabschnitt : lernabschnitte) {
			final DTOSchuljahresabschnitte abschnittLeistungsdaten = schuljahresabschnitte.get(lernabschnitt.Schuljahresabschnitts_ID);
			if (abschnittLeistungsdaten == null)
				continue;

			final DTOJahrgang dtoJahrgang = mapJahrgaenge.get(lernabschnitt.Jahrgang_ID);
			final Jahrgaenge jahrgang = ((dtoJahrgang == null) || (dtoJahrgang.ASDJahrgang == null)) ? null : Jahrgaenge.getByKuerzel(dtoJahrgang.ASDJahrgang);
			if (jahrgang == null)
				continue;
			final GostHalbjahr halbjahr = GostHalbjahr.fromJahrgangUndHalbjahr(jahrgang.daten.kuerzel, abschnittLeistungsdaten.Abschnitt);
			if (halbjahr == null)
				continue;
			if (Boolean.TRUE.equals(lernabschnitt.SemesterWertung))
				daten.bewertetesHalbjahr[halbjahr.id] = true;
			final List leistungen = conn.queryList(DTOSchuelerLeistungsdaten.QUERY_BY_ABSCHNITT_ID,
					DTOSchuelerLeistungsdaten.class, lernabschnitt.ID);
			if (leistungen.isEmpty())
				daten.bewertetesHalbjahr[halbjahr.id] = false;
			for (final DTOSchuelerLeistungsdaten leistung : leistungen)
				getLeistung(daten, lernabschnitt, leistung, abschnittLeistungsdaten, jahrgang, halbjahr, sprachendaten, gostFaecher, faecher);
		}
		// Sortiere Fächer anhand der SII-Sortierung der Fächer
		faecher.values().stream()
				.sorted((a, b) -> Integer.compare(a.fach.sortierung, b.fach.sortierung))
				.forEach(daten.faecher::add);
		return daten;
	}



	/**
	 * Ermittelt die Leistungsdaten der gymnasialen Oberstufe für die Schüler mit den
	 * angegebenen IDs aus der Datenbank.
	 *
	 * @param conn   die Datenbank-Verbindung
	 * @param ids    die IDs der Schüler
	 *
	 * @return die Leistungsdaten der gymnasialen Oberstufe für die Schüler mit den
	 *         angegebenen IDs
	 *
	 * @throws ApiOperationException   im Fehlerfall
	 */
	public static Map getLeistungsdaten(final DBEntityManager conn, final List ids) throws ApiOperationException {
		final Map mapJahrgaenge = conn.queryAll(DTOJahrgang.class).stream().collect(Collectors.toMap(j -> j.ID, j -> j));
		// TODO Ermittle die Abi-Jahrgangsspezifische Fächerliste !
		final GostFaecherManager gostFaecher = DBUtilsFaecherGost.getFaecherManager(conn, null);

		final Map schuljahresabschnitte =
				conn.queryAll(DTOSchuljahresabschnitte.class).stream().collect(Collectors.toMap(a -> a.ID, a -> a));

		// TODO optimize DB-Access by using db queries with IN (...)
		final HashMap result = new HashMap<>();
		for (final Long id : ids) {
			if (id == null)
				throw new ApiOperationException(Status.BAD_REQUEST);

			final DTOSchueler schueler = conn.queryByKey(DTOSchueler.class, id);
			if (schueler == null)
				throw new ApiOperationException(Status.NOT_FOUND);

			final DTOSchuljahresabschnitte abschnittSchueler = schuljahresabschnitte.get(schueler.Schuljahresabschnitts_ID);
			if (abschnittSchueler == null)
				throw new ApiOperationException(Status.NOT_FOUND);

			final Sprachendaten sprachendaten = DBUtilsSchueler.getSchuelerSprachendaten(conn, id);

			// Bestimme alle Lernabschnitte der Oberstufe des Schülers, sortiert nach dem Schuljahr und dem Abschnitt
			final List lernabschnitte = conn.queryList(DTOSchuelerLernabschnittsdaten.QUERY_BY_SCHUELER_ID,
					DTOSchuelerLernabschnittsdaten.class, id).stream()
					.sorted((l1, l2) -> {
						final DTOSchuljahresabschnitte a1 = schuljahresabschnitte.get(l1.Schuljahresabschnitts_ID);
						final DTOSchuljahresabschnitte a2 = schuljahresabschnitte.get(l2.Schuljahresabschnitts_ID);
						return (a1.Jahr != a2.Jahr) ? Integer.compare(a1.Jahr, a2.Jahr) : Integer.compare(a1.Abschnitt, a2.Abschnitt);
					})
					.toList();

			// Bestimme den neuesten Lernabschnitt des Schülers. Aus diesem kann das voraussichliche Abiturjahr ermittelt werden.
			final DTOSchuelerLernabschnittsdaten aktLernabschnitt = lernabschnitte.get(lernabschnitte.size() - 1);
			final DTOJahrgang dtoAktJahrgang = mapJahrgaenge.get(aktLernabschnitt.Jahrgang_ID);
			final Jahrgaenge aktJahrgang =
					((dtoAktJahrgang == null) || (dtoAktJahrgang.ASDJahrgang == null)) ? null : Jahrgaenge.getByKuerzel(dtoAktJahrgang.ASDJahrgang);

			// Ermittle nun die Leistungsdaten aus den Lernabschnitten
			final GostLeistungen daten = new GostLeistungen();
			daten.id = schueler.ID;
			daten.aktuellesSchuljahr = abschnittSchueler.Jahr;
			daten.aktuellerJahrgang = (aktJahrgang == null) ? null : aktJahrgang.daten.kuerzel;
			daten.sprachendaten = sprachendaten;
			final String biliZweig = aktLernabschnitt.BilingualerZweig;
			if ((biliZweig != null) && (!"".equals(biliZweig)))
				daten.bilingualeSprache = biliZweig.toUpperCase().substring(0, 1);
			// eine HashMap zur temporären Speicherung der Fächer -> muss später noch sortiert werden
			final HashMap faecher = new HashMap<>();
			for (final DTOSchuelerLernabschnittsdaten lernabschnitt : lernabschnitte) {
				final DTOSchuljahresabschnitte abschnittLeistungsdaten = schuljahresabschnitte.get(lernabschnitt.Schuljahresabschnitts_ID);
				if (abschnittLeistungsdaten == null)
					continue;
				final DTOJahrgang dtoJahrgang = mapJahrgaenge.get(lernabschnitt.Jahrgang_ID);
				final Jahrgaenge jahrgang =
						((dtoJahrgang == null) || (dtoJahrgang.ASDJahrgang == null)) ? null : Jahrgaenge.getByKuerzel(dtoJahrgang.ASDJahrgang);
				if ((jahrgang == null) || !JahrgangsUtils.istGymOb(jahrgang.daten.kuerzel))
					continue;
				final GostHalbjahr halbjahr = GostHalbjahr.fromJahrgangUndHalbjahr(jahrgang.daten.kuerzel, abschnittLeistungsdaten.Abschnitt);
				if (halbjahr == null)
					continue;
				if (Boolean.TRUE.equals(lernabschnitt.SemesterWertung))
					daten.bewertetesHalbjahr[halbjahr.id] = true;

				final List leistungen = conn.queryList(DTOSchuelerLeistungsdaten.QUERY_BY_ABSCHNITT_ID,
						DTOSchuelerLeistungsdaten.class, lernabschnitt.ID);
				if (leistungen.isEmpty())
					daten.bewertetesHalbjahr[halbjahr.id] = false;
				for (final DTOSchuelerLeistungsdaten leistung : leistungen)
					getLeistung(daten, lernabschnitt, leistung, abschnittLeistungsdaten, jahrgang, halbjahr, sprachendaten, gostFaecher, faecher);
			}
			// Sortiere Fächer anhand der Sortierung der Fächer
			faecher.values().stream()
					.sorted((a, b) -> Integer.compare(a.fach.sortierung, b.fach.sortierung))
					.forEach(daten.faecher::add);
			result.put(id, daten);
		}
		return result;
	}


	/**
	 * Ermittelt die Leistungsdaten der gymnasialen Oberstufe für die Schüler mit den
	 * angegebenen IDs aus der Datenbank.
	 *
	 * @param ids                          die IDs der Schüler
	 * @param gostFaecherManager           der Manager für die Fächer des Abiturjahrgangs
	 * @param mapSchuljahresabschnitte     die Schuljahresabschnitte
	 * @param mapSchueler                  die DTOs der Schüler
	 * @param mapAlleGostAbschnitte        die Lernabschnitte der Schüler
	 * @param mapLeistungenByAbschnittID   die Leistungsdaten zu den Lernabschnitten
	 * @param mapSprachendaten             die Sprachendaten der Schüler
	 * @param mapJahrgaenge                die Jahrgänge der Schule
	 *
	 * @return die Leistungsdaten der gymnasialen Oberstufe für die Schüler mit den
	 *         angegebenen IDs
	 *
	 * @throws ApiOperationException   im Fehlerfall
	 */
	public static Map getLeistungsdatenFromDTOs(final List ids, final GostFaecherManager gostFaecherManager,
			final Map mapSchuljahresabschnitte, final Map mapSchueler,
			final Map> mapAlleGostAbschnitte,
			final Map> mapLeistungenByAbschnittID,
			final Map mapSprachendaten,
			final Map mapJahrgaenge) throws ApiOperationException {
		final HashMap result = new HashMap<>();
		for (final long id : ids) {
			final DTOSchueler schueler = mapSchueler.get(id);
			if (schueler == null)
				throw new ApiOperationException(Status.NOT_FOUND);

			final DTOSchuljahresabschnitte abschnittSchueler = mapSchuljahresabschnitte.get(schueler.Schuljahresabschnitts_ID);
			if (abschnittSchueler == null)
				throw new ApiOperationException(Status.NOT_FOUND);

			final Sprachendaten sprachendaten = mapSprachendaten.get(id);

			// Bestimme alle Lernabschnitte der Oberstufe des Schülers, sortiert nach dem Schuljahr und dem Abschnitt
			final List lernabschnitte = mapAlleGostAbschnitte.get(id)
					.stream()
					.sorted((l1, l2) -> {
						final DTOSchuljahresabschnitte a1 = mapSchuljahresabschnitte.get(l1.Schuljahresabschnitts_ID);
						final DTOSchuljahresabschnitte a2 = mapSchuljahresabschnitte.get(l2.Schuljahresabschnitts_ID);
						return (a1.Jahr != a2.Jahr) ? Integer.compare(a1.Jahr, a2.Jahr) : Integer.compare(a1.Abschnitt, a2.Abschnitt);
					})
					.toList();

			// Bestimme den neuesten Lernabschnitt des Schülers. Aus diesem kann das voraussichliche Abiturjahr ermittelt werden.
			final DTOSchuelerLernabschnittsdaten aktLernabschnitt = lernabschnitte.isEmpty() ? null : lernabschnitte.get(lernabschnitte.size() - 1);

			// Ermittle nun die Leistungsdaten aus den Lernabschnitten
			final GostLeistungen daten = new GostLeistungen();
			daten.id = schueler.ID;
			daten.aktuellesSchuljahr = abschnittSchueler.Jahr;
			if (aktLernabschnitt == null) {
				daten.aktuellerJahrgang = null;
				daten.bilingualeSprache = null;
			} else {
				final DTOJahrgang jg = (aktLernabschnitt.Jahrgang_ID == null) ? null : mapJahrgaenge.get(aktLernabschnitt.Jahrgang_ID);
				daten.aktuellerJahrgang = (jg == null) ? null : Jahrgaenge.getByKuerzel(jg.ASDJahrgang).daten.kuerzel;
				final String biliZweig = aktLernabschnitt.BilingualerZweig;
				if ((biliZweig != null) && (!"".equals(biliZweig)))
					daten.bilingualeSprache = biliZweig.toUpperCase().substring(0, 1);
			}
			daten.sprachendaten = sprachendaten;
			// eine HashMap zur temporären Speicherung der Fächer -> muss später noch sortiert werden
			final HashMap faecher = new HashMap<>();
			for (final DTOSchuelerLernabschnittsdaten lernabschnitt : lernabschnitte) {
				final DTOSchuljahresabschnitte abschnittLeistungsdaten = mapSchuljahresabschnitte.get(lernabschnitt.Schuljahresabschnitts_ID);
				if (abschnittLeistungsdaten == null)
					continue;
				final DTOJahrgang dtoJahrgang = mapJahrgaenge.get(lernabschnitt.Jahrgang_ID);
				final Jahrgaenge jahrgang = ((dtoJahrgang == null) || (dtoJahrgang.ASDJahrgang == null))
						? null : Jahrgaenge.getByKuerzel(dtoJahrgang.ASDJahrgang);
				if ((jahrgang == null) || !JahrgangsUtils.istGymOb(jahrgang.daten.kuerzel))
					continue;
				final GostHalbjahr halbjahr = GostHalbjahr.fromJahrgangUndHalbjahr(jahrgang.daten.kuerzel, abschnittLeistungsdaten.Abschnitt);
				if (halbjahr == null)
					continue;
				if (Boolean.TRUE.equals(lernabschnitt.SemesterWertung))
					daten.bewertetesHalbjahr[halbjahr.id] = true;

				List leistungen = mapLeistungenByAbschnittID.get(lernabschnitt.ID);
				if (leistungen == null)
					leistungen = new ArrayList<>();
				if (leistungen.isEmpty())
					daten.bewertetesHalbjahr[halbjahr.id] = false;
				for (final DTOSchuelerLeistungsdaten leistung : leistungen)
					getLeistung(daten, lernabschnitt, leistung, abschnittLeistungsdaten, jahrgang, halbjahr, sprachendaten, gostFaecherManager, faecher);
			}
			// Sortiere Fächer anhand der Sortierung der Fächer
			faecher.values().stream()
					.sorted((a, b) -> Integer.compare(a.fach.sortierung, b.fach.sortierung))
					.forEach(daten.faecher::add);
			result.put(id, daten);
		}
		return result;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy