Initialer Commit

This commit is contained in:
2026-02-19 17:01:11 +01:00
parent bf796f3335
commit 3f0a62405b
169 changed files with 32719 additions and 1 deletions

717
src/modules/folien.py Normal file
View File

@@ -0,0 +1,717 @@
import os, sys, locale
from datetime import datetime
def erzeugeIndex(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, pdf):
body = ''
alleklassen = sorted(alleklassen)
if pdf:
body += '<a name="startseite"></a>'
body += '<section>'
body += '<h2>Noten '+str(schuljahr)+'/'+str((schuljahr-2000)+1)+', '+str(halbjahr)+'. Hj.</h2>'
last_klasse = ''
# Durchlaufe alle Klassen
for klasse in alleklassen:
if (last_klasse==''):
body += '<p class="index">'
else:
if not(klasse.startswith(last_klasse)):
body += '<br/>'
else:
body += ' - '
klasseschoen = klasse
if (klasseschoen.startswith('0')):
klasseschoen = klasseschoen[1:]
body += '<a href="#klasse-'+klasse+'">'+klasseschoen+'</a>'
last_klasse = klasse[0:2]
body += '</p>'
locale.setlocale(locale.LC_TIME, "de_DE")
jetzt = datetime.now()
body += '<p class="time">Erzeugt: '+jetzt.strftime('%a %d. %B %Y, %H:%M Uhr')+'</p>'
body += '</section>'
return body
def erzeugeKlassenFolien(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, pdf):
# Optionen festlegen
jahrgaenge_oberstufe = ''
jahrgang_einführung = ''
jahrgang_abi = ''
try:
jahrgaenge_oberstufe = inputs["Jahrgänge"]["jahrgänge_oberstufe"] + ","
jahrgang_einführung = inputs["Jahrgänge"]["jahrgang_einführung"]
jahrgang_abitur = inputs["Jahrgänge"]["jahrgang_abitur"]
except KeyError:
print('Der Schlüssel Jahrgänge oder "oberstufe" / "abijahrgang" existiert nicht in der Input-Datei!')
exit(0)
# Durchlaufe alle Klassen
body = ''
alleklassen = sorted(alleklassen)
for klasse in alleklassen:
if pdf:
body += '<pdf:nextpage />'
body += '<a name="klasse-'+klasse+'"></a>'
body += '<section id="klasse-'+klasse+'">\n'
klasseschoen = klasse
if (klasseschoen.startswith('0')):
klasseschoen = klasseschoen[1:]
oberstufe = False
if (klasseschoen+"," in jahrgaenge_oberstufe):
oberstufe = True
einführungsphase = False
if (klasseschoen == jahrgang_einführung):
einführungsphase = True
qualiphase2 = False
if (klasseschoen == jahrgang_abitur):
qualiphase2 = True
hometext = ''
if pdf:
hometext = '<a href="#startseite">&nbsp;<img class="icon" src="modules/pdf/home.svg"></img></a>&nbsp;'
body += '<h1>'+hometext+'Klasse '+klasseschoen+'</h1>\n'
body += '</section>\n'
dieschueler = klassenschueler[klasse]
# Durchlaufe alle Schüler der Klasse (bzw. Jahrgangsstufe)
for derschueler in dieschueler:
data = derschueler.split('#')
name = data[0].strip()
body += '<section>\n'
# Bestimme die für den Schüler relevanten Abschnitte
# und prüfe, ob sie existieren. Suche ggf. Ersatz.
fehler = ""
abschnitte = []
ersatz = False
if (qualiphase2): # Q2/13 (zwei Schuljahre relevant)
if (halbjahr==1):
erster = [schuljahr-1, 1]
zweiter = [schuljahr-1, 2]
letzter = [schuljahr, 1]
test1 = alleabschnitte.get(derschueler+str(schuljahr-1)+str(1))
test2 = alleabschnitte.get(derschueler+str(schuljahr-1)+str(2))
if (test1 and test2):
gewertet1 = test1[7]
gewertet2 = test2[7]
if (gewertet1=='J' and gewertet2=='J'): # Default-Fall
abschnitte.append(erster)
abschnitte.append(zweiter)
else: # Suche Ersatz (Schuljahr zuvor nicht gewertet, d.h. Q2 wiederholt)
ersatz1 = alleabschnitte.get(derschueler+str(schuljahr-2)+str(1))
ersatz2 = alleabschnitte.get(derschueler+str(schuljahr-2)+str(2))
if (ersatz1 and ersatz2):
gewertet1 = ersatz1[7]
gewertet2 = ersatz2[7]
if (gewertet1=='J' and gewertet2=='J'):
erster = [schuljahr-2, 1]
zweiter = [schuljahr-2, 2]
abschnitte.append(erster)
abschnitte.append(zweiter)
else:
fehler += "Lernabschnitte der Q1/12 nicht gewertet. Kein gewerteter Ersatz gefunden."
else:
fehler += "Lernabschnitte der Q1/12 nicht gewertet. Kein Ersatz gefunden."
else:
fehler += "Lernabschnitte der Q1/12 nicht vorhanden."
abschnitte.append(letzter)
else: # 2. Halbjahr
erster = [schuljahr-1, 1]
zweiter = [schuljahr-1, 2]
dritter = [schuljahr, 1]
letzter = [schuljahr, 2]
test1 = alleabschnitte.get(derschueler+str(schuljahr-1)+str(1))
test2 = alleabschnitte.get(derschueler+str(schuljahr-1)+str(2))
test3 = alleabschnitte.get(derschueler+str(schuljahr)+str(1))
if (test3):
gewertet3 = test3[7]
if (gewertet3=='J'):
if test1 and test2: # Default-Fall
gewertet1 = test1[7]
gewertet2 = test2[7]
if (gewertet1=='J' and gewertet2=='J'): # Default-Fall
abschnitte.append(erster)
abschnitte.append(zweiter)
abschnitte.append(dritter)
else: # Suche Ersatz (evtl. Q1 wiederholt)
erster = [schuljahr-2, 1]
zweiter = [schuljahr-2, 2]
dritter = [schuljahr, 1]
letzter = [schuljahr, 2]
ersatz1 = alleabschnitte.get(derschueler+str(schuljahr-2)+str(1))
ersatz2 = alleabschnitte.get(derschueler+str(schuljahr-2)+str(2))
if (ersatz1 and ersatz2):
gewertet1 = ersatz1[7]
jahrgang1 = ersatz1[6]
gewertet2 = ersatz2[7]
jahrgang2 = ersatz2[6]
if (gewertet1=='J' and gewertet2=='J' and jahrgang1=='Q1' and jahrgang2=='Q1'):
ersatz = True
abschnitte.append(erster)
abschnitte.append(zweiter)
abschnitte.append(dritter)
else:
fehler += "Lernabschnitte Q1/12 nicht gefunden oder nicht gewertet. Kein gewerteter Ersatz gefunden."
abschnitte.append(dritter)
else:
fehler += "Lernabschnitte Q1/12 nicht gefunden oder nicht gewertet. Kein Ersatz gefunden."
abschnitte.append(dritter)
else:
fehler += "Lernabschnitte Q1.1/Q1.2 bzw. 12.1/12.2 nicht gefunden."
else: # Suche Ersatz (evtl. übergreifende Wiederholung)
erster = [schuljahr-2, 1]
zweiter = [schuljahr-2, 2]
dritter = [schuljahr-1, 1]
letzter = [schuljahr, 2]
test1 = alleabschnitte.get(derschueler+str(schuljahr-2)+str(1))
test2 = alleabschnitte.get(derschueler+str(schuljahr-2)+str(2))
test3 = alleabschnitte.get(derschueler+str(schuljahr-1)+str(1))
if (test1 and test2 and test3):
gewertet1 = test1[7]
gewertet2 = test2[7]
gewertet3 = test3[7]
if (gewertet1=='J' and gewertet2=='J' and gewertet3=='J'): # Default-Fall
abschnitte.append(erster)
abschnitte.append(zweiter)
abschnitte.append(dritter)
else:
fehler += "Lernabschnitte vor Q2.2 bzw. 13.2 nicht gefunden oder nicht gewertet. Kein gewerteter Ersatz gefunden."
else:
fehler += "Lernabschnitte vor Q2.2 bzw. 13.2 nicht gefunden oder nicht gewertet. Kein Ersatz gefunden."
else:
fehler += "Lernabschnitte Q1.2 und Q2.1 bzw. 12.2 und 13.1 fehlen."
abschnitte.append(letzter)
else: # Jahrgang 5 bis Q1 (nur ein Jahrgang relevant)
if (halbjahr==1):
erster = [schuljahr, 1]
abschnitte.append(erster)
else: # 2. Halbjahr
erster = [schuljahr, 1]
zweiter = [schuljahr, 2]
test = alleabschnitte.get(derschueler+str(schuljahr)+str(1))
if test:
gewertet = test[7]
if (gewertet=='J'):
abschnitte.append(erster)
else: # Suche Ersatz im Schuljahr zuvor
ersatz = True
ersatz = alleabschnitte.get(derschueler+str(schuljahr-1)+str(1))
if ersatz:
gewertet2 = ersatz[7]
if (gewertet2=='J'):
erster = [schuljahr-1, 1]
abschnitte.append(erster)
else:
fehler = "Lernabschnitt "+str(schuljahr)+".1 wird nicht gewertet. Kein gewerteter Ersatz gefunden."
else:
fehler = "Lernabschnitt "+str(schuljahr)+".1 wird nicht gewertet. Kein Ersatz gefunden."
else:
fehler = "Lernabschnitt "+str(schuljahr)+".1 nicht vorhanden."
abschnitte.append(zweiter)
letzter_abschnitt = alleabschnitte.get(derschueler+str(schuljahr)+str(halbjahr))
# Lernabschnitt fehlt? (Fall sollte eigentlich nicht eintreten!)
if not(letzter_abschnitt):
body += '<h3>'+name+', '+klasseschoen+'</h3>\n'
body += '<h4>Fehler: kein Lernabschnitt vorhanden!</h4>\n'
body += '</section>'
continue
# Lernabschnitt nicht gewertet? (Fall sollte eigentlich nicht eintreten!)
gewertet = letzter_abschnitt[7]
if not(gewertet=='J'):
body += '<h3>'+name+', '+klasseschoen+'</h3>\n'
body += '<h4>Fehler: Aktueller Lernabschnitt nicht gewertet!</h4>\n'
body += '</section>'
continue
wiederholung = letzter_abschnitt[0]
wdh_text = ""
if (wiederholung=='J'):
wdh_text = " (Wdh.)"
body += '<h3>'+name+', '+klasseschoen+wdh_text+'</h3>\n'
# Bestimme die Kurse aller Abschnitte
allekursedesschuelers = {}
for derabschnitt in abschnitte:
aktuell_sj = derabschnitt[0]
aktuell_hj = derabschnitt[1]
kurse = allekurse.get(derschueler+str(aktuell_sj)+str(aktuell_hj))
# Kurse fehlen? (Fall sollte eigentlich nicht eintreten!)
if not(kurse):
fehler += "Kurse im Abschnitt "+str(aktuell_sj)+"."+str(aktuell_hj)+" fehlen."
continue
for derkurs in kurse:
if derkurs[0] in allekursedesschuelers:
if allekursedesschuelers[derkurs[0]] == 1000:
allekursedesschuelers[derkurs[0]] = derkurs[8]
else:
allekursedesschuelers[derkurs[0]] = derkurs[8]
# Sortierung aller Kurse
sorted_kurse = sorted(allekursedesschuelers.items(), key=lambda x:x[1])
body += '<table>\n'
body += '<tr><th class="halbjahr">&nbsp;</th>\n'
for derkurs in sorted_kurse:
kursbez = derkurs[0]
body += '<th>'+kursbez+'</th>'
body += '</tr>\n'
# Durchlaufe die relevanten Abschnitte
for derabschnitt in abschnitte:
aktuell_sj = derabschnitt[0]
sj_kurz = aktuell_sj - 2000
sj_schoen = str(aktuell_sj)+"/"+str(sj_kurz+1)
aktuell_hj = derabschnitt[1]
aktueller_abschnitt = alleabschnitte.get(derschueler+str(aktuell_sj)+str(aktuell_hj))
# Abschnitt fehlt? (Fall sollte eigentlich nicht eintreten!)
if not(aktueller_abschnitt):
fehler += "Abschnitt "+str(aktuell_sj)+"."+str(aktuell_hj)+" fehlt."
continue
aktuell_jg = aktueller_abschnitt[6]
jg_schoen = aktuell_jg
if (jg_schoen.startswith('0')):
jg_schoen = jg_schoen[1:]
body += '<tr>\n'
body += '<td class="halbjahr"><span class="jahrgang">'+str(jg_schoen)+'.'+str(aktuell_hj)+'</span><br/>'
body += '<span class="schuljahr">'+str(sj_schoen)+'.'+str(aktuell_hj)+'</span></td>\n'
kurse = allekurse.get(derschueler+str(aktuell_sj)+str(aktuell_hj))
# Kurse fehlen? (Fall sollte eigentlich nicht eintreten!)
if not(kurse):
fehler += "Kurse im Abschnitt "+str(aktuell_sj)+"."+str(aktuell_hj)+" fehlen."
continue
# Durchlaufe die zuvor sortierten Gesamtkurse
for meinkurs in sorted_kurse:
# Suche einen passenden Kurs im aktuellen Abschnitt
gefunden = False
for derkurs in kurse:
if (meinkurs[0]==derkurs[0]):
# Treffer!
gefunden = True
note = derkurs[3]
kursbez = derkurs[0]
lehrer = derkurs[1]
kursart = derkurs[2]
mahnung = derkurs[7]
if (len(note)==0):
note = '-'
# Bewertung = Einfärbung der Note
topnoten = { '1+', '1', '1-', '2+', '2', '2-' }
defizite = { '5+', '5', '5-', '6' }
defizite_q = { '4-', '5+', '5', '5-', '6' }
cssklasse = ''
if (note in topnoten):
cssklasse = 'top'
if oberstufe:
if einführungsphase:
if (note in defizite):
cssklasse = 'def'
if (aktuell_hj==2) and (mahnung=='N'):
cssklasse = 'nw'
else:
if (note in defizite_q):
cssklasse = 'def'
else:
if (note in defizite):
cssklasse = 'def'
if (aktuell_hj==2) and (mahnung=='N'):
cssklasse = 'nw'
if (len(cssklasse)>0):
cssklasse = ' class="'+cssklasse+'"'
# Füge Note ein
body += '<td'+cssklasse+'><span class="note">'+note+'</span><br/>'
body += '<span class="lehrer">'+lehrer+"</span>"
if (len(kursart)>0 and kursart!='PUK'):
etext = ""
if (kursart=="LK1" or kursart=="LK2"):
etext = " lk"
if (kursart=="AB3" or kursart=="AB4"):
etext = " ab"
body += '<br/><span class="kursart'+etext+'">'+kursart+"</span>"
elif ((klasse in epochen) and ((kursbez+",") in epochen[klasse])):
body += '<br/><span class="epoche">Epoche</span>'
body += '</td>\n'
if (not(gefunden)):
body += '<td></td>'
body += '</tr>\n'
body += '</table>\n'
# Ergänze die Daten des Fokus-Abschnitts: Fehlstunden, Versetzung, Abschluss
fehlstunden = letzter_abschnitt[4]
if (len(fehlstunden)==0):
fehlstunden = "-"
unentschuldigt = letzter_abschnitt[5]
if (len(unentschuldigt)==0):
unentschuldigt = "-"
if (unentschuldigt=='0' or unentschuldigt=='-'):
ftext = 'Fehlstunden: &nbsp;'+fehlstunden+' / '+unentschuldigt
else:
ftext = 'Fehlstunden: &nbsp;'+fehlstunden+' / <span class="ue">'+unentschuldigt+'</span>'
versetzt = letzter_abschnitt[1]
abschluss = letzter_abschnitt[2]
abschlusstyp = letzter_abschnitt[3]
vtext = ""
if (len(versetzt)>0):
if (versetzt=='V'):
vtext += 'Versetzung: &nbsp;ja'
elif (versetzt=='N'):
vtext += 'Versetzung: <span class="nv">nein</span>'
elif (versetzt=='NP'):
vtext += 'Versetzung: <span class="nv">NP</span>'
if (len(abschluss)>0 and abschluss=="1"):
if (len(vtext)>0):
vtext += ", &nbsp;Abschluss: &nbsp;"+abschlusstyp
else:
vtext = "Abschluss: "+abschlusstyp
if pdf:
body += '<p class="fehlversetzung">'+ftext
if (len(vtext)>0):
body += ', &nbsp;'+vtext
body += '</p>'
else:
body += '<p class="fehl">'+ftext+'</p>'
body += '<p class="versetzung">'+vtext+'</p>'
# Ergänze evtl. Fehlerhinweis
if (len(fehler)>0):
body += '<p class="hinweis">Hinweis: '+fehler+'</p>'
if pdf:
body += '<p class="separator">&nbsp;<p>'
body += '</section>'
return body
def erzeugeNotenTabellen(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, pdf):
# Optionen festlegen
jahrgaenge_oberstufe = ''
jahrgang_abi = ''
try:
jahrgaenge_oberstufe = inputs["Jahrgänge"]["jahrgänge_oberstufe"] + ","
jahrgang_einführung = inputs["Jahrgänge"]["jahrgang_einführung"] + ","
jahrgang_abitur = inputs["Jahrgänge"]["jahrgang_abitur"] + ","
except KeyError:
print('Der Schlüssel Jahrgänge oder "oberstufe" / "abijahrgang" existiert nicht in der Input-Datei!')
exit(0)
# Durchlaufe alle Klassen
body = ''
alleklassen = sorted(alleklassen)
for klasse in alleklassen:
klasseschoen = klasse
if (klasseschoen.startswith('0')):
klasseschoen = klasseschoen[1:]
oberstufe = False
if (klasseschoen+"," in jahrgaenge_oberstufe):
oberstufe = True
einführungsphase = False
if (klasseschoen == jahrgang_einführung):
einführungsphase = True
qualiphase2 = False
if (klasseschoen == jahrgang_abitur):
qualiphase2 = True
if (oberstufe==True): # Übersichtstabellen nur für Sek. I sinnvoll
continue
dieschueler = klassenschueler[klasse]
allekursederklasse = {}
# Durchlaufe alle Schüler und ermittle alle Fächer
for derschueler in dieschueler:
if derschueler+str(schuljahr)+str(halbjahr) in allekurse:
kurse = allekurse[derschueler+str(schuljahr)+str(halbjahr)]
for derkurs in kurse:
if derkurs[0] in allekursederklasse:
if allekursederklasse[derkurs[0]] == 1000:
allekursederklasse[derkurs[0]] = derkurs[8]
else:
allekursederklasse[derkurs[0]] = derkurs[8]
sorted_kurse = sorted(allekursederklasse.items(), key=lambda x:x[1])
body += '<table>'
body += '<tr><th class="name">'+klasseschoen+'</th>'
body += '<th class="fehl">Fehl</th>'
if (halbjahr==2):
body += '<th class="versetzung">Vers</th>'
for derkurs in sorted_kurse:
body += '<th>'+derkurs[0]+'</th>'
body += '</tr>'
# Durchlaufe alle Schüler und ermittle alle Noten
for derschueler in dieschueler:
data = derschueler.split('#')
name = data[0].strip()
if (not(derschueler+str(schuljahr)+str(halbjahr) in allekurse)):
body += '<tr><td>'+name+'</td></tr>'
elif (not(derschueler+str(schuljahr)+str(halbjahr) in alleabschnitte)):
body += '<tr><td>'+name+'</td></tr>'
else:
kurse = allekurse[derschueler+str(schuljahr)+str(halbjahr)]
abschnitt = alleabschnitte[derschueler+str(schuljahr)+str(halbjahr)]
wiederholung = abschnitt[0]
wdh_text = ""
if (wiederholung=='J'):
wdh_text = " (W)"
body += '<tr><td class="name">'+name+wdh_text+'</td>'
fehlstunden = abschnitt[4]
if (len(fehlstunden)==0):
fehlstunden = "-"
unentschuldigt = abschnitt[5]
if (len(unentschuldigt)==0):
unentschuldigt = "-"
if (unentschuldigt=='0' or unentschuldigt=='-'):
ftext = fehlstunden+' / '+unentschuldigt
else:
ftext = fehlstunden+' / <span class="ue">'+unentschuldigt+'</span>'
body += '<td class="fehl">'+ftext+'</td>'
versetzt = abschnitt[1]
vtext = ""
if (len(versetzt)>0):
if (versetzt=='V'):
vtext += 'V'
elif (versetzt=='N'):
vtext += '<span class="nv">NV</span>'
elif (versetzt=='NP'):
vtext += '<span class="nv">NP</span>'
if (halbjahr==2):
body += '<td class="versetzung">'+vtext+'</td>'
for derkurs in sorted_kurse:
found = False
for meinkurs in kurse:
if meinkurs[0] == derkurs[0]:
found = True
note = meinkurs[3]
kursbez = meinkurs[0]
lehrer = meinkurs[1]
kursart = meinkurs[2]
mahnung = meinkurs[7]
if (len(note)==0):
note = '-'
topnoten = { '1+', '1', '1-', '2+', '2', '2-' }
defizite = { '5+', '5', '5-', '6' }
defizite_q = { '4-', '5+', '5', '5-', '6' }
cssklasse = ''
if (note in topnoten):
cssklasse = 'top'
if oberstufe:
if (klasse.startswith('EF')):
if (note in defizite):
cssklasse = 'def'
if (halbjahr==2) and (mahnung=='N'):
cssklasse = 'nw'
else:
if (note in defizite_q):
cssklasse = 'def'
else:
if (note in defizite):
cssklasse = 'def'
if (halbjahr==2) and (mahnung=='N'):
cssklasse = 'nw'
if (len(cssklasse)>0):
cssklasse = ' class="'+cssklasse+'"'
body += '<td'+cssklasse+'><span class="note">'+note+'</span>'
body += '</td>'
if (found==False):
body += '<td></td>'
body += '</tr>'
body += '</table>'
body += '<pdf:nextpage />'
return body

