Example #1
0
def make1(pid, rtype, rtag, kname):
    """View: Edit data for the report to be created, submit to build it.
    <rtype> is the report type.
    <rtag> is a TERM field entry from the GRADES table (term or date).
    <kname> is the school-class with stream tag.
    """
    class _Form(FlaskForm):
        DATE_D = DateField('Ausgabedatum', validators=[InputRequired()])

    def prepare():
        # Get the name of the relevant grade scale configuration file:
        grademap = klass.match_map(CONF.MISC.GRADE_SCALE)
        gradechoices = [(g, g) for g in CONF.GRADES[grademap].VALID]
        # Get existing grades
        grades = getGradeData(schoolyear, pid, rtag)

        ### Get template fields which need to be set here
        gdata = GradeReportData(schoolyear, rtype, klass)
        groups = []
        for sgroup in sorted(gdata.sgroup2sids):  # grouped subject-ids
            fields = []
            for sid in gdata.sgroup2sids[sgroup]:
                if sid.startswith('__'):
                    gcalc.append(sid)
                    continue
                sname = gdata.courses.subjectName(sid)
                try:
                    grade = grades['GRADES'][sid]
                except:
                    grade = '/'
                sfield = SelectField(sname,
                                     choices=gradechoices,
                                     default=grade)
                key = sgroup + '_' + sid
                setattr(_Form, key, sfield)
                fields.append(key)
            if fields:
                groups.append((sgroup, fields))
        # "Extra" fields like "_GS" (one initial underline!)
        xfields = []
        # Build roughly as for subjects, but in group <None>
        for tag in gdata.alltags:
            if tag.startswith('grades._'):
                xfield = tag.split('.', 1)[1]
                if xfield[1] == '_':
                    # Calculated fields should not be presented here
                    continue
                # Get options/field type
                try:
                    xfconf = CONF.GRADES.XFIELDS[xfield]
                    values = xfconf.VALUES
                except:
                    flash(
                        "Feld %s unbekannt: Vorlage %s" %
                        (xfield, gdata.template.filename), "Error")
                    continue
                # Check class/report-type validity
                rtypes = klass.match_map(xfconf.KLASS)
                if not rtypes:
                    continue
                if rtype not in rtypes.split():
                    continue
                # Get existing value for this field
                try:
                    val = grades['GRADES'][xfield]
                except:
                    val = None
                # Determine field type
                if xfield.endswith('_D'):
                    # An optional date field:
                    d = datetime.date.fromisoformat(val) if val else None
                    sfield = DateField(xfconf.NAME,
                                       default=d,
                                       validators=[Optional()])
                else:
                    try:
                        # Assume a select field.
                        # The choices depend on the tag.
                        choices = [(c, c) for c in xfconf.VALUES]
                        sfield = SelectField(xfconf.NAME,
                                             choices=choices,
                                             default=val)
                    except:
                        flash(
                            "Unbekannter Feldtyp: %s in Vorlage %s" %
                            (xfield, gdata.template.filename), "Error")
                        continue
                key = 'Z_' + xfield
                setattr(_Form, key, sfield)
                xfields.append(key)
        if xfields:
            groups.append((None, xfields))
        return groups

    def enterGrades():
        # Add calculated grade entries
        gradeCalc(gmap, gcalc)
        # Enter grade data into db
        singleGrades2db(schoolyear,
                        pid,
                        klass,
                        term=rtag,
                        date=DATE_D,
                        rtype=rtype,
                        grades=gmap)
        return True

    schoolyear = session['year']
    klass = Klass(kname)
    gcalc = []  # list of composite sids
    groups = REPORT.wrap(prepare, suppressok=True)
    if not groups:
        # Return to caller
        return redirect(request.referrer)

    # Get pupil data
    pupils = Pupils(schoolyear)
    pdata = pupils.pupil(pid)
    pname = pdata.name()

    form = _Form()
    if form.validate_on_submit():
        # POST
        DATE_D = form.DATE_D.data.isoformat()
        gmap = {}  # grade mapping {sid -> "grade"}
        for g, keys in groups:
            for key in keys:
                gmap[key.split('_', 1)[1]] = form[key].data
        if REPORT.wrap(enterGrades, suppressok=True):
            pdfBytes = REPORT.wrap(makeOneSheet, schoolyear, DATE_D, pdata,
                                   rtag, rtype)
            session['filebytes'] = pdfBytes
            session['download'] = 'Notenzeugnis_%s.pdf' % (
                pdata['PSORT'].replace(' ', '_'))
            return redirect(url_for('bp_grades.pupils', klass=klass.klass))

