# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2024 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 # ############################################################################## """Synchronisation des listes d'étudiants avec liste portail (Apogée) """ import time from operator import itemgetter from flask import g, url_for from flask_login import current_user from app import db, log from app.models import Admission, Adresse, FormSemestre, Identite, ScolarNews import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb from app.scodoc import html_sco_header from app.scodoc import sco_cache from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_groups from app.scodoc import sco_inscr_passage from app.scodoc import sco_portal_apogee from app.scodoc import sco_etud from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_permissions import Permission # Clés utilisées pour la synchro EKEY_APO = "nip" EKEY_SCO = "code_nip" EKEY_NAME = "code NIP" # view: def formsemestre_synchro_etuds( formsemestre_id, etuds: list = None, inscrits_without_key: list = None, annee_apogee=None, submitted=False, dialog_confirmed=False, export_cat_xls=None, read_only=False, ): """Synchronise les étudiants de ce semestre avec ceux d'Apogée. etuds : liste des codes NIP des etudiants a inscrire (ou deja inscrits) inscrits_without_key : etudids des etudiants sans code NIP a laisser inscrits read_only : Affiche sans permettre modifications On a plusieurs cas de figure: L'étudiant peut être 1- présent dans Apogée et inscrit dans le semestre ScoDoc (etuds_ok) 2- dans Apogée, dans ScoDoc, mais pas inscrit dans le semestre (etuds_noninscrits) 3- dans Apogée et pas dans ScoDoc (a_importer) 4- inscrit dans le semestre ScoDoc, mais pas trouvé dans Apogée (sur la base du code NIP) Que faire ? Cas 1: rien à faire Cas 2: inscrire dans le semestre Cas 3: importer l'étudiant (le créer) puis l'inscrire à ce semestre. Cas 4: lister les etudiants absents d'Apogée (indiquer leur code NIP...) - présenter les différents cas - l'utilisateur valide (cocher les étudiants à importer/inscrire) - go etuds: apres sélection par l'utilisateur, la liste des étudiants selectionnés que l'on va importer/inscrire """ etuds = etuds or [] formsemestre = FormSemestre.get_formsemestre(formsemestre_id) inscrits_without_key = inscrits_without_key or [] log(f"formsemestre_synchro_etuds: formsemestre_id={formsemestre_id}") sem = sco_formsemestre.get_formsemestre(formsemestre_id) sem["etape_apo_str"] = sco_formsemestre.formsemestre_etape_apo_str(sem) # Write access ? if not current_user.has_permission(Permission.EtudInscrit): read_only = True if read_only: submitted = False dialog_confirmed = False # -- check lock if not sem["etat"]: raise ScoValueError("opération impossible: semestre verrouille") if not sem["etapes"]: raise ScoValueError( f"""opération impossible: ce semestre n'a pas de code étape (voir Modifier ce semestre) """, safe=True, ) footer = html_sco_header.sco_footer() base_url = url_for( "notes.formsemestre_synchro_etuds", scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, annee_apogee=annee_apogee or None, # si None, le param n'est pas dans l'URL ) if annee_apogee is None: # année d'inscription par défaut annee_apogee = scu.annee_scolaire_debut( sem["annee_debut"], sem["mois_debut_ord"] ) annee_apogee = str(annee_apogee) if isinstance(etuds, str): etuds = etuds.split(",") # vient du form de confirmation elif isinstance(etuds, int): etuds = [str(etuds)] if isinstance(inscrits_without_key, int): inscrits_without_key = [inscrits_without_key] elif isinstance(inscrits_without_key, str): inscrits_without_key = inscrits_without_key.split(",") elif not isinstance(inscrits_without_key, list): raise ValueError("invalid type for inscrits_without_key") inscrits_without_key = [int(x) for x in inscrits_without_key if x] ( etuds_by_cat, a_importer, a_inscrire, inscrits_set, inscrits_without_key_all, etudsapo_ident, ) = list_synch(sem, annee_apogee=annee_apogee) if export_cat_xls: filename = export_cat_xls xls = _build_page( sem, etuds_by_cat, annee_apogee, export_cat_xls=export_cat_xls, base_url=base_url, read_only=read_only, ) return scu.send_file( xls, mime=scu.XLS_MIMETYPE, filename=filename, suffix=scu.XLSX_SUFFIX, ) H = [html_sco_header.sco_header(page_title="Synchronisation étudiants")] if not submitted: H += _build_page( sem, etuds_by_cat, annee_apogee, base_url=base_url, read_only=read_only, ) else: etuds_set = set(etuds) a_importer = a_importer.intersection(etuds_set) a_desinscrire = inscrits_set - etuds_set log("inscrits_without_key_all=%s" % set(inscrits_without_key_all)) log("inscrits_without_key=%s" % inscrits_without_key) a_desinscrire_without_key = set(inscrits_without_key_all) - set( inscrits_without_key ) log("a_desinscrire_without_key=%s" % a_desinscrire_without_key) inscrits_ailleurs = set(sco_inscr_passage.list_inscrits_date(formsemestre)) a_inscrire = a_inscrire.intersection(etuds_set) if not dialog_confirmed: # Confirmation if a_importer: H.append("

