Creation d'une partition avec les groupes d'étapes

This commit is contained in:
viennet 2020-12-01 16:46:45 +01:00
parent 9477caf06a
commit 317252575a
11 changed files with 938 additions and 425 deletions

View File

@ -1616,8 +1616,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
security.declareProtected(ScoView, "view_module_abs") security.declareProtected(ScoView, "view_module_abs")
def view_module_abs(self, REQUEST, moduleimpl_id, format="html"): def view_module_abs(self, REQUEST, moduleimpl_id, format="html"):
"""Visulalisation des absences a un module """Visulalisation des absences a un module"""
"""
M = self.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0] M = self.do_moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
sem = sco_formsemestre.get_formsemestre(self, M["formsemestre_id"]) sem = sco_formsemestre.get_formsemestre(self, M["formsemestre_id"])
debut_sem = DateDMYtoISO(sem["date_debut"]) debut_sem = DateDMYtoISO(sem["date_debut"])
@ -1903,7 +1902,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
_formsemestre_inscriptionEditor = EditableTable( _formsemestre_inscriptionEditor = EditableTable(
"notes_formsemestre_inscription", "notes_formsemestre_inscription",
"formsemestre_inscription_id", "formsemestre_inscription_id",
("formsemestre_inscription_id", "etudid", "formsemestre_id", "etat"), ("formsemestre_inscription_id", "etudid", "formsemestre_id", "etat", "etape"),
sortkey="formsemestre_id", sortkey="formsemestre_id",
) )
@ -2264,8 +2263,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
security.declareProtected(ScoEtudInscrit, "etud_desinscrit_ue") security.declareProtected(ScoEtudInscrit, "etud_desinscrit_ue")
def etud_desinscrit_ue(self, etudid, formsemestre_id, ue_id, REQUEST=None): def etud_desinscrit_ue(self, etudid, formsemestre_id, ue_id, REQUEST=None):
"""Desinscrit l'etudiant de tous les modules de cette UE dans ce semestre. """Desinscrit l'etudiant de tous les modules de cette UE dans ce semestre."""
"""
sco_moduleimpl_inscriptions.do_etud_desinscrit_ue( sco_moduleimpl_inscriptions.do_etud_desinscrit_ue(
self, etudid, formsemestre_id, ue_id, REQUEST=REQUEST self, etudid, formsemestre_id, ue_id, REQUEST=REQUEST
) )
@ -2278,8 +2276,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
security.declareProtected(ScoEtudInscrit, "etud_inscrit_ue") security.declareProtected(ScoEtudInscrit, "etud_inscrit_ue")
def etud_inscrit_ue(self, etudid, formsemestre_id, ue_id, REQUEST=None): def etud_inscrit_ue(self, etudid, formsemestre_id, ue_id, REQUEST=None):
"""Inscrit l'etudiant de tous les modules de cette UE dans ce semestre. """Inscrit l'etudiant de tous les modules de cette UE dans ce semestre."""
"""
sco_moduleimpl_inscriptions.do_etud_inscrit_ue( sco_moduleimpl_inscriptions.do_etud_inscrit_ue(
self, etudid, formsemestre_id, ue_id, REQUEST=REQUEST self, etudid, formsemestre_id, ue_id, REQUEST=REQUEST
) )
@ -2411,8 +2408,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
REQUEST=None, REQUEST=None,
**kw **kw
): ):
"""Create an evaluation """Create an evaluation"""
"""
args = locals() args = locals()
log("do_evaluation_create: args=" + str(args)) log("do_evaluation_create: args=" + str(args))
self._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id) self._evaluation_check_write_access(REQUEST, moduleimpl_id=moduleimpl_id)
@ -3319,8 +3315,7 @@ class ZNotes(ObjectManager, PropertyManager, RoleManager, Item, Persistent, Impl
def formsemestre_validation_suppress_etud( def formsemestre_validation_suppress_etud(
self, formsemestre_id, etudid, REQUEST=None, dialog_confirmed=False self, formsemestre_id, etudid, REQUEST=None, dialog_confirmed=False
): ):
"""Suppression des decisions de jury pour un etudiant. """Suppression des decisions de jury pour un etudiant."""
"""
if not self._can_validate_sem(REQUEST, formsemestre_id): if not self._can_validate_sem(REQUEST, formsemestre_id):
return self.confirmDialog( return self.confirmDialog(
message="<p>Opération non autorisée pour %s</h2>" message="<p>Opération non autorisée pour %s</h2>"

File diff suppressed because it is too large Load Diff

View File

@ -487,6 +487,7 @@ CREATE TABLE notes_formsemestre_inscription (
etudid text REFERENCES identite(etudid), etudid text REFERENCES identite(etudid),
formsemestre_id text REFERENCES notes_formsemestre(formsemestre_id), formsemestre_id text REFERENCES notes_formsemestre(formsemestre_id),
etat text, -- I inscrit, D demission en cours de semestre, DEF si "defaillant" etat text, -- I inscrit, D demission en cours de semestre, DEF si "defaillant"
etape text, -- etape apogee d'inscription (experimental 2020)
UNIQUE(formsemestre_id, etudid) UNIQUE(formsemestre_id, etudid)
) WITH OIDS; ) WITH OIDS;

View File

@ -45,10 +45,11 @@ def do_formsemestre_inscription_with_modules(
etudid, etudid,
group_ids=[], group_ids=[],
etat="I", etat="I",
etape=None,
REQUEST=None, REQUEST=None,
method="inscription_with_modules", method="inscription_with_modules",
): ):
"""Inscrit cet etudiant a ce semestre et TOUS ses modules STANDARDS """Inscrit cet etudiant à ce semestre et TOUS ses modules STANDARDS
(donc sauf le sport) (donc sauf le sport)
""" """
# inscription au semestre # inscription au semestre
@ -258,8 +259,7 @@ def formsemestre_inscription_with_modules(
def formsemestre_inscription_option(context, etudid, formsemestre_id, REQUEST=None): def formsemestre_inscription_option(context, etudid, formsemestre_id, REQUEST=None):
"""Dialogue pour (des)inscription a des modules optionnels """Dialogue pour (dés)inscription à des modules optionnels."""
"""
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
if sem["etat"] != "1": if sem["etat"] != "1":
raise ScoValueError("Modification impossible: semestre verrouille") raise ScoValueError("Modification impossible: semestre verrouille")
@ -320,15 +320,12 @@ def formsemestre_inscription_option(context, etudid, formsemestre_id, REQUEST=No
sem_origin = sco_formsemestre.get_formsemestre( sem_origin = sco_formsemestre.get_formsemestre(
context, ue_status["formsemestre_id"] context, ue_status["formsemestre_id"]
) )
ue_descr += ( ue_descr += ' <a class="discretelink" href="formsemestre_bulletinetud?formsemestre_id=%s&amp;etudid=%s" title="%s">(capitalisée le %s)' % (
' <a class="discretelink" href="formsemestre_bulletinetud?formsemestre_id=%s&amp;etudid=%s" title="%s">(capitalisée le %s)'
% (
sem_origin["formsemestre_id"], sem_origin["formsemestre_id"],
etudid, etudid,
sem_origin["titreannee"], sem_origin["titreannee"],
DateISOtoDMY(ue_status["event_date"]), DateISOtoDMY(ue_status["event_date"]),
) )
)
descr.append( descr.append(
( (
"sec_%s" % ue_id, "sec_%s" % ue_id,

View File

@ -63,7 +63,7 @@ def checkGroupName(
): # XXX unused: now allow any string as a group or partition name ): # XXX unused: now allow any string as a group or partition name
"Raises exception if not a valid group name" "Raises exception if not a valid group name"
if groupName and ( if groupName and (
not re.match("^\w+$", groupName) or (simplesqlquote(groupName) != groupName) not re.match(r"^\w+$", groupName) or (simplesqlquote(groupName) != groupName)
): ):
log("!!! invalid group name: " + groupName) log("!!! invalid group name: " + groupName)
raise ValueError("invalid group name: " + groupName) raise ValueError("invalid group name: " + groupName)
@ -103,8 +103,7 @@ def get_group(context, group_id):
def group_delete(context, group, force=False): def group_delete(context, group, force=False):
"""Delete a group. """Delete a group."""
"""
# if not group['group_name'] and not force: # if not group['group_name'] and not force:
# raise ValueError('cannot suppress this group') # raise ValueError('cannot suppress this group')
# remove memberships: # remove memberships:
@ -156,8 +155,7 @@ def get_default_partition(context, formsemestre_id):
def get_formsemestre_groups(context, formsemestre_id, with_default=False): def get_formsemestre_groups(context, formsemestre_id, with_default=False):
"""Returns ( partitions, { partition_id : { etudid : group } } ) """Returns ( partitions, { partition_id : { etudid : group } } )."""
"""
partitions = get_partitions_list( partitions = get_partitions_list(
context, formsemestre_id, with_default=with_default context, formsemestre_id, with_default=with_default
) )
@ -179,8 +177,7 @@ def get_partition_groups(context, partition):
def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=None): def get_default_group(context, formsemestre_id, fix_if_missing=False, REQUEST=None):
"""Returns group_id for default ('tous') group """Returns group_id for default ('tous') group"""
"""
r = SimpleDictFetch( r = SimpleDictFetch(
context, context,
"SELECT gd.group_id FROM group_descr gd, partition p WHERE p.formsemestre_id=%(formsemestre_id)s AND p.partition_name is NULL AND p.partition_id = gd.partition_id", "SELECT gd.group_id FROM group_descr gd, partition p WHERE p.formsemestre_id=%(formsemestre_id)s AND p.partition_name is NULL AND p.partition_id = gd.partition_id",
@ -261,10 +258,8 @@ def get_group_members(context, group_id, etat=None):
def get_group_infos(context, group_id, etat=None): # was _getlisteetud def get_group_infos(context, group_id, etat=None): # was _getlisteetud
"""legacy code: used by group_list and trombino """legacy code: used by group_list and trombino"""
"""
cnx = context.GetDBConnexion() cnx = context.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ScoDocCursor)
group = get_group(context, group_id) group = get_group(context, group_id)
sem = sco_formsemestre.get_formsemestre(context, group["formsemestre_id"]) sem = sco_formsemestre.get_formsemestre(context, group["formsemestre_id"])
@ -370,8 +365,7 @@ def formsemestre_get_etud_groupnames(context, formsemestre_id, attr="group_name"
def etud_add_group_infos(context, etud, sem, sep=" "): def etud_add_group_infos(context, etud, sem, sep=" "):
"""Add informations on partitions and group memberships to etud (a dict with an etudid) """Add informations on partitions and group memberships to etud (a dict with an etudid)"""
"""
etud[ etud[
"partitions" "partitions"
] = collections.OrderedDict() # partition_id : group + partition_name ] = collections.OrderedDict() # partition_id : group + partition_name
@ -553,8 +547,7 @@ def set_group(context, etudid, group_id):
def change_etud_group_in_partition( def change_etud_group_in_partition(
context, etudid, group_id, partition=None, REQUEST=None context, etudid, group_id, partition=None, REQUEST=None
): ):
"""Inscrit etud au groupe de cette partition, et le desinscrit d'autres groupes de cette partition. """Inscrit etud au groupe de cette partition, et le desinscrit d'autres groupes de cette partition."""
"""
log("change_etud_group_in_partition: etudid=%s group_id=%s" % (etudid, group_id)) log("change_etud_group_in_partition: etudid=%s group_id=%s" % (etudid, group_id))
# 0- La partition # 0- La partition
@ -700,7 +693,7 @@ def createGroup(context, partition_id, group_name="", default=False, REQUEST=Non
""" """
partition = get_partition(context, partition_id) partition = get_partition(context, partition_id)
formsemestre_id = partition["formsemestre_id"] formsemestre_id = partition["formsemestre_id"]
if not context.Notes.can_change_groups(REQUEST, formsemestre_id): if REQUEST and not context.Notes.can_change_groups(REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
# #
if group_name: if group_name:
@ -756,7 +749,7 @@ def partition_create(
redirect=1, redirect=1,
): ):
"""Create a new partition""" """Create a new partition"""
if not context.Notes.can_change_groups(REQUEST, formsemestre_id): if REQUEST and not context.Notes.can_change_groups(REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
if partition_name: if partition_name:
partition_name = partition_name.strip() partition_name = partition_name.strip()
@ -800,7 +793,8 @@ def getArrowIconsTags(context, REQUEST):
def editPartitionForm(context, formsemestre_id=None, REQUEST=None): def editPartitionForm(context, formsemestre_id=None, REQUEST=None):
"""Form to create/suppress partitions""" """Form to create/suppress partitions"""
# ad-hoc form # ad-hoc form
canedit = context.Notes.can_change_groups(REQUEST, formsemestre_id) if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
partitions = get_partitions_list(context, formsemestre_id) partitions = get_partitions_list(context, formsemestre_id)
arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST) arrow_up, arrow_down, arrow_none = getArrowIconsTags(context, REQUEST)
suppricon = icontag( suppricon = icontag(
@ -1294,6 +1288,48 @@ def get_prev_moy(context, etudid, formsemestre_id):
return 0.0 return 0.0
def create_etapes_partition(context, formsemestre_id, partition_name="apo_etapes"):
"""Crée une partition "apo_etapes" avec un groupe par étape Apogée.
Cette partition n'est crée que si plusieurs étapes différentes existent dans ce
semestre.
Si la partition existe déjà, ses groupes sont mis à jour (les groupes devenant
vides ne sont pas supprimés).
"""
log("create_etapes_partition(%s)" % formsemestre_id)
ins = context.do_formsemestre_inscription_list(
args={"formsemestre_id": formsemestre_id}
)
etapes = {i["etape"] for i in ins if i["etape"]}
partitions = get_partitions_list(context, formsemestre_id, with_default=False)
partition = None
for p in partitions:
if p["partition_name"] == partition_name:
partition = p
break
if len(etapes) < 2 and not partition:
return # moins de deux étapes, pas de création
if partition:
pid = partition["partition_id"]
else:
pid = partition_create(
context, formsemestre_id, partition_name=partition_name, redirect=False
)
partition = get_partition(context, pid)
groups = get_partition_groups(context, partition)
groups_by_names = {g["group_name"]: g for g in groups}
for etape in etapes:
if not (etape in groups_by_names):
gid = createGroup(context, pid, etape)
g = get_group(context, gid)
groups_by_names[etape] = g
# Place les etudiants dans les groupes
for i in ins:
if i["etape"]:
change_etud_group_in_partition(
context, i["etudid"], groups_by_names[i["etape"]]["group_id"], partition
)
def do_evaluation_listeetuds_groups( def do_evaluation_listeetuds_groups(
context, evaluation_id, groups=None, getallstudents=False, include_dems=False context, evaluation_id, groups=None, getallstudents=False, include_dems=False
): ):

View File

@ -47,8 +47,6 @@ def affectGroups(context, partition_id, REQUEST=None):
if not context.Notes.can_change_groups(REQUEST, formsemestre_id): if not context.Notes.can_change_groups(REQUEST, formsemestre_id):
raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération") raise AccessDenied("vous n'avez pas la permission d'effectuer cette opération")
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
H = [ H = [
context.sco_header( context.sco_header(
REQUEST, REQUEST,

View File

@ -429,8 +429,12 @@ def groups_table(
): ):
"""liste etudiants inscrits dans ce semestre """liste etudiants inscrits dans ce semestre
format: csv, json, xml, xls, allxls, xlsappel, moodlecsv, pdf format: csv, json, xml, xls, allxls, xlsappel, moodlecsv, pdf
Si with_codes, ajoute 3 colonnes avec les codes etudid, NIP, INE Si with_codes, ajoute 4 colonnes avec les codes etudid, NIP, INE et etape
""" """
log(
"enter groups_table %s: %s"
% (groups_infos.members[0]["nom"], groups_infos.members[0].get("etape", "-"))
)
authuser = REQUEST.AUTHENTICATED_USER authuser = REQUEST.AUTHENTICATED_USER
with_codes = int(with_codes) with_codes = int(with_codes)
@ -784,8 +788,7 @@ def groups_table(
def tab_absences_html(context, groups_infos, etat=None, REQUEST=None): def tab_absences_html(context, groups_infos, etat=None, REQUEST=None):
"""contenu du tab "absences et feuilles diverses" """contenu du tab "absences et feuilles diverses" """
"""
authuser = REQUEST.AUTHENTICATED_USER authuser = REQUEST.AUTHENTICATED_USER
H = ['<div class="tab-content">'] H = ['<div class="tab-content">']
if not groups_infos.members: if not groups_infos.members:
@ -841,8 +844,7 @@ def tab_absences_html(context, groups_infos, etat=None, REQUEST=None):
def tab_photos_html(context, groups_infos, etat=None, REQUEST=None): def tab_photos_html(context, groups_infos, etat=None, REQUEST=None):
"""contenu du tab "photos" """contenu du tab "photos" """
"""
if not groups_infos.members: if not groups_infos.members:
return '<div class="tab-content"><h3>Aucun étudiant !</h3></div>' return '<div class="tab-content"><h3>Aucun étudiant !</h3></div>'
@ -850,8 +852,7 @@ def tab_photos_html(context, groups_infos, etat=None, REQUEST=None):
def form_choix_jour_saisie_hebdo(context, groups_infos, REQUEST=None): def form_choix_jour_saisie_hebdo(context, groups_infos, REQUEST=None):
"""Formulaire choix jour semaine pour saisie. """Formulaire choix jour semaine pour saisie."""
"""
authuser = REQUEST.AUTHENTICATED_USER authuser = REQUEST.AUTHENTICATED_USER
if not authuser.has_permission(ScoAbsChange, context): if not authuser.has_permission(ScoAbsChange, context):
return "" return ""

View File

@ -508,7 +508,7 @@ def check_paiement_etuds(context, etuds):
Seuls les etudiants avec code NIP sont renseignés. Seuls les etudiants avec code NIP sont renseignés.
Renseigne l'attribut booleen 'paiementinscription' dans chaque etud. Renseigne l'attribut booleen 'paiementinscription' dans chaque etud, ainsi que l'étape.
En sortie: modif les champs de chaque etud En sortie: modif les champs de chaque etud
'paiementinscription' : True, False ou None 'paiementinscription' : True, False ou None

View File

@ -596,6 +596,8 @@ def formsemestre_pvjury_pdf(
Si etudid, PV pour un seul etudiant. Sinon, tout les inscrits au groupe indiqué. Si etudid, PV pour un seul etudiant. Sinon, tout les inscrits au groupe indiqué.
""" """
sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id)
# Mise à jour des groupes d'étapes:
sco_groups.create_etapes_partition(context, formsemestre_id)
groups_infos = None groups_infos = None
if etudid: if etudid:
# PV pour ce seul étudiant: # PV pour ce seul étudiant:

View File

@ -438,7 +438,7 @@ def table_suivi_cohorte(
for s in sems: for s in sems:
ins = context.do_formsemestre_inscription_list( ins = context.do_formsemestre_inscription_list(
args={"formsemestre_id": s["formsemestre_id"]} args={"formsemestre_id": s["formsemestre_id"]}
) # avec dems ) # sans dems
inset = Set([i["etudid"] for i in ins]) inset = Set([i["etudid"] for i in ins])
s["members"] = orig_set.intersection(inset) s["members"] = orig_set.intersection(inset)
nb_dipl = 0 # combien de diplomes dans ce semestre ? nb_dipl = 0 # combien de diplomes dans ce semestre ?

View File

@ -597,6 +597,7 @@ def do_import_etuds_from_portal(context, sem, a_importer, etudsapo_ident, REQUES
# Les champs suivants sont facultatifs (pas toujours renvoyés par le portail) # Les champs suivants sont facultatifs (pas toujours renvoyés par le portail)
"code_ine": etud.get("ine", "").strip(), "code_ine": etud.get("ine", "").strip(),
"sexe": gender2sex(etud["gender"].strip()), "sexe": gender2sex(etud["gender"].strip()),
"etape": etud.get("etape", None),
"email": etud.get("mail", "").strip(), "email": etud.get("mail", "").strip(),
"emailperso": etud.get("mailperso", "").strip(), "emailperso": etud.get("mailperso", "").strip(),
"date_naissance": etud.get("naissance", "").strip(), "date_naissance": etud.get("naissance", "").strip(),
@ -619,7 +620,7 @@ def do_import_etuds_from_portal(context, sem, a_importer, etudsapo_ident, REQUES
do_import_etud_admission(context, cnx, args["etudid"], etud) do_import_etud_admission(context, cnx, args["etudid"], etud)
# Adresse # Adresse
adresse_id = scolars.adresse_create(cnx, args) scolars.adresse_create(cnx, args)
# Inscription au semestre # Inscription au semestre
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
@ -627,6 +628,7 @@ def do_import_etuds_from_portal(context, sem, a_importer, etudsapo_ident, REQUES
sem["formsemestre_id"], sem["formsemestre_id"],
args["etudid"], args["etudid"],
etat="I", etat="I",
etape=args["etape"],
REQUEST=REQUEST, REQUEST=REQUEST,
method="synchro_apogee", method="synchro_apogee",
) )
@ -754,6 +756,18 @@ def get_bac(etud):
return serie_bac, spe_bac return serie_bac, spe_bac
def update_etape_formsemestre_inscription(context, ins, etud):
"""Met à jour l'étape de l'inscription.
Args:
ins (dict): formsemestre_inscription
etud (dict): etudiant portail Apo
"""
if etud["etape"] != ins["etape"]:
ins["etape"] = etud["etape"]
context.do_formsemestre_inscription_edit(args=ins)
def formsemestre_import_etud_admission( def formsemestre_import_etud_admission(
context, formsemestre_id, import_identite=True, import_email=False context, formsemestre_id, import_identite=True, import_email=False
): ):
@ -797,6 +811,7 @@ def formsemestre_import_etud_admission(
# pas vu dans les etudiants de l'étape, tente en individuel # pas vu dans les etudiants de l'étape, tente en individuel
etud = sco_portal_apogee.get_etud_apogee(context, code_nip) etud = sco_portal_apogee.get_etud_apogee(context, code_nip)
if etud: if etud:
update_etape_formsemestre_inscription(context, i, etud)
do_import_etud_admission( do_import_etud_admission(
context, context,
cnx, cnx,