30/05/2026 - 21h00

Signed-off-by: Cherif <cbalde@mysy-training.com>
master_Elyos_FI
Cherif 2026-05-30 21:05:09 +02:00
parent a0bf6933c4
commit f13e7e2dea
9 changed files with 7110 additions and 8 deletions

View File

@ -8,9 +8,11 @@
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Log/log_file.log" beforeDir="false" afterPath="$PROJECT_DIR$/Log/log_file.log" afterDir="false" />
<change beforePath="$PROJECT_DIR$/base_class_calcul_note.py" beforeDir="false" afterPath="$PROJECT_DIR$/base_class_calcul_note.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/jury_mgt.py" beforeDir="false" afterPath="$PROJECT_DIR$/jury_mgt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/class_mgt.py" beforeDir="false" afterPath="$PROJECT_DIR$/class_mgt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/email_mgt.py" beforeDir="false" afterPath="$PROJECT_DIR$/email_mgt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/note_evaluation_mgt.py" beforeDir="false" afterPath="$PROJECT_DIR$/note_evaluation_mgt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/partner_invoice.py" beforeDir="false" afterPath="$PROJECT_DIR$/partner_invoice.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/unite_enseignement_mgt.py" beforeDir="false" afterPath="$PROJECT_DIR$/unite_enseignement_mgt.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />

File diff suppressed because one or more lines are too long

View File

