Initial commit
This commit is contained in:
commit
536ff43ce4
158 files changed
+30355
No files matched your search
@@ -0,0 +1,96 @@
|
||||
"""Leerlingfacturatie: facturen en creditnota's van de leerlingen van de actieve school (Informat Rekeningen API)."""
|
||||
import csv
|
||||
import io
|
||||
import time
|
||||
from datetime import date
|
||||
|
||||
from flask import Blueprint, render_template, request, Response, redirect, url_for, flash
|
||||
|
||||
from blueprints.auth import login_required
|
||||
from rechten import recht_vereist
|
||||
from services.facturatie_service import FacturatieService, FacturatieFout, schooljaren
|
||||
from tenancy import huidige_school
|
||||
|
||||
facturatie_bp = Blueprint('facturatie', __name__)
|
||||
|
||||
STATUS_LABELS = {'open': 'Open', 'gedeeltelijk': 'Gedeeltelijk betaald', 'betaald': 'Betaald', 'credit': 'Creditnota'}
|
||||
|
||||
|
||||
def _schooljaar():
|
||||
jaren = schooljaren()
|
||||
gekozen = request.args.get('schooljaar') or ''
|
||||
return gekozen if gekozen in jaren else jaren[0], jaren
|
||||
|
||||
|
||||
@facturatie_bp.route("/", methods=["GET"])
|
||||
@login_required
|
||||
@recht_vereist('leerlingfacturatie')
|
||||
def overzicht():
|
||||
school = huidige_school()
|
||||
schooljaar, jaren = _schooljaar()
|
||||
rijen, groepen, fout, opgehaald = [], [], None, None
|
||||
if not school.heeft('INFORMAT_ID', 'INFORMAT_SECRET'):
|
||||
fout = "Informat is nog niet ingesteld voor deze school (🔌 Koppelingen › Informat)."
|
||||
else:
|
||||
try:
|
||||
rijen, groepen, t = FacturatieService().facturen(schooljaar, vernieuw=bool(request.args.get('vernieuw')))
|
||||
opgehaald = time.strftime('%d-%m-%Y %H:%M', time.localtime(t))
|
||||
except FacturatieFout as e:
|
||||
fout = str(e)
|
||||
except Exception as e:
|
||||
fout = f"Facturen ophalen mislukt: {e}"
|
||||
return render_template("facturatie.html", rijen=rijen, groepen=groepen, fout=fout, opgehaald=opgehaald,
|
||||
schooljaar=schooljaar, jaren=jaren, school_naam=school.naam, labels=STATUS_LABELS,
|
||||
today=date.today())
|
||||
|
||||
|
||||
@facturatie_bp.route("/pdf/<toegangsgroep>/<invoice_id>", methods=["GET"])
|
||||
@login_required
|
||||
@recht_vereist('leerlingfacturatie')
|
||||
def pdf(toegangsgroep, invoice_id):
|
||||
try:
|
||||
inhoud = FacturatieService().pdf(toegangsgroep, invoice_id)
|
||||
except FacturatieFout as e:
|
||||
flash(str(e), "error")
|
||||
return redirect(url_for('facturatie.overzicht', schooljaar=request.args.get('schooljaar')))
|
||||
except Exception as e:
|
||||
flash(f"De PDF kon niet opgehaald worden: {e}", "error")
|
||||
return redirect(url_for('facturatie.overzicht', schooljaar=request.args.get('schooljaar')))
|
||||
naam = (request.args.get('naam') or 'factuur').replace('"', '')
|
||||
return Response(inhoud, mimetype='application/pdf',
|
||||
headers={'Content-Disposition': f'inline; filename="{naam}.pdf"'})
|
||||
|
||||
|
||||
@facturatie_bp.route("/export.csv", methods=["GET"])
|
||||
@login_required
|
||||
@recht_vereist('leerlingfacturatie')
|
||||
def export():
|
||||
"""CSV met dezelfde filters als de tabel: ?schooljaar=&groep=&status=&zoek="""
|
||||
schooljaar, _ = _schooljaar()
|
||||
try:
|
||||
rijen, _, _ = FacturatieService().facturen(schooljaar)
|
||||
except Exception as e:
|
||||
flash(str(e), "error")
|
||||
return redirect(url_for('facturatie.overzicht', schooljaar=schooljaar))
|
||||
groep, status = request.args.get('groep') or '', request.args.get('status') or ''
|
||||
zoek = (request.args.get('zoek') or '').strip().lower()
|
||||
if groep:
|
||||
rijen = [r for r in rijen if str(r['groep_id']) == groep]
|
||||
if status == 'onbetaald':
|
||||
rijen = [r for r in rijen if r['status'] in ('open', 'gedeeltelijk')]
|
||||
elif status:
|
||||
rijen = [r for r in rijen if r['status'] == status]
|
||||
if zoek:
|
||||
rijen = [r for r in rijen if zoek in ' '.join(str(r[k]) for k in ('naam', 'voornaam', 'stamnummer', 'klas', 'groep', 'ogm')).lower()]
|
||||
bedrag = lambda x: f"{x:.2f}".replace('.', ',')
|
||||
datum = lambda d: d.strftime('%d/%m/%Y') if d else ''
|
||||
buf = io.StringIO()
|
||||
w = csv.writer(buf, delimiter=';')
|
||||
w.writerow(['Naam', 'Voornaam', 'Stamnummer', 'Klas', 'Factuurgroep', 'Soort', 'Datum', 'Vervaldag', 'Totaal', 'Betaald',
|
||||
'Open', 'Status', 'Gestructureerde mededeling'])
|
||||
for r in rijen:
|
||||
w.writerow([r['naam'], r['voornaam'], r['stamnummer'], r['klas'], r['groep'], 'Creditnota' if r['type'] == 'CREDIT_NOTE' else 'Factuur',
|
||||
datum(r['datum']), datum(r['vervaldag']), bedrag(r['totaal'] * r['teken']), bedrag(r['betaald'] * r['teken']), bedrag(r['open'] * r['teken']),
|
||||
STATUS_LABELS.get(r['status'], r['status']), r['ogm']])
|
||||
return Response('' + buf.getvalue(), mimetype='text/csv; charset=utf-8', headers={
|
||||
'Content-Disposition': f"attachment; filename=Facturen_{huidige_school().code}_{schooljaar}_{date.today():%Y%m%d}.csv"})
|
||||
Reference in new issue
Block a user