"""ScoDoc 9 models : Unités d'Enseignement (UE) """ from app import db from app.models import APO_CODE_STR_LEN from app.models import SHORT_STR_LEN from app.scodoc import sco_utils as scu class UniteEns(db.Model): """Unité d'Enseignement (UE)""" __tablename__ = "notes_ue" id = db.Column(db.Integer, primary_key=True) ue_id = db.synonym("id") formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id")) acronyme = db.Column(db.Text(), nullable=False) numero = db.Column(db.Integer) # ordre de présentation titre = db.Column(db.Text()) # Le semestre_idx n'est pas un id mais le numéro du semestre: 1, 2, ... # En ScoDoc7 et pour les formations classiques, il est NULL # (le numéro du semestre étant alors déterminé par celui des modules de l'UE) # Pour les formations APC, il est obligatoire (de 1 à 6 pour le BUT): semestre_idx = db.Column(db.Integer, nullable=True, index=True) # Type d'UE: 0 normal ("fondamentale"), 1 "sport", 2 "projet et stage (LP)", # 4 "élective" type = db.Column(db.Integer, default=0, server_default="0") # Les UE sont "compatibles" (pour la capitalisation) ssi elles ont ^m code # note: la fonction SQL notes_newid_ucod doit être créée à part ue_code = db.Column( db.String(SHORT_STR_LEN), server_default=db.text("notes_newid_ucod()"), nullable=False, ) ects = db.Column(db.Float) # nombre de credits ECTS is_external = db.Column(db.Boolean(), default=False, server_default="false") # id de l'element pedagogique Apogee correspondant: code_apogee = db.Column(db.String(APO_CODE_STR_LEN)) # coef UE, utilise seulement si l'option use_ue_coefs est activée: coefficient = db.Column(db.Float) # coef. pour le calcul de moyennes de RCUE. Par défaut, 1. coef_rcue = db.Column(db.Float, nullable=False, default=1.0, server_default="1.0") color = db.Column(db.Text()) # BUT niveau_competence_id = db.Column(db.Integer, db.ForeignKey("apc_niveau.id")) niveau_competence = db.relationship("ApcNiveau", back_populates="ues") # relations matieres = db.relationship("Matiere", lazy="dynamic", backref="ue") modules = db.relationship("Module", lazy="dynamic", backref="ue") def __repr__(self): return f"""<{self.__class__.__name__}(id={self.id}, formation_id={ self.formation_id}, acronyme='{self.acronyme}', semestre_idx={ self.semestre_idx} { 'EXTERNE' if self.is_external else ''})>""" def to_dict(self): """as a dict, with the same conversions as in ScoDoc7 (except ECTS: keep None) """ e = dict(self.__dict__) e.pop("_sa_instance_state", None) # ScoDoc7 output_formators e["ue_id"] = self.id e["numero"] = e["numero"] if e["numero"] else 0 e["ects"] = e["ects"] e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0 e["code_apogee"] = e["code_apogee"] or "" # pas de None return e def is_locked(self): """True if UE should not be modified (contains modules used in a locked formsemestre) """ # XXX todo : à ré-écrire avec SQLAlchemy from app.scodoc import sco_edit_ue return sco_edit_ue.ue_is_locked(self.id) def can_be_deleted(self) -> bool: """True si l'UE n'est pas utilisée dans des formsemestre et n'a pas de module rattachés """ # "pas un seul module de cette UE n'a de modimpl..."" return (self.modules.count() == 0) or not any( m.modimpls.all() for m in self.modules ) def guess_semestre_idx(self) -> None: """Lorsqu'on prend une ancienne formation non APC, les UE n'ont pas d'indication de semestre. Cette méthode fixe le semestre en prenant celui du premier module, ou à défaut le met à 1. """ if self.semestre_idx is None: module = self.modules.first() if module is None: self.semestre_idx = 1 else: self.semestre_idx = module.semestre_id db.session.add(self) db.session.commit() def get_ressources(self): "Liste des modules ressources rattachés à cette UE" return self.modules.filter_by(module_type=scu.ModuleType.RESSOURCE).all() def get_saes(self): "Liste des modules SAE rattachés à cette UE" return self.modules.filter_by(module_type=scu.ModuleType.SAE).all() def get_modules_not_apc(self): "Listes des modules non SAE et non ressource (standards, mais aussi bonus...)" return self.modules.filter( (Module.module_type != scu.ModuleType.SAE), (Module.module_type != scu.ModuleType.RESSOURCE), ).all() def get_codes_apogee(self) -> set[str]: """Les codes Apogée (codés en base comme "VRT1,VRT2")""" if self.code_apogee: return {x.strip() for x in self.code_apogee.split(",") if x} return set()