# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2020 Emmanuel Viennet. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Emmanuel Viennet emmanuel.viennet@viennet.net # ############################################################################## """Form. pour inscription rapide des etudiants d'un semestre dans un autre Utilise les autorisations d'inscription délivrées en jury. """ from gen_tables import GenTable from notesdb import * from sco_utils import * from notes_log import log import sco_codes_parcours import sco_pvjury import sco_formsemestre import sco_formsemestre_inscriptions import sco_formsemestre import sco_groups import scolars def list_authorized_etuds_by_sem(context, sem, delai=274): """Liste des etudiants autorisés à s'inscrire dans sem. delai = nb de jours max entre la date de l'autorisation et celle de debut du semestre cible. """ src_sems = list_source_sems(context, sem, delai=delai) inscrits = list_inscrits(context, sem["formsemestre_id"]) r = {} candidats = {} # etudid : etud (tous les etudiants candidats) nb = 0 # debug for src in src_sems: liste = list_etuds_from_sem(context, src, sem) liste_filtree = [] for e in liste: # Filtre ceux qui se sont déjà inscrit dans un semestre APRES le semestre src auth_used = False # autorisation deja utilisée ? etud = context.getEtudInfo(etudid=e["etudid"], filled=True)[0] for isem in etud["sems"]: if DateDMYtoISO(isem["date_debut"]) >= DateDMYtoISO(src["date_fin"]): auth_used = True if not auth_used: candidats[e["etudid"]] = etud liste_filtree.append(e) nb += 1 r[src["formsemestre_id"]] = { "etuds": liste_filtree, "infos": { "id": src["formsemestre_id"], "title": src["titreannee"], "title_target": "formsemestre_status?formsemestre_id=%s" % src["formsemestre_id"], }, } # ajoute attribut inscrit qui indique si l'étudiant est déjà inscrit dans le semestre dest. for e in r[src["formsemestre_id"]]["etuds"]: e["inscrit"] = inscrits.has_key(e["etudid"]) # Ajoute liste des etudiants actuellement inscrits for e in inscrits.values(): e["inscrit"] = True r[sem["formsemestre_id"]] = { "etuds": inscrits.values(), "infos": { "id": sem["formsemestre_id"], "title": "Semestre cible: " + sem["titreannee"], "title_target": "formsemestre_status?formsemestre_id=%s" % sem["formsemestre_id"], "comment": " actuellement inscrits dans ce semestre", "help": "Ces étudiants sont actuellement inscrits dans ce semestre. Si vous les décochez, il seront désinscrits.", }, } return r, inscrits, candidats def list_inscrits(context, formsemestre_id, with_dems=False): """Etudiants déjà inscrits à ce semestre { etudid : etud } """ if not with_dems: ins = context.Notes.do_formsemestre_inscription_listinscrits( formsemestre_id ) # optimized else: args = {"formsemestre_id": formsemestre_id} ins = context.Notes.do_formsemestre_inscription_list(args=args) inscr = {} for i in ins: etudid = i["etudid"] inscr[etudid] = context.getEtudInfo(etudid=etudid, filled=True)[0] return inscr def list_etuds_from_sem(context, src, dst): """Liste des etudiants du semestre src qui sont autorisés à passer dans le semestre dst.""" target = dst["semestre_id"] dpv = sco_pvjury.dict_pvjury(context, src["formsemestre_id"]) if not dpv: return [] etuds = [ x["identite"] for x in dpv["decisions"] if target in [a["semestre_id"] for a in x["autorisations"]] ] return etuds def list_inscrits_date(context, sem): """Liste les etudiants inscrits dans n'importe quel semestre SAUF sem à la date de début de sem. """ cnx = context.GetDBConnexion() cursor = cnx.cursor(cursor_factory=ScoDocCursor) sem["date_debut_iso"] = DateDMYtoISO(sem["date_debut"]) cursor.execute( """select I.etudid from notes_formsemestre_inscription I, notes_formsemestre S where I.formsemestre_id = S.formsemestre_id and I.formsemestre_id != %(formsemestre_id)s and S.date_debut <= %(date_debut_iso)s and S.date_fin >= %(date_debut_iso)s""", sem, ) return [x[0] for x in cursor.fetchall()] def do_inscrit(context, sem, etudids, REQUEST=None, inscrit_groupes=False): """Inscrit ces etudiants dans ce semestre (la liste doit avoir été vérifiée au préalable) En option: inscrit aux mêmes groupes que dans le semestre origine """ log("do_inscrit (inscrit_groupes=%s): %s" % (inscrit_groupes, etudids)) for etudid in etudids: sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( context, sem["formsemestre_id"], etudid, etat="I", REQUEST=REQUEST, method="formsemestre_inscr_passage", ) if inscrit_groupes: # Inscription dans les mêmes groupes que ceux du semestre d'origine, # s'ils existent. # (mise en correspondance à partir du nom du groupe, sans tenir compte # du nom de la partition: évidemment, cela ne marche pas si on a les # même noms de groupes dans des partitions différentes) etud = context.getEtudInfo(etudid=etudid, filled=True)[0] log("cherche groupes de %(nom)s" % etud) # recherche le semestre origine (il serait plus propre de l'avoir conservé!) if len(etud["sems"]) < 2: continue prev_formsemestre = etud["sems"][1] sco_groups.etud_add_group_infos(context, etud, prev_formsemestre) cursem_groups_by_name = dict( [ (g["group_name"], g) for g in sco_groups.get_sem_groups(context, sem["formsemestre_id"]) if g["group_name"] ] ) # forme la liste des groupes présents dans les deux semestres: partition_groups = [] # [ partition+group ] (ds nouveau sem.) for partition_id in etud["partitions"]: prev_group_name = etud["partitions"][partition_id]["group_name"] if prev_group_name in cursem_groups_by_name: new_group = cursem_groups_by_name[prev_group_name] partition_groups.append(new_group) # inscrit aux groupes for partition_group in partition_groups: sco_groups.change_etud_group_in_partition( context, etudid, partition_group["group_id"], partition_group, REQUEST=REQUEST, ) def do_desinscrit(context, sem, etudids, REQUEST): log("do_desinscrit: %s" % etudids) for etudid in etudids: context.do_formsemestre_desinscription( etudid, sem["formsemestre_id"], REQUEST=REQUEST ) def list_source_sems(context, sem, delai=None): """Liste des semestres sources sem est le semestre destination """ # liste des semestres débutant a moins # de delai (en jours) de la date de fin du semestre d'origine. sems = sco_formsemestre.do_formsemestre_list(context) othersems = [] d, m, y = [int(x) for x in sem["date_debut"].split("/")] date_debut_dst = datetime.date(y, m, d) d, m, y = [int(x) for x in sem["date_fin"].split("/")] date_fin_dst = datetime.date(y, m, d) delais = datetime.timedelta(delai) for s in sems: # pdb.set_trace() # if s['etat'] != '1': # continue # saute semestres pas ouverts if s["formsemestre_id"] == sem["formsemestre_id"]: continue # saute le semestre destination if s["date_fin"]: d, m, y = [int(x) for x in s["date_fin"].split("/")] date_fin = datetime.date(y, m, d) if date_debut_dst - date_fin > delais: continue # semestre trop ancien if date_fin > date_debut_dst: continue # semestre trop récent # Elimine les semestres de formations speciales (sans parcours) if s["semestre_id"] == sco_codes_parcours.NO_SEMESTRE_ID: continue # F = context.formation_list(args={"formation_id": s["formation_id"]})[0] parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"]) if not parcours.ALLOW_SEM_SKIP: if s["semestre_id"] < (sem["semestre_id"] - 1): continue othersems.append(s) return othersems def formsemestre_inscr_passage( context, formsemestre_id, etuds=[], inscrit_groupes=False, submitted=False, dialog_confirmed=False, REQUEST=None, ): """Form. pour inscription des etudiants d'un semestre dans un autre (donné par formsemestre_id). Permet de selectionner parmi les etudiants autorisés à s'inscrire. Principe: - trouver liste d'etud, par semestre - afficher chaque semestre "boites" avec cases à cocher - si l'étudiant est déjà inscrit, le signaler (gras, nom de groupes): il peut être désinscrit - on peut choisir les groupes TD, TP, TA - seuls les etudiants non inscrits changent (de groupe) - les etudiants inscrit qui se trouvent décochés sont désinscrits - Confirmation: indiquer les étudiants inscrits et ceux désinscrits, le total courant. """ inscrit_groupes = int(inscrit_groupes) # log('formsemestre_inscr_passage: formsemestre_id=%s submitted=%s, dialog_confirmed=%s len(etuds)=%d' # % (formsemestre_id, submitted, dialog_confirmed, len(etuds)) ) cnx = context.GetDBConnexion() sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) # -- check lock if sem["etat"] != "1": raise ScoValueError("opération impossible: semestre verrouille") header = context.sco_header(REQUEST, page_title="Passage des étudiants") footer = context.sco_footer(REQUEST) H = [header] if type(etuds) == type(""): etuds = etuds.split(",") # vient du form de confirmation auth_etuds_by_sem, inscrits, candidats = list_authorized_etuds_by_sem(context, sem) etuds_set = set(etuds) candidats_set = set(candidats) inscrits_set = set(inscrits) candidats_non_inscrits = candidats_set - inscrits_set inscrits_ailleurs = set(list_inscrits_date(context, sem)) def set_to_sorted_etud_list(etudset): etuds = [candidats[etudid] for etudid in etudset] etuds.sort(lambda x, y: cmp(x["nom"], y["nom"])) return etuds if submitted: a_inscrire = etuds_set.intersection(candidats_set) - inscrits_set a_desinscrire = inscrits_set - etuds_set else: a_inscrire = a_desinscrire = [] # log('formsemestre_inscr_passage: a_inscrire=%s' % str(a_inscrire) ) # log('formsemestre_inscr_passage: a_desinscrire=%s' % str(a_desinscrire) ) if not submitted: H += build_page( context, REQUEST, sem, auth_etuds_by_sem, inscrits, candidats_non_inscrits, inscrits_ailleurs, inscrit_groupes=inscrit_groupes, ) else: if not dialog_confirmed: # Confirmation if a_inscrire: H.append("