Étudiants à importer et inscrire :

    ") for key in a_importer: nom = f"""{etudsapo_ident[key]['nom']} {etudsapo_ident[key].get("prenom", "")}""" H.append(f"
  1. {nom}
  2. ") H.append("
") if a_inscrire: H.append("

Étudiants à inscrire :

    ") for key in a_inscrire: nom = f"""{etudsapo_ident[key]['nom']} {etudsapo_ident[key].get("prenom", "")}""" H.append(f"
  1. {nom}
  2. ") H.append("
") a_inscrire_en_double = inscrits_ailleurs.intersection(a_inscrire) if a_inscrire_en_double: H.append( "

dont étudiants déjà inscrits dans un autre semestre:

    " ) for key in a_inscrire_en_double: nom = f"""{etudsapo_ident[key]['nom']} {etudsapo_ident[key].get("prenom", "")}""" H.append(f'
  1. {nom}
  2. ') H.append("
") if a_desinscrire: H.append("

Étudiants à désinscrire :

    ") for key in a_desinscrire: etud = sco_etud.get_etud_info(filled=True, code_nip=key)[0] H.append('
  1. %(nomprenom)s
  2. ' % etud) H.append("
") if a_desinscrire_without_key: H.append("

Étudiants à désinscrire (sans code):

    ") for etudid in a_desinscrire_without_key: etud = inscrits_without_key_all[etudid] sco_etud.format_etud_ident(etud) H.append('
  1. %(nomprenom)s
  2. ' % etud) H.append("
") todo = ( a_importer or a_inscrire or a_desinscrire or a_desinscrire_without_key ) if not todo: H.append("""

Il n'y a rien à modifier !

""") H.append( scu.confirm_dialog( dest_url="formsemestre_synchro_etuds", add_headers=False, cancel_url="formsemestre_synchro_etuds?formsemestre_id=" + str(formsemestre_id), OK="Effectuer l'opération" if todo else "OK", parameters={ "formsemestre_id": formsemestre_id, "etuds": ",".join(etuds), "inscrits_without_key": ",".join( [str(x) for x in inscrits_without_key] ), "submitted": 1, "annee_apogee": annee_apogee, }, ) ) else: # OK, do it # Conversions des listes de codes NIP en listes de codes etudid def nip2etudid(code_nip): etud = sco_etud.get_etud_info(code_nip=code_nip)[0] return etud["etudid"] etudids_a_inscrire = [nip2etudid(x) for x in a_inscrire] etudids_a_desinscrire = [nip2etudid(x) for x in a_desinscrire] etudids_a_desinscrire += a_desinscrire_without_key # # check decisions jury ici pour éviter de recontruire le cache # après chaque desinscription sco_formsemestre_inscriptions.check_if_has_decision_jury( formsemestre, a_desinscrire ) with sco_cache.DeferredSemCacheManager(): do_import_etuds_from_portal(formsemestre, a_importer, etudsapo_ident) sco_inscr_passage.do_inscrit(formsemestre, etudids_a_inscrire) sco_inscr_passage.do_desinscrit( formsemestre, etudids_a_desinscrire, check_has_dec_jury=False ) H.append( f"""

Opération effectuée