# -*- 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@gmail.com # ############################################################################## """ Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudiant """ from types import StringType import safehtml import sco_utils as scu import notesdb from notes_log import log import VERSION from sco_exceptions import AccessDenied from scolog import logdb from gen_tables import GenTable import sco_formsemestre import sco_groups import sco_tag_module def report_debouche_date(context, start_year=None, format="html", REQUEST=None): """Rapport (table) pour les débouchés des étudiants sortis à partir de l'année indiquée.""" if not start_year: return report_debouche_ask_date(context, REQUEST=REQUEST) if format == "xls": keep_numeric = True # pas de conversion des notes en strings else: keep_numeric = False etudids = get_etudids_with_debouche(context, start_year) tab = table_debouche_etudids(context, etudids, keep_numeric=keep_numeric) tab.filename = scu.make_filename("debouche_scodoc_%s" % start_year) tab.origin = "Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "" tab.caption = "Récapitulatif débouchés à partir du 1/1/%s." % start_year tab.base_url = "%s?start_year=%s" % (REQUEST.URL0, start_year) return tab.make_page( context, title="""

Débouchés étudiants

""", init_qtip=True, javascripts=["js/etud_info.js"], format=format, REQUEST=REQUEST, with_html_headers=True, ) def get_etudids_with_debouche(context, start_year): """Liste des etudids de tous les semestres terminant à partir du 1er janvier de start_year et ayant un 'debouche' renseigné. """ start_date = str(start_year) + "-01-01" # Recupere tous les etudid avec un debouché renseigné et une inscription dans un semestre # posterieur à la date de depart: # r = notesdb.SimpleDictFetch(context, # """SELECT DISTINCT i.etudid # FROM notes_formsemestre_inscription i, admissions adm, notes_formsemestre s # WHERE adm.debouche is not NULL # AND i.etudid = adm.etudid AND i.formsemestre_id = s.formsemestre_id # AND s.date_fin >= %(start_date)s # """, # {'start_date' : start_date }) r = notesdb.SimpleDictFetch( context, """SELECT DISTINCT i.etudid FROM notes_formsemestre_inscription i, notes_formsemestre s, itemsuivi it WHERE i.etudid = it.etudid AND i.formsemestre_id = s.formsemestre_id AND s.date_fin >= %(start_date)s """, {"start_date": start_date}, ) return [x["etudid"] for x in r] def table_debouche_etudids(context, etudids, keep_numeric=True): """Rapport pour ces etudiants""" L = [] for etudid in etudids: etud = context.getEtudInfo(filled=1, etudid=etudid)[0] # retrouve le "dernier" semestre (au sens de la date de fin) sems = etud["sems"] es = [(sems[i]["date_fin_iso"], i) for i in range(len(sems))] imax = max(es)[1] last_sem = sems[imax] nt = context._getNotesCache().get_NotesTable( context, last_sem["formsemestre_id"] ) row = { "etudid": etudid, "sexe": etud["sexe"], "nom": etud["nom"], "prenom": etud["prenom"], "_nom_target": "ficheEtud?etudid=" + etud["etudid"], "_prenom_target": "ficheEtud?etudid=" + etud["etudid"], "_nom_td_attrs": 'id="%s" class="etudinfo"' % (etud["etudid"]), # 'debouche' : etud['debouche'], "moy": scu.fmt_note(nt.get_etud_moy_gen(etudid), keep_numeric=keep_numeric), "rang": nt.get_etud_rang(etudid), "effectif": len(nt.T), "semestre_id": last_sem["semestre_id"], "semestre": last_sem["titre"], "date_debut": last_sem["date_debut"], "date_fin": last_sem["date_fin"], "periode": "%s - %s" % (last_sem["mois_debut"], last_sem["mois_fin"]), "sem_ident": "%s %s" % (last_sem["date_debut_iso"], last_sem["titre"]), # utile pour tris } # recherche des débouchés debouche = itemsuivi_list_etud(context, etudid) # liste de plusieurs items if debouche: row["debouche"] = "
".join( [ str(it["item_date"]) + " : " + it["situation"] + " " + it["tags"] + "" for it in debouche ] ) # else: row["debouche"] = "non renseigné" L.append(row) L.sort(key=lambda x: x["sem_ident"]) titles = { "sexe": "", "nom": "Nom", "prenom": "Prénom", "semestre": "Dernier semestre", "semestre_id": "S", "periode": "Dates", "moy": "Moyenne", "rang": "Rang", "effectif": "Eff.", "debouche": "Débouché", } tab = GenTable( columns_ids=( "semestre", "semestre_id", "periode", "sexe", "nom", "prenom", "moy", "rang", "effectif", "debouche", ), titles=titles, rows=L, # html_col_width='4em', html_sortable=True, html_class="table_leftalign table_listegroupe", preferences=context.get_preferences(), ) return tab def report_debouche_ask_date(context, REQUEST=None): """Formulaire demande date départ""" return ( context.sco_header(REQUEST) + """
Date de départ de la recherche:
""" + context.sco_footer(REQUEST) ) # ---------------------------------------------------------------------------- # # Nouveau suivi des etudiants (nov 2017) # # ---------------------------------------------------------------------------- # OBSOLETE (this field has been copied to itemsuivi) # def debouche_set(context, object, value, REQUEST=None): # """Set debouche (field in admission table, may be deprecated ?) # """ # if not context.can_edit_suivi(REQUEST): # raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") # adm_id = object # debouche = value.strip('-_ \t') # cnx = context.GetDBConnexion() # adms = scolars.admission_list(cnx, {'etudid' : etudid}) # if not adms: # raise ValueError('no admission info for %s !' % etudid) # adm = adms[0] # adm['debouche'] = debouche # admission_edit(cnx, adm) _itemsuiviEditor = notesdb.EditableTable( "itemsuivi", "itemsuivi_id", ("itemsuivi_id", "etudid", "item_date", "situation"), sortkey="item_date desc", convert_null_outputs_to_empty=True, output_formators={ "situation": safehtml.HTML2SafeHTML, "item_date": notesdb.DateISOtoDMY, }, input_formators={"item_date": notesdb.DateDMYtoISO}, ) _itemsuivi_create = _itemsuiviEditor.create _itemsuivi_delete = _itemsuiviEditor.delete _itemsuivi_list = _itemsuiviEditor.list _itemsuivi_edit = _itemsuiviEditor.edit class ItemSuiviTag(sco_tag_module.ScoTag): """Les tags sur les items""" tag_table = "itemsuivi_tags" # table (tag_id, title) assoc_table = "itemsuivi_tags_assoc" # table (tag_id, object_id) obj_colname = "itemsuivi_id" # column name for object_id in assoc_table def itemsuivi_get(cnx, itemsuivi_id, ignore_errors=False): """get an item""" items = _itemsuivi_list(cnx, {"itemsuivi_id": itemsuivi_id}) if items: return items[0] elif not ignore_errors: raise ValueError("invalid itemsuivi_id") return None def itemsuivi_suppress(context, itemsuivi_id, REQUEST=None): """Suppression d'un item""" if not context.can_edit_suivi(REQUEST): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") cnx = context.GetDBConnexion() item = itemsuivi_get(cnx, itemsuivi_id, ignore_errors=True) if item: _itemsuivi_delete(cnx, itemsuivi_id) logdb(REQUEST, cnx, method="itemsuivi_suppress", etudid=item["etudid"]) log("suppressed itemsuivi %s" % (itemsuivi_id,)) def itemsuivi_create( context, etudid, item_date=None, situation="", REQUEST=None, format=None ): """Creation d'un item""" if not context.can_edit_suivi(REQUEST): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") cnx = context.GetDBConnexion() itemsuivi_id = _itemsuivi_create( cnx, args={"etudid": etudid, "item_date": item_date, "situation": situation} ) logdb(REQUEST, cnx, method="itemsuivi_create", etudid=etudid) log("created itemsuivi %s for %s" % (itemsuivi_id, etudid)) item = itemsuivi_get(cnx, itemsuivi_id) if format == "json": return scu.sendJSON(REQUEST, item) return item def itemsuivi_set_date(context, itemsuivi_id, item_date, REQUEST=None): """set item date item_date is a string dd/mm/yyyy """ if not context.can_edit_suivi(REQUEST): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") # log('itemsuivi_set_date %s : %s' % (itemsuivi_id, item_date)) cnx = context.GetDBConnexion() item = itemsuivi_get(cnx, itemsuivi_id) item["item_date"] = item_date _itemsuivi_edit(cnx, item) def itemsuivi_set_situation(context, object, value, REQUEST=None): """set situation""" if not context.can_edit_suivi(REQUEST): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") itemsuivi_id = object situation = value.strip("-_ \t") # log('itemsuivi_set_situation %s : %s' % (itemsuivi_id, situation)) cnx = context.GetDBConnexion() item = itemsuivi_get(cnx, itemsuivi_id) item["situation"] = situation _itemsuivi_edit(cnx, item) return situation or scu.IT_SITUATION_MISSING_STR def itemsuivi_list_etud(context, etudid, format=None, REQUEST=None): """Liste des items pour cet étudiant, avec tags""" cnx = context.GetDBConnexion() items = _itemsuivi_list(cnx, {"etudid": etudid}) for it in items: it["tags"] = ", ".join(itemsuivi_tag_list(context, it["itemsuivi_id"])) if format == "json": return scu.sendJSON(REQUEST, items) return items def itemsuivi_tag_list(context, itemsuivi_id): """les noms de tags associés à cet item""" r = notesdb.SimpleDictFetch( context, """SELECT t.title FROM itemsuivi_tags_assoc a, itemsuivi_tags t WHERE a.tag_id = t.tag_id AND a.itemsuivi_id = %(itemsuivi_id)s """, {"itemsuivi_id": itemsuivi_id}, ) return [x["title"] for x in r] def itemsuivi_tag_search(context, term, REQUEST=None): """List all used tag names (for auto-completion)""" # restrict charset to avoid injections if not scu.ALPHANUM_EXP.match(term.decode(scu.SCO_ENCODING)): data = [] else: r = notesdb.SimpleDictFetch( context, "SELECT title FROM itemsuivi_tags WHERE title LIKE %(term)s", {"term": term + "%"}, ) data = [x["title"] for x in r] return scu.sendJSON(REQUEST, data) def itemsuivi_tag_set(context, itemsuivi_id="", taglist=[], REQUEST=None): """taglist may either be: a string with tag names separated by commas ("un;deux") or a list of strings (["un", "deux"]) """ if not context.can_edit_suivi(REQUEST): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") if not taglist: taglist = [] elif type(taglist) == StringType: taglist = taglist.split(",") taglist = [t.strip() for t in taglist] # log('itemsuivi_tag_set: itemsuivi_id=%s taglist=%s' % (itemsuivi_id, taglist)) # Sanity check: cnx = context.GetDBConnexion() _ = itemsuivi_get(cnx, itemsuivi_id) newtags = set(taglist) oldtags = set(itemsuivi_tag_list(context, itemsuivi_id)) to_del = oldtags - newtags to_add = newtags - oldtags # should be atomic, but it's not. for tagname in to_add: t = ItemSuiviTag(context, tagname, object_id=itemsuivi_id) for tagname in to_del: t = ItemSuiviTag(context, tagname) t.remove_tag_from_object(itemsuivi_id)