====== Programmierung mit Groovy (für Experten) ====== Diese Seite richtet sich nur an Anwender mit tiefgreifender Erfahrung im Bereich Informatik und Anwendungsentwicklung. Das ASV-Team, die LTMs und die MULTIs leisten hierzu keinen technischen Support! ==== 1) Überblick: Datenzugriff in ASV ==== Zum technischen Verständnis: die Daten in ASV sind bei der Enterprise-Installation in einer relationalen Datenbank abgelegt. Der Zugriff auf die Datenschicht erfolgt ausschließlich (!) über die Business-Objekte in Form von Klassen, z.B. die Klasse Schueler, Lehrer, Unterricht oder SchuelerSchuljahr, SchuelerStamm usw. Ein Zugriff direkt auf die ASV-Datenkbank ist nicht vorgesehen und kann, bedingt durch die mehrschichte Systemarchitektur, zur Lieferung falscher Daten führen. Damit der Datenzugriff dennoch möglich ist, arbeitet die ASV mit einem Mehr-Schicht-Datenzugriffs-Modell: ^ Schicht ^ Bezeichnung ^ Zugriff möglich für ^ Anwendung ^ | Schicht 0 | Datenbank-Ebene | nur ASV-Kernteam \\ und NUR im Supportfall auf Zuspielung einer schulscharfen Sicherung durch die Schule | nicht möglich (u.A. wegen Datenschutz) | | Schicht 1 | Java-Ebene | nur ASV-Kernteam, Anwendungsentwicklung | nicht möglich | | Schicht 2 | Java-Ebene | nur ASV-Kernteam, Berichte-Ersteller | Jasper-Reports | | Schicht 3 | Business-Objekt-Ebene | Erfahrene Benutzer (z.B. Zugriff auf item.schuelerStamm.geschlecht()) | Textfeld mit OnLoad-Event (Syntax: Groovy) \\ im Serienbrief-, Listen-, Etiketten-Generator und im Exportformat | | Schicht 4 | Virtuelle Felder | jeder Benutzer | Virtuelle Felder (= Datenfeld)\\ im Serienbrief-, Listen-, Etiketten-Generator und im Exportformat | | Schicht 5 | ASV-Anwendung | jeder Benutzer (= das, was man in der Oberfläche sieht) | Anwendung der ASV (= das, was man in den Modulen sieht) | * mit Groovy greifen Sie auf Schicht 3 zu * normale Berichte, Listen, usw., die den Assistenten für Datenfelder nutzen, sind Schicht 3 * zentral bereitgestellte, komplexe Berichte, greifen auf Schicht 1 und 2 zu ==== 2) Vorgehensweise: Programmierung mit Groovy ==== * vorab lesen: (nicht abschließende) [[bers:berichte:listengenerator#datenfelder|Liste der Datenfelder in ASV]] * vorab prüfen: [[bers:berichte:serienbriefgenerator:virtuelle_felder|fehlende virtuelle Felder]] in ASV * technische Dokumentation: [[alle:anwendungsdaten:berichte:werkzeuge:groovy:start|Programmieren mit Groovy]] ==== 3) Datenzugriff auf spezielle Felder (Serienbriefe, Listengenerator) ==== Abhängig vom Bericht kann es sein, dass Sie \\ obj?.schuelerSchuljahr. durch obj? \\ ersetzen müssen, weil Sie sich möglicherweise schon im Datenbereich SchülerSchuljahr befinden. ASV kann diese Code-Stücke für alle Ausgabe-Arten verarbeiten. Abhängig von der Ausgabe-Art müssen Sie aber beachten: * Serienbrief \\ item.value = Variable_zur_Ausgabe * Liste, Office-Schablone, Exportformat: \\ return Variable_zur_Ausgabe * Schüler Straße und Hausnummer ausgeben: def st = obj?.schuelerStamm; return st.schStrasse + " " + st.schHausnummer + "\n"; * Betrieb Straße und Hausnummer ausgeben: def stb = obj?.schuelerStamm?.ausbildungBetrieb; String strReturn = ""; if (stb != null) { if (stb?.betriebName1 != null) { strReturn = stb?.anschrStrasse + " " + stb?.anschriftHausnr + "\n"; } } * Schüler > Ein-Austritt > Höchster allgemeinbildender Schulabschlussobj?.schuelerStamm.vorbildungSchulischM?.kurzform * Schüler > Ein-Austritt > Austritt Bildungsgang amobj.schuelerStamm?.austrittsdatumBldg; * Schüler > Ein-Austritt > Austritt Bildungsgang Abschluss Beruflich am Ende des Bildungsgangsobj.schuelerStamm?.abschlussBeruflichBldg?.kurzform * Schüler > Ein-Austritt > Austrittsgrund (Kurzform, Anzeigeform)obj?.schuelerStamm?.wlAustrittGrund obj?.schuelerStamm?.wlAustrittGrund?.anzeigeform * Schüler > Schuljahr XX/YY > Ausbildung > Ausbildungsberuf obj?.schuelerStamm?.ausbBeruf; obj?.schuelerStamm?.ausbBerufLang; obj?.schuelerStamm?.ausbBerufWeiblich; obj?.schuelerStamm?.ausbBerufWeiblichLang; * Schüler > Schuljahr XX/YY > Ausbildungsberuf, egal ob männlich oder weiblich, ohne Klammerung def berufsbez = ""; if(obj.schuelerStamm.m_w.kurzform == "M") { berufsbez = obj?.schuelerStamm?.ausbBerufLang; } else { berufsbez = obj?.schuelerStamm?.ausbBerufWeiblichLang; } berufsbez = berufsbez.toString(); if (berufsbez.length() > 0) { berufsbez = berufsbez.replace("]",""); berufsbez = berufsbez.replace("[",""); } // Ausgabe im Serienbrief item.value = berufsbez; // Ausgabe in Filtern, Office-Schablonen und Listen return berufsbez; * Schüler > Schuljahr XX/YY > Ausbildung > Beschäftigungsart obj?.schuelerStamm.getWlStellungImBeruf().getAnzeigeform() obj?.schuelerStamm.getWlStellungImBeruf().getKurzform() * Schüler > Schuljahr XX/YY > Ausbildung > Maßnahmenträgerobj?.schuelerStamm.wlKostentraeger.anzeigeform obj?.schuelerStamm.wlKostentraeger.kurzform * Schüler > Schuljahr XX/YY > Gastschulverhältnis obj?.schuelerSchuljahr.wlGastschuelerart?.anzeigeform obj?.schuelerSchuljahr.wlGastschuelerart?.kurzform * Schüler > Schuljahr XX/YY > Förderungsnummer obj?.schuelerStamm.foerderungsnummer * Schüler > Schuljahr XX/YY > Kammer-ID (nur BS)obj?.schuelerSchuljahr?.kammer * Schüler > Schuljahr XX/YY > zuständige Stelle, Kammer (nur BS, z.B. IHK, HWK, usw.) aus Betriebe > Ansprechpartner > Ansprechpartner neu mit ASV 2.21def strReturn = ""; def strReturn = ""; if (obj?.getAusbildung() != null) { if (obj?.getAusb().getBetriebBerufPerson() != null) { def objPersonList = obj?.getAusb().getBetriebBerufPerson().getBetriebBerufPersonAusbildungsberufList(); if (objPersonList != null) { objPersonList.each() { objPerson -> if (objPerson.getWlBbig() != null) { // Prüfung auf den Ausbildungsberuf des Ansprechpartners = Beruf des Schülers if (objPerson.getAusbildungsberuf().getKurzform() == obj?.getAusbildungsberuf().getKurzform()) { strReturn += objPerson.getWlBbig().getKurzform(); } } } } } } if (strReturn.length() < 1) { strReturn = "ohne Kammer"; } return strReturn; * Filter für einzelne Kammern können Sie selbst erstellen. Dieses Beispiel zeigt den nötigen Code. Der gelb markierte Text muss durch den Werk (Kammer - Kurzform) Ihrer schuleigenen Werteliste ersetzt werden. Sie können je Kammer nur einen eigenen Filter erstellen. Es ist technisch nicht möglich vor Aufruf des Filters dynamisch ein Dialogfenster zu öffnen, das die Eingabe der zu filternden Kammer ermöglicht. \\ \\ * def strReturn = ""; if (obj?.getAusbildung() != null) { if (obj?.getAusbildung().getBetriebBerufPerson() != null) { def objPersonList = obj?.getAusbildung().getBetriebBerufPerson().getBetriebBerufPersonAusbildungsberufList(); if (objPersonList != null) { objPersonList.each() { objPerson -> if (objPerson.getWlBbig() != null) { // Prüfung auf den Ausbildungsberuf des Ansprechpartners = Beruf des Schülers if (objPerson.getAusbildungsberuf().getKurzform() == obj?.getAusbildungsberuf().getKurzform()) { strReturn += objPerson.getWlBbig().getKurzform(); } } } } } } if (strReturn.length() < 1) { strReturn = "ohne Kammer"; } if (strReturn == 'IHK_Beispiel_Kürzel') { return true; } else { return false; } * Schüler > Stammdaten > Abschluss Beruflich obj?.schuelerStamm?.abschlussBeruflich?.getAnzeigeform() * Zeugnissote BS > Durchschnitt des BS-Abschlusszeugnisses. Setzt voraus, dass das BS-Abschlusszeugnis bereits gedruckt wurde. Die Vorschau oder ein Speichern als .PDF-Datei reicht nicht. def strReturn = " "; obj?.zeugnisSchuelerListe?.each{zeugnisSchueler-> if(zeugnisSchueler?.getZeugnisFormular().getWlZeugnisart().getSchluessel() == "30"){ zeugnisSchueler?.zeugnisTextList.each{zeugnisText-> if (zeugnisText.getElementname() == "txtBSDurchschnittsnoteAZ" && zeugnisText.getText() != null) { strReturn = zeugnisText.getText().replace("Durchschnittsnote ",""); } } } } // Rückgabe in Serienbrief item.value = strReturn; // Rückgabe in Liste, Office-Schablone, Exportformat return strReturn; * Betriebe > Ansprechpartner > Anrede des Ansprechpartners (liefert Herr/Frau)obj?.schuelerSchuljahr?.ausbildung?.betriebBerufPerson?.person?.anredeAnzeigeform alternativ, wenn Sie bereits im Datenbereich Schüler sind \\ obj?.ausbildung?.betriebBerufPerson?.person?.anredeAnzeigeform * Klasse > Organisationsformobj?.schuelerStamm?.klassengruppe?.klasse?.wlOrganisationsform?.getKurzform() obj?.schuelerStamm?.klassengruppe?.klasse?.wlOrganisationsform?.getAnzeigeform() * Klasse > Anzahl tatsächlich erteilter Unterrichtsstundenobj?.schuelerStamm?.klassengruppe?.klasse?.getUnterrichtsstundenProWoche() * Klasse > Klassenleiter mit Amtsbezeichnung def tempGeschlechtAmtsb = ""; if(obj?.klassengruppe?.klasse?.getKlasseninformationenKlassenleiter()?.getLehrerStamm()?.getWlGeschlecht()?.kurzform == "W") tempGeschlechtAmtsb = obj?.klassengruppe?.klasse?.getKlasseninformationenKlassenleiter()?.getLehrerStamm()?.getAmtsbezeichnung()?.getKurzformW(); else tempGeschlechtAmtsb = obj?.klassengruppe?.klasse?.getKlasseninformationenKlassenleiter()?.getLehrerStamm()?.getAmtsbezeichnung()?.getKurzform(); * Ersetzung je nach Geschlecht: "Der Schüler" bzw. "Die Schülerin": return (obj.schuelerStamm.m_w.kurzform == "M") ? "Der Schüler" : "Die Schülerin" * Geburtsdatum des Schülers: return obj?.schuelerStamm?.geburtsdatum.format("dd.MM.yyyy") * Aktuelles Schuljahr: return obj.schuljahr.kurzform * Erster Tag des Schuljahres:\\ Anmerkung: Da das Datum für den letzten (Schul-)Tag des Schuljahres in der Datenbank nicht hinterlegt ist, kann für diesen Fall kein Code erstellt werden. def Date ersterST = new Date() ersterST = obj.schuljahr.ersterSchultag return ersterST.format('dd.MM.yyyy') * Vorname und Name des Klassenleiters/der Klassenleiterin: return obj.klassengruppe.klasse.klassenleitungName * Vollständige Schüleradresse mit Umbrüchen ausgeben: def st = obj?.schuelerStamm; String strReturn = ""; strReturn += st.familienname + "\n" strReturn += st.rufname + "\n" strReturn += st.schStrasse + " " + st.schHausnummer + "\n"; strReturn += st.schAnschrPLZ + " " + st.schAnschrOrt + "\n"; if (st.schStaat != null) { if (st.schStaat.anzeigeform.equals("Deutschland") == true) { strReturn += "\n"; } else { strReturn += st.schStaat.anzeigeform + "\n"; } } return strReturn; * Vollständige Betriebeadresse mit Umbrüchen ausgeben: String strBetriebName1 = ""; String strBetriebeAdresse = ""; def stb = obj?.schuelerStamm?.ausbildungBetrieb; if (stb != null) { if (stb?.betriebName1 != null) { strBetriebName1 = stb?.betriebName1; strBetriebeAdresse = stb?.betriebName1 + "\n" if (stb?.betriebName2 != null) { if (stb?.betriebName2.length() > 1) { strBetriebeAdresse += stb?.betriebName2 + "\n" } } if (stb?.ansprVORNAMEN.get(0) != null) { strBetriebeAdresse += "zu Hd." if (stb?.ansprAkad.get(0) != null) { strBetriebeAdresse += " " + stb?.ansprAkad.get(0); } strBetriebeAdresse += " " + stb?.ansprVORNAMEN.get(0) + " " + stb?.ansprName.get(0) + "\n"; } strBetriebeAdresse += stb?.anschrStrasse + " " + stb?.anschriftHausnr + "\n"; strBetriebeAdresse += stb?.anschriftPLZ + " " + stb?.anschriftOrt + "\n"; if (stb?.anschriftStaat != null) { if (stb?.anschriftStaat?.anzeigeform.equals("Deutschland") == false) { strBetriebeAdresse += + stb?.anschriftStaat?.anzeigeform + "\n"; } } } } return strBetriebeAdresse; * Name des aktuell eingeloggten Benutzers \\ Dieser Code muss unter Modulbezogene-Funktionen > Globales Scripting eingefügt werden: public class Tools { public static Benutzer getBenutzer() { String login = AuthUtils.getCurrentUserLogin(); List benutzerList = Locator.getInstance(BenutzerDAO.class).findByKennung(login); if (benutzerList.size() > 0) { Benutzer benutzer = (Benutzer) benutzerList.get(0); return benutzer; } return null; } } Dieser Code muss im Feldaufruf genutzt werden: Tools.getBenutzer.getBenutzerName(); Tools.getBenutzer.getBenutzerVorname(); Tools.getBenutzer.getFullname(); Tools.getBenutzer.getVorname(); Tools.getBenutzer.getName(); Tools.getBenutzer.getNameVorname() * Einbinden des Schullogos (Element Bild > Bild aus Datenbank) im ONLOAD_EVENT: item.src = obj.schuelerStamm.schuleStamm?.schullogo * Kategorie für UPZ-Berechnung bei einer Lehrkraft ausgeben: item.value = obj?.wlKategorieupzberechnung?.toString(); ==== 4) Datenzugriff auf spezielle Felder (Exportformate) ==== * Dienstliche E-Mail-Adresse Schüler \\ \\ Einfügen in Global_Scriptingimport de.isb.svp.domain.pojo.SchuelerSchuljahr; import de.isb.svp.domain.pojo.SchuelerKommunikation; Einfügen in Spalte "Skript": final SchuelerSchuljahr ssj = obj; List skListe = ssj.getSchuelerStamm().getKommunikationen(); String ausgabe = ""; for (SchuelerKommunikation k : skListe) { if(k.getKommunikation().getWlKommunikationstyp().getSchluessel().equals("10")) ausgabe = k.getKommunikation().getKommunikationsadresse(); } return (ausgabe); ==== 5) Ersetzen, Umformatieren, Arbeiten mit Datumswerten (Serienbriefe, Listengenerator) ==== Eine Gute Informationsquelle über Groovy ist auch eine [[https://www.tutorialspoint.com/groovy/index.htm|Online-Dokumentation]]. * Aktuelles Datum ausgeben: return new Date().format("dd.MM.yyyy") * Aktuelles Datum + 10 Tage ausgeben: datum = new Date() datum = datum + 10 return datum.format("dd.MM.yyyy") * Datum umformatieren new SimpleDateFormat("dd.MM.yyyy").format(feld.getDate()) * Klammern entfernen item.value = "alter Wert"; item.value = item.value.replace("]",""); item.value = item.value.replace("[",""); * Null-Werte abfangen (null wird von ASV immer dann ausgegeben, wenn ein Wert nicht vorhanden ist)if (obj?.schuelerStamm.feldname != null) { // Feldwert zurückgeben item.value = obj?.schuelerStamm.feldname; } else { // Entwertungszeichen oder Text zurückgeben item.value = "-"; } ==== 6) Aufrufe im Globalen Scripting (Serienbriefe, Etiketten) ==== Serienbriefe oder Etiketten benötigen, um auf alle Felder der ASV zugreifen zu können, einige Imports im Global Scripting. Diese finden Sie im Serienbrief-Generator > Modulbezogene Funktionen > **Globales Scripting**. import javax.swing.*; import de.isb.svp.client.ze.scripting.objects.*; import de.isb.svp.domain.pojo.SchuleStamm; import de.isb.svp.domain.pojo.SchuleSchuljahr; import de.isb.svp.domain.pojo.WlSchuljahr; import de.isb.svp.domain.pojo.LehrerStamm; import de.isb.svp.domain.pojo.Benutzer; import de.isb.svp.domain.pojo.Anschrift; import de.isb.svp.domain.pojo.Aussenstelle; import de.isb.svp.domain.BenutzerDAO; import de.isb.svp.domain.Schulart; import de.isb.svp.auth.AuthUtils; import de.isb.base.business.Locator; import de.isb.base.utils.Strings; import bayern.asv.api.tools.SchulnameFormatter; import bayern.asv.reports.api.st.schulwechsel.SchulwechselHelper; import bayern.asv.reports.api.tools.unterzeichner.UnterzeichnerDatenHelper; import java.util.*; import java.lang.* import java.text.* import javax.swing.*