Ela_Back/model_planning_sequence_mgt.py

759 lines
29 KiB
Python

"""
Ce fichier permet de gerer les modèles de planning
Un modele de planning est defini par :
- modele_session_formation_sequence_header : entete avec le nom, public pour perso, etc
- modele_session_formation_sequence_detail : detail (contenu de la collection modele_session_formation
Pour rappeler et appliquer un planning modèle, on va se baser sur 2 variables:
- la date_debut d'application du planning
- l'application du calendrier (date et jours travaillés)
"""
import ast
import bson
import pymongo
from pymongo import MongoClient
import json
from bson import ObjectId
import re
from datetime import datetime
import prj_common as mycommon
import secrets
import inspect
import sys, os
import csv
import pandas as pd
from pymongo import ReturnDocument
import GlobalVariable as MYSY_GV
from math import isnan
import GlobalVariable as MYSY_GV
from datetime import timedelta
import ela_index_bdd_classes as eibdd
import email_mgt as email
import jinja2
from flask import send_file
from xhtml2pdf import pisa
from email.message import EmailMessage
from email.mime.text import MIMEText
from email import encoders
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import base_config_modele_journee as base_config_modele_journee
"""
Ajout d'un planning modele
"""
def Add_Sequence_Planning_Model(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token','session_id', 'code', 'nom', 'is_public', 'comment']
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', 'code', 'is_public',]
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
new_data = diction
del diction['token']
# Initialisation des champs non envoyés à vide
for val in field_list:
if val not in diction.keys():
new_data[str(val)] = ""
new_data['valide'] = "1"
new_data['locked'] = "0"
new_data['date_create'] = str(datetime.now())
new_data['date_update'] = str(datetime.now())
new_data['update_by'] = str(my_partner['_id'])
new_data['partner_owner_recid'] = str(my_partner['recid'])
if( "token" in new_data.keys() ):
del new_data['token']
print("new_data = ", new_data)
planning_model_header_inserted_id = MYSY_GV.dbname['planning_model_header'].insert_one(new_data).inserted_id
if (not planning_model_header_inserted_id):
mycommon.myprint(
" Impossible d'ajouter le modèle de planning (2) ")
return False, " Impossible d'ajouter le modèle de planning (2) "
"""
Apres ajout de l'entete, creation des lignes dans la collection
'planning_model_header_line'
"""
for New_retVal in MYSY_GV.dbname['session_formation_sequence'].find({'session_id':str(diction['session_id']),
'partner_owner_recid':str(my_partner['recid']), 'valide':'1', 'locked':'0'}):
user = New_retVal
del user['_id']
if( "update_by" in user.keys() ):
del user['update_by']
user['planning_model_header_id'] = str(planning_model_header_inserted_id)
user['valide'] = "1"
user['locked'] = "0"
user['date_update'] = str(datetime.now())
user['update_by'] = str(my_partner['_id'])
user['partner_owner_recid'] = str(my_partner['recid'])
planning_model_line_inserted_id = MYSY_GV.dbname['planning_model_line'].insert_one(user).inserted_id
return True, " Le modèle de planning a été correctement ajouté"
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible d'ajouter le modèle de planning "
"""
Mise à jour d'un modele de planning
"""
def Delete_Sequence_Planning_Model(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token','_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','_id']
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
"""
Verifier la validité du modele de planning
"""
is_valide_modele_planning = MYSY_GV.dbname['planning_model_header'].count_documents({'_id':ObjectId(str(diction['_id'])),
'valide':'1',
'locked':'0',
'partner_owner_recid':str(my_partner['recid'])})
if( is_valide_modele_planning != 1 ):
mycommon.myprint(
str(inspect.stack()[0][3]) + " L'identifiant du modèle de planning est invalide ")
return False, " L'identifiant du modèle de planning est invalide "
"""
Suppression des lignes
"""
deleted_data_lines_qry = {'planning_model_header_id': str(diction['_id']),
'partner_owner_recid': str(my_partner['recid']), }
# print(" ### deleted_data_qry = ", deleted_data_qry)
deleted_data = MYSY_GV.dbname['planning_model_line'].delete_many(deleted_data_lines_qry)
deleted_data_header_qry = {'_id': ObjectId(str(diction['_id'])),
'partner_owner_recid': str(my_partner['recid']), }
# print(" ### deleted_data_qry = ", deleted_data_qry)
deleted_header_data = MYSY_GV.dbname['planning_model_header'].delete_many(deleted_data_header_qry)
return True, " Le modèle de planning a été correctement supprimé"
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible de supprimer le modèle de planning "
"""
Recuperer la liste des modeles de planning,(SEULEMENT LES ENTETES)
"""
def Get_List_Sequence_Planning_Model_Header(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token',]
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',]
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
data_header_qry = {'partner_owner_recid': str(my_partner['recid']),
'valide':'1',
'locked':'0'}
RetObject = []
val_tmp = 0
for retval in MYSY_GV.dbname['planning_model_header'].find(data_header_qry):
user = retval
user['id'] = str(val_tmp)
val_tmp = val_tmp + 1
RetObject.append(mycommon.JSONEncoder().encode(user))
return True, RetObject
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible de récuperer le modèle de planning "
"""
Recuperer la liste des modeles de planning
"""
def Get_Given_Sequence_Planning_Model(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token', '_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', '_id']
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
"""
Verifier la validité du modele de planning
"""
is_valide_modele_planning = MYSY_GV.dbname['planning_model_header'].count_documents(
{'_id': ObjectId(str(diction['_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': str(my_partner['recid'])})
if (is_valide_modele_planning != 1):
mycommon.myprint(
str(inspect.stack()[0][3]) + " L'identifiant du modèle de planning est invalide ")
return False, " L'identifiant du modèle de planning est invalide "
data_header_qry = {'_id': ObjectId(str(diction['_id'])),
'partner_owner_recid': str(my_partner['recid']), }
header_data = []
for retval in MYSY_GV.dbname['planning_model_header'].find(data_header_qry):
user = retval
user['id'] = str(val_tmp)
val_tmp = val_tmp + 1
header_data.append(user)
data_lines_qry = {'planning_model_header_id': str(diction['_id']),
'partner_owner_recid': str(my_partner['recid']), }
lines_data = []
for retval in MYSY_GV.dbname['planning_model_line'].find(data_lines_qry):
user = retval
user['id'] = str(val_tmp)
val_tmp = val_tmp + 1
lines_data.append(user)
RetObject = {}
RetObject['header_data'] = mycommon.JSONEncoder().encode(header_data)
RetObject['lines_data'] = mycommon.JSONEncoder().encode(lines_data)
return True, RetObject
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible de récuperer le modèle de planning "
"""
Recuperer la liste des modeles de planning avec les options suivantes :
- la date_debut d'application du planning
- l'application du calendrier (date et jours travaillés)
"""
def Get_Given_Sequence_Planning_Model_With_Option(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token', '_id', 'date_debut']
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', '_id', 'date_debut',]
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
"""
Si le "jounree_modele_id" est vide, cela veut dire qu'il faut aller chercher le modele par default
"""
jounree_modele_id = ""
jounree_modele_data = MYSY_GV.dbname['base_config_modele_journee'].find_one(
{'partner_owner_recid': str(my_partner['recid']),
'valide': '1', 'locked': '0'})
if (jounree_modele_data is None):
mycommon.myprint(
str(inspect.stack()[0][3]) + " - Aucun modèle de journée n'est configuré ")
return False, " Aucun modèle de journée n'est configuré. "
jounree_modele_id = str(jounree_modele_data['_id'])
"""
Verifier la validité du modele de planning
"""
is_valide_modele_planning = MYSY_GV.dbname['planning_model_header'].count_documents(
{'_id': ObjectId(str(diction['_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': str(my_partner['recid'])})
if (is_valide_modele_planning != 1):
mycommon.myprint(
str(inspect.stack()[0][3]) + " L'identifiant du modèle de planning est invalide ")
return False, " L'identifiant du modèle de planning est invalide "
# Controle de cohérence sur les dates
date_debut = ""
if( "date_debut" in diction.keys() and diction['date_debut']):
local_status = mycommon.CheckisDate(str(diction['date_debut'])[0:10])
if (local_status is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " La date de debut n'est pas au format jj/mm/aaaa ")
return False, " La date de debut n'est pas au format jj/mm/aaaa "
date_debut = str(diction['date_debut'])[0:10]
data_header_qry = {'_id': ObjectId(str(diction['_id'])),
'partner_owner_recid': str(my_partner['recid']), }
header_data = []
for retval in MYSY_GV.dbname['planning_model_header'].find(data_header_qry):
user = retval
header_data.append(user)
"""
data_lines_qry = {'planning_model_header_id': str(diction['_id']),
'partner_owner_recid': str(my_partner['recid']), }
"""
data_lines_qry = ([
{"$addFields": {
"mysy_sequence_start": {
'$dateFromString': {
'dateString': '$sequence_start',
'format': "%d/%m/%Y %H:%M"
}
}
}
},
{'$match': {'planning_model_header_id': str(diction['_id']),
'partner_owner_recid': str(my_partner['recid']), }
},
{ "$sort": {"mysy_sequence_start": 1}}
])
lines_data = []
new_lines_data = []
for retval in MYSY_GV.dbname['planning_model_line'].aggregate(data_lines_qry):
user = retval
lines_data.append(user)
#print(" ### 1ere date du planning precedent est : ", str(lines_data[0]['sequence_start'])[0:10])
"""
Traiter l'application des options au calendrier
"""
#print(" jounree_modele_id = ", jounree_modele_id, " date_debut = ", date_debut)
if( jounree_modele_id and date_debut ):
mytoday = datetime.today().strftime("%d/%m/%Y")
decalage_planning = (datetime.strptime(str(date_debut), '%d/%m/%Y') - datetime.strptime(str(str(lines_data[0]['sequence_start'])[0:10]), '%d/%m/%Y') ).days
#print(" ### ce planning doit etre appliqué avec un de calage de "+str(decalage_planning)+" jours ")
for planning_line in lines_data:
new_planning_line_node = {}
new_planning_line_node = planning_line
planning_line_sequence_start = str(planning_line['sequence_start'])
local_status = mycommon.CheckisDate_Hours(planning_line_sequence_start)
if (local_status is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " La date de debut de séquence " + str(
planning_line_sequence_start) + " n'est pas au format 'jj/mm/aaaa hh:mm' ")
return False, " La date de debut de séquence " + str(
planning_line_sequence_start) + " n'est pas au format 'jj/mm/aaaa hh:mm'"
planning_line_sequence_start_datetime = datetime.strptime(str(planning_line_sequence_start).strip(), '%d/%m/%Y %H:%M')
planning_line_sequence_end = str(planning_line['sequence_end'])
local_status = mycommon.CheckisDate_Hours(planning_line_sequence_end)
if (local_status is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " La date de debut de séquence " + str(
planning_line_sequence_end) + " n'est pas au format 'jj/mm/aaaa hh:mm' ")
return False, " La date de debut de séquence " + str(
planning_line_sequence_end) + " n'est pas au format 'jj/mm/aaaa hh:mm'"
planning_line_sequence_end_datetime = datetime.strptime(str(planning_line_sequence_end).strip(),
'%d/%m/%Y %H:%M')
planning_line_sequence_date = planning_line_sequence_start_datetime.date()
duree_sequence = planning_line_sequence_end_datetime - planning_line_sequence_start_datetime
new_planning_line_sequence_start_datetime = planning_line_sequence_start_datetime + timedelta(days=decalage_planning)
new_planning_line_sequence_end_datetime = new_planning_line_sequence_start_datetime+ timedelta(seconds=duree_sequence.seconds)
#print(" init_planning_line_sequence_start_datetime = ", planning_line_sequence_start_datetime)
#print(" init_planning_line_sequence_end_datetime = ", planning_line_sequence_end_datetime)
#print(" declage en jour = ", decalage_planning)
#print(" new_planning_line_sequence_start_datetime = ", new_planning_line_sequence_start_datetime)
#print(" new_planning_line_sequence_end_datetime = ", new_planning_line_sequence_end_datetime)
date_jour = str(new_planning_line_sequence_start_datetime.strftime("%Y-%m-%d"))
jour_name = new_planning_line_sequence_start_datetime.strftime("%A")
#print(" date_jour = ", date_jour)
#print(" jour_name = ", jour_name)
is_off_day_of_week = "0"
if (str(jour_name) in jounree_modele_data.keys()):
is_off_day_of_week = jounree_modele_data[str(jour_name)]['is_off_day']
#if (date_jour not in jounree_modele_data['date_off'] and is_off_day_of_week != "1"):
#print(" DATE / JOUR OKKKKK")
while (date_jour in jounree_modele_data['date_off'] or is_off_day_of_week == "1"):
#print(str(date_jour)+" est KOOOO ")
#print(str(jour_name) + " est KOOOO ")
decalage_planning = decalage_planning + 1
new_planning_line_sequence_start_datetime = planning_line_sequence_start_datetime + timedelta(
days=decalage_planning)
new_planning_line_sequence_end_datetime = new_planning_line_sequence_start_datetime + timedelta(
seconds=duree_sequence.seconds)
#print(" new_planning_line_sequence_start_datetime = ", new_planning_line_sequence_start_datetime)
#print(" new_planning_line_sequence_end_datetime = ", new_planning_line_sequence_end_datetime)
date_jour = str(new_planning_line_sequence_start_datetime.strftime("%Y-%m-%d"))
jour_name = new_planning_line_sequence_start_datetime.strftime("%A")
if (str(jour_name) in jounree_modele_data.keys()):
is_off_day_of_week = jounree_modele_data[str(jour_name)]['is_off_day']
#print(" new_planning_line_sequence_start_datetime = ", new_planning_line_sequence_start_datetime.strftime("%d/%m/%Y %H:%M"))
#print(" new_planning_line_sequence_end_datetime = ", new_planning_line_sequence_end_datetime.strftime("%d/%m/%Y %H:%M"))
new_planning_line_node['new_sequence_start'] = new_planning_line_sequence_start_datetime.strftime("%d/%m/%Y %H:%M")
new_planning_line_node['new_sequence_end'] = new_planning_line_sequence_end_datetime.strftime("%d/%m/%Y %H:%M")
new_lines_data.append(new_planning_line_node)
print(" ### new_lines_data = ", new_lines_data)
RetObject = {}
RetObject['header_data'] = mycommon.JSONEncoder().encode(header_data)
RetObject['lines_data'] = mycommon.JSONEncoder().encode(new_lines_data)
return True, RetObject
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible de récuperer le modèle de planning "
"""
Cette fonction permet d'appliquer un nouveau planning à une session apres avoir
choisir un planning modele
"""
def Apply_Planning_Model_To_Session(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token','session_id', 'tab_sequence_modele']
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', 'tab_sequence_modele']
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
tab_sequence_modele = diction['tab_sequence_modele']
tab_sequence_modele_JSON = ast.literal_eval(tab_sequence_modele)
"""
Suppression de la planification existant de cette session s'il en existe
1 - Suppression dans "session_formation_sequence_affectation"
2 - Suppression dans "session_formation_sequence"
"""
for tmp in MYSY_GV.dbname['session_formation_sequence'].find({'session_id':str(diction['session_id']),
'partner_owner_recid':str(my_partner['recid'])}):
MYSY_GV.dbname['session_formation_sequence_affectation'].delete_many({'sequence_session_id':str(tmp['_id']),
'partner_owner_recid':str(my_partner['recid'])})
deleted_data = MYSY_GV.dbname['session_formation_sequence'].delete_many({'session_id':str(diction['session_id']),
'partner_owner_recid':str(my_partner['recid'])})
#print(" ### deleted_data.deleted_count = ", deleted_data.deleted_count )
"""
Enregistrement du nouveau planning
"""
for new_sequence in tab_sequence_modele_JSON:
local_start = str(new_sequence['start'])
local_start_datetime = datetime.strptime(local_start, "%d/%m/%Y %H:%M")
local_start_datetime_str = str(local_start_datetime.strftime('%d/%m/%Y %H:%M'))
local_end = str(new_sequence['end'])
local_end_datetime = datetime.strptime(local_end, "%d/%m/%Y %H:%M")
local_end_datetime_str = str(local_end_datetime.strftime('%d/%m/%Y %H:%M'))
local_node = {}
local_node['session_id'] = str(diction['session_id'])
local_node['sequence_title'] = str(new_sequence['title'])
local_node['sequence_start'] = str(local_start_datetime_str)
local_node['sequence_end'] = str(local_end_datetime_str)
local_node['agenda'] = str(new_sequence['local_agenda'])
local_node['objectif'] = str(new_sequence['local_objectif'])
local_node['commentaire'] = str(new_sequence['local_comment'])
if( "type" in new_sequence.keys() ):
local_node['type'] = str(new_sequence['type'])
else:
local_node['type'] = ""
local_node['valide'] = "1"
local_node['locked'] = "0"
local_node['partner_owner_recid'] = str(my_partner['recid'])
local_node['update_by'] = str(my_partner['_id'])
local_node['date_update'] = str(datetime.now())
local_node['grp_apprenant_id'] = ""
local_node['ue_id'] = ""
local_node['ue_planif_line_id'] = ""
MYSY_GV.dbname['session_formation_sequence'].insert_one(local_node)
return True, " Le planning a été correctement appliqué"
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible d'appliquer le planning "