69
src/modules/pdf.py Normal file
View File

@@ -0,0 +1,69 @@
import os, sys
from xhtml2pdf import pisa
import folien
def erzeugePDFAusdruck(outputpath, alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, farbe):
body = ''
body += folien.erzeugeIndex(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, True)
body += folien.erzeugeKlassenFolien(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, True)
html_source = '<html><head>'
if farbe:
html_source += '<link rel="stylesheet" href="modules/pdf/pdf-color.css">'
else:
html_source += '<link rel="stylesheet" href="modules/pdf/pdf-sw.css">'
html_source += '</head><body>'+body+'</body></html>'
pisa.showLogging()
if farbe:
datei_ausgabe = outputpath + '/pdf/ausdruck-farbe.pdf'
else:
datei_ausgabe = outputpath + '/pdf/ausdruck-sw.pdf'
with open(datei_ausgabe, "w+b") as result_file:
# convert HTML to PDF
pisa_status = pisa.CreatePDF(
html_source, # page data
dest=result_file, # destination file
)
# Check for errors
if pisa_status.err:
print("Fehler bei der Erzeugung der PDF aus HTML!")
def erzeugePDFÜbersichtSI(outputpath, alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs):
body = ''
body += folien.erzeugeNotenTabellen(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, True)
html_source = '<html><head>'
html_source += '<link rel="stylesheet" href="modules/pdf/pdf-tabelle.css">'
html_source += '</head><body>'+body+'</body></html>'
pisa.showLogging()
datei_ausgabe = outputpath + '/pdf/uebersichten.pdf'
with open(datei_ausgabe, "w+b") as result_file:
# convert HTML to PDF
pisa_status = pisa.CreatePDF(
html_source, # page data
dest=result_file, # destination file
)
# Check for errors
if pisa_status.err:
print("Fehler bei der Erzeugung der PDF aus HTML!")

