# -*- coding: utf-8 -*-
##############################################################################
#
# ScoDoc
#
# Copyright (c) 1999 - 2021 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
#
##############################################################################
"""
Module scolar: vues de .../ScoDoc/ '
% etud
]
header = html_sco_header.sco_header(
page_title="Changement adresse de %(nomprenom)s" % etud
)
tf = TrivialFormulator(
request.base_url,
scu.get_request_args(),
(
("adresse_id", {"input_type": "hidden"}),
("etudid", {"input_type": "hidden"}),
(
"email",
{
"size": 40,
"title": "e-mail",
"explanation": "adresse institutionnelle",
},
),
(
"emailperso",
{
"size": 40,
"title": "e-mail",
"explanation": "adresse personnelle",
},
),
(
"domicile",
{"size": 65, "explanation": "numéro, rue", "title": "Adresse"},
),
("codepostaldomicile", {"size": 6, "title": "Code postal"}),
("villedomicile", {"size": 20, "title": "Ville"}),
("paysdomicile", {"size": 20, "title": "Pays"}),
("", {"input_type": "separator", "default": " "}),
("telephone", {"size": 13, "title": "Téléphone"}),
("telephonemobile", {"size": 13, "title": "Mobile"}),
),
initvalues=adr,
submitlabel="Valider le formulaire",
)
dest_url = url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
if tf[0] == 0:
return header + "\n".join(H) + tf[1] + html_sco_header.sco_footer()
elif tf[0] == -1:
return flask.redirect(dest_url)
else:
if adrs:
sco_etud.adresse_edit(cnx, args=tf[2])
else:
sco_etud.adresse_create(cnx, args=tf[2])
logdb(cnx, method="changeCoordonnees", etudid=etudid)
return flask.redirect(dest_url)
# --- Gestion des groupes:
sco_publish(
"/affectGroups",
sco_groups_edit.affectGroups,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/XMLgetGroupsInPartition", sco_groups.XMLgetGroupsInPartition, Permission.ScoView
)
sco_publish(
"/formsemestre_partition_list",
sco_groups.formsemestre_partition_list,
Permission.ScoView,
)
sco_publish("/setGroups", sco_groups.setGroups, Permission.ScoView)
sco_publish("/createGroup", sco_groups.createGroup, Permission.ScoView)
sco_publish("/suppressGroup", sco_groups.suppressGroup, Permission.ScoView)
sco_publish(
"/group_set_name",
sco_groups.group_set_name,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/group_rename",
sco_groups.group_rename,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/groups_auto_repartition",
sco_groups.groups_auto_repartition,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/editPartitionForm",
sco_groups.editPartitionForm,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/partition_delete",
sco_groups.partition_delete,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/partition_set_attr",
sco_groups.partition_set_attr,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/partition_move",
sco_groups.partition_move,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/partition_set_name",
sco_groups.partition_set_name,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/partition_rename",
sco_groups.partition_rename,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/partition_create",
sco_groups.partition_create,
Permission.ScoView,
methods=["GET", "POST"],
)
# @bp.route("/partition_create", methods=["GET", "POST"])
# @scodoc
# @permission_required(Permission.ScoView)
# @scodoc7func
# def partition_create(
#
# formsemestre_id,
# partition_name="",
# default=False,
# numero=None,
# redirect=1):
# return sco_groups.partition_create( formsemestre_id,
sco_publish("/etud_info_html", sco_page_etud.etud_info_html, Permission.ScoView)
# --- Gestion des photos:
sco_publish("/get_photo_image", sco_photos.get_photo_image, Permission.ScoView)
sco_publish("/etud_photo_html", sco_photos.etud_photo_html, Permission.ScoView)
@bp.route("/etud_photo_orig_page")
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def etud_photo_orig_page(etudid=None):
"Page with photo in orig. size"
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
H = [
html_sco_header.sco_header(page_title=etud["nomprenom"]),
" Photo actuelle (%(photoloc)s):
"""
% etud,
sco_photos.etud_photo_html(etud, title="photo actuelle"),
""" Le fichier ne doit pas dépasser 500Ko (recadrer l'image, format "portrait" de préférence). L'image sera automagiquement réduite pour obtenir une hauteur de 90 pixels. Erreur:' + diag + " Confirmer la suppression de la photo de %(nomprenom)s ? '
% etud
]
H.append(
""" Confirmer l'annulation de la %s ? En général, il est recommandé d'importer les étudiants depuis Apogée.
N'utilisez ce formulaire que pour les cas particuliers ou si votre établissement
n'utilise pas d'autre logiciel de gestion des inscriptions. L'étudiant créé ne sera pas inscrit.
Pensez à l'inscrire dans un semestre ! %s Pas d'informations d'Apogée " + A + F
elif tf[0] == -1:
return "\n".join(H) + tf[1] + " " + A + F
# return '\n'.join(H) + ' "
+ A
+ F
)
# log('NbHomonyms=%s' % NbHomonyms)
if not tf[2]["dont_check_homonyms"] and NbHomonyms > 0:
return (
"\n".join(H)
+ tf_error_message(
"""Attention: il y a déjà un étudiant portant des noms et prénoms proches. Vous pouvez forcer la présence d'un homonyme en cochant "autoriser les homonymes" en bas du formulaire."""
)
+ tf[1]
+ " "
+ A
+ F
)
if not edit:
etud = sco_etud.create_etud(cnx, args=tf[2])
etudid = etud["etudid"]
else:
# modif d'un etudiant
sco_etud.etudident_edit(cnx, tf[2])
etud = sco_etud.etudident_list(cnx, {"etudid": etudid})[0]
sco_etud.fill_etuds_info([etud])
# Inval semesters with this student:
to_inval = [s["formsemestre_id"] for s in etud["sems"]]
for formsemestre_id in to_inval:
sco_cache.invalidate_formsemestre(
formsemestre_id=formsemestre_id
) # > etudident_create_or_edit
#
return flask.redirect("ficheEtud?etudid=" + str(etudid))
@bp.route("/etudident_delete", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudInscrit)
@scodoc7func
def etudident_delete(etudid, dialog_confirmed=False):
"Delete a student"
cnx = ndb.GetDBConnexion()
etuds = sco_etud.etudident_list(cnx, {"etudid": etudid})
if not etuds:
raise ScoValueError("Etudiant inexistant !")
else:
etud = etuds[0]
sco_etud.fill_etuds_info([etud])
if not dialog_confirmed:
return scu.confirm_dialog(
"""Opérations effectuées sur l'étudiant %(nomprenom)s
" % etud,
filename="log_" + scu.make_filename(etud["nomprenom"]),
html_next_section=f"""
""",
preferences=sco_preferences.SemPreferences(),
)
return tab.make_page(format=format)
# ---------- PAGE ACCUEIL (listes) --------------
@bp.route("/")
@bp.route("/index_html")
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def index_html(showcodes=0, showsemtable=0):
return sco_dept.index_html(showcodes=showcodes, showsemtable=showsemtable)
sco_publish(
"/trombino", sco_trombino.trombino, Permission.ScoView, methods=["GET", "POST"]
)
sco_publish(
"/pdf_trombino_tours", sco_trombino_tours.pdf_trombino_tours, Permission.ScoView
)
sco_publish(
"/pdf_feuille_releve_absences",
sco_trombino_tours.pdf_feuille_releve_absences,
Permission.ScoView,
)
sco_publish(
"/trombino_copy_photos",
sco_trombino.trombino_copy_photos,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish("/groups_view", sco_groups_view.groups_view, Permission.ScoView)
sco_publish(
"/export_groups_as_moodle_csv",
sco_groups_view.export_groups_as_moodle_csv,
Permission.ScoView,
)
# -------------------------- INFOS SUR ETUDIANTS --------------------------
@bp.route("/getEtudInfo")
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def getEtudInfo(etudid=False, code_nip=False, filled=False, format=None):
"""infos sur un etudiant (API)
On peut specifier etudid ou code_nip
ou bien cherche dans les arguments de la requête: etudid, code_nip, code_ine
(dans cet ordre).
"""
etud = sco_etud.get_etud_info(etudid=etudid, code_nip=code_nip, filled=filled)
if format is None:
return etud
else:
return scu.sendResult(etud, name="etud", format=format)
sco_publish(
"/search_etud_in_dept",
sco_find_etud.search_etud_in_dept,
Permission.ScoView,
methods=["GET", "POST"],
)
@bp.route("/search_etud_by_name")
@bp.route("/Notes/search_etud_by_name") # for JS apis
@scodoc
@permission_required(Permission.ScoView)
def search_etud_by_name():
term = request.args["term"]
data = sco_find_etud.search_etud_by_name(term)
return jsonify(data)
# XMLgetEtudInfos était le nom dans l'ancienne API ScoDoc 6
@bp.route("/etud_info", methods=["GET", "POST"]) # pour compat anciens clients PHP)
@bp.route(
"/XMLgetEtudInfos", methods=["GET", "POST"]
) # pour compat anciens clients PHP)
@bp.route(
"/Absences/XMLgetEtudInfos", methods=["GET", "POST"]
) # pour compat anciens clients PHP
@bp.route(
"/Notes/XMLgetEtudInfos", methods=["GET", "POST"]
) # pour compat anciens clients PHP
@scodoc
@permission_required_compat_scodoc7(Permission.ScoView)
@scodoc7func
def etud_info(etudid=None, format="xml"):
"Donne les informations sur un etudiant"
t0 = time.time()
args = sco_etud.make_etud_args(etudid=etudid)
cnx = ndb.GetDBConnexion()
etuds = sco_etud.etudident_list(cnx, args)
if not etuds:
# etudiant non trouvé: message d'erreur
d = {
"etudid": etudid,
"nom": "?",
"nom_usuel": "",
"prenom": "?",
"civilite": "?",
"sexe": "?", # for backward compat
"email": "?",
"emailperso": "",
"error": "code etudiant inconnu",
}
return scu.sendResult(
d, name="etudiant", format=format, force_outer_xml_tag=False
)
d = {}
etud = etuds[0]
sco_etud.fill_etuds_info([etud])
etud["date_naissance_iso"] = ndb.DateDMYtoISO(etud["date_naissance"])
for a in (
"etudid",
"code_nip",
"code_ine",
"nom",
"nom_usuel",
"prenom",
"nomprenom",
"email",
"emailperso",
"domicile",
"codepostaldomicile",
"villedomicile",
"paysdomicile",
"telephone",
"telephonemobile",
"fax",
"bac",
"specialite",
"annee_bac",
"nomlycee",
"villelycee",
"codepostallycee",
"codelycee",
"date_naissance_iso",
):
d[a] = scu.quote_xml_attr(etud[a])
d["civilite"] = scu.quote_xml_attr(
etud["civilite_str"]
) # exception: ne sort pas la civilite brute
d["sexe"] = d["civilite"] # backward compat pour anciens clients
d["photo_url"] = scu.quote_xml_attr(sco_photos.etud_photo_url(etud))
sem = etud["cursem"]
if sem:
sco_groups.etud_add_group_infos(etud, sem)
d["insemestre"] = [
{
"current": "1",
"formsemestre_id": sem["formsemestre_id"],
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
"date_fin": ndb.DateDMYtoISO(sem["date_fin"]),
"etat": scu.quote_xml_attr(sem["ins"]["etat"]),
"groupes": scu.quote_xml_attr(
etud["groupes"]
), # slt pour semestre courant
}
]
else:
d["insemestre"] = []
for sem in etud["sems"]:
if sem != etud["cursem"]:
d["insemestre"].append(
{
"formsemestre_id": sem["formsemestre_id"],
"date_debut": ndb.DateDMYtoISO(sem["date_debut"]),
"date_fin": ndb.DateDMYtoISO(sem["date_fin"]),
"etat": scu.quote_xml_attr(sem["ins"]["etat"]),
}
)
log("etud_info (%gs)" % (time.time() - t0))
return scu.sendResult(d, name="etudiant", format=format, force_outer_xml_tag=False)
# -------------------------- FICHE ETUDIANT --------------------------
sco_publish("/ficheEtud", sco_page_etud.ficheEtud, Permission.ScoView)
sco_publish(
"/etud_upload_file_form",
sco_archives_etud.etud_upload_file_form,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/etud_delete_archive",
sco_archives_etud.etud_delete_archive,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/etud_get_archived_file",
sco_archives_etud.etud_get_archived_file,
Permission.ScoView,
)
sco_publish(
"/etudarchive_import_files_form",
sco_archives_etud.etudarchive_import_files_form,
Permission.ScoView,
methods=["GET", "POST"],
)
sco_publish(
"/etudarchive_generate_excel_sample",
sco_archives_etud.etudarchive_generate_excel_sample,
Permission.ScoView,
)
# Debouche / devenir etudiant
sco_publish(
"/itemsuivi_suppress",
sco_debouche.itemsuivi_suppress,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
)
sco_publish(
"/itemsuivi_create",
sco_debouche.itemsuivi_create,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
)
sco_publish(
"/itemsuivi_set_date",
sco_debouche.itemsuivi_set_date,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
)
sco_publish(
"/itemsuivi_set_situation",
sco_debouche.itemsuivi_set_situation,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
)
sco_publish(
"/itemsuivi_list_etud", sco_debouche.itemsuivi_list_etud, Permission.ScoView
)
sco_publish("/itemsuivi_tag_list", sco_debouche.itemsuivi_tag_list, Permission.ScoView)
sco_publish(
"/itemsuivi_tag_search", sco_debouche.itemsuivi_tag_search, Permission.ScoView
)
sco_publish(
"/itemsuivi_tag_set",
sco_debouche.itemsuivi_tag_set,
Permission.ScoEtudChangeAdr,
methods=["GET", "POST"],
)
@bp.route("/doAddAnnotation", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudAddAnnotations)
@scodoc7func
def doAddAnnotation(etudid, comment):
"ajoute annotation sur etudiant"
cnx = ndb.GetDBConnexion()
sco_etud.etud_annotations_create(
cnx,
args={
"etudid": etudid,
"comment": comment,
"author": current_user.user_name,
},
)
logdb(cnx, method="addAnnotation", etudid=etudid)
return flask.redirect(
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
)
@bp.route("/doSuppressAnnotation", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def doSuppressAnnotation(etudid, annotation_id):
"""Suppression annotation."""
if not sco_permissions_check.can_suppress_annotation(annotation_id):
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
cnx = ndb.GetDBConnexion()
annos = sco_etud.etud_annotations_list(cnx, args={"id": annotation_id})
if len(annos) != 1:
raise ScoValueError("annotation inexistante !")
anno = annos[0]
log("suppress annotation: %s" % str(anno))
logdb(cnx, method="SuppressAnnotation", etudid=etudid)
sco_etud.etud_annotations_delete(cnx, annotation_id)
return flask.redirect(
url_for(
"scolar.ficheEtud",
scodoc_dept=g.scodoc_dept,
etudid=etudid,
head_message="Annotation%%20supprimée",
)
)
@bp.route("/formChangeCoordonnees", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func
def formChangeCoordonnees(etudid):
"edit coordonnees etudiant"
cnx = ndb.GetDBConnexion()
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
adrs = sco_etud.adresse_list(cnx, {"etudid": etudid})
if adrs:
adr = adrs[0]
else:
adr = {} # no data for this student
H = [
'Changement des coordonnées de %(nomprenom)s
%s
" % etud["nomprenom"],
'",
html_sco_header.sco_footer(),
]
return "\n".join(H)
@bp.route("/formChangePhoto", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoEtudChangeAdr)
@scodoc7func
def formChangePhoto(etudid=None):
"""Formulaire changement photo étudiant"""
etud = sco_etud.get_etud_info(filled=True)[0]
if sco_photos.etud_photo_is_local(etud):
etud["photoloc"] = "dans ScoDoc"
else:
etud["photoloc"] = "externe"
H = [
html_sco_header.sco_header(page_title="Changement de photo"),
"""Changement de la photo de %(nomprenom)s
%(operation_name)s de %(nomprenom)s (semestre %(semtitre)s)
Création d'un étudiant
Modification d\'un étudiant (fiche)
'
% url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid)
)
initvalues = sco_etud.etudident_list(cnx, {"etudid": etudid})
assert len(initvalues) == 1
initvalues = initvalues[0]
submitlabel = "Modifier les données"
# recuperation infos Apogee
# Si on a le code NIP, fait juste une requete, sinon tente de rechercher par nom
# (la recherche par nom ne fonctionne plus à Paris 13)
# XXX A terminer
# code_nip = initvalues.get("code_nip", "")
# if code_nip:
# try:
# infos = sco_portal_apogee.get_etud_apogee(code_nip)
# except ValueError:
# infos = None
# pass # XXX a terminer
vals = scu.get_request_args()
nom = vals.get("nom", None)
if nom is None:
nom = initvalues.get("nom", None)
if nom is None:
infos = []
else:
prenom = vals.get("prenom", "")
if vals.get("tf_submitted", False) and not prenom:
prenom = initvalues.get("prenom", "")
infos = sco_portal_apogee.get_infos_apogee(nom, prenom)
if infos:
formatted_infos = [
"""
"""
]
nanswers = len(infos)
nmax = 10 # nb max de reponse montrees
infos = infos[:nmax]
for i in infos:
formatted_infos.append("
")
m = "%d étudiants trouvés" % nanswers
if len(infos) != nanswers:
m += " (%d montrés)" % len(infos)
A = """")
for k in i.keys():
if k != "nip":
item = "
Informations Apogée
annulation
' + F
else:
# form submission
if edit:
etudid = tf[2]["etudid"]
else:
etudid = None
ok, NbHomonyms = sco_etud.check_nom_prenom(
cnx, nom=tf[2]["nom"], prenom=tf[2]["prenom"], etudid=etudid
)
if not ok:
return (
"\n".join(H)
+ tf_error_message("Nom ou prénom invalide")
+ tf[1]
+ "Confirmer la suppression de l'étudiant {e[nomprenom]} ?
Prenez le temps de vérifier que vous devez vraiment supprimer cet étudiant !
Cette opération irréversible efface toute trace de l'étudiant: inscriptions, notes, absences... dans tous les semestres qu'il a fréquenté.
Dans la plupart des cas, vous avez seulement besoin de le
Vérifier la fiche de {e[nomprenom]}
""".format( e=etud, fiche_url=url_for( "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid ), ), dest_url="", cancel_url=url_for( "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid ), OK="Supprimer définitivement cet étudiant", parameters={"etudid": etudid}, ) log("etudident_delete: etudid=%(etudid)s nomprenom=%(nomprenom)s" % etud) # delete in all tables ! tables = [ "notes_appreciations", "scolar_autorisation_inscription", "scolar_formsemestre_validation", "scolar_events", "notes_notes_log", "notes_notes", "notes_moduleimpl_inscription", "notes_formsemestre_inscription", "group_membership", "entreprise_contact", "etud_annotations", "scolog", "admissions", "adresse", "absences", "absences_notifications", "billet_absence", ] cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) for table in tables: cursor.execute("delete from %s where etudid=%%(etudid)s" % table, etud) cursor.execute("delete from identite where id=%(etudid)s", etud) cnx.commit() # Inval semestres où il était inscrit: to_inval = [s["formsemestre_id"] for s in etud["sems"]] for formsemestre_id in to_inval: sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre_id) # > return flask.redirect(scu.ScoURL() + r"?head_message=Etudiant%20supprimé") @bp.route("/check_group_apogee") @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func def check_group_apogee(group_id, etat=None, fix=False, fixmail=False): """Verification des codes Apogee et mail de tout un groupe. Si fix == True, change les codes avec Apogée. XXX A re-écrire pour API 2: prendre liste dans l'étape et vérifier à partir de cela. """ etat = etat or None members, group, _, sem, _ = sco_groups.get_group_infos(group_id, etat=etat) formsemestre_id = group["formsemestre_id"] cnx = ndb.GetDBConnexion() H = [ html_sco_header.html_sem_header( "Etudiants du %s" % (group["group_name"] or "semestre"), sem, ), 'Nom | Nom usuel | Prénom | NIP (ScoDoc) | Apogée | |
---|---|---|---|---|---|
%s | %s | %s | %s | %s | %s |
Retour au semestre """ % ( request.base_url, formsemestre_id, scu.strnone(group_id), scu.strnone(etat), formsemestre_id, ) ) H.append( """
Retour au semestre """ % ( request.base_url, formsemestre_id, scu.strnone(group_id), scu.strnone(etat), formsemestre_id, ) ) return "\n".join(H) + html_sco_header.sco_footer() @bp.route("/form_students_import_excel", methods=["GET", "POST"]) @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func def form_students_import_excel(formsemestre_id=None): "formulaire import xls" formsemestre_id = int(formsemestre_id) if formsemestre_id else None if formsemestre_id: sem = sco_formsemestre.get_formsemestre(formsemestre_id) dest_url = ( # scu.ScoURL() + "/formsemestre_status?formsemestre_id=%s" % formsemestre_id # TODO: Remplacer par for_url ? url_for( "notes.formsemestre_status", scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, ) ) else: sem = None dest_url = scu.ScoURL() if sem and not sem["etat"]: raise ScoValueError("Modification impossible: semestre verrouille") H = [ html_sco_header.sco_header(page_title="Import etudiants"), """
A utiliser pour importer de nouveaux étudiants (typiquement au premier semestre).
Si les étudiants à inscrire sont déjà dans un autre semestre, utiliser le menu "Inscriptions (passage des étudiants) depuis d'autres semestres à partir du semestre destination.
Si vous avez un portail Apogée, il est en général préférable d'importer les étudiants depuis Apogée, via le menu "Synchroniser avec étape Apogée".
L'opération se déroule en deux étapes. Dans un premier temps, vous téléchargez une feuille Excel type. Vous devez remplir cette feuille, une ligne décrivant chaque étudiant. Ensuite, vous indiquez le nom de votre fichier dans la case "Fichier Excel" ci-dessous, et cliquez sur "Télécharger" pour envoyer au serveur votre liste.
""", ] # ' if sem: H.append( """Les étudiants importés seront inscrits dans le semestre %s
""" % sem["titremois"] ) else: H.append( """Pour inscrire directement les étudiants dans un semestre de formation, il suffit d'indiquer le code de ce semestre (qui doit avoir été créé au préalable). Cliquez ici pour afficher les codes
""" % (scu.ScoURL()) ) H.append("""Le fichier Excel décrivant les étudiants doit comporter les colonnes suivantes.
Les colonnes peuvent être placées dans n'importe quel ordre, mais le titre exact (tel que ci-dessous) doit être sur la première ligne.
Les champs avec un astérisque (*) doivent être présents (nulls non autorisés).
Attribut | Type | Description | |
%s | %s | %s | %s |