placement fait

This commit is contained in:
Jean-Marie Place 2021-09-11 19:35:30 +02:00
parent 050e54de3e
commit 35768e9241

View File

@ -141,14 +141,15 @@ class PlacementForm(FlaskForm):
self.groups.choices = choices self.groups.choices = choices
def placement_eval_selectetuds(evaluation_id, REQUEST=None): def placement_eval_selectetuds(evaluation_id):
"""Creation de l'écran de placement"""
form = PlacementForm( form = PlacementForm(
request.form, request.form,
data={"evaluation_id": int(evaluation_id), "groups": PlacementForm.TOUS}, data={"evaluation_id": int(evaluation_id), "groups": PlacementForm.TOUS},
) )
form.set_evaluation_infos(evaluation_id) form.set_evaluation_infos(evaluation_id)
if form.validate_on_submit(): if form.validate_on_submit():
exec_placement(form) exec_placement(form) # calcul et generation du fichier
return flask.redirect(titi()) return flask.redirect(titi())
H = [html_sco_header.sco_header(init_jquery_ui=True)] H = [html_sco_header.sco_header(init_jquery_ui=True)]
H.append(sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)) H.append(sco_evaluations.evaluation_describe(evaluation_id=evaluation_id))
@ -158,238 +159,227 @@ def placement_eval_selectetuds(evaluation_id, REQUEST=None):
return "\n".join(H) + "<p>" + F return "\n".join(H) + "<p>" + F
def do_placement_selectetuds(): # def do_placement_selectetuds():
""" # """
Choisi les étudiants et les infos sur la salle pour leur placement. # Choisi les étudiants et les infos sur la salle pour leur placement.
""" # """
# M = sco_moduleimpl.do_moduleimpl_list( moduleimpl_id=E["moduleimpl_id"])[0] # # M = sco_moduleimpl.do_moduleimpl_list( moduleimpl_id=E["moduleimpl_id"])[0]
# description de l'evaluation # # description de l'evaluation
H = [ # H = [
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id), # sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
"<h3>Placement et émargement des étudiants</h3>", # "<h3>Placement et émargement des étudiants</h3>",
] # ]
# # #
descr = [ # descr = [
("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}), # ("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}),
( # (
"placement_method", # "placement_method",
{ # {
"input_type": "radio", # "input_type": "radio",
"default": "xls", # "default": "xls",
"allow_null": False, # "allow_null": False,
"allowed_values": ["pdf", "xls"], # "allowed_values": ["pdf", "xls"],
"labels": ["fichier pdf", "fichier xls"], # "labels": ["fichier pdf", "fichier xls"],
"title": "Format de fichier :", # "title": "Format de fichier :",
}, # },
), # ),
("teachers", {"size": 25, "title": "Surveillants :"}), # ("teachers", {"size": 25, "title": "Surveillants :"}),
("building", {"size": 25, "title": "Batiment :"}), # ("building", {"size": 25, "title": "Batiment :"}),
("room", {"size": 10, "title": "Salle :"}), # ("room", {"size": 10, "title": "Salle :"}),
( # (
"columns", # "columns",
{ # {
"input_type": "radio", # "input_type": "radio",
"default": "5", # "default": "5",
"allow_null": False, # "allow_null": False,
"allowed_values": ["3", "4", "5", "6", "7", "8"], # "allowed_values": ["3", "4", "5", "6", "7", "8"],
"labels": [ # "labels": [
"3 colonnes", # "3 colonnes",
"4 colonnes", # "4 colonnes",
"5 colonnes", # "5 colonnes",
"6 colonnes", # "6 colonnes",
"7 colonnes", # "7 colonnes",
"8 colonnes", # "8 colonnes",
], # ],
"title": "Nombre de colonnes :", # "title": "Nombre de colonnes :",
}, # },
), # ),
( # (
"numbering", # "numbering",
{ # {
"input_type": "radio", # "input_type": "radio",
"default": "coordinate", # "default": "coordinate",
"allow_null": False, # "allow_null": False,
"allowed_values": ["continuous", "coordinate"], # "allowed_values": ["continuous", "coordinate"],
"labels": ["continue", "coordonnées"], # "labels": ["continue", "coordonnées"],
"title": "Numérotation :", # "title": "Numérotation :",
}, # },
), # ),
] # ]
if no_groups: # if no_groups:
submitbuttonattributes = [] # submitbuttonattributes = []
descr += [ # descr += [
( # (
"group_ids", # "group_ids",
{ # {
"default": [ # "default": [
g["group_id"] # pylint: disable=invalid-sequence-index # g["group_id"] # pylint: disable=invalid-sequence-index
for g in groups # for g in groups
], # ],
"input_type": "hidden", # "input_type": "hidden",
"type": "list", # "type": "list",
}, # },
) # )
] # ]
else: # else:
descr += [ # descr += [
( # (
"group_ids", # "group_ids",
{ # {
"input_type": "checkbox", # "input_type": "checkbox",
"title": "Choix groupe(s) d'étudiants :", # "title": "Choix groupe(s) d'étudiants :",
"allowed_values": grnams, # "allowed_values": grnams,
"labels": grlabs, # "labels": grlabs,
"attributes": ['onchange="gr_change(this);"'], # "attributes": ['onchange="gr_change(this);"'],
}, # },
) # )
] # ]
#
if not ("group_ids" in REQUEST.form and REQUEST.form["group_ids"]): # if not ("group_ids" in REQUEST.form and REQUEST.form["group_ids"]):
submitbuttonattributes = ['disabled="1"'] # submitbuttonattributes = ['disabled="1"']
else: # else:
submitbuttonattributes = [] # groupe(s) preselectionnés # submitbuttonattributes = [] # groupe(s) preselectionnés
H.append( # H.append(
# JS pour desactiver le bouton OK si aucun groupe selectionné # # JS pour desactiver le bouton OK si aucun groupe selectionné
"""<script type="text/javascript"> # """<script type="text/javascript">
function gr_change(e) { # function gr_change(e) {
var boxes = document.getElementsByName("group_ids:list"); # var boxes = document.getElementsByName("group_ids:list");
var nbchecked = 0; # var nbchecked = 0;
for (var i=0; i < boxes.length; i++) { # for (var i=0; i < boxes.length; i++) {
if (boxes[i].checked) # if (boxes[i].checked)
nbchecked++; # nbchecked++;
} # }
if (nbchecked > 0) { # if (nbchecked > 0) {
document.getElementsByName('gr_submit')[0].disabled=false; # document.getElementsByName('gr_submit')[0].disabled=false;
} else { # } else {
document.getElementsByName('gr_submit')[0].disabled=true; # document.getElementsByName('gr_submit')[0].disabled=true;
} # }
} # }
</script> # </script>
""" # """
) # )
#
tf = TrivialFormulator( # tf = TrivialFormulator(
REQUEST.URL0, # REQUEST.URL0,
REQUEST.form, # REQUEST.form,
descr, # descr,
cancelbutton="Annuler", # cancelbutton="Annuler",
submitbuttonattributes=submitbuttonattributes, # submitbuttonattributes=submitbuttonattributes,
submitlabel="OK", # submitlabel="OK",
formid="gr", # formid="gr",
) # )
if tf[0] == 0: # if tf[0] == 0:
# H.append( """<div class="saisienote_etape1"> # # H.append( """<div class="saisienote_etape1">
# <span class="titredivplacementetudiants">Choix du groupe et de la localisation</span> # # <span class="titredivplacementetudiants">Choix du groupe et de la localisation</span>
# """) # # """)
H.append("""<div class="saisienote_etape1">""") # H.append("""<div class="saisienote_etape1">""")
return "\n".join(H) + "\n" + tf[1] + "\n</div>" # return "\n".join(H) + "\n" + tf[1] + "\n</div>"
elif tf[0] == -1: # elif tf[0] == -1:
return flask.redirect( # return flask.redirect(
"%s/Notes/moduleimpl_status?moduleimpl_id=%s" # "%s/Notes/moduleimpl_status?moduleimpl_id=%s"
% (scu.ScoURL(), E["moduleimpl_id"]) # % (scu.ScoURL(), E["moduleimpl_id"])
) # )
else: # else:
placement_method = tf[2]["placement_method"] # placement_method = tf[2]["placement_method"]
teachers = tf[2]["teachers"] # teachers = tf[2]["teachers"]
building = tf[2]["building"] # building = tf[2]["building"]
room = tf[2]["room"] # room = tf[2]["room"]
group_ids = tf[2]["group_ids"] # group_ids = tf[2]["group_ids"]
columns = tf[2]["columns"] # columns = tf[2]["columns"]
numbering = tf[2]["numbering"] # numbering = tf[2]["numbering"]
if columns in ("3", "4", "5", "6", "7", "8"): # if columns in ("3", "4", "5", "6", "7", "8"):
gs = [ # gs = [
("group_ids%3Alist=" + six.moves.urllib.parse.quote_plus(x)) # ("group_ids%3Alist=" + six.moves.urllib.parse.quote_plus(x))
for x in group_ids # for x in group_ids
] # ]
query = ( # query = (
"evaluation_id=%s&placement_method=%s&teachers=%s&building=%s&room=%s&columns=%s&numbering=%s&" # "evaluation_id=%s&placement_method=%s&teachers=%s&building=%s&room=%s&columns=%s&numbering=%s&"
% ( # % (
evaluation_id, # evaluation_id,
placement_method, # placement_method,
teachers, # teachers,
building, # building,
room, # room,
columns, # columns,
numbering, # numbering,
) # )
+ "&".join(gs) # + "&".join(gs)
) # )
return flask.redirect(scu.NotesURL() + "/do_placement?" + query) # return flask.redirect(scu.NotesURL() + "/do_placement?" + query)
else: # else:
raise ValueError( # raise ValueError(
"invalid placement_method (%s)" % tf[2]["placement_method"] # "invalid placement_method (%s)" % tf[2]["placement_method"]
) # )
def exec_placement(form): def exec_placement(form):
try: """Calcul et génération du fichier sur la base des données du formulaire"""
evaluation_id = int(form["evaluation_id"].data)
except:
raise ScoValueError(
"Formulaire incomplet ! Vous avez sans doute attendu trop longtemps, veuillez vous reconnecter. Si le problème persiste, contacter l'administrateur. Merci."
)
eval_data = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
# Check access
# (admin, respformation, and responsable_id)
if not sco_permissions_check.can_edit_notes(
current_user, eval_data["moduleimpl_id"]
):
return (
"<h2>Génération du placement impossible pour %s</h2>" % authusername
+ """<p>(vérifiez que le semestre n'est pas verrouillé et que vous
avez l'autorisation d'effectuer cette opération)</p>
<p><a href="moduleimpl_status?moduleimpl_id=%s">Continuer</a></p>
"""
% E["moduleimpl_id"]
)
plan = repartition(form, eval_data)
breakpoint() breakpoint()
sem_preferences = sco_preferences.SemPreferences() d = {
space = sem_preferences.get("feuille_placement_emargement") "evaluation_id": form["evaluation_id"].data,
maxlines = sem_preferences.get("feuille_placement_positions") "etiquetage": form["etiquetage"].data,
"surveillants": form["surveillants"].data,
"batiment": form["batiment"].data,
"salle": form["salle"].data,
"nb_rangs": form["nb_rangs"].data,
"groups": form["groups"].data,
}
d["eval_data"] = sco_evaluations.do_evaluation_list(d)[0]
# Check access (admin, respformation, and responsable_id)
d["current_user"] = current_user
d["moduleimpl_id"] = d["eval_data"]["moduleimpl_id"]
if not sco_permissions_check.can_edit_notes(d["current_user"], d["moduleimpl_id"]):
return (
"""<h2>Génération du placement impossible pour %(current_user)s</h2>
<p>(vérifiez que le semestre n'est pas verrouillé et que vous
avez l'autorisation d'effectuer cette opération)</p>
<p><a href="moduleimpl_status?moduleimpl_id=%(module_id)s">Continuer</a></p>
"""
% d
)
d["cnx"] = ndb.GetDBConnexion()
d["plan"] = repartition(d)
d["gr_title_filename"] = sco_groups.listgroups_filename(d['groups'])
# gr_title = sco_groups.listgroups_abbrev(d['groups'])
d["moduleimpl_data"] = sco_moduleimpl.do_moduleimpl_list(moduleimpl_id=d["moduleimpl_id"])
d["Mod"] = sco_edit_module.do_module_list(args={"module_id": d["moduleimpl_id"]})[0]
d["sem"] = sco_formsemestre.get_formsemestre(d["moduleimpl_data"]["formsemestre_id"])
d["evalname"] = "%s-%s" % (d["Mod"]["code"], ndb.DateDMYtoISO(eval_data["jour"]))
if d["eval_data"]["description"]:
d["evaltitre"] = d["eval_data"]["description"]
else:
d["evaltitre"] = "évaluation du %s" % eval_data["jour"]
d["desceval"] = [
["%s" % d["sem"]["titreannee"]],
["Module : %s - %s" % (d["Mod"]["code"], d["Mod"]["abbrev"])],
["Surveillants : %(surveillant)s" % d],
["Batiment : %(batiment)s - Salle : %(salle)s" % d],
["Controle : %s (coef. %g)" % (d["evaltitre"], d["eval_data"]["coefficient"])],
] # une liste de liste de chaines: description de l'evaluation
if form["file_format"].data == "xls":
production_xls(d)
else:
production_pdf(d)
def repartition(form, eval_data): def repartition(d):
""" """
Calcule le placement. retourne une liste de couples ((nom, prenom), position) Calcule le placement. retourne une liste de couples ((nom, prenom), position)
""" """
cnx = ndb.GetDBConnexion()
# Infos transmises
evaluation_id = form["evaluation_id"].data
etiquetage = form["etiquetage"].data
teachers = form["surveillants"].data
building = form["batiment"].data
room = form["salle"].data
nb_rangs = form["nb_rangs"].data
group_ids = form["groups"].data
# Construit liste des etudiants # Construit liste des etudiants
groups = sco_groups.listgroups(group_ids) groups = sco_groups.listgroups(d["groups"])
gr_title_filename = sco_groups.listgroups_filename(groups) d["listetud"] = build_listetud(d)
# gr_title = sco_groups.listgroups_abbrev(groups) return affectation_places(d)
moduleimpl_data = sco_moduleimpl.do_moduleimpl_list(
moduleimpl_id=eval_data["moduleimpl_id"]
)[0]
Mod = sco_edit_module.do_module_list(
args={"module_id": moduleimpl_data["module_id"]}
)[0]
sem = sco_formsemestre.get_formsemestre(moduleimpl_data["formsemestre_id"])
evalname = "%s-%s" % (Mod["code"], ndb.DateDMYtoISO(eval_data["jour"]))
if eval_data["description"]:
evaltitre = eval_data["description"]
else:
evaltitre = "évaluation du %s" % eval_data["jour"]
desceval = [
["%s" % sem["titreannee"]],
["Module : %s - %s" % (Mod["code"], Mod["abbrev"])],
["Surveillants : %s" % teachers],
["Batiment : %s - Salle : %s" % (building, room)],
["Controle : %s (coef. %g)" % (evaltitre, eval_data["coefficient"])]
] # une liste de liste de chaines: description de l'evaluation
listetud = build_listetud(cnx, groups, evaluation_id, moduleimpl_data)
return affectation_places(listetud, etiquetage, nb_rangs)
def build_listetud(cnx, groups, evaluation_id, moduleimpl_data): def build_listetud(cnx, groups, evaluation_id, moduleimpl_data):
@ -446,99 +436,96 @@ class Distributeur2D:
return retour return retour
def affectation_places(listetud, etiquetage, nb_rangs=1): def affectation_places(d):
affectation = [] plan = []
if etiquetage == "continu": if d["etiquetage"] == "continu":
distributeur = DistributeurContinu() distributeur = DistributeurContinu()
else: else:
distributeur = Distributeur2D(nb_rangs) distributeur = Distributeur2D(d["nb_rangs"])
for etud in listetud: for etud in d["listetud"]:
affectation.append((etud, distributeur.suivant())) plan.append((etud, distributeur.suivant()))
return affectation return plan
def production_xls(file_format, eval_dat, plan): def production_xls(d):
filename = f"placement_{evalname}_{gr_title_filename}{scu.XLSX_SUFFIX}"
xls = _excel_feuille_placement(
d["eval_data"],
d["desceval"],
d["listetud"],
d["nb_rangs"],
d["batiment"],
d["salle"],
d["etiquetage"],
)
return sco_excel.send_excel_file(REQUEST, xls, filename)
def production(file_format, eval_dat, plan): def production_pdf(d):
if file_format == "xls": pdf_title = d["desceval"]
filename = f"placement_{evalname}_{gr_title_filename}{scu.XLSX_SUFFIX}" pdf_title += (
xls = _excel_feuille_placement( "Date : %(jour)s - Horaire : %(heure_debut)s à %(heure_fin)s" % d["eval_data"]
eval_data, desceval, listetud, columns, space, maxlines, building, room, numbering )
)
return sco_excel.send_excel_file(REQUEST, xls, filename) filename = "placement_%(evalname)s_%(gr_title_filename)s.pdf" % d
titles = {
"nom": "Nom",
"prenom": "Prenom",
"colonne": "Colonne",
"ligne": "Ligne",
"place": "Place",
}
nbcolumns = int(columns)
if numbering == "coordinate":
columns_ids = ["nom", "prenom", "colonne", "ligne"]
else: else:
nbcolumns = int(columns) columns_ids = ["nom", "prenom", "place"]
pdf_title = "%s<br/>" % sem["titreannee"] # etudiants
pdf_title += "Module : %s - %s<br/>" % (Mod["code"], Mod["abbrev"]) line = 1
pdf_title += "Surveillants : %s<br/>" % teachers col = 1
pdf_title += "Batiment : %s - Salle : %s<br/>" % (building, room) orderetud = []
pdf_title += "Controle : %s (coef. %g)<br/>" % (evaltitre, E["coefficient"]) for etudid in listetud:
pdf_title += "Date : %s - Horaire : %s à %s" % (
E["jour"],
E["heure_debut"],
E["heure_fin"],
)
filename = "placement_%s_%s.pdf" % (evalname, gr_title_filename)
titles = {
"nom": "Nom",
"prenom": "Prenom",
"colonne": "Colonne",
"ligne": "Ligne",
"place": "Place",
}
if numbering == "coordinate": if numbering == "coordinate":
columns_ids = ["nom", "prenom", "colonne", "ligne"] orderetud.append((etudid[0], etudid[1], col, line))
else: else:
columns_ids = ["nom", "prenom", "place"] orderetud.append((etudid[0], etudid[1], col + (line - 1) * nbcolumns))
# etudiants if col == nbcolumns:
line = 1 col = 0
col = 1 line += 1
orderetud = [] col += 1
for etudid in listetud:
if numbering == "coordinate":
orderetud.append((etudid[0], etudid[1], col, line))
else:
orderetud.append((etudid[0], etudid[1], col + (line - 1) * nbcolumns))
if col == nbcolumns: rows = []
col = 0 orderetud.sort()
line += 1 for etudid in orderetud:
col += 1 if numbering == "coordinate":
rows.append(
{
"nom": etudid[0],
"prenom": etudid[1],
"colonne": etudid[2],
"ligne": etudid[3],
}
)
else:
rows.append({"nom": etudid[0], "prenom": etudid[1], "place": etudid[2]})
rows = [] tab = GenTable(
orderetud.sort() titles=titles,
for etudid in orderetud: columns_ids=columns_ids,
if numbering == "coordinate": rows=rows,
rows.append( filename=filename,
{ origin="Généré par %s le " % sco_version.SCONAME
"nom": etudid[0], + scu.timedate_human_repr()
"prenom": etudid[1], + "",
"colonne": etudid[2], pdf_title=pdf_title,
"ligne": etudid[3], # pdf_shorttitle = '',
} preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
) # html_generate_cells=False # la derniere ligne (moyennes) est incomplete
else: )
rows.append({"nom": etudid[0], "prenom": etudid[1], "place": etudid[2]}) t = tab.make_page(format="pdf", with_html_headers=False, REQUEST=REQUEST)
return t
tab = GenTable(
titles=titles,
columns_ids=columns_ids,
rows=rows,
filename=filename,
origin="Généré par %s le " % sco_version.SCONAME
+ scu.timedate_human_repr()
+ "",
pdf_title=pdf_title,
# pdf_shorttitle = '',
preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
# html_generate_cells=False # la derniere ligne (moyennes) est incomplete
)
t = tab.make_page(format="pdf", with_html_headers=False, REQUEST=REQUEST)
return t
def placement_eval_selectetuds_old(evaluation_id, REQUEST=None): def placement_eval_selectetuds_old(evaluation_id, REQUEST=None):
@ -704,16 +691,16 @@ def _titres(ws, description, evaluation, building, room, styles):
def _feuille0( def _feuille0(
ws0, ws0,
description, description,
evaluation, evaluation,
styles, styles,
numbering, numbering,
listetud, listetud,
nbcolumns, nbcolumns,
building, building,
room, room,
space, space,
): ):
_titres(ws0, description, evaluation, building, room, styles) _titres(ws0, description, evaluation, building, room, styles)
# entetes colonnes - feuille0 # entetes colonnes - feuille0
@ -801,16 +788,16 @@ def _next_page(ws):
def _feuille1( def _feuille1(
ws, ws,
description, description,
evaluation, evaluation,
styles, styles,
numbering, numbering,
maxlines, maxlines,
nbcolumns, nbcolumns,
building, building,
room, room,
listetud, listetud,
): ):
# etudiants - feuille1 # etudiants - feuille1
# structuration: # structuration:
@ -867,21 +854,24 @@ def _feuille1(
def _excel_feuille_placement( def _excel_feuille_placement(
evaluation, evaluation,
description, description,
listetud, listetud,
columns, columns,
space, space,
maxlines, maxlines,
building, building,
room, room,
numbering, numbering,
): ):
"""Genere feuille excel pour placement des etudiants. """Genere feuille excel pour placement des etudiants.
E: evaluation (dict) E: evaluation (dict)
lines: liste de tuples lines: liste de tuples
(etudid, nom, prenom, etat, groupe, val, explanation) (etudid, nom, prenom, etat, groupe, val, explanation)
""" """
sem_preferences = sco_preferences.SemPreferences()
space = sem_preferences.get("feuille_placement_emargement")
maxlines = sem_preferences.get("feuille_placement_positions")
nbcolumns = int(columns) nbcolumns = int(columns)
column_width_ratio = 1 / 250 # changement d unités entre pyExcelerator et openpyxl column_width_ratio = 1 / 250 # changement d unités entre pyExcelerator et openpyxl
@ -897,7 +887,7 @@ def _excel_feuille_placement(
ws0.set_column_dimension_width("A", 750 * column_width_ratio) ws0.set_column_dimension_width("A", 750 * column_width_ratio)
for col in range(nbcolumns): for col in range(nbcolumns):
ws0.set_column_dimension_width( ws0.set_column_dimension_width(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[col + 1: col + 2], width "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[col + 1 : col + 2], width
) )
SheetName1 = "Positions" SheetName1 = "Positions"