1
src/modules/pdf/home.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" transform="rotate(0 0 0)"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.45 4.90342C12.1833 4.70342 11.8167 4.70342 11.55 4.90342L5.05 9.77842C4.86115 9.92006 4.75 10.1423 4.75 10.3784V18.4998C4.75 18.9141 5.08579 19.2498 5.5 19.2498H9V16.9998C9 15.343 10.3431 13.9998 12 13.9998C13.6569 13.9998 15 15.343 15 16.9998V19.2498H18.5C18.9142 19.2498 19.25 18.9141 19.25 18.4998V10.3784C19.25 10.1423 19.1389 9.92006 18.95 9.77842L12.45 4.90342ZM10.65 3.70342C11.45 3.10342 12.55 3.10342 13.35 3.70342L19.85 8.57842C20.4166 9.00334 20.75 9.67021 20.75 10.3784V18.4998C20.75 19.7425 19.7426 20.7498 18.5 20.7498H14.25C13.8358 20.7498 13.5 20.4141 13.5 19.9998V16.9998C13.5 16.1714 12.8284 15.4998 12 15.4998C11.1716 15.4998 10.5 16.1714 10.5 16.9998V19.9998C10.5 20.4141 10.1642 20.7498 9.75 20.7498H5.5C4.25736 20.7498 3.25 19.7425 3.25 18.4998V10.3784C3.25 9.67021 3.58344 9.00334 4.15 8.57842L10.65 3.70342Z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,22 @@
@import url("pdf.css");
/* Einfärbungen */
td.top {
background-color: lightgreen;
}
td.def {
background-color: salmon;
}
td.nw {
background-color: orange;
}
.lk {
background-color: darkgrey;
}
.ab {
background-color: lightgrey;
}
.ue, .nv {
color: red;
}