@ -3836,8 +3836,6 @@ on peut lui mettre la valeur "archived" à "1", verrouiller les calcul déja fai
ainsi, on ira toujours traiter les lignes dans 'archived' est different 1
"""
def Calcul_Moyen_evaluation_participant_note_BC_UE(diction):
try:
diction = mycommon.strip_dictionary(diction)
@ -4115,14 +4113,20 @@ def Calcul_Moyen_evaluation_participant_note_BC_UE(diction):
#print(" ## POUR SESSION _ UE _ DIPLOME _ BC = ", ue_id_with_compet_diplome)
ue_id_code = ""
local_eu_id = ""
local_eu_conclusive = "0"
if("ue_id" in ue_id_with_compet_diplome.keys() and ue_id_with_compet_diplome['ue_id']):
ue_id_data = MYSY_GV.dbname['unite_enseignement'].find_one({'_id':ObjectId(str(ue_id_with_compet_diplome['ue_id'])),
'partner_owner_recid':str(my_partner['recid']),}, {'code':1})
'partner_owner_recid':str(my_partner['recid']),}, {'code':1, 'conclusive':1})
if( ue_id_data and 'code' in ue_id_data.keys()):
ue_id_code = ue_id_data['code']
local_eu_id = str(ue_id_data['_id'])
if (ue_id_data and 'conclusive' in ue_id_data.keys()):
local_eu_conclusive = str(ue_id_data['conclusive'])
domaine_competence_id_code = ""
local_domaine_competence_id = ""
if ("domaine_competence_id" in ue_id_with_compet_diplome.keys() and ue_id_with_compet_diplome['domaine_competence_id']):
@ -4327,6 +4331,7 @@ def Calcul_Moyen_evaluation_participant_note_BC_UE(diction):
local_node_moyenne_par_promo_diplome_bc_ue_semestre['ue_id'] = ue_id_with_compet_diplome['ue_id']
local_node_moyenne_par_promo_diplome_bc_ue_semestre['ue_id_code'] = str(ue_id_code)
local_node_moyenne_par_promo_diplome_bc_ue_semestre['conclusive'] = str(local_eu_conclusive)
local_node_moyenne_par_promo_diplome_bc_ue_semestre['moyenne_avant_coef'] = str(moyenne_avant_coef)
local_node_moyenne_par_promo_diplome_bc_ue_semestre['is_eu_validated'] = str(is_eu_validated)
@ -4546,6 +4551,8 @@ def Get_List_Evaluation_by_ue_bc_diplome_session_semestre_With_Filter(diction):
user['inscription_id_nom'] = inscription_id_nom
user['inscription_id_prenom'] = inscription_id_prenom
if( "is_domaine_competence_validated" not in user.keys() or user['is_domaine_competence_validated'] not in ['','0', '1']):
user['is_domaine_competence_validated'] = ""
RetObject.append(mycommon.JSONEncoder().encode(user))
@ -4841,3 +4848,226 @@ def Get_List_Detailled_Note_After_UE_Calculation_With_Filter(diction):
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible de récupérer la liste des détaillée des notes "
"""
Cette fonction permet d'appliquer la regle de compensation suivants :
- Dans un bloc de compétence, la moyennes des UE se compensent
"""
def Run_BC_Compensation_Rules_01(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token', 'session_id', 'diplome_id', 'tab_domaine_competence_ids',
'class_id']
incom_keys = diction.keys()
for val in incom_keys:
if val not in field_list and val.startswith('my_') is False:
mycommon.myprint(str(
inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé")
return False, " Les informations fournies sont incorrectes"
"""
Verification des champs obligatoires
"""
field_list_obligatoire = ['token', 'session_id', 'diplome_id', 'tab_domaine_competence_ids' ]
for val in field_list_obligatoire:
if val not in diction:
mycommon.myprint(
str(inspect.stack()[0][
3]) + " - La valeur '" + val + "' n'est pas presente dans la liste des arguments ")
return False, " Les informations fournies sont incorrectes",
"""
Verification de l'identité et autorisation de l'entité qui
appelle cette API
"""
token = ""
if ("token" in diction.keys()):
if diction['token']:
token = diction['token']
local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
if (local_status is not True):
return local_status, my_partner
is_session_valide_count = MYSY_GV.dbname['session_formation'].count_documents(
{'_id': ObjectId(str(diction['session_id'])),
'valide': '1',
'partner_owner_recid': str(my_partner['recid'])})
if (is_session_valide_count != 1):
mycommon.myprint(
str(inspect.stack()[0][3]) + " L'identifiant de la session est invalide ")
return False, " L'identifiant de la session est invalide ",
is_session_valide_data = MYSY_GV.dbname['session_formation'].find_one(
{'_id': ObjectId(str(diction['session_id'])),
'valide': '1',
'partner_owner_recid': str(my_partner['recid'])})
session_class_id = str(is_session_valide_data['class_id'])
tab_domaine_competence_ids = []
tab_domaine_competence_ids_work = []
tab_domaine_competence_ids_ObjectId = []
if( "tab_domaine_competence_ids" in diction.keys()):
tab_domaine_competence_ids_work = str(diction['tab_domaine_competence_ids']).strip().split(",")
for tmp in tab_domaine_competence_ids_work :
if( tmp ):
is_valide_domaine_competence_id = MYSY_GV.dbname['domaine_competence_pedagogique'].count_documents({'_id':ObjectId(str(tmp)),
'valide': '1',
'locked':'0',
'partner_owner_recid': str(
my_partner[
'recid'])
})
if( is_valide_domaine_competence_id != 1):
mycommon.myprint(
str(inspect.stack()[0][3]) + " Le domaine de compétence "+str(tmp) +" est invalide ")
return False, " Le domaine de compétence "+str(tmp) +" est invalide ",
tab_domaine_competence_ids.append(str(tmp))
tab_domaine_competence_ids_ObjectId.append(ObjectId(str(tmp)))
"""
Si on ne fourni pas de domaine de compétence, on va aller chercher tous les domaines de compétence
associé à la promotion
"""
default_tab_domaine_competence_ids = []
if ("tab_domaine_competence_ids" not in diction.keys()):
if ("list_unite_enseignement" in is_session_valide_data.keys() and is_session_valide_data[
'list_unite_enseignement']):
for session_ue_data in is_session_valide_data['list_unite_enseignement']:
if ("domaine_competence_id" in session_ue_data.keys() and session_ue_data[
'domaine_competence_id'] not in default_tab_domaine_competence_ids):
default_tab_domaine_competence_ids.append(session_ue_data['domaine_competence_id'])
print(" €€€ default_tab_domaine_competence_ids = ", default_tab_domaine_competence_ids)
tab_domaine_competence_ids = default_tab_domaine_competence_ids
for domaine_competence_id in tab_domaine_competence_ids:
print(" TRAINTEMENT COMPENSATION DOMAINE DE COMPETENCE ", domaine_competence_id)
tab_inscrit_id = []
for inscrit in MYSY_GV.dbname['inscription'].find({'valide': '1', 'status': '1',
'partner_owner_recid': str(my_partner['recid']),
'session_id': str(is_session_valide_data['_id'])}):
tab_inscrit_id.append(str(inscrit['_id']))
"""
Etape 3 :
Aller recuperer les types d'evaluation
pour calculer les moyennes par UE
"""
for inscrit_id in tab_inscrit_id:
"""
Aller chercher la liste des note concernées par :
- ce type d'evaluation (ex : les td, tp, exam)
- ce diplome
- ce bloc de compétence
- pour chaque inscrit, calculer la moyenne : tab_inscrit_id.append(str(inscrit['_id']))
"""
if( str(inscrit_id) == "69d38f86b4469130284c79c2"):
print(" ## inscrit_id = ", inscrit_id)
inscrit_data = MYSY_GV.dbname['inscription'].find_one({'valide': '1', 'status': '1',
'partner_owner_recid': str(my_partner['recid']),
'_id': ObjectId(inscrit_id)},
{'_id': 1, 'nom': 1, 'email': 1, 'prenom': 1})
print(" ======================================================== ")
print(" ## INSCRIT = ", str(inscrit_data['nom']), str(inscrit_data['prenom']),str(inscrit_data['email']))
"""
Recuprer les notes calculée (par Diplome / BC / UE de cet etudiant
"""
qry_get_data = {}
qry_get_data['inscrit_id'] = str(inscrit_id)
qry_get_data['domaine_competence_id'] = str(domaine_competence_id)
qry_get_data['diplome_id'] = str(diction['diplome_id'])
qry_get_data['partner_owner_recid'] = str(my_partner['recid'])
print(" qry_get_data = ", qry_get_data)
cpt = 0
non_conclusive_nb_item = 0
non_conclusive_somme_note = 0
non_conclusive_moyenne_note = 0
is_non_conclusive_not_validated_moyenne = 0
is_one_conclusive_not_validated = 0
for calculeted_note in MYSY_GV.dbname['work_calcul_moyenne_by_ue_bc_diplome_session_semestre'].find(qry_get_data):
cpt = cpt +1
if( "conclusive" in calculeted_note.keys() and calculeted_note['conclusive'] != "1" and "moyenne_avant_coef" in calculeted_note.keys()):
print("calculeted_note : NON CONCLUSIVE Ligne= ", calculeted_note)
non_conclusive_nb_item = non_conclusive_nb_item + 1
non_conclusive_somme_note = non_conclusive_somme_note + mycommon.tryFloat(calculeted_note['moyenne_avant_coef'])
if( "conclusive" in calculeted_note.keys() and calculeted_note['conclusive'] == "1" and "is_eu_validated" in calculeted_note.keys() ):
print("calculeted_note : CONCLUSIVE Ligne= ", calculeted_note)
if( calculeted_note['is_eu_validated'] != "1" ):
is_one_conclusive_not_validated = 1
print(" KOOOOOOO CONCLUSIVE Ligne NON VALIDEEE _id = ", str(calculeted_note['_id']), " NOTEE = ", str(calculeted_note['moyenne_avant_coef']), " SEUIL VAL = ", str(calculeted_note['ue_seuil_validation']) )
else:
print(" OKKKK TOP CONCLUSIVE Ligne VALIDEEE _id = ", str(calculeted_note['_id']), " NOTEE = ", str(calculeted_note['moyenne_avant_coef']), " SEUIL VAL = ", str(calculeted_note['ue_seuil_validation']) )
if( non_conclusive_nb_item > 0 ):
non_clusive_moyenne_note = round(non_conclusive_somme_note/non_conclusive_nb_item, 2)
print(" SOMME = ", str(non_conclusive_somme_note), " --- NB LIGNE = ", str(non_conclusive_nb_item), " -- non_clusive_moyenne_note = ", str(non_clusive_moyenne_note))
if( non_clusive_moyenne_note < 10 ):
is_non_conclusive_not_validated_moyenne = 1
print(" PAS VALIDEEE COMPENSATION DES NON CONCLUSIVES < 10 = ", str(non_clusive_moyenne_note))
else:
is_non_conclusive_not_validated_moyenne = 0
print(" OUI VALIDEEE COMPENSATION DES NON CONCLUSIVES > 10 = ", str(non_clusive_moyenne_note))
data_key = {}
data_key['inscrit_id'] = str(inscrit_id)
data_key['domaine_competence_id'] = str(domaine_competence_id)
data_key['diplome_id'] = str(diction['diplome_id'])
data_key['partner_owner_recid'] = str(my_partner['recid'])
data_update = {}
if( is_non_conclusive_not_validated_moyenne == 0 and is_one_conclusive_not_validated == 0 and cpt > 0):
print(" ETUDIANT A VALIDER LE domaine_competence_id = ", str(domaine_competence_id))
data_update['is_domaine_competence_validated'] = "1"
else:
print(" ETUDIANT KOOOOO VALIDATION LE domaine_competence_id = ", str(domaine_competence_id))
data_update['is_domaine_competence_validated'] = "0"
print("data_key == ", data_key)
result = MYSY_GV.dbname['work_calcul_moyenne_by_ue_bc_diplome_session_semestre'].update_many(
data_key,
{"$set": data_update},
)
return True, "Ok, La compensation (R01) a bien été appliquées"
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
return False, " Impossible d'appliquer la règle de compensation R01"

View File

@ -4887,7 +4887,7 @@ def Get_Partner_All_Class_Few_Fields(diction):
# Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
# field_list.
'''
field_list = [ 'token', ]
field_list = [ 'token', 'is_ftion_initiale']
incom_keys = diction.keys()
for val in incom_keys:
if val not in field_list and val.startswith('my_') is False:
@ -4927,6 +4927,11 @@ def Get_Partner_All_Class_Few_Fields(diction):
filt_scope_class_id['_id'] = {'$in':tab_class_id_ObjectId}
filt_is_ftion_initiale = {}
if( "is_ftion_initiale" in diction.keys() and diction['is_ftion_initiale'] in ['0', '1', '']):
filt_is_ftion_initiale = {'is_ftion_initiale':str(diction['is_ftion_initiale'])}
RetObject = []
val_tmp = 0
@ -4935,7 +4940,7 @@ def Get_Partner_All_Class_Few_Fields(diction):
for retVal in MYSY_GV.dbname['myclass'].find( {"$and":[
{'partner_owner_recid': my_partner['recid'],
'valide':'1',
'locked':'0'},filt_scope_class_id, filt_archive]},
'locked':'0'},filt_scope_class_id, filt_archive, filt_is_ftion_initiale]},
{'_id': 1, 'external_code': 1, 'internal_code': 1, 'internal_url': 1, }
).sort([("_id", pymongo.DESCENDING), ]):
# mycommon.myprint(str(retVal))

View File

@ -2993,6 +2993,110 @@ def ManualSendInvoiceEmailRIB_CIC_BureauVallee(diction):
return False, " impossible d'envoyer la facure"
"""
Creation manuelle d'une facture avec RIB CIC pour TECHFIRM IS OUEST
"""
def ManualSendInvoiceEmailRIB_CIC_TECHFIRM_IS_OUEST(diction):
try:
'''
Verification des données obligatoires
'''
'''
Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
On controle que les champs obligatoires sont presents dans la liste
'''
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
tomorrow_day = tomorrow.strftime("%A")
print("debut envoi mail de test ")
# on rentre les renseignements pris sur le site du fournisseur
#smtpserver = smtplib.SMTP(MYSY_GV.O365_SMTP_COUNT_smtpsrv, MYSY_GV.O365_SMTP_COUNT_port)
# msg = MIMEMultipart("alternative")
#msg = EmailMessage()
# JINJA2
templateLoader = jinja2.FileSystemLoader(searchpath="./")
templateEnv = jinja2.Environment(loader=templateLoader)
TEMPLATE_FILE = "Template/MySy_Invoice_RIB_Techfirm_tpl.html"
template = templateEnv.get_template(TEMPLATE_FILE)
body = {
"params": {"order_id": "N/A",
"date_order": ": 13/05/2026",
"periode":"26/05/2026 au 31/05/2026",
"total_ht": "1 600",
"tva": "320",
"total_ttc": "1 920",
"client_name": "TECHFIRM IS OUEST",
"client_address": "Chez HQ Ravezies, CS 80112, 32 allée de Boutaut",
"client_zip_ville": "33000 Bordeaux,",
"client_pays": "France",
"packs": "Prestation de service ",
"detail_packs": "Direction de projets IT / MOE du Ministère de l'Agriculture, de l'Agro-alimentaire et de la Souveraineté Alimentaire",
"qty": "4 jours",
"unit_price": "400 €",
"montant": "1 600 €",
"invoice_id": "FACT_20260525",
"invoice_date": "31/05/2026",
"due_date": "15/06/2026",
"orign_order": "N/A",
}
}
#print(" ### body 1 = ", body)
sourceHtml = template.render(params=body["params"])
"""msg.set_content(sourceHtml, subtype='html')
msg['From'] = MYSY_GV.O365_SMTP_COUNT_From_User
msg['Bcc'] = 'contact@mysy-training.com'
msg['Subject'] = "[MySy Training Technology] : Votre facture N° FACT_230500030"
msg['To'] = 'billardman1@gmail.com'
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.login(MYSY_GV.O365_SMTP_COUNT_user, MYSY_GV.O365_SMTP_COUNT_password)
val = smtpserver.send_message(msg)
smtpserver.close()
"""
#print(" Email envoyé " + str(val))
### CREATION DE LA FACTION PDF
templateLoader = jinja2.FileSystemLoader(searchpath="./")
templateEnv = jinja2.Environment(loader=templateLoader)
#TEMPLATE_FILE = "Template/MySy_Invoice_RIB_tpl.html"
TEMPLATE_FILE = "Template/invoice_RIB_Techfirme_tpl.html"
template = templateEnv.get_template(TEMPLATE_FILE)
# This data can come from database query
#print(" ### body 22 = ", body)
sourceHtml = template.render(json_data=body["params"])
orig_file_name = "invoice_FACT_20260525.pdf"
outputFilename = str(MYSY_GV.INVOICE_DIRECTORY) + str(orig_file_name)
# open output file for writing (truncated binary)
resultFile = open(outputFilename, "w+b")
# convert HTML to PDF
pisaStatus = pisa.CreatePDF(
src=sourceHtml, # the HTML to convert
dest=resultFile) # file handle to receive result
# close output file
resultFile.close()
return True, " facture envoyée"
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
return False, " impossible d'envoyer la facure"
"""

35
main.py
View File

@ -3416,6 +3416,22 @@ def ManualSendInvoiceEmailRIB_CIC_BureauVallee():
"""
API Creation manuelle d'une facture avec RIB CIC pour pour TECHFIRM IS OUEST - MAASA
"""
@app.route('/myclass/api/ManualSendInvoiceEmailRIB_CIC_TECHFIRM_IS_OUEST/', methods=['POST','GET'])
@crossdomain(origin='*')
def ManualSendInvoiceEmailRIB_CIC_TECHFIRM_IS_OUEST():
# On recupere le corps (payload) de la requete
payload = mycommon.strip_dictionary (request.form.to_dict())
print(" ### ManualSendInvoiceEmailRIB_CIC_TECHFIRM_IS_OUEST : payload = ",str(payload))
localStatus, message= emails.ManualSendInvoiceEmailRIB_CIC_TECHFIRM_IS_OUEST(payload)
return jsonify(status=localStatus, message=message )
"""
API de recuperation au formation CSV de la liste des inscrits à une formation
avec les statuts (validé ou pas)
@ -18208,6 +18224,25 @@ def Get_List_Detailled_Note_After_UE_Calculation_With_Filter():
"""
API pour appliquer la regle de compensation R01 sur les notes
- - Dans un bloc de compétence, la moyennes des UE se compensent
"""
@app.route('/myclass/api/Run_BC_Compensation_Rules_01', methods=['POST','GET'])
@crossdomain(origin='*')
def Run_BC_Compensation_Rules_01():
# On recupere le corps (payload) de la requete
payload = mycommon.strip_dictionary(request.form.to_dict())
print(" ### Run_BC_Compensation_Rules_01 : payload = ",payload)
localStatus, message= base_class_calcul_note.Run_BC_Compensation_Rules_01(payload)
return jsonify(status=localStatus, message=message )
if __name__ == '__main__':
print(" debut api")

View File

@ -3182,6 +3182,10 @@ def Get_List_Participant_Notes(diction):
elif ("is_validated" in retval.keys() and retval['is_validated'] != "1"):
user['is_validated'] = False
if( "semestre" in retval['note_evaluation_collection'][0].keys() ):
user['semestre'] = str(retval['note_evaluation_collection'][0]['semestre'])
else:
user['semestre'] = ""
user['note_evaluation_id'] = str(retval['note_evaluation_collection'][0]['_id'])
user['note_evaluation_code'] = str(retval['note_evaluation_collection'][0]['code'])
@ -3229,6 +3233,7 @@ def Get_List_Participant_Notes(diction):
nb_val = nb_val + 1
RetObject.append(mycommon.JSONEncoder().encode(user))
return True, RetObject

View File

@ -5316,6 +5316,12 @@ def Create_Invoice_Avoir_Total(diction):
'valide':'1',
'locked':'0'}):
initial_invoice_reste_to_paye = ""
if( "reste_to_paye" in local_invoice.keys() ):
initial_invoice_reste_to_paye = mycommon.tryFloat(str(local_invoice['reste_to_paye']))
else:
initial_invoice_reste_to_paye = mycommon.tryFloat(str(local_invoice['total_header_toutes_taxes']))
local_credit_note = local_invoice
list_champs_a_inverser = ['total_header_hors_taxe_before_header_reduction', 'total_header_toutes_taxes',
@ -5326,6 +5332,13 @@ def Create_Invoice_Avoir_Total(diction):
inversed_tmp = mycommon.tryFloat(str(local_credit_note[tmp]).strip()) * (-1)
local_credit_note[tmp] = inversed_tmp
"""
30/05/2026 - on présise que le montant de l'avoir = au reste à payer de la facture initiale
"""
#print("### initial_invoice_reste_to_paye = ", initial_invoice_reste_to_paye)
local_credit_note['total_header_toutes_taxes'] = mycommon.tryFloat(str(initial_invoice_reste_to_paye).strip()) * (-1)
local_credit_note['invoice_header_origin'] = local_invoice['invoice_header_ref_interne']
local_credit_note['invoice_header_ref_interne'] = credit_notes_reference
local_credit_note['invoice_header_type'] = "avoir"

View File

@ -885,8 +885,8 @@ def Get_List_Unite_Enseignement_Of_Given_Class(diction):
user['duration_concat'] = str(ue_data['duration']) + " m"
elif (str(ue_data['duration_unite']) == "annee"):
user['duration_concat'] = str(ue_data['duration']) + " a"
else:
user['duration_concat'] = str(ue_data['duration']) + " ?"
#else:
# user['duration_concat'] = str(ue_data['duration']) + " ?"
# On ecrase les données si il y a les meme données sur la formation
if (eu_class_coef ):