#TODO: ?
# There is no point to +/-, as these won't appear in the report and
# are only intended for Notenkonferenzen. However, they might be of
# interest for future reference?

# GET
# Set initial date of issue
    try:
        form.DATE_D.data = datetime.date.fromisoformat(rtag)
    except ValueError:
        form.DATE_D.data = datetime.date.today()
    return render_template(os.path.join(_BPNAME, 'make1.html'),
                           form=form,
                           groups=groups,
                           heading=_HEADING,
                           pid=pid,
                           pname=pname,
                           rtype=rtype,
                           klass=klass.klass,
                           stream=klass.stream)
Example #2
0
def pupil(pid):
    """View: select report type and [edit-existing vs. new] for single report.

    All existing report dates for this pupil will be presented for
    selection.
    If there are no existing dates for this pupil, the only option is to
    construct a new one.
    Also a report type can be selected. The list might include invalid
    types as it is difficult at this stage (considering potential changes
    of stream or even school-class) to determine exactly which ones are
    valid.
    """
    class _Form(FlaskForm):
        KLASS = SelectField("Klasse")
        STREAM = SelectField("Maßstab")
        EDITNEW = SelectField("Ausgabedatum")
        RTYPE = SelectField("Zeugnistyp")

    schoolyear = session['year']
    # Get pupil data
    pupils = Pupils(schoolyear)
    pdata = pupils.pupil(pid)
    pname = pdata.name()
    klass = pdata.getKlass(withStream=True)
    # Get existing dates.
    db = DB(schoolyear)
    rows = db.select('GRADES', PID=pid)
    dates = [_NEWDATE]
    for row in db.select('GRADES', PID=pid):
        dates.append(row['TERM'])
    # If the stream, or even school-class have changed since an
    # existing report, the templates and available report types may be
    # different. To keep it simple, a list of all report types from the
    # configuration file GRADES.REPORT_TEMPLATES is presented for selection.
    # An invalid choice can be flagged at the next step.
    # If there is a mismatch between school-class/stream of the pupil as
    # selected on this page and that of the existing GRADES entry, a
    # warning can be shown at the next step.
    rtypes = [
        rtype for rtype in CONF.GRADES.REPORT_TEMPLATES if rtype[0] != '_'
    ]

    kname = klass.klass
    stream = klass.stream
    form = _Form(KLASS=kname, STREAM=stream, RTYPE=_DEFAULT_RTYPE)
    form.KLASS.choices = [(k, k) for k in reversed(pupils.classes())]
    form.STREAM.choices = [(s, s) for s in CONF.GROUPS.STREAMS]
    form.EDITNEW.choices = [(d, d) for d in dates]
    form.RTYPE.choices = [(t, t) for t in rtypes]

    if form.validate_on_submit():
        # POST
        klass = Klass.fromKandS(form.KLASS.data, form.STREAM.data)
        rtag = form.EDITNEW.data
        rtype = form.RTYPE.data
        kmap = CONF.GRADES.REPORT_TEMPLATES[rtype]
        tfile = klass.match_map(kmap)
        if tfile:
            return redirect(
                url_for('bp_grades.make1',
                        pid=pid,
                        kname=klass,
                        rtag=rtag,
                        rtype=rtype))
        else:
            flash(
                "Zeugnistyp '%s' nicht möglich für Gruppe %s" % (rtype, klass),
                "Error")

    # GET
    return render_template(os.path.join(_BPNAME, 'pupil.html'),
                           form=form,
                           heading=_HEADING,
                           klass=kname,
                           pname=pname)