View File

@@ -0,0 +1,21 @@
@import url("pdf.css");
/* Einfärbungen */
td.top {
}
td.def {
background-color: lightgrey;
}
td.nw {
background-color: #F3F4F9;
}
.lk {
background-color: darkgrey;
}
.ab {
background-color: darkgrey;
}
.ue, .nv {
background-color: lightgrey;
}

View File

@@ -0,0 +1,74 @@
@page {
size: a4 landscape;
margin-left: 1.5cm;
margin-right: 1.5cm;
margin-top: 1cm;
margin-bottom: 1cm;
}
/* Schrift */
h1, th, td, h1, h2, h3, p {
font-family: Helvetica;
}
th, td {
font-size: 120% !important;
}
th {
font-weight: 500 !important;
}
/* Notentabelle */
table, tr, td {
border: 0.5px solid black;
}
th, td {
text-align: center !important;
padding-left: 5px !important;
padding-right: 5px !important;
width: 10%;
}
th {
line-height: 90%;
vertical-align: bottom !important;
padding-top: 5px !important;
padding-bottom: 1px !important;
}
td {
line-height: 90%;
vertical-align: top !important;
padding-top: 3px !important;
padding-bottom: 3px !important;
}
th.name, td.name {
width: 30%;
}
th.fehl, td.fehl {
width: 15%;
}
th.versetzung, td.versetzung {
width: 10%;
}
/* Einfärbungen */
td.top {
background-color: lightgreen;
}
td.def {
background-color: salmon;
}
td.nw {
background-color: orange;
}
.lk {
background-color: darkgrey;
}
.ab {
background-color: lightgrey;
}
.ue, .nv {
color: red;
}

