Clonage formation: conserve ue_code, même si vide

This commit is contained in:
Emmanuel Viennet 2024-01-26 14:57:50 +01:00
parent 431dd20911
commit 79f07deac0
6 changed files with 50 additions and 27 deletions

View File

@ -5,6 +5,7 @@ from flask import g
import pandas as pd
from app import db, log
from app import models
from app.models import APO_CODE_STR_LEN
from app.models import SHORT_STR_LEN
from app.models.but_refcomp import ApcNiveau, ApcParcours
@ -12,7 +13,7 @@ from app.models.modules import Module
from app.scodoc import sco_utils as scu
class UniteEns(db.Model):
class UniteEns(models.ScoDocModel):
"""Unité d'Enseignement (UE)"""
__tablename__ = "notes_ue"
@ -81,7 +82,7 @@ class UniteEns(db.Model):
'EXTERNE' if self.is_external else ''})>"""
def clone(self):
"""Create a new copy of this ue.
"""Create a new copy of this ue, add to session.
Ne copie pas le code, ni le code Apogée, ni les liens au réf. de comp.
(parcours et niveau).
"""
@ -100,8 +101,26 @@ class UniteEns(db.Model):
coef_rcue=self.coef_rcue,
color=self.color,
)
db.session.add(ue)
return ue
@classmethod
def convert_dict_fields(cls, args: dict) -> dict:
"""Convert fields from the given dict to model's attributes values. No side effect.
args: dict with args in application.
returns: dict to store in model's db.
"""
args = args.copy()
if "type" in args:
args["type"] = int(args["type"] or 0)
if "is_external" in args:
args["is_external"] = scu.to_bool(args["is_external"])
if "ects" in args:
args["ects"] = float(args["ects"])
return args
def to_dict(self, convert_objects=False, with_module_ue_coefs=True):
"""as a dict, with the same conversions as in ScoDoc7.
If convert_objects, convert all attributes to native types

View File

@ -300,6 +300,7 @@ class EditableTable(object):
output_formators={},
input_formators={},
aux_tables=[],
convert_empty_to_nulls=True, # les arguments vides sont traduits en NULL
convert_null_outputs_to_empty=True,
html_quote=False, # changed in 9.0.10
fields_creators={}, # { field : [ sql_command_to_create_it ] }
@ -321,6 +322,7 @@ class EditableTable(object):
self.output_formators = output_formators
self.input_formators = input_formators
self.convert_null_outputs_to_empty = convert_null_outputs_to_empty
self.convert_empty_to_nulls = convert_empty_to_nulls
self.html_quote = html_quote
self.fields_creators = fields_creators
self.filter_nulls = filter_nulls
@ -351,6 +353,7 @@ class EditableTable(object):
self.table_name,
vals,
commit=True,
convert_empty_to_nulls=self.convert_empty_to_nulls,
return_id=(self.id_name is not None),
ignore_conflicts=self.insert_ignore_conflicts,
)
@ -444,7 +447,7 @@ def dictfilter(d, fields, filter_nulls=True):
"""returns a copy of d with only keys listed in "fields" and non null values"""
r = {}
for f in fields:
if f in d and (d[f] != None or not filter_nulls):
if f in d and (d[f] is not None or not filter_nulls):
try:
val = d[f].strip()
except:

View File

@ -89,6 +89,7 @@ _ueEditor = ndb.EditableTable(
"color",
"niveau_competence_id",
),
convert_empty_to_nulls=False, # necessaire pour ue_code == ""
sortkey="numero",
input_formators={
"type": ndb.int_null_is_zero,
@ -110,7 +111,7 @@ def ue_list(*args, **kw):
return _ueEditor.list(cnx, *args, **kw)
def do_ue_create(args):
def do_ue_create(args, allow_empty_ue_code=False):
"create an ue"
cnx = ndb.GetDBConnexion()
# check duplicates
@ -120,18 +121,18 @@ def do_ue_create(args):
f"""Acronyme d'UE "{args['acronyme']}" déjà utilisé !
(chaque UE doit avoir un acronyme unique dans la formation)"""
)
if (
(not "ue_code" in args)
or (args["ue_code"] is None)
or (not args["ue_code"].strip())
):
# évite les conflits de code
while True:
cursor = db.session.execute(sa.text("select notes_newid_ucod();"))
code = cursor.fetchone()[0]
if UniteEns.query.filter_by(ue_code=code).count() == 0:
break
args["ue_code"] = code
if "ue_code" not in args or args["ue_code"] is None or not args["ue_code"].strip():
if allow_empty_ue_code:
args["ue_code"] = ""
else:
# évite les conflits: génère nouveau ue_code
while True:
cursor = db.session.execute(sa.text("select notes_newid_ucod();"))
code = cursor.fetchone()[0]
if UniteEns.query.filter_by(ue_code=code).count() == 0:
break
args["ue_code"] = code
# create
ue_id = _ueEditor.create(cnx, args)
log(f"do_ue_create: created {ue_id} with {args}")

View File

@ -168,16 +168,14 @@ def formsemestre_associate_new_version(
formation_id=new_formation_id,
)
)
else:
return flask.redirect(
url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
)
return flask.redirect(
url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
)
else:
raise ScoValueError("Méthode invalide")
)
raise ScoValueError("Méthode invalide")
def do_formsemestres_associate_new_version(

View File

@ -117,6 +117,7 @@ def formation_export_dict(
ues = ues.all()
ues.sort(key=lambda u: (u.semestre_idx or 0, u.numero or 0, u.acronyme))
f_dict["ue"] = []
ue: UniteEns
for ue in ues:
ue_dict = ue.to_dict()
f_dict["ue"].append(ue_dict)
@ -363,7 +364,9 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
ue_info[1]["niveau_competence_id"] = _formation_retreive_apc_niveau(
referentiel_competence_id, ue_info[1]
)
ue_id = sco_edit_ue.do_ue_create(ue_info[1])
# Note: si le code est indiqué "" dans le xml, il faut le conserver vide
# pour la comparaison ultérieure des formations XXX
ue_id = sco_edit_ue.do_ue_create(ue_info[1], allow_empty_ue_code=True)
ue: UniteEns = db.session.get(UniteEns, ue_id)
assert ue
if xml_ue_id:

View File

@ -824,7 +824,6 @@ def ue_clone():
ue_id = int(request.form.get("ue_id"))
ue = UniteEns.query.get_or_404(ue_id)
ue2 = ue.clone()
db.session.add(ue2)
db.session.commit()
flash(f"UE {ue.acronyme} dupliquée")
return flask.redirect(