Etudiants à inscrire

    ") for etud in set_to_sorted_etud_list(a_inscrire): H.append("
  1. %(nomprenom)s
  2. " % etud) H.append("
") a_inscrire_en_double = inscrits_ailleurs.intersection(a_inscrire) if a_inscrire_en_double: H.append("

dont étudiants déjà inscrits:

") if a_desinscrire: H.append("

Etudiants à désinscrire

    ") for etudid in a_desinscrire: H.append( '
  1. %(nomprenom)s
  2. ' % inscrits[etudid] ) H.append("
") if not a_inscrire and not a_desinscrire: H.append("""

Il n'y a rien à modifier !

""") H.append( context.confirmDialog( dest_url="formsemestre_inscr_passage", add_headers=False, cancel_url="formsemestre_inscr_passage?formsemestre_id=" + formsemestre_id, OK="Effectuer l'opération", parameters={ "formsemestre_id": formsemestre_id, "etuds": ",".join(etuds), "inscrit_groupes": inscrit_groupes, "submitted": 1, }, REQUEST=REQUEST, ) ) else: # Inscription des étudiants au nouveau semestre: do_inscrit( context, sem, a_inscrire, REQUEST=REQUEST, inscrit_groupes=inscrit_groupes, ) # Desincriptions: do_desinscrit(context, sem, a_desinscrire, REQUEST) H.append( """

Opération effectuée