137
src/modules/pdf/pdf.css Normal file
View File

@@ -0,0 +1,137 @@
@page {
size: a4 portrait;
margin-left: 1.25cm;
margin-right: 1.25cm;
margin-top: 1.25cm;
margin-bottom: 1cm;
}
/* Seitentrennung */
h3 {
-pdf-keep-with-next: true;
}
table {
-pdf-keep-with-next: true;
}
p.fehlversetzung {
-pdf-keep-with-next: true;
}
p.separator {
-pdf-keep-with-next: false;
}
/* Schrift */
h1, th, td, h1, h2, h3, p {
font-family: Helvetica;
}
th, td {
font-size: 140% !important;
}
th {
font-weight: 500 !important;
}
/* Index */
h2 {
font-size: 300% !important;
text-align: center;
padding-top: 50pt;
}
p.index {
font-size: 250% !important;
text-align: center;
}
a {
text-decoration: none;
color: rgb(42, 118, 221);
}
p.time {
text-align: center !important;
font-size: 200%;
}
/* Überschriften Klasse und Schüler */
h1 {
font-size: 200% !important;
padding-left: -8pt;
}
img.icon {
width: 18pt;
height: 18pt;
padding-left: 0pt;
padding-right: 0pt;
}
h3 {
font-size: 175% !important;
padding-top: 0px !important;
padding-bottom: -15px !important;
}
/* Notentabelle */
table, tr, td {
border: 0.5px solid black;
}
th, td {
text-align: center !important;
padding-left: 5px !important;
padding-right: 5px !important;
width: 10%;
}
th.halbjahr, td.halbjahr {
width: 15% !important;
}
th {
vertical-align: bottom !important;
font-size: 160% !important;
border-spacing: 0px;
padding-left: 0px;
padding-right: 0px;
padding-top: 5px !important;
padding-bottom: 1px !important;
}
td {
line-height: 120%;
vertical-align: top !important;
border-spacing: 0px;
padding-left: 0px;
padding-right: 0px;
padding-top: 3px !important;
padding-bottom: 3px !important;
}
.note {
font-size: 140% !important;
}
.lehrer {
font-size: 75% !important;
}
.kursart {
font-size: 75% !important;
}
.epoche {
font-size: 60% !important;
}
.jahrgang {
font-size: 140% !important;
}
.schuljahr {
font-size: 80% !important;
}
/* Zusatzangaben */
p.fehlversetzung {
font-size: 160%;
}
p.hinweis {
font-size: 160%;
padding-top: -10pt;
}
p.separator {
padding-top: -10pt;
padding-bottom: -10pt;
}

