forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
87
app/but/bulletin_but_court.py
Normal file
87
app/but/bulletin_but_court.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
##############################################################################
|
||||||
|
# ScoDoc
|
||||||
|
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
||||||
|
# See LICENSE
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Génération bulletin BUT synthétique en une page
|
||||||
|
|
||||||
|
On génère du HTML. Il sera si possible traduit en PDF par weasyprint.
|
||||||
|
|
||||||
|
Le HTML est lui même généré à partir d'un template Jinja.
|
||||||
|
|
||||||
|
## Données
|
||||||
|
|
||||||
|
Ces données sont des objets passés au template.
|
||||||
|
|
||||||
|
- `etud: Identite` : l'étudiant
|
||||||
|
- `formsemestre: FormSemestre` : le formsemestre d'où est émis ce bulletin
|
||||||
|
- `bulletins_sem: BulletinBUT` les données bulletins pour tous les étudiants
|
||||||
|
- `bul: dict` : le bulletin (dict, même structure que le json publié)
|
||||||
|
- `cursus: EtudCursusBUT`: infos sur le cursus BUT (niveaux validés etc)
|
||||||
|
- `decision_ues: dict`: `{ acronyme_ue : { 'code' : 'ADM' }}` accès aux décisions
|
||||||
|
de jury d'UE
|
||||||
|
- `ects_total` : nombre d'ECTS validées dans ce cursus
|
||||||
|
- `ue_validation_by_niveau : dict` : les validations d'UE de chaque niveau du cursus
|
||||||
|
"""
|
||||||
|
import datetime
|
||||||
|
import time
|
||||||
|
|
||||||
|
from flask import render_template, url_for
|
||||||
|
from flask import g, request
|
||||||
|
|
||||||
|
from app.but.bulletin_but import BulletinBUT
|
||||||
|
from app.but import cursus_but, validations_view
|
||||||
|
from app.decorators import (
|
||||||
|
scodoc,
|
||||||
|
permission_required,
|
||||||
|
)
|
||||||
|
from app.models import FormSemestre, FormSemestreInscription, Identite
|
||||||
|
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences
|
||||||
|
from app.scodoc.sco_logos import find_logo
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
from app.views import notes_bp as bp
|
||||||
|
from app.views import ScoData
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/bulletin_but/<int:formsemestre_id>/<int:etudid>")
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoView)
|
||||||
|
def bulletin_but(formsemestre_id: int, etudid: int = None):
|
||||||
|
"""Page HTML affichant le bulletin BUT simplifié"""
|
||||||
|
etud: Identite = Identite.query.get_or_404(etudid)
|
||||||
|
formsemestre: FormSemestre = (
|
||||||
|
FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
|
.join(FormSemestreInscription)
|
||||||
|
.filter_by(etudid=etudid)
|
||||||
|
.first_or_404()
|
||||||
|
)
|
||||||
|
bulletins_sem = BulletinBUT(formsemestre)
|
||||||
|
bul = bulletins_sem.bulletin_etud(etud, formsemestre) # dict
|
||||||
|
decision_ues = {x["acronyme"]: x for x in bul["semestre"]["decision_ue"]}
|
||||||
|
cursus = cursus_but.EtudCursusBUT(etud, formsemestre.formation)
|
||||||
|
refcomp = formsemestre.formation.referentiel_competence
|
||||||
|
if refcomp is None:
|
||||||
|
raise ScoNoReferentielCompetences(formation=formsemestre.formation)
|
||||||
|
ue_validation_by_niveau = validations_view.get_ue_validation_by_niveau(
|
||||||
|
refcomp, etud
|
||||||
|
)
|
||||||
|
ects_total = sum((v.ects() for v in ue_validation_by_niveau.values()))
|
||||||
|
|
||||||
|
logo = find_logo(logoname="header", dept_id=g.scodoc_dept_id)
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"but/bulletin_court_page.j2",
|
||||||
|
bul=bul,
|
||||||
|
bulletins_sem=bulletins_sem,
|
||||||
|
cursus=cursus,
|
||||||
|
datetime=datetime,
|
||||||
|
decision_ues=decision_ues,
|
||||||
|
ects_total=ects_total,
|
||||||
|
etud=etud,
|
||||||
|
formsemestre=formsemestre,
|
||||||
|
logo=logo,
|
||||||
|
sco=ScoData(formsemestre=formsemestre, etud=etud),
|
||||||
|
time=time,
|
||||||
|
ue_validation_by_niveau=ue_validation_by_niveau,
|
||||||
|
)
|
@ -426,6 +426,7 @@ def dict_decision_jury(
|
|||||||
etud: Identite, formsemestre: FormSemestre, with_decisions: bool = False
|
etud: Identite, formsemestre: FormSemestre, with_decisions: bool = False
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""dict avec decision pour bulletins json
|
"""dict avec decision pour bulletins json
|
||||||
|
- autorisation_inscription
|
||||||
- decision : décision semestre
|
- decision : décision semestre
|
||||||
- decision_ue : list des décisions UE
|
- decision_ue : list des décisions UE
|
||||||
- situation
|
- situation
|
||||||
@ -511,7 +512,10 @@ def dict_decision_jury(
|
|||||||
d["autorisation_inscription"] = []
|
d["autorisation_inscription"] = []
|
||||||
for aut in decision["autorisations"]:
|
for aut in decision["autorisations"]:
|
||||||
d["autorisation_inscription"].append(
|
d["autorisation_inscription"].append(
|
||||||
dict(semestre_id=aut["semestre_id"])
|
dict(
|
||||||
|
semestre_id=aut["semestre_id"],
|
||||||
|
date=aut["date"].isoformat() if aut["date"] else None,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
d["decision"] = dict(code="", etat="DEM")
|
d["decision"] = dict(code="", etat="DEM")
|
||||||
|
118
app/static/css/bulletin_court.css
Normal file
118
app/static/css/bulletin_court.css
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
|
||||||
|
div.but_bul_court {
|
||||||
|
width: 17cm;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 6cm 11cm;
|
||||||
|
font-size: 11pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#infos_etudiant {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
border-radius: 3mm;
|
||||||
|
border: 1px solid black;
|
||||||
|
background-color: white;
|
||||||
|
padding: 5mm;
|
||||||
|
}
|
||||||
|
.nom {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo img {
|
||||||
|
text-align: right;
|
||||||
|
height: 3cm;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.but_bul_court table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: 2px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.but_bul_court table th,
|
||||||
|
div.but_bul_court table td {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid black; /* Thin black border between cells */
|
||||||
|
padding: 2px 4px 2px 4px; /* Padding inside the cells */
|
||||||
|
}
|
||||||
|
|
||||||
|
table td.col_ue {
|
||||||
|
width: 18mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ues {
|
||||||
|
grid-row: 2;
|
||||||
|
grid-column: 1/3;
|
||||||
|
justify-self: end;
|
||||||
|
margin-top: 5mm;
|
||||||
|
margin-bottom: 5mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ues tr.titre_table th {
|
||||||
|
background-color: rgb(183,235,255);
|
||||||
|
padding: 2mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.titres_ues td, tr.jury td {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.resultats_modules {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ressources {
|
||||||
|
grid-row: 3;
|
||||||
|
grid-column: 1/3;
|
||||||
|
margin-bottom: 5mm;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#ressources tr.titres_ues td:first-child {
|
||||||
|
background-color: rgb(255, 192, 0);
|
||||||
|
}
|
||||||
|
#saes {
|
||||||
|
grid-row: 4;
|
||||||
|
grid-column: 1/3;
|
||||||
|
margin-bottom: 5mm;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#saes tr.titres_ues td:first-child {
|
||||||
|
background-color: rgb(176, 255, 99);
|
||||||
|
}
|
||||||
|
|
||||||
|
#row_situation {
|
||||||
|
grid-row: 5;
|
||||||
|
grid-column: 1/3;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
#cursus_etud, #situation {
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
#situation {
|
||||||
|
background-color: white;
|
||||||
|
justify-self: end;
|
||||||
|
margin-left: 1cm;
|
||||||
|
border-radius: 3mm;
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 5mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
grid-row: 6;
|
||||||
|
grid-column: 1/3;
|
||||||
|
margin-top: 5mm;
|
||||||
|
font-size: 9pt;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.but_bul_court .cursus_but {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
162
app/templates/but/bulletin_court_page.j2
Normal file
162
app/templates/but/bulletin_court_page.j2
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
{% extends "sco_page.j2" %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
{{super()}}
|
||||||
|
<link href="{{scu.STATIC_DIR}}/css/jury_but.css" rel="stylesheet" type="text/css" />
|
||||||
|
<link href="{{scu.STATIC_DIR}}/css/cursus_but.css" rel="stylesheet" type="text/css" />
|
||||||
|
<link href="{{scu.STATIC_DIR}}/css/bulletin_court.css" rel="stylesheet" type="text/css" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% macro table_modules(mod_type, title) -%}
|
||||||
|
<table class="resultats_modules">
|
||||||
|
<thead>
|
||||||
|
<tr class="titre_table">
|
||||||
|
<th colspan="2"></th>
|
||||||
|
<th colspan="{{ bul.ues|length }}">Unités d'enseignement</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="titres_ues">
|
||||||
|
<td colspan="2">{{title}}</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{ue}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for mod in bul[mod_type] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{mod}}</td>
|
||||||
|
<td>{{bul[mod_type][mod].titre}}</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td>{{
|
||||||
|
bul.ues[ue][mod_type][mod].moyenne
|
||||||
|
if mod in bul.ues[ue][mod_type] else ""
|
||||||
|
}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
|
||||||
|
<div class="but_bul_court">
|
||||||
|
<div id="infos_etudiant">
|
||||||
|
<div class="nom">{{etud.nomprenom}}</div>
|
||||||
|
<div class="formation">BUT {{formsemestre.formation.referentiel_competence.specialite}}</div>
|
||||||
|
{% if formsemestre.etuds_inscriptions[etud.id].parcour %}
|
||||||
|
<div class="parcours">Parcours {{formsemestre.etuds_inscriptions[etud.id].parcour.code}}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="annee_scolaire">Année {{formsemestre.annee_scolaire_str()}}</div>
|
||||||
|
<div class="semestre">Semestre {{formsemestre.semestre_id}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="logo">
|
||||||
|
{% if logo %}
|
||||||
|
{{logo.html()|safe}}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="ues">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr class="titre_table">
|
||||||
|
<th colspan="{{ 1 + bul.ues|length }}">Unités d'enseignement du semestre {{formsemestre.semestre_id}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="titres_ues">
|
||||||
|
<td></td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{ue}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Moyenne</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{bul.ues[ue].moyenne.value}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Bonus</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{bul.ues[ue].bonus if bul.ues[ue].bonus != "00.00" else ""}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Malus</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{bul.ues[ue].malus if bul.ues[ue].malus != "00.00" else ""}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Rang</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{bul.ues[ue].moyenne.rang}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Effectif</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{bul.ues[ue].moyenne.total}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ECTS</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{bul.ues[ue].moyenne.ects}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
<tr class="jury">
|
||||||
|
<td>Jury</td>
|
||||||
|
{% for ue in bul.ues %}
|
||||||
|
<td class="col_ue">{{decision_ues[ue].code}}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="ressources">
|
||||||
|
{{ table_modules("ressources", "Ressources") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="saes">
|
||||||
|
{{ table_modules("saes", "Situations d'Apprentissage et d'Évaluation (SAÉ)") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="row_situation">
|
||||||
|
<div id="cursus_etud">
|
||||||
|
{% include "but/cursus_etud.j2" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="situation">
|
||||||
|
<div>ECTS acquis : {{ects_total}}</div>
|
||||||
|
<div class="descr_jury">
|
||||||
|
{% if bul.semestre.decision_annee %}
|
||||||
|
Jury tenu le {{
|
||||||
|
datetime.datetime.fromisoformat(bul.semestre.decision_annee.date).strftime("%d/%m/%Y à %H:%M")
|
||||||
|
}},
|
||||||
|
année BUT {{bul.semestre.decision_annee.code}}.
|
||||||
|
{% endif %}
|
||||||
|
{% set virg = joiner(", ") %}
|
||||||
|
{% for aut in bul.semestre.autorisation_inscription -%}
|
||||||
|
{% if loop.first %}
|
||||||
|
Autorisé à s'inscrire en
|
||||||
|
{% endif %}
|
||||||
|
{{- virg() }}S{{aut.semestre_id -}}
|
||||||
|
{%- if loop.last -%}
|
||||||
|
.
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="footer">
|
||||||
|
Bulletin généré par ScoDoc le {{time.strftime("%d/%m/%Y à %Hh%M")}}. Explication des codes sur
|
||||||
|
<a href="https://scodoc.org/CodesJuryBUT">https://scodoc.org/CodesJuryBUT</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -35,7 +35,7 @@ from operator import itemgetter
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import abort, flash, redirect, render_template, url_for
|
from flask import flash, redirect, render_template, url_for
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
@ -44,6 +44,7 @@ from app import models
|
|||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
from app.but import (
|
from app.but import (
|
||||||
apc_edit_ue,
|
apc_edit_ue,
|
||||||
|
bulletin_but_court,
|
||||||
cursus_but,
|
cursus_but,
|
||||||
jury_edit_manual,
|
jury_edit_manual,
|
||||||
jury_but,
|
jury_but,
|
||||||
@ -58,7 +59,6 @@ from app.comp import jury, res_sem
|
|||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
from app.models import (
|
from app.models import (
|
||||||
Formation,
|
Formation,
|
||||||
ScolarFormSemestreValidation,
|
|
||||||
ScolarAutorisationInscription,
|
ScolarAutorisationInscription,
|
||||||
ScolarNews,
|
ScolarNews,
|
||||||
Scolog,
|
Scolog,
|
||||||
|
@ -4,4 +4,4 @@ Architecture: amd64
|
|||||||
Maintainer: Emmanuel Viennet <emmanuel@viennet.net>
|
Maintainer: Emmanuel Viennet <emmanuel@viennet.net>
|
||||||
Description: ScoDoc 9
|
Description: ScoDoc 9
|
||||||
Un logiciel pour le suivi de la scolarité universitaire.
|
Un logiciel pour le suivi de la scolarité universitaire.
|
||||||
Depends: adduser, curl, gcc, graphviz, graphviz-dev, libpq-dev, postfix|exim4, cracklib-runtime, libcrack2-dev, python3-dev, python3-venv, python3-pip, python3-wheel, nginx, postgresql, libpq-dev, redis, ufw
|
Depends: adduser, curl, gcc, graphviz, graphviz-dev, libpq-dev, postfix|exim4, cracklib-runtime, libcrack2-dev, libpango-1.0-0, pango1.0-tools, python3-dev, python3-venv, python3-pip, python3-wheel, nginx, postgresql, libpq-dev, redis, ufw
|
||||||
|
Loading…
Reference in New Issue
Block a user