def makeAbiReport (outpath, pdata): """Build an Abitur grade report for a pupil. The necessary information is supplied in the mapping <pdata>: {key: value}. The keys are user-fields in the document template (odt), the values are the strings to be inserted. The resulting file is placed at <outpath>, creating leading folders if necessary. <outpath> need not end in '.odt', if not present it will be added automatically. """ NOTCHOSEN = CONF.FORMATTING.NOTCHOSEN ## Get template path template = Paths.getUserPath ('FILE_ABITUR_REPORT_TEMPLATE') # fieldnames = OdtUserFields.listUserFields (template) ## Convert the dates. for f in pdata: d = pdata [f] if f.endswith ('_D'): # print ("???", f, d) if d: pdata [f] = Dates.dateConv (d) # Substitute non-date empty cells elif not d: pdata [f] = NOTCHOSEN folder = os.path.dirname (outpath) if not os.path.isdir (folder): os.makedirs (folder) ofile, used, missing = OdtUserFields.fillUserFields ( template, outpath, pdata) REPORT.Info (_ABIREPORTDONE, path=ofile) return ofile
def test_02(): pdfBytes = makeSheets(_year, _date, Klass(_klass)) folder = Paths.getUserPath('DIR_TEXT_REPORT_TEMPLATES') fpath = os.path.join(folder, 'test.pdf') with open(fpath, 'wb') as fh: fh.write(pdfBytes) REPORT.Test(" --> %s" % fpath)
def test_05(): _klass_stream = Klass('11') pdfBytes = makeReports(_year, _term, _klass_stream, _date) folder = Paths.getUserPath('DIR_GRADE_REPORT_TEMPLATES') fpath = os.path.join(folder, 'test_%s_%s.pdf' % (_klass_stream, _date)) with open(fpath, 'wb') as fh: fh.write(pdfBytes)
def __init__ (self, schoolyear, klass): self._class = klass self._year = schoolyear self._month = Month (self._year) # Get the template self._tpath = Paths.getUserPath ('TEMPLATE_ATTENDANCE_TABLE') self._table = Table (self._tpath) self._wsInfo = self._table.getSheet (0) self._wsMonth = self._table.getSheet (1)
def test_07(): # Reports for second term _term = '2' _date = '2016-06-22' for _ks in '11', '12.RS-HS-_', '12.Gym': _klass_stream = Klass(_ks) pdfBytes = makeReports(_year, _term, _klass_stream, _date) folder = Paths.getUserPath('DIR_GRADE_REPORT_TEMPLATES') fpath = os.path.join(folder, 'test_%s_%s.pdf' % (_klass_stream, _date)) with open(fpath, 'wb') as fh: fh.write(pdfBytes)
def tSheets(schoolyear, manager, date): courses = CourseTables(schoolyear) tidmap = {} for k in courses.classes(): klass = Klass(k) sid2tids = courses.filterText(klass) for sid, tids in sid2tids.items(): if tids.TEXT: if not tids: tids = [_nn] for tid in tids: try: tmap = tidmap[tid] except: tidmap[tid] = {klass.klass: {sid}} continue try: tmap[klass.klass].add(sid) except: tmap[klass.klass] = {sid} noreports = [] teachers = [] for tid in courses.teacherData: lines = [] tname = courses.teacherData.getTeacherName(tid) try: tmap = tidmap[tid] except: noreports.append(tname) continue for k in sorted(tmap): for sid in tmap[k]: sname = courses.subjectName(sid) lines.append((k, sname)) teachers.append((tname, lines)) tpdir = Paths.getUserPath('DIR_TEXT_REPORT_TEMPLATES') templateLoader = jinja2.FileSystemLoader(searchpath=tpdir) templateEnv = jinja2.Environment(loader=templateLoader, autoescape=True) tpfile = 'summary-teachers.html' try: template = templateEnv.get_template(tpfile) except: REPORT.Fail(_NOTEMPLATE, path=os.path.join(tpdir, tpfile)) source = template.render(year=printSchoolYear(schoolyear), manager=manager, date=Dates.dateConv(date), teachers=teachers, noreports=noreports) html = HTML(string=source) pdfBytes = html.write_pdf() return pdfBytes
def test_01(): from wz_compat.template import openTemplate, getTemplateTags, pupilFields from glob import glob fbase = Paths.getUserPath('DIR_TEMPLATES') fx = 'Notenzeugnis/*.html' fmask = os.path.join(fbase, *fx.split('/')) for f in glob(fmask): fname = os.path.basename(f) fpath = fx.rsplit('/', 1)[0] + '/' + os.path.basename(f) REPORT.Test("TEMPLATE: %s" % fpath) t = openTemplate(fpath) tags = getTemplateTags(t) REPORT.Test("Pupil fields: %s" % repr(pupilFields(tags)))
def test_03(): _k = '12K' _k = '12' _klass = Klass(_k) pupils = Pupils(_year) plist = pupils.classPupils(_klass) pdata = plist[0] pdfBytes = makeOneSheet(_year, _date, _klass, pdata) folder = Paths.getUserPath('DIR_TEXT_REPORT_TEMPLATES') fpath = os.path.join(folder, 'test1.pdf') with open(fpath, 'wb') as fh: fh.write(pdfBytes) REPORT.Test(" --> %s" % fpath)
def test_06(): #TODO: Perhaps if _GS is set, the type should be overriden? _klass = Klass('12') _pid = '200407' pupils = Pupils(_year) pall = pupils.classPupils(_klass) # list of data for all pupils pdata = pall.pidmap[_pid] pdfBytes = makeOneSheet(_year, '2016-02-03', pdata, _term, 'Abgang') folder = Paths.getUserPath('DIR_GRADE_REPORT_TEMPLATES') ptag = pdata['PSORT'].replace(' ', '_') fpath = os.path.join(folder, 'test_%s_Abgang.pdf' % ptag) with open(fpath, 'wb') as fh: fh.write(pdfBytes) REPORT.Test(" --> %s" % fpath)
def choiceTable(schoolyear, klass): """Build a subject choice table for the given school-class. <klass> is a <Klass> instance. """ template = Paths.getUserPath('FILE_SUBJECT_CHOICE_TEMPLATE') table = KlassMatrix(template) # Title already set in template: #table.setTitle("Kurswahl") # "Translation" of info items: kmap = CONF.TABLES.COURSE_PUPIL_FIELDNAMES info = ( (kmap['SCHOOLYEAR'], str(schoolyear)), (kmap['CLASS'], klass.klass), ) table.setInfo(info) ### Manage subjects courses = CourseTables(schoolyear) sid2tlist = courses.classSubjects(klass) # <table.headers> is a list of cell values in the header row. rsid = table.rowindex - 1 # row tag for sid rsname = table.rowindex # row tag for subject name # Go through the template columns and check if they are needed: for sid in sid2tlist: if sid[0] != '_': sname = courses.subjectName(sid) # Add subject col = table.nextcol() table.write(rsid, col, sid) table.write(rsname, col, sname) # Delete excess columns table.delEndCols(col + 1) ### Add pupils pupils = Pupils(schoolyear) for pdata in pupils.classPupils(klass): row = table.nextrow() table.write(row, 0, pdata['PID']) table.write(row, 1, pdata.name()) table.write(row, 2, pdata['STREAM']) # Delete excess rows table.delEndRows(row + 1) ### Save file table.protectSheet() return table.save()
def openTemplate(tpath): """Return a jinja2 <Template> instance. <tpath> is the path (folder separator '/') to the template file, relative to the main templates folder. The filepath is available as attribute <filename>. """ tpsplit = tpath.split('/') fname = tpsplit.pop() tpdir = Paths.getUserPath('DIR_TEMPLATES') if tpsplit: tpdir = os.path.join(tpdir, *tpsplit) templateLoader = jinja2.FileSystemLoader(searchpath=tpdir) templateEnv = jinja2.Environment(loader=templateLoader, autoescape=True) try: return templateEnv.get_template(fname) except: REPORT.Fail(_NO_TEMPLATE, fname=os.path.join(tpdir, fname))
def ksSheets(schoolyear, manager, date): courses = CourseTables(schoolyear) tidmap = { tid: courses.teacherData.getTeacherName(tid) for tid in courses.teacherData } klasses = [] for k in courses.classes(): klass = Klass(k) sidmap = {} sid2tids = courses.filterText(klass) for sid, tids in sid2tids.items(): if tids.TEXT: if not tids: tids = [_nn] for tid in tids: try: sidmap[sid].add(tid) except: sidmap[sid] = {tid} lines = [] for sid, tids in sidmap.items(): sname = courses.subjectName(sid) for tid in tids: lines.append((sname, tidmap[tid])) klasses.append((klass.klass, lines)) tpdir = Paths.getUserPath('DIR_TEXT_REPORT_TEMPLATES') templateLoader = jinja2.FileSystemLoader(searchpath=tpdir) templateEnv = jinja2.Environment(loader=templateLoader, autoescape=True) tpfile = 'summary-classes.html' try: template = templateEnv.get_template(tpfile) except: REPORT.Fail(_NOTEMPLATE, path=os.path.join(tpdir, tpfile)) source = template.render(year=printSchoolYear(schoolyear), manager=manager, date=Dates.dateConv(date), klasses=klasses) html = HTML(string=source) pdfBytes = html.write_pdf() return pdfBytes
def makeAbiTables (schoolyear, klass, date): """Build grade tables (one for each student) for the final Abitur grades. These tables are used to prepare the grades for (automatic) entry into the certificates. The new tables are placed in a subfolder of the normal folder (see configuration file PATHS: FILE_ABITABLE_NEW). This is to avoid accidentally overwriting existing tables which already contain data. Most of the necessary "cleverness" is built into the template file. """ template = Paths.getUserPath ('FILE_ABITUR_GRADE_TEMPLATE') outpath = Paths.getYearPath (schoolyear, 'FILE_ABITABLE_NEW', klass=klass) for f in glob (os.path.join (os.path.dirname (outpath), '*')): os.remove (f) outpath += '.xlsx' sheetname = CONF.TABLES.ABITUR_RESULTS.GRADE_TABLE_SHEET FrHr = {} for v in CONF.TABLES.ABITUR_RESULTS.P_FrHr: k, v = v.split (':') FrHr [k] = v ncourses = CONF.TABLES.ABITUR_RESULTS.NCOURSES.nat () courseTables = CourseTables (schoolyear) pupils = Pupils (schoolyear).classPupils (klass, date) sid2info = courseTables.filterGrades (klass, realonly=True) subjects = [] for sid, sinfo in sid2info.items (): subjects.append ((sid, sinfo.COURSE_NAME)) teacherMatrix = FormattedMatrix.readMatrix (schoolyear, 'FILE_CLASS_SUBJECTS', klass) i = 0 # pid index for ordering files files = [] # list of created files (full paths) for pdata in pupils: pid = pdata ['PID'] pname = pdata.name () i += 1 filepath = outpath.replace ('*', '{pnum:02d}-{pid}-{name}'.format ( pnum=i, pid=pid, name=Paths.asciify (pname))) fields = {'YEAR': str (schoolyear), 'LASTNAME': pdata ['LASTNAME'], 'FIRSTNAMES': pdata ['FIRSTNAMES'], 'DOB_D': pdata ['DOB_D'], 'POB': pdata ['POB'], 'HOME': pdata ['HOME']} try: fields ['FrHr'] = FrHr [pdata ['SEX']] except: REPORT.Error (_BADSEXFIELD, klass=klass, pname=pname, sex=pdata ['SEX']) fields ['FrHr'] = ' ' f = 0 for sid, sname in subjects: if not teacherMatrix [pid][sid]: continue f += 1 fields ['F' + str (f)] = sname.split ('|') [0].rstrip () if ncourses and f != ncourses: REPORT.Error (_NOTNCOURSES, klass=klass, pname=pname, n=f, nc0=ncourses) continue unused = XLS_template (filepath, template, fields, sheetname=sheetname) files.append (filepath) REPORT.Info (_MADENTABLES, klass=klass, n=len (files)) return files
def test_02 (): ifile = Paths.getUserPath ('FILE_ABITUR_GRADE_EXAMPLE') outfile = os.path.join (os.path.dirname (ifile), 'tmp', 'AbiZeugnis.odt') pdata = readTableData (ifile, table='Daten') REPORT.Test ("??? Fields: %s" % repr(pdata)) REPORT.Test ("\n --> %s" % makeAbiReport (outfile, pdata))
def makeGradeTable(schoolyear, term, klass, title): """Make a grade table for the given school-class/group. <klass> is a <Klass> instance. <term> is a string. """ # Info concerning grade tables: gtinfo = CONF.GRADES.GRADE_TABLE_INFO # Determine table template t = klass.match_map(gtinfo.GRADE_TABLE_TEMPLATE) if not t: REPORT.Fail(_NO_TEMPLATE, ks=klass) template = Paths.getUserPath('FILE_GRADE_TABLE_TEMPLATE').replace('*', t) table = KlassMatrix(template) ### Insert general info table.setTitle(title) # "Translation" of info items: kmap = CONF.TABLES.COURSE_PUPIL_FIELDNAMES info = ( (kmap['SCHOOLYEAR'], str(schoolyear)), (kmap['CLASS'], klass.klass), (kmap['TERM'], term) ) table.setInfo(info) ### Manage subjects courses = CourseTables(schoolyear) sid2tlist = courses.classSubjects(klass) # print ("???1", list(sid2tlist)) # Go through the template columns and check if they are needed: colmap = {} col = _FIRSTSIDCOL for k in table.headers[_FIRSTSIDCOL:]: if k: if k in sid2tlist: colmap[k] = col elif k == _UNUSED: table.hideCol(col, True) else: # Handle extra _tags klassmap = gtinfo.get(k) if klassmap: m = klass.match_map(klassmap) if m and term in m.split(): colmap[k] = col else: table.hideCol(col, True) else: table.hideCol(col, True) col += 1 # print("???COLMAP:", colmap) ### Add pupils pupils = Pupils(schoolyear) for pdata in pupils.classPupils(klass): row = table.nextrow() pid = pdata['PID'] table.write(row, 0, pid) table.write(row, 1, pdata.name()) table.write(row, 2, pdata['STREAM']) # Add existing grades gd = getGradeData(schoolyear, pid, term) # print("\n???", pid, gd) if gd: grades = gd['GRADES'] if grades: for k, v in grades.items(): try: col = colmap[k] except KeyError: # print("!!! excess subject:", k) continue if k: if k.startswith('__'): # Calculated entry continue table.write(row, col, v) # Delete excess rows table.delEndRows(row + 1) ### Save file table.protectSheet() return table.save()
def stripTable(schoolyear, term, klass, title): """Build a basic pupil/subject table for entering grades. <klass> is a <Klass> instance. <term> is a string. """ # Info concerning grade tables: gtinfo = CONF.GRADES.GRADE_TABLE_INFO ### Determine table template (output) t = klass.match_map(gtinfo.GRADE_INPUT_TEMPLATE) if not t: REPORT.Fail(_NO_ITEMPLATE, ks=klass) template = Paths.getUserPath('FILE_GRADE_TABLE_TEMPLATE').replace('*', t) table = KlassMatrix(template) table.setTitle(title) table.setInfo([]) ### Read input table template (for determining subjects and order) # Determine table template (input) t = klass.match_map(gtinfo.GRADE_TABLE_TEMPLATE) if not t: REPORT.Fail(_NO_TEMPLATE, ks=klass) template0 = Paths.getUserPath('FILE_GRADE_TABLE_TEMPLATE').replace('*', t) table0 = KlassMatrix(template0) i, x = 0, 0 for row0 in table0.rows: i += 1 if row0[0] and row0[0] != '#': # The subject key line break # <row0> is the title row. ### Manage subjects courses = CourseTables(schoolyear) sid2tlist = courses.classSubjects(klass) # print ("???1", list(sid2tlist)) # Set klass cell rowix = table.rowindex - 1 table.write(rowix, 0, table.headers[0].replace('*', klass.klass)) # Go through the template columns and check if they are needed: col = 0 for sid in row0: if sid and sid[0] != '_' and sid in sid2tlist: sname = courses.subjectName(sid) # Add subject col = table.nextcol() table.write(rowix, col, sname) # Delete excess columns table.delEndCols(col + 1) ### Add pupils pupils = Pupils(schoolyear) for pdata in pupils.classPupils(klass): row = table.nextrow() table.write(row, 0, pdata.name()) table.write(row, 1, pdata['STREAM']) # Delete excess rows table.delEndRows(row + 1) ### Save file table.protectSheet() return table.save()