29
src/modules/reveal.py Normal file
View File

@@ -0,0 +1,29 @@
import os, sys
import folien
def erzeugeHTMLSeite(outputpath, alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs):
body = ''
body += ' <div class="reveal">'
body += ' <div class="slides">'
body += folien.erzeugeIndex(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, False)
body += folien.erzeugeKlassenFolien(alleklassen, klassenschueler, allekurse, alleabschnitte, epochen, schuljahr, halbjahr, inputs, False)
body += ' </div>'
body += ' </div>'
text_file = open(os.path.join(outputpath, 'html/', 'folien.html'), "w", encoding="utf8")
header_file = open(os.path.join(outputpath, 'html/templates/', 'header.html'), encoding="utf8")
text_file.write(header_file.read())
text_file.write(body)
header_file = open(os.path.join(outputpath, 'html/templates/', 'footer.html'), encoding="utf8")
text_file.write(header_file.read())
text_file.close()

199
src/modules/schild.py Normal file
View File

@@ -0,0 +1,199 @@
import os, sys, csv
def liesDaten(inputpath, schuljahr, halbjahr, inputs):
# 0. Optionen festlegen
jahrgaenge_zusammen = ''
try:
jahrgaenge_zusammen = inputs["Jahrgänge"]["als_eine_Klasse"] + ","
except KeyError:
print('Der Schlüssel Jahrgänge oder "als_eine_Klasse" existiert nicht in der Input-Datei!')
exit(0)
ignoriere_jahrgaenge = ''
try:
ignoriere_jahrgaenge = inputs["Jahrgänge"]["ignoriere_Jahrgänge"] + ","
except KeyError:
print('Der Schlüssel Jahrgänge oder "ignoriere_Jahrgänge" existiert nicht in der Input-Datei!')
exit(0)
# 1. Leistungsdaten einlesen
leistungsdaten = open(os.path.join(inputpath, 'SchuelerLeistungsdaten.dat'), encoding="utf8")
leistungsdatenReader = csv.reader(leistungsdaten, delimiter='|')
linecount = 0
schuelercount = 0
schueler = ''
aktuell_kurse = []
alleklassen = set()
klassenschueler = {}
allekurse = {}
for row in leistungsdatenReader:
linecount = linecount + 1
if (linecount>1) and (len(row)>0): # Ignoriere den Header und evtl. Leerzeilen
zelle = row[0]
aktuell_klasse = ""
if "#" in zelle:
data = zelle.split('#')
aktuell_nachname = data[0].strip()
aktuell_klasse = data[1]
aktuell_jahrgang = aktuell_klasse[0:-1]
if ((aktuell_jahrgang+",") in jahrgaenge_zusammen):
aktuell_klasse = aktuell_jahrgang
else:
aktuell_nachname = zelle
aktuell_vorname = row[1].strip()
aktuell_gebdatum = row[2]
aktuell = aktuell_vorname+" "+aktuell_nachname+"#"+aktuell_gebdatum # Datensatz eindeutig bestimmt
aschuljahr = row[3]
ahalbjahr = row[4]
fach = row[5]
lehrer = row[6]
kursart = row[7]
kurszelle = row[8]
note = row[9]
abifach = row[10]
fehlstunden = row[17]
unentschuldigt = row[18]
mahnung = row[19]
if (row[20]==''):
sortierung = 1000
else:
sortierung = int(row[20])
if not(aktuell_klasse in alleklassen):
if not(aktuell_jahrgang+"," in ignoriere_jahrgaenge):
if not(aktuell_klasse+"," in ignoriere_jahrgaenge):
alleklassen.add(aktuell_klasse) # nur aktualisieren für aktuelles Halbjahr
if (aktuell!=schueler):
# neuen Schüler einfügen
if (not aktuell_klasse in klassenschueler):
dieschueler = []
dieschueler.append(aktuell)
klassenschueler[aktuell_klasse] = dieschueler
else:
schuelerliste = klassenschueler[aktuell_klasse]
schuelerliste.append(aktuell)
schueler = aktuell
aktkurs = []
aktkurs.append(fach)
aktkurs.append(lehrer)
aktkurs.append(kursart)
aktkurs.append(note)
aktkurs.append(abifach)
aktkurs.append(fehlstunden)
aktkurs.append(unentschuldigt)
aktkurs.append(mahnung)
aktkurs.append(sortierung)
diekurse = allekurse.get(aktuell+aschuljahr+ahalbjahr)
if diekurse:
diekurse.append(aktkurs)
else:
diekurse = []
diekurse.append(aktkurs)
allekurse[aktuell+aschuljahr+ahalbjahr] = diekurse
# 2. optional: Epochenunterricht einlesen
epochen = {}
epochenpfad = os.path.join(inputpath, 'epoche.csv')
if os.path.exists(epochenpfad):
epochendaten = open(epochenpfad, encoding="utf8")
epochendatenReader = csv.reader(epochendaten, delimiter='|')
linecount = 0
for row in epochendatenReader:
linecount = linecount + 1
if linecount > 1: # Ignoriere den header
klasse = row[0]
faecher = row[1]
epochen[klasse] = faecher+","
# 3. Lernabschnittsdaten einlesen
abschnittsdaten = open(os.path.join(inputpath, 'SchuelerLernabschnittsdaten.dat'), encoding="utf8")
abschnittsdatenReader = csv.reader(abschnittsdaten, delimiter='|')
alleabschnitte = {}
linecount = 0
for row in abschnittsdatenReader:
linecount = linecount + 1
if (linecount > 1) and (len(row)>0): # Ignoriere den header
zelle = row[0]
aktuell_klasse = ""
if "#" in zelle:
data = zelle.split('#')
aktuell_nachname = data[0].strip()
aktuell_klasse = data[1]
else:
aktuell_nachname = zelle
aktuell_vorname = row[1].strip()
aktuell_gebdatum = row[2]
aktuell = aktuell_vorname+" "+aktuell_nachname+"#"+aktuell_gebdatum # Datensatz eindeutig bestimmt
aschuljahr = row[3]
ahalbjahr = row[4]
ajahrgang = row[5]
wertung = row[14]
wdh = row[15]
versetzt = row[17]
abschluss = row[18]
fehlstunden = row[22]
unentschuldigt = row[23]
abschlusstyp = row[24]
aktabschnitt = []
aktabschnitt.append(wdh)
aktabschnitt.append(versetzt)
aktabschnitt.append(abschluss)
aktabschnitt.append(abschlusstyp)
aktabschnitt.append(fehlstunden)
aktabschnitt.append(unentschuldigt)
aktabschnitt.append(ajahrgang)
aktabschnitt.append(wertung)
alleabschnitte[aktuell+str(aschuljahr)+str(ahalbjahr)] = aktabschnitt
return alleklassen, klassenschueler, allekurse, alleabschnitte, epochen