"""
Ce fichier gere les sessions de formation
"""
import ast
from email import encoders
from email.mime.base import MIMEBase

import jinja2
import pymongo
from flask import send_file
from pymongo import MongoClient
import json
from bson import ObjectId
import re
from datetime import datetime, date

from xhtml2pdf import pisa

import Session_Formation_Sequence
import partner_client
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
from datetime import timedelta
import Inscription_mgt as Inscription_mgt
from zipfile import ZipFile

"""
Fonction de creation et mise à jour  d'une session de formation.


/!\ : le champ 'source' definit la source de la creation de la session

si le champ 'session_id' est renseigné alors c'est une mise à jour.
"""
def Add_Update_SessionFormation(diction):
    try:

        '''
               # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
               # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
               # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
               # field_list.
               '''
        field_list = ['token', 'date_debut', 'date_fin', 'nb_participant',  'adresse',
                      'code_postal', 'ville',  'code_session',
                      'class_internal_url', 'session_status', 'date_debut_inscription', 'date_fin_inscription',
                      'attestation_certif',  "distantiel", "presentiel", "prix_session", 'contenu_ftion', 'lms_class_code',
                      'session_ondemande', 'source', 'session_id', 'session_etape', 'pays', 'formateur_id',
                      'titre', 'location_type', 'is_bpf']

        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, " Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token',  'class_internal_url','code_session']

        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 liste ")
                return False, "Toutes les informations necessaires n'ont pas été fournies"

        mydata = {}
        query_key = {}

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_token = diction['token']

        # Verifier la validité du token
        retval = mycommon.check_partner_token_validity("", my_token)
        if retval is False:
            return "Err_Connexion", " La session de connexion n'est pas valide"

        data_for_check_connexion = {'token':my_token}
        local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(data_for_check_connexion)
        if (local_status is not True):
            return local_status, my_partner


        session_id = ""
        if ("session_id" in diction.keys()):
            session_id = diction['session_id']


        code_session = ""
        if ("code_session" in diction.keys()):
            mydata['code_session'] = diction['code_session']
            query_key['code_session'] = diction['code_session']


        class_internal_url = ""
        if ("class_internal_url" in diction.keys()):
            mydata['class_internal_url'] = diction['class_internal_url']
            class_internal_url = diction['class_internal_url']
            query_key['class_internal_url'] = diction['class_internal_url']

        class_source = ""
        if ("source" in diction.keys()):
            if diction['source']:
                class_source = diction['source']


        partner_recid = mycommon.get_parnter_recid_from_token(my_token)
        if (partner_recid is False):
            mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible  de récupérer les données du partenaire ")
            return False, "Impossible de récupérer les données du partenaire "


        """
        update du 20/08/23 : 
        on ajouter un champs 'owner_recid' a la session.
        en effet 2 partenaire peuvent avoir exactement la meme formation et les memes code session. 
        il faut arriver à les distinguer tout de meme
        """
        mydata['partner_owner_recid'] = str(partner_recid)


        if ("date_debut" in diction.keys()):
            mydata['date_debut'] = str(diction['date_debut'])[0:10]

        etape = ""
        if ("session_etape" in diction.keys()):
            etape = str(diction['session_etape'])


        mydata['session_etape'] = etape


        if ("date_fin" in diction.keys()):
            mydata['date_fin'] = str(diction['date_fin'])[0:10]


        if ("distantiel" in diction.keys()):
            mydata['distantiel'] = str(mycommon.tryInt(str(diction['distantiel'])))
        else:
            mydata['distantiel'] = "0"

        if ("presentiel" in diction.keys()):
            mydata['presentiel'] = str(mycommon.tryInt(str(diction['presentiel'])))
        else:
            mydata['presentiel'] = "0"


        if ("session_ondemande" in diction.keys()):
            mydata['session_ondemande'] = str(mycommon.tryInt(str(diction['session_ondemande'])))
        else:
            mydata['session_ondemande'] = "0"



        if ("nb_participant" in diction.keys()):
            nb_particants = str(mycommon.tryInt(str(diction['nb_participant'])))
            if( nb_particants == "0" ):
                nb_particants = "1"
            mydata['nb_participant'] = str(mycommon.tryInt(str(diction['nb_participant'])))
        else:
            mydata['nb_participant'] = "1"

        if ("prix_session" in diction.keys()):
            mydata['prix_session'] = diction['prix_session']


        if ("titre" in diction.keys()):
            mydata['titre'] = diction['titre']
        else:
            mydata['titre'] = ""

        if ("location_type" in diction.keys()):
            mydata['location_type'] = str(diction['location_type']).lower()
            if (str(diction['location_type']).lower() not in MYSY_GV.TRAINING_LOCATION_TYPE):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Le champ 'location_type' est incorrecte.")
                return False, "Le champ 'location_type' est incorrect."


        if ("is_bpf" in diction.keys()):
            if( str(diction['is_bpf']) not in ['0', '1']):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Le champ 'bpf' est incorrect. Les valeurs acceptées sont : '1' ou '0' ")
                return False, "Le champ 'bpf' est incorrect.  Les valeurs acceptées sont : '1' ou '0' "

            mydata['is_bpf'] = diction['is_bpf']


        formateur_id = ""
        if ("formateur_id" in diction.keys() and diction['formateur_id']):
            formateur_id = diction['formateur_id']
            # Verification de la validité du formateur (collection employé)
            is_formateur_id_ok = MYSY_GV.dbname['ressource_humaine'].count_documents({'_id':ObjectId(str(formateur_id)),
                                                                                      'partner_recid':str(partner_recid),
                                                                                      'valide':'1',
                                                                                      'locked':'0'
                                                                                      })

            if(is_formateur_id_ok <= 0  ):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - L'identifiant du formateur est invalide")
                return False, " L'identifiant du formateur est invalide "

        mydata['formateur_id'] = formateur_id

        if ("adresse" in diction.keys()):
            if diction['adresse']:
                mydata['adresse'] = diction['adresse']
            else:
                mydata['adresse'] = " "


        if ("code_postal" in diction.keys()):
            if diction['code_postal']:
                if( "." in str(diction['code_postal']) ):
                    #/!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                    mydata['code_postal'] = str(diction['code_postal']).split(".")[0]
                elif( "." in str(diction['code_postal']) ):
                    #/!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                    mydata['code_postal'] = str(diction['code_postal']).split(",")[0]
                else:
                    mydata['code_postal'] = str(diction['code_postal'])

            else:
                mydata['code_postal'] = ""

        if ("ville" in diction.keys()):
            if diction['ville']:
                mydata['ville'] = diction['ville']
            else:
                mydata['ville'] = ""

        if ("pays" in diction.keys()):
            if diction['pays']:
                mydata['pays'] = diction['pays']
            else:
                mydata['pays'] = ""

        """ 
        if ("attestation_certif" in diction.keys()):
            mydata['attestation_certif'] = diction['attestation_certif']
        """

        if ("session_status" in diction.keys()):
            mydata['session_status'] = str(mycommon.tryInt(str(diction['session_status'])))
        else:
            mydata['session_status'] = ""

        if ("date_debut_inscription" in diction.keys()):
            mydata['date_debut_inscription'] = str(diction['date_debut_inscription'])[0:10]
        else:
            mydata['date_debut_inscription'] = ""

        if ("date_fin_inscription" in diction.keys()):
            mydata['date_fin_inscription'] = str(diction['date_fin_inscription'])[0:10]
        else:
            mydata['date_fin_inscription'] = ""

        """"
        if ("formateur" in diction.keys()):
            mydata['formateur'] = diction['formateur']
        """

        if ("contenu_ftion" in diction.keys()):
            mydata['contenu_ftion'] = diction['contenu_ftion']
        else:
            mydata['contenu_ftion'] = ""

        """
                        Update du 22/10/2023 - Gestion des champs spécifiques ajoutés par le partenaire
                        """

        # Recuperation des champs spécifiques se trouvant dans le dictionnaire. ils commencent tous par 'my_'
        for val in diction.keys():
            if (val.startswith('my_')):
                if (MYSY_GV.dbname['base_specific_fields'].count_documents(
                        {'partner_owner_recid': str(partner_recid),
                         'related_collection': 'session_formation',
                         'field_name': str(val),
                         'valide': '1',
                         'locked': '0'}) != 1):
                    mycommon.myprint(str(
                        inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé ")
                    return False, " Les informations fournies sont incorrectes"

                mydata[str(val)] = diction[str(val)]


        mydata['date_update'] = str(datetime.now())
        mydata['update_by'] = str(my_partner['_id'])
        mydata['valide'] = "1"

        # Controle de cohérence sur les dates
        local_status = mycommon.CheckisDate(str(diction['date_debut'])[0:10])
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " - Formation : "+str(code_session)+" : Impossible de créer/mettre à jour la session de formation. La date de debut n'est pas au format jj/mm/aaaa ")

            return False, " - Formation : "+str(code_session)+" : Impossible de créer/mettre à jour la session de formation. La date de debut n'est pas au format jj/mm/aaaa "

        local_status = mycommon.CheckisDate(str(diction['date_fin'])[0:10])
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " -Formation : "+str(code_session)+" : Impossible de créer/mettre à jour la session de formation. La date de fin n'est pas au format jj/mm/aaaa ")

            return False, " -Formation : "+str(code_session)+" :  La date de fin n'est pas au format jj/mm/aaaa "


        if (datetime.strptime(str(diction['date_debut'])[0:10], '%d/%m/%Y') > datetime.strptime(str(diction['date_fin'])[0:10], '%d/%m/%Y')):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " Session de  Formation : La date debut " + str(
                    diction['date_debut'])[0:10] +
                " est postérieure à la date de fin " + str(diction['date_fin'])[0:10] )

            return False, " Session de Formation : La date debut de formation " + str(diction['date_debut'])[0:10] + \
                   " est postérieure à la date de fin de formation " + str(diction['date_fin'])[0:10] + "  "

        # Verification de la cohérence des dates d'inscription si on a bien une date debut et une date de fin
        if( "date_debut_inscription" in diction.keys() and "date_fin_inscription" in diction.keys() ):
            if (str(diction['date_debut_inscription']).strip() != "" and str(
                    diction['date_fin_inscription']).strip() != ""):
                local_status = mycommon.CheckisDate(str(diction['date_debut_inscription'])[0:10])
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Formation : " + str(
                            code_session) + " : Impossible de créer/mettre à jour la session de formation. La  date_debut_inscription  n'est pas au format jj/mm/aaaa ")

                    return False, " -Formation : " + str(
                        code_session) + " : La date de début d'inscription  n'est pas au format jj/mm/aaaa "

                local_status = mycommon.CheckisDate(str(diction['date_fin_inscription'])[0:10])
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " -Formation : " + str(
                            code_session) + " : La date de fin d'inscription n'est pas au format jj/mm/aaaa ")

                    return False, " - Formation : " + str(
                        code_session) + " :La date de fin d'inscription n'est pas au format jj/mm/aaaa "


                if (datetime.strptime(str(diction['date_debut_inscription'])[0:10], '%d/%m/%Y') > datetime.strptime(
                        str(diction['date_fin_inscription'])[0:10], '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " Formation : "+str(code_session)+" : La  date de début d'inscription " + str(diction['date_debut_inscription'])[0:10] + \
                           " est postérieure à la date de fin d'inscription  " + str(diction['date_fin_inscription'])[0:10] + "  " )

                    return False, " Formation : "+str(code_session)+" : La  date de début d'inscription " + str(diction['date_debut_inscription'])[0:10] + \
                           " est postérieure à la date de fin d'inscription  " + str(diction['date_fin_inscription'])[0:10] + "  "



                # Verification : Date de debut inscription n'est pas >  date de fin de formation
                if (datetime.strptime(str(diction['date_debut_inscription'])[0:10], '%d/%m/%Y') > datetime.strptime(
                        str(diction['date_fin'])[0:10], '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " - Session de Formation : La date de debut d'inscription " + str( diction['date_debut_inscription'])+ " est postérieure à la date de fin de formation  " + str(diction['date_fin']))

                    return False, " Session de Formation : La date de debut d'inscription  " + str( diction['date_debut_inscription'])[0:10] + " est postérieure à la date de fin de formation  " + str(diction['date_fin'])[0:10]+" "

                # Verification : Date de fin inscription n'est pas >  date de fin de formation
                if (datetime.strptime(str(diction['date_fin_inscription'])[0:10], '%d/%m/%Y') > datetime.strptime(
                        str(diction['date_fin'])[0:10], '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " -Formation : "+str(code_session)+" :  La date de fin d'inscription " + str(
                            diction['date_fin_inscription'])[0:10] + " est postérieure à la date de fin de la formation  " + str(
                            diction['date_fin'])[0:10])

                    return False, " Formation : "+str(code_session)+" : La date de fin d'inscription  " + str(
                        diction['date_fin_inscription'])[0:10] + " est postérieure à la date de fin de la formation  " + str(
                        diction['date_fin'])[0:10] + " "


        """
        mytoday = datetime.today().strftime("%d/%m/%Y")
        if (datetime.strptime(str(diction['date_debut'])[0:10], '%d/%m/%Y') < datetime.strptime(str(mytoday).strip(), '%d/%m/%Y')) :
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " - Impossible de créer/mettre à jour la session de formation : La date de debut de sessions " + str(
                    diction['date_debut']) +" est antérieure à la date du jour  ")

            return False, "  - Impossible de créer/mettre à jour la session de formation : La date de debut de sessions " + str(
                    diction['date_debut']) +" est antérieure à la date du jour   "

        """
        # Fin Controle de cohérence sur les dates


        """
        Verification avant ajout ou mise à jour
        1 - si le champ 'session_id' est renseingé alors c'est une mise à jour.
        Dans le cas d'une mise à jour, 
        je verifie s'il y a des inscription avec les code session actuellement en base, si oui, alors on refuse la modication
        /!\ : DU CODE SESSION, mais on accepte les autres champs car le session est deja utilisé.
        
        2 - Si le champ 'session_id' N'EST PAS renseingé alors c'est une creation. 
        On verifie que ce code session n'est pas deja utilisé pour cette formation.
        .
        
        """
        Warning_Message = ""
        if(len(str(session_id)) > 0 ):
            # Il s'agit d'une mise à jour

            # Etape 1 : recuperation du code session en base
            local_retval1 = MYSY_GV.dbname['session_formation'].find_one({'_id':ObjectId(str(session_id))})
            if( local_retval1 is None or 'code_session' not in  local_retval1.keys() or 'class_internal_url' not in  local_retval1.keys() ):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Cette session n'as pas de code session ")
                return False, "Impossible de récupérer le code de la session (1) "

            existing_session_code = local_retval1['code_session']
            existing_class_internal_url = local_retval1['class_internal_url']
            current_step = local_retval1['session_etape']





            local_retval = MYSY_GV.dbname['inscription'].count_documents({'session_id':str(existing_session_code),
                                                                          'class_internal_url':str(existing_class_internal_url)})

            if( local_retval > 0):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Cette session a déjà des inscriptions. Le code de la session ne peut etre modifié. Les autres champs ont été correctement mis à jour")
                mydata['code_session'] = existing_session_code  # On remet le actuellement en base de données
                Warning_Message = "Cette session a déjà des inscriptions. Le code de la session ne peut etre modifié. Les autres champs ont été correctement mis à jour"


            #print(" ###laaa mydata = ", mydata)
            coll_name = MYSY_GV.dbname['session_formation']
            ret_val = coll_name.find_one_and_update(
                {'_id':ObjectId(str(session_id)), 'valide':'1'},
                {"$set": mydata},
                upsert=False,
                return_document=ReturnDocument.AFTER
            )

            if (ret_val is None or '_id' not in ret_val.keys()):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Impossible d'ajouter/mettre à jour la session '" + str(
                        diction['code_session']) + "' ")
                return False, "Impossible d'ajouter/mettre à jour la session '" + str(diction['code_session']) + "' "

            new_step = ret_val['session_etape']


            """
            # Ajout de l'evenement dans l'historique
            """

            # Cas particulier : Verifier s'il y a eu changement d'session_etape, pour préciser cela dans le log de l'historique
            major_change_text = ""
            if( str(new_step) != str(current_step)):
                major_change_text = " Changement étape : "+str(current_step)+" ==> "+str(new_step)+" "

            now = str(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
            history_event_dict = {}
            history_event_dict['token'] = diction['token']
            history_event_dict['related_collection'] = "session_formation"
            history_event_dict['related_collection_recid'] = str(ret_val['_id'])
            history_event_dict['action_date'] = str(now)
            if( major_change_text == "" ):
                history_event_dict['action_description'] = "Mise à jour "
            else:
                history_event_dict['action_description'] = str(major_change_text)

            local_status, local_retval = mycommon.Collection_Historique.Add_Historique_Event(history_event_dict)
            if (local_status is False):
                mycommon.myprint(
                    " WARNING : Impossible de logguer l'historique pour l'évènement : " + str(history_event_dict))


            print("len(str(Warning_Message)) = ", len(str(Warning_Message)), )
            if(len(str(Warning_Message)) > 2 ):
                return True, str(Warning_Message)

            return True, " La session de formation  à bien été mise à jour"

        if (len(str(session_id)) <= 0):
            # La session n'existe pas, on fait une simple creation

            #print(" ### mydata = ", mydata)
            coll_name = MYSY_GV.dbname['session_formation']
            ret_val = coll_name.insert_one(mydata)

            local_inserted_id = ret_val.inserted_id

            if (ret_val is None or not hasattr(ret_val, 'inserted_id') ):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Impossible d'ajouter la session '" + str(
                        diction['code_session']) + "' ")
                return False, "Impossible d'ajouter la session '" + str(diction['code_session']) + "' "

            """
                    # Ajout de l'evenement dans l'historique
                    """
            now = str(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
            history_event_dict = {}
            history_event_dict['token'] = diction['token']
            history_event_dict['related_collection'] = "session_formation"
            history_event_dict['related_collection_recid'] = str(local_inserted_id)
            history_event_dict['action_date'] = str(now)
            history_event_dict['action_description'] = "Creation "
            local_status, local_retval = mycommon.Collection_Historique.Add_Historique_Event(history_event_dict)
            if (local_status is False):
                mycommon.myprint(
                    " WARNING : Impossible de logguer l'historique pour l'évènement : " + str(history_event_dict))


            return True, " La session de formation  à bien été créée"


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de créer / mettre à jour la session de formation"


"""
Fonction de recuperation d'une session de formation. 

/!\ : il ne doit pas y avoir plus d'une session.

si le result > 1 une session, alors erreur d'inchorence d'info.
"""

def GetSessionFormation(diction):
    try:

        field_list = ['token', 'class_internal_url', 'session_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é, Creation partenaire annulée")
                return False, "de récupérer la liste des stagiaires . Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token', 'class_internal_url', 'session_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 liste ")
                return False, "Impossible de récupérer la liste des stagiaires, Toutes les informations necessaires n'ont pas été fournies"

        # Recuperation du recid du partner
        mydata = {}
        mytoken = ""
        if ("token" in diction.keys()):
            if diction['token']:
                mytoken = diction['token']

        local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data({'token':str(diction['token'])})
        if (local_status is not True):
            return local_status, my_partner

        partner_recid = my_partner['recid']

        class_internal_url = ""
        if ("class_internal_url" in diction.keys()):
            if diction['class_internal_url']:
                class_internal_url = diction['class_internal_url']

        session_id = ""
        if ("session_id" in diction.keys()):
            if diction['session_id']:
                session_id = diction['session_id']

        if(str(session_id).strip() == ""):
            return True, []

        coll_session = MYSY_GV.dbname['session_formation']

        myquery = [{'$match':{'_id':ObjectId(str(session_id)), 'class_internal_url':class_internal_url, 'partner_owner_recid':str(partner_recid)}},
            {'$lookup':
                {
                    'from': 'myclass',
                    'localField': 'class_internal_url',
                    'foreignField': 'internal_url',
                    'pipeline': [{'$project': {'title': 1, 'lms_class_code':1, 'external_code':1, 'published':1}}],
                    'as': 'myclass'
                }
            }
        ]

        #print(" ##### myquery GetSessionFormation = "+str(myquery))
        RetObject = []

        nb_val = 0
        for retval in coll_session.aggregate(myquery):
            #print(" ##### retval = " + str(retval))
            user = {}
            user = retval
            user['id'] = str(nb_val)
            nb_val = nb_val + 1
            title = ""
            lms_class_code = ""
            class_external_code = ""
            class_ispublished = "0"

            if ('myclass' in retval.keys() and len(retval['myclass']) > 0):

                if( "title" in retval['myclass'][0].keys()):
                    title = retval['myclass'][0]['title']

                if ("lms_class_code" in retval['myclass'][0].keys()):
                    lms_class_code = retval['myclass'][0]['lms_class_code']


                if ("external_code" in retval['myclass'][0].keys()):
                    class_external_code = retval['myclass'][0]['external_code']


                if ("published" in retval['myclass'][0].keys()):
                    class_ispublished = retval['myclass'][0]['published']

            user['title'] = title
            user['lms_class_code'] = lms_class_code
            user['class_external_code'] = class_external_code
            user['class_ispublished'] = class_ispublished

            formateur_nom_prenom = ""
            # Si il y a un code formateur_id, alors on va recuperer les nom et prenom du formation
            if( "formateur_id" in retval.keys() and retval['formateur_id']):

                formateur_data = MYSY_GV.dbname['ressource_humaine'].find_one({'_id':ObjectId(str(retval['formateur_id'])),
                                                                               'valide':'1',
                                                                               'locked':'0',
                                                                               'partner_recid':str(partner_recid)
                                                                               })

                if(formateur_data and "nom" in formateur_data.keys() and "prenom" in formateur_data.keys() ):
                    formateur_nom_prenom = str(formateur_data['nom'])+" "+str(formateur_data['prenom'])


            user['formateur_nom_prenom'] = formateur_nom_prenom
            #print(" ### user = ", user)
            RetObject.append(mycommon.JSONEncoder().encode(user))



        # Si le nombre de session trouvé est > 1 alors incohérence, retourner une message d'erreur
        if( nb_val > 1 ):
            mycommon.myprint(str(inspect.stack()[0][3]) + " - la query  "+str(myquery)+" retourne "+str(nb_val)+" session. ceci n'est pas normal. il ne doit pas y avoir plus 1 session")
            return False, " Les informations de la session "+str(session_id)+" sont incohérentes. Merci de contacter le support"

        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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de récupérer la session de formation"




"""
Cette fonction recupere la liste de toutes les sessions de formation actives et valides
d'une formation données ET les sessions "on demande"

/!\ : Cette fonction est utilisée en mode non connecté et en mode  connecté.
Donc faire attention au controle de la connexion
"""
def GetActiveSessionFormation_List(diction):
    try:

        field_list = ['token', 'class_internal_url']
        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é, Creation partenaire annulée")
                return False, " Impossible de récupérer la liste des session de formation"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = [  'class_internal_url', ]
        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 liste ")
                return False, "Impossible de récupérer la liste des session de formation"

        # Le controle de token n'est effectué que une valeur est fournie dans le token
        if( 'token' in diction.keys() and len(str(diction['token'])) > 0) :
            local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
            if (local_status is not True):
                return local_status, my_partner


        # Recuperation du recid du partner
        mydata = {}

        class_internal_url = ""
        if ("class_internal_url" in diction.keys()):
            if diction['class_internal_url']:
                class_internal_url = diction['class_internal_url']

        coll_session = MYSY_GV.dbname['session_formation']
        myquery = {}
        myquery['class_internal_url'] = class_internal_url


        myquery['valide'] = "1"
        myquery['session_status'] = "1"


        RetObject = []

        print(" ### GetActiveSessionFormation_List myquery = ", myquery)
        for retval in coll_session.find(myquery):

            local_tmp = retval
            ## Verification des conditions supplementaires :
            # en realité c'est parce que c'est chaud de le faire avec pymongo
            tmp_debut_inscritp = str(local_tmp['date_debut_inscription']).strip().split(" ")
            tmp_fin_inscritp = str(local_tmp['date_fin_inscription']).strip().split(" ")

            debut_inscr = datetime.strptime(str(tmp_debut_inscritp[0]).strip(), '%d/%m/%Y')
            fin_inscr = datetime.strptime(str(tmp_fin_inscritp[0]).strip(), '%d/%m/%Y')

            #print(" #### date_debut_inscription = ", debut_inscr,  " date_fin_inscription = ", fin_inscr, " NOW = ",datetime.now())
            if(debut_inscr <= datetime.now() and  fin_inscr >= datetime.now()):
                RetObject.append(mycommon.JSONEncoder().encode(retval))
            else:
                if ("session_ondemande" in local_tmp.keys()):
                    if( str(local_tmp['session_ondemande']).strip() == "1"):
                        RetObject.append(mycommon.JSONEncoder().encode(retval))



        #print("####  GetActiveSessionFormation_List RetObject = "+str(RetObject))
        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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de récupérer la liste des sessions de formation valides et actives."



"""
Cette fonction recupere UNIQUEMENT LES VILLES ET SI A DISTANCEsessions de formation actives et valides
d'une formation données ET les sessions "on demande"

on doit renvoyer les villes de manière unique et eviter les doublon de villes

"""
def GetActiveSession_Cities_And_Distance_Formation_List(diction):
    try:

        field_list = ['token', 'class_internal_url']
        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é, Creation partenaire annulée")
                return False, " Impossible de récupérer la liste des session de formation"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = [  'class_internal_url', ]
        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 liste ")
                return False, "Impossible de récupérer la liste des session de formation"

        # Le controle de token n'est effectué que une valeur est fournie dans le token
        if( 'token' in diction.keys() and len(str(diction['token'])) > 0) :
            local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
            if (local_status is not True):
                return local_status, my_partner


        # Recuperation du recid du partner
        mydata = {}

        liste_session_cities = []

        class_internal_url = ""
        if ("class_internal_url" in diction.keys()):
            if diction['class_internal_url']:
                class_internal_url = diction['class_internal_url']

        coll_session = MYSY_GV.dbname['session_formation']
        myquery = {}
        myquery['class_internal_url'] = class_internal_url


        myquery['valide'] = "1"
        myquery['session_status'] = "1"


        RetObject = []

        print(" ### GetActiveSessionFormation_List myquery = ", myquery)
        for retval in coll_session.find(myquery):

            local_tmp = retval
            ## Verification des conditions supplementaires :
            # en realité c'est parce que c'est chaud de le faire avec pymongo
            tmp_debut_inscritp = str(local_tmp['date_debut_inscription']).strip().split(" ")
            tmp_fin_inscritp = str(local_tmp['date_fin_inscription']).strip().split(" ")

            debut_inscr = datetime.strptime(str(tmp_debut_inscritp[0]).strip(), '%d/%m/%Y')
            fin_inscr = datetime.strptime(str(tmp_fin_inscritp[0]).strip(), '%d/%m/%Y')

            #print(" #### date_debut_inscription = ", debut_inscr,  " date_fin_inscription = ", fin_inscr, " NOW = ",datetime.now())
            if(debut_inscr <= datetime.now() and  fin_inscr >= datetime.now()):

                if( "ville" in retval.keys() and retval['ville']):
                    if( str(retval['ville']) not in liste_session_cities):
                        liste_session_cities.append(str(retval['ville']))
                        RetObject.append(mycommon.JSONEncoder().encode(str(retval['ville'])))

                elif( "distantiel" in retval.keys() and str(retval['distantiel']) == "1"):
                    if ( "A Distance" not in liste_session_cities):
                        liste_session_cities.append("A Distance")
                        RetObject.append(mycommon.JSONEncoder().encode("A Distance"))

            else:
                if ("session_ondemande" in local_tmp.keys()):
                    if( str(local_tmp['session_ondemande']).strip() == "1"):
                        if ("A la demande" not in liste_session_cities):
                            liste_session_cities.append("A la demande")
                            RetObject.append(mycommon.JSONEncoder().encode("A la demande"))


        #print("####  GetActiveSessionFormation_List RetObject = "+str(RetObject))
        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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de récupérer la liste des villes des sessions de formation valides et actives."




"""
Cette fonction récupérer la liste des toutes les sessions
de formation valides pour une formation données.
Qu'elles soient cloturées ou pas."""
def GetAllValideSessionFormation_List(diction):
    try:

        field_list = ['token', 'class_internal_url']
        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é, Creation partenaire annulée")
                return False, " Impossible de récupérer la liste des session de formation"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token', 'class_internal_url', ]
        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 liste ")
                return False, "Impossible de récupérer la liste des session de formation"

        # Recuperation du recid du partner
        mydata = {}

        local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
        if (local_status is not True):
            return local_status, my_partner

        class_internal_url = ""
        if ("class_internal_url" in diction.keys()):
            if diction['class_internal_url']:
                class_internal_url = diction['class_internal_url']

        coll_session = MYSY_GV.dbname['session_formation']
        myquery = {}
        myquery['class_internal_url'] = class_internal_url
        myquery['partner_owner_recid'] = str(my_partner['recid'])
        myquery['valide'] = "1"

        print(" ##### myquery tt = "+str(myquery))
        RetObject = []

        for retval in coll_session.find(myquery):
            #print(" ##### retval = " + str(retval))
            RetObject.append(mycommon.JSONEncoder().encode(retval))

        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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de récupérer la liste des sessions de formation valides et actives."


"""
Cette fonction recupere toutes les sessions de formation d'un partenaire
"""
def GetAllValideSessionPartner_List(diction):
    try:

        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é, Creation partenaire annulée")
                return False, " Impossible de récupérer la liste des session de formation"

        """
        Verification de la liste 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 liste ")
                return False, "Impossible de récupérer la liste des session de formation"

        # Recuperation du recid du partner
        mydata = {}

        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


        coll_session = MYSY_GV.dbname['session_formation']

        filt_class_partner_recid = {'partner_owner_recid': str(my_partner['recid'])}

        query = [{'$match': {'partner_owner_recid':str(my_partner['recid'])}},
                 { '$sort': {'_id': -1}},
            {'$lookup':
                {
            'from': 'myclass',
           'localField': 'class_internal_url',
           'foreignField':'internal_url',
          'pipeline': [{'$match': filt_class_partner_recid}, {'$project': {'title': 1, 'domaine': 1,
                                                                             'duration': 1, 'duration_unit': 1,  'external_code':1, 'published':1}}],
           'as': 'myclass_collection'
                }
            }
        ]
        #print("#### query = ", query)
        RetObject = []
        cpt = 1
        for retVal in MYSY_GV.dbname['session_formation'].aggregate(query):
            if ('myclass_collection' in retVal.keys() and len(retVal['myclass_collection']) > 0):
                val = {}
                val['id'] = str(cpt)
                cpt = cpt + 1
                val['class_internal_url'] = retVal['class_internal_url']
                val['_id'] = retVal['_id']
                val['code_session'] = retVal['code_session']

                if( "session_etape" in retVal.keys()):
                    val['session_etape'] = retVal['session_etape']
                else:
                    val['session_etape'] = ""

                if( "titre" in retVal.keys()):
                    val['titre'] = retVal['titre']
                else:
                    val['titre'] = ""

                if ("location_type" in retVal.keys()):
                    val['location_type'] = retVal['location_type']
                else:
                    val['location_type'] = ""

                if ("is_bpf" in retVal.keys()):
                    val['is_bpf'] = retVal['is_bpf']
                else:
                    val['is_bpf'] = ""


                if ("session_status" in retVal.keys()):
                    val['session_status'] = retVal['session_status']
                else:
                    val['session_status'] = "0"



                val['date_debut'] = retVal['date_debut'][0:10]
                val['date_fin'] = retVal['date_fin'][0:10]
                val['date_debut_inscription'] = retVal['date_debut_inscription'][0:10]
                val['date_fin_inscription'] = retVal['date_fin_inscription'][0:10]

                val['distantiel'] = retVal['distantiel']


                if ("formateur_id" in retVal.keys() and  retVal['formateur_id']):
                    val['formateur_id'] = retVal['formateur_id']


                    # On va aller chercher le nom et prenom du formateur
                    fomateur_data = MYSY_GV.dbname['ressource_humaine'].find_one(
                        {'_id': ObjectId(str(retVal['formateur_id'])),
                         'valide': '1',
                         'locked': '0',
                         'partner_recid': str(my_partner['recid'])})
                    if (fomateur_data is None):
                        val['formateur'] = " Invalide"
                    else:
                        nom = ""
                        prenom = ""
                        if ("nom" in fomateur_data.keys()):
                            nom = fomateur_data['nom']
                        if ("prenom" in fomateur_data.keys()):
                            prenom = fomateur_data['prenom']
                        val['formateur'] = str(nom) + " " + str(prenom)

                else:
                    val['formateur_id'] = ""


                nb_participant = "1"
                if( "nb_participant" in retVal.keys()):
                    nb_participant = retVal['nb_participant']

                val['nb_participant'] = nb_participant


                val['presentiel'] = retVal['presentiel']
                val['prix_session'] = retVal['prix_session']

                val['title'] = retVal['myclass_collection'][0]['title']
                val['class_published'] = retVal['myclass_collection'][0]['published']
                val['domaine'] = retVal['myclass_collection'][0]['domaine']
                val['class_external_code'] = retVal['myclass_collection'][0]['external_code']

                if( str(retVal['myclass_collection'][0]['duration_unit']) == "heure"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration'])+" h"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "jour"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " j"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "semaine"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " s"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "mois"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " m"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "annee"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " a"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "user_rythme"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " u"

                else :
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " ?"

                val['duration'] = str(retVal['myclass_collection'][0]['duration'])
                val['duration_unit'] = retVal['myclass_collection'][0]['duration_unit']

                ## Recuperation du nombre d'inscrits
                Count_Inscrit = MYSY_GV.dbname['inscription'].count_documents({'session_id':str(retVal['_id']), 'class_internal_url':str(retVal['class_internal_url']),
                                                                               'status':"1", 'partner_owner_recid':str(my_partner['recid'])})

                qry_nb_inscrit = {'session_id':str(retVal['_id']), 'class_internal_url':str(retVal['class_internal_url']),
                                                                               'status':"1", 'partner_owner_recid':str(my_partner['recid'])}


                val['nb_inscrit'] = str(Count_Inscrit)

                ## Recuperation du nombre de preinscrits
                Count_Preinscrit = MYSY_GV.dbname['inscription'].count_documents(
                    {'session_id': str(retVal['_id']), 'class_internal_url': str(retVal['class_internal_url']),
                     'status': "0",
                     'partner_owner_recid':str(my_partner['recid'])})

                val['nb_preinscrit'] = str(Count_Preinscrit)

                taux_remplissage = "0"
                if( str(nb_participant) != "0" and str(nb_participant).strip() != ""):
                    taux_remplissage = round(int(mycommon.tryInt(Count_Inscrit)) / int(mycommon.tryInt(nb_participant)), 2)

                val['taux_remplissage'] = str(taux_remplissage)


                RetObject.append(mycommon.JSONEncoder().encode(val))

        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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de récupérer la liste des sessions de formation valides et actives."


"""
Recuperation de la liste avec des filter du type like 
"""
def GetAllValideSessionPartner_List_filter_like(diction):
    try:

        field_list = ['token','class_title', 'code_session', 'class_external_code', 'session_start_date', 'session_end_date']
        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é, Creation partenaire annulée")
                return False, " Impossible de récupérer la liste des session de formation"

        """
        Verification de la liste 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 liste ")
                return False, "Impossible de récupérer la liste des session de formation"

        # Recuperation du recid du partner
        mydata = {}

        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

        nb_hour_per_day = mycommon.Get_Partner_Hour_Per_Day(str(my_partner['recid']))
        if (nb_hour_per_day is False):
            nb_hour_per_day = "7"


        filt_class_title = {}
        if ("class_title" in diction.keys()):
            filt_class_title = {'title': {'$regex': str(diction['class_title']),"$options": "i"}}

        filt_class_external_code = {}
        if ("class_external_code" in diction.keys()):
            filt_class_external_code = {'external_code': {'$regex': str(diction['class_external_code']), "$options": "i"}}

        filt_code_session = {}
        if ("code_session" in diction.keys()):
            filt_code_session = {'code_session': {'$regex': str(diction['code_session']), "$options": "i"}}

        filt_session_start_date = ""
        if ("session_start_date" in diction.keys()):
            filt_session_start_date = str(diction['session_start_date'])[0:10]
            local_status = mycommon.CheckisDate(filt_session_start_date)
            if (local_status is False):
                mycommon.myprint(str(inspect.stack()[0][3]) + " Le filtre : 'date de debut de session' n'est pas au format jj/mm/aaaa.")
                return False, " Le filtre : 'date de debut de session' n'est pas au format jj/mm/aaaa."


        filt_session_end_date = ""
        if ("session_end_date" in diction.keys()):
            filt_session_end_date = str(diction['session_end_date'])[0:10]
            local_status = mycommon.CheckisDate(filt_session_end_date)
            if (local_status is False):
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + " Le filtre : 'date de fin de session' n'est pas au format jj/mm/aaaa.")
                return False, " Le filtre : 'date de fin de session' n'est pas au format jj/mm/aaaa."

        coll_session = MYSY_GV.dbname['session_formation']

        query = [ {'$match':{ '$and' : [ filt_code_session,{'partner_owner_recid':str(my_partner['recid'])}] }} ,
                  {'$sort': {'_id': -1}},
            {'$lookup':
                {
                    'from': 'myclass',
                    'localField': 'class_internal_url',
                    'foreignField': 'internal_url',
                    'pipeline': [{'$match': { '$and' : [ filt_class_title,filt_class_external_code, {'partner_owner_recid':str(my_partner['recid'])} ]} }, {'$project': {'title': 1, 'domaine':1,
                                                                                               'duration':1, 'duration_unit':1, 'external_code':1}}],
                    'as': 'myclass_collection'
                }
            }
        ]

        #print("#### GetAllValideSessionPartner_List_filter_likequery = ", query)
        RetObject = []
        cpt = 1
        for retVal in MYSY_GV.dbname['session_formation'].aggregate(query):
            if( 'myclass_collection' in  retVal.keys() and len(retVal['myclass_collection']) > 0  ):

                val = {}
                val['id'] = str(cpt)
                cpt = cpt + 1
                val['_id'] = retVal['_id']
                val['class_internal_url'] = retVal['class_internal_url']
                val['code_session'] = retVal['code_session']

                if ("titre" in retVal.keys()):
                    val['titre'] = retVal['titre']
                else:
                    val['titre'] = ""

                if ("location_type" in retVal.keys()):
                    val['location_type'] = retVal['location_type']
                else:
                    val['location_type'] = ""

                if ("is_bpf" in retVal.keys()):
                    val['is_bpf'] = retVal['is_bpf']
                else:
                    val['is_bpf'] = ""


                if( "session_etape" in retVal.keys()):
                    val['session_etape'] = retVal['session_etape']
                else:
                    val['session_etape'] = ""

                if( "session_status" in retVal.keys()):
                    val['session_status'] = retVal['session_status']
                else:
                    val['session_status'] = "0"

                val['date_debut'] = retVal['date_debut'][0:10]
                val['date_fin'] = retVal['date_fin'][0:10]
                val['date_debut_inscription'] = retVal['date_debut_inscription'][0:10]
                val['date_fin_inscription'] = retVal['date_fin_inscription'][0:10]

                if ("distantiel" in retVal.keys()):
                    val['distantiel'] = retVal['distantiel']
                else:
                    val['distantiel'] = "0"


                if ("formateur_id" in retVal.keys() and  retVal['formateur_id']):
                    val['formateur_id'] = retVal['formateur_id']

                    # On va aller chercher le nom et prenom du formateur
                    fomateur_data = MYSY_GV.dbname['ressource_humaine'].find_one({'_id':ObjectId(str(retVal['formateur_id'])),
                                                                                  'valide':'1',
                                                                                  'locked':'0',
                                                                                  'partner_recid':str(my_partner['recid'])})
                    if( fomateur_data is None):
                        val['formateur'] = " Invalide"
                    else:
                        nom = ""
                        prenom = ""
                        if( "nom" in fomateur_data.keys()):
                            nom = fomateur_data['nom']
                        if ("prenom" in fomateur_data.keys()):
                            prenom = fomateur_data['prenom']
                        val['formateur'] = str(nom)+" "+str(prenom)


                else:
                    val['formateur_id'] = ""

                nb_participant = "1"
                if ("nb_participant" in retVal.keys()):
                    nb_participant = retVal['nb_participant']

                val['nb_participant'] = nb_participant

                if ("presentiel" in retVal.keys()):
                    val['presentiel'] = retVal['presentiel']
                else:
                    val['presentiel'] = "0"

                if ("prix_session" in retVal.keys()):
                    val['prix_session'] = retVal['prix_session']
                else:
                    val['prix_session'] = "0"

                val['title'] = retVal['myclass_collection'][0]['title']
                val['domaine'] = retVal['myclass_collection'][0]['domaine']
                val['class_external_code'] = retVal['myclass_collection'][0]['external_code']

                if (str(retVal['myclass_collection'][0]['duration_unit']) == "heure"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " h"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "jour"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " j"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "semaine"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " s"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "mois"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " m"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "annee"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " a"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "user_rythme"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " u"

                else:
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " ?"

                val['duration'] = retVal['myclass_collection'][0]['duration']
                val['duration_unit'] = retVal['myclass_collection'][0]['duration_unit']

                ## Recuperation du nombre d'inscrits
                Count_Inscrit = MYSY_GV.dbname['inscription'].count_documents(
                    {'session_id': str(retVal['_id']), 'class_internal_url': str(retVal['class_internal_url']),
                     'status': "1"})
                val['nb_inscrit'] = str(Count_Inscrit)

                ## Recuperation du nombre de preinscrits
                Count_Preinscrit = MYSY_GV.dbname['inscription'].count_documents(
                    {'session_id': str(retVal['_id']), 'class_internal_url': str(retVal['class_internal_url']),
                     'status': "0"})

                val['nb_preinscrit'] = str(Count_Preinscrit)

                taux_remplissage = "0"
                if (str(nb_participant) != "0"):
                    taux_remplissage = round(int(mycommon.tryInt(Count_Inscrit)) / int(mycommon.tryInt(nb_participant)),
                                            2)

                val['taux_remplissage'] = str(taux_remplissage)

                if (filt_session_start_date and filt_session_end_date):
                    # Si on a un filtre sur la date debut et de fin de session
                    if ((datetime.strptime(str(retVal['date_debut'][0:10]).strip(), '%d/%m/%Y') >= datetime.strptime(
                            str(filt_session_start_date).strip(), '%d/%m/%Y'))
                            and
                            (datetime.strptime(str(retVal['date_fin'][0:10]).strip(),
                                               '%d/%m/%Y') <= datetime.strptime(str(filt_session_end_date).strip(),
                                                                                '%d/%m/%Y'))
                    ):
                        RetObject.append(mycommon.JSONEncoder().encode(val))


                elif (filt_session_start_date):
                    # Si on a un filtre uniquement sur la date de debut de session
                    if ((datetime.strptime(str(retVal['date_debut'][0:10]).strip(), '%d/%m/%Y') >= datetime.strptime(
                            str(filt_session_start_date).strip(), '%d/%m/%Y'))):
                        RetObject.append(mycommon.JSONEncoder().encode(val))


                elif (filt_session_end_date):
                    # Si on a un filtre uniquement sur la date de fin session
                    if ((datetime.strptime(str(retVal['date_fin'][0:10]).strip(), '%d/%m/%Y') <= datetime.strptime(
                            str(filt_session_end_date).strip(), '%d/%m/%Y'))):
                        RetObject.append(mycommon.JSONEncoder().encode(val))


                else:
                    RetObject.append(mycommon.JSONEncoder().encode(val))

        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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de récupérer la liste des sessions de formation valides et actives."


"""
Recuperation de la liste sans filtre
"""
def GetAllValideSessionPartner_List_no_filter(diction):
    try:

        field_list = ['token','class_title', 'code_session']
        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é, Creation partenaire annulée")
                return False, " Impossible de récupérer la liste des session de formation"

        """
        Verification de la liste 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 liste ")
                return False, "Impossible de récupérer la liste des session de formation"

        # Recuperation du recid du partner
        mydata = {}

        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


        coll_session = MYSY_GV.dbname['session_formation']

        query = [{'$match':{'partner_owner_recid': str(my_partner['recid'])}   },
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'class_internal_url',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'partner_owner_recid': str(my_partner['recid'])}  },
                                      {'$project': {'title': 1, 'domaine': 1,
                                                    'duration': 1, 'duration_unit': 1, 'external_code':1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]

        print("#### GetAllValideSessionPartner_List_filter_likequery = ", query)
        RetObject = []
        cpt = 1
        for retVal in MYSY_GV.dbname['session_formation'].aggregate(query):
            if( 'myclass_collection' in  retVal.keys() and len(retVal['myclass_collection']) > 0  ):
                val = {}
                val['id'] = str(cpt)
                cpt = cpt + 1
                val['_id'] = retVal['_id']
                val['class_internal_url'] = retVal['class_internal_url']
                val['code_session'] = retVal['code_session']

                if ("titre" in retVal.keys()):
                    val['titre'] = retVal['titre']
                else:
                    val['titre'] = ""

                if ("location_type" in retVal.keys()):
                    val['location_type'] = retVal['location_type']
                else:
                    val['location_type'] = ""

                if ("is_bpf" in retVal.keys()):
                    val['is_bpf'] = retVal['is_bpf']
                else:
                    val['is_bpf'] = ""


                if( "session_etape" in retVal.keys()):
                    val['session_etape'] = retVal['session_etape']
                else:
                    val['session_etape'] = ""

                if( "session_status" in retVal.keys()):
                    val['session_status'] = retVal['session_status']
                else:
                    val['session_status'] = "0"

                val['date_debut'] = retVal['date_debut'][0:10]
                val['date_fin'] = retVal['date_fin'][0:10]
                val['date_debut_inscription'] = retVal['date_debut_inscription'][0:10]
                val['date_fin_inscription'] = retVal['date_fin_inscription'][0:10]

                if ("distantiel" in retVal.keys()):
                    val['distantiel'] = retVal['distantiel']
                else:
                    val['distantiel'] = "0"


                if ("formateur_id" in retVal.keys() and  retVal['formateur_id']):
                    val['formateur_id'] = retVal['formateur_id']

                    # On va aller chercher le nom et prenom du formateur
                    fomateur_data = MYSY_GV.dbname['ressource_humaine'].find_one(
                        {'_id': ObjectId(str(retVal['formateur_id'])),
                         'valide': '1',
                         'locked': '0',
                         'partner_recid': str(my_partner['recid'])})
                    if (fomateur_data is None):
                        val['formateur'] = " Invalide"
                    else:
                        nom = ""
                        prenom = ""
                        if ("nom" in fomateur_data.keys()):
                            nom = fomateur_data['nom']
                        if ("prenom" in fomateur_data.keys()):
                            prenom = fomateur_data['prenom']
                        val['formateur'] = str(nom) + " " + str(prenom)
                else:
                    val['formateur_id'] = ""


                nb_participant = "1"
                if ("nb_participant" in retVal.keys()):
                    nb_participant = retVal['nb_participant']

                val['nb_participant'] = nb_participant

                if ("presentiel" in retVal.keys()):
                    val['presentiel'] = retVal['presentiel']
                else:
                    val['presentiel'] = "0"

                if ("prix_session" in retVal.keys()):
                    val['prix_session'] = retVal['prix_session']
                else:
                    val['prix_session'] = "0"

                val['title'] = retVal['myclass_collection'][0]['title']
                val['domaine'] = retVal['myclass_collection'][0]['domaine']
                val['class_external_code'] = retVal['myclass_collection'][0]['external_code']

                if (str(retVal['myclass_collection'][0]['duration_unit']) == "heure"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " h"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "jour"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " j"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "semaine"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " s"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "mois"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " m"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "annee"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " a"

                elif (str(retVal['myclass_collection'][0]['duration_unit']) == "user_rythme"):
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " u"

                else:
                    val['duration_concat'] = str(retVal['myclass_collection'][0]['duration']) + " ?"

                val['duration'] = retVal['myclass_collection'][0]['duration']
                val['duration_unit'] = retVal['myclass_collection'][0]['duration_unit']

                ## Recuperation du nombre d'inscrits
                Count_Inscrit = MYSY_GV.dbname['inscription'].count_documents(
                    {'session_id': str(retVal['_id']), 'class_internal_url': str(retVal['class_internal_url']),
                     'status': "1"})
                val['nb_inscrit'] = str(Count_Inscrit)

                ## Recuperation du nombre de preinscrits
                Count_Preinscrit = MYSY_GV.dbname['inscription'].count_documents(
                    {'session_id': str(retVal['_id']), 'class_internal_url': str(retVal['class_internal_url']),
                     'status': "0"})

                val['nb_preinscrit'] = str(Count_Preinscrit)

                taux_remplissage = "0"
                if (str(nb_participant) != "0"):
                    taux_remplissage = round(int(mycommon.tryInt(Count_Inscrit)) / int(mycommon.tryInt(nb_participant)),
                                            2)

                val['taux_remplissage'] = str(taux_remplissage)



                RetObject.append(mycommon.JSONEncoder().encode(val))

        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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de récupérer la liste des sessions de formation valides et actives."



"""
Cette fonction crée les sessions de formation en mass
par exemple avec l'import d'un fichier csv
"""
def Add_Update_SessionFormation_mass(file=None, Folder=None, diction=None):
    try:
        '''
               # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
               # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
               # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
               # field_list.
               '''
        field_list = ['token', 'class_internal_url']
        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'existe pas, Creation session annulée")
                return False, " Le champ  '" + val + "' n'existe pas, Creation session annulée "

        '''
        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 
        '''
        field_list_obligatoire = ['token', 'class_internal_url']

        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 liste ")
                return False, " La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_token = diction['token']

        # Verifier la validité du token
        retval = mycommon.check_partner_token_validity("", my_token)
        if retval is False:
            return "Err_Connexion", " La session de connexion n'est pas valide"


        class_internal_url = ""
        if ("class_internal_url" in diction.keys()):
            if diction['class_internal_url']:
                class_internal_url = diction['class_internal_url']

        if (len(str(class_internal_url).strip()) <= 0):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " Le code de la formation est vide : Impossible d'importer la liste des sessions ")
            return False, "Le code de la formation est vide. Impossible d'importer la liste des sessions"


        partner_recid = mycommon.get_parnter_recid_from_token(my_token)
        if (partner_recid is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - partner_recid KO : Impossible d'importer la liste des sessions ")
            return False, "les information de connexion sont incorrectes. Impossible d'importer la liste des sessions"

        status, saved_file = mycommon.Upload_Save_CSV_File(file, Folder)
        if (status == False):
            return False, "Impossible d'importer la liste des sessions, le nom du fichier est incorrect "

        # " Lecture du fichier "
        # print(" Lecture du fichier : "+saved_file)
        nb_line = 0

        """"
        update du 31/08/23 : Controle de l'integrité du fichier avant import
        """
        local_controle_status, local_controle_message = Controle_Add_Update_SessionFormation_mass(saved_file,
                                                                                                           Folder,
                                                                                                           diction)

        if (local_controle_status is False):
            return local_controle_status, local_controle_message

        print(" #### local_controle_message = ", local_controle_message)


        df = pd.read_csv(saved_file, encoding='utf8', on_bad_lines='skip', sep=';', encoding_errors='ignore')
        df = df.fillna('')
        # Dictionnaire des champs utilisables
        '''
        # Verification que les noms des colonne sont bien corrects"
        '''
        field_list = ['date_debut', 'date_fin', 'nb_participant', 'adresse', 'code_postal', 'ville', 'pays',
                      'session_status', 'date_debut_inscription', 'date_fin_inscription', 'attestation', 'formateur',
                      'code_session', "distanciel", "presentiel", "prix_session", 'contenu_ftion', 'lms_class_code',
                      'session_ondemande', 'session_etape', 'formation_code_externe', 'formateur_email', 'titre', 'location_type', 'is_bpf']

        # Controle du nombre de lignes dans le fichier.
        total_rows = len(df)
        if (total_rows > MYSY_GV.MAX_PARTICIPANT_BY_CSV):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le fichier comporte plus de " + str(
                    MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes.")
            return False, " Le fichier comporte plus de " + str(MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes."

        # print(df.columns)
        for val in df.columns:
            if str(val).lower() not in field_list:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " : entete du fichier csv. '" + val + "' n'est pas acceptée")
                return False, " Entete du fichier csv. La Colonne '" + val + "' n'est pas acceptée"


        # Verification des champs obligatoires dans le fichier
        field_list_obligatoire_file = ['date_debut', 'date_fin', 'session_status',  'code_session', 'formation_code_externe']

        for val in field_list_obligatoire_file:
            if val not in df.columns:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " : Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire")
                return False, " Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire "


        # Recuperation des info de la formation.
        formation_data = MYSY_GV.dbname['myclass'].find_one({'internal_url': str(class_internal_url), 'valide':'1', 'locked':'0'})
        if (formation_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " La session de formation n'existe pas : Impossible d'importer la liste des participants ")
            return False, "la session de formation n'existe pas. Impossible d'importer la liste des participants"

        x = range(0, total_rows)
        ignored_line = ""
        nb_inserted_line = 0


        for n in x:
            mydata = {}

            nb_inserted_line = nb_inserted_line + 1
            # Si une ligne n'a aucune information obligatoire, alors on ignore la ligne
            if (str(df['code_session'].values[n]) == "nan" or str(df['session_status'].values[n]) == "nan" or
            str(df['date_debut'].values[n]) == "nan" or str(df['date_fin'].values[n]) == "nan" ):
                mycommon.myprint(str(
                    inspect.stack()[0][
                        3]) + " - La ligne " + str(n + 2) + " a été ignorée")
                ignored_line = str(n + 2) + " , " + str(ignored_line)

                nb_inserted_line = nb_inserted_line - 1
                continue

            external_code = ""
            if ("formation_code_externe" in df.keys()):
                if (str(df['formation_code_externe'].values[n])):
                    external_code = str(df['formation_code_externe'].values[n]).strip()

                    # On verifie l'existance de l'external code pour ce une des formations de ce partner
                    count_class = MYSY_GV.dbname['myclass'].count_documents(
                        {'external_code': str(external_code), 'valide': '1',
                         'locked': '0', 'partner_owner_recid': str(partner_recid)})

                    if (count_class < 0):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Ligne " + str( n + 2) + " : Le code_externe n'est pas valide.")
                        return False, " Ligne " + str( n + 2) + " : Le code_externe n'est pas valide."

                    if (count_class > 1):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Erreur : Ligne " + str(n + 2) + " : Le code_externe corresponds à plus d'une formation.")
                        return False, " Erreur : Ligne " + str(n + 2) + " : Le code_externe corresponds à plus d'une formation."

                    class_date = MYSY_GV.dbname['myclass'].find_one(
                        {'external_code': str(external_code), 'valide': '1',
                         'locked': '0', 'partner_owner_recid': str(partner_recid)})

                    if( class_date['external_code'] != formation_data['external_code']):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Erreur : Ligne " + str( n + 2) + " : Le code externe dans le fichier excel ne correpond pas au code externe de la formation sur la quelle vous etes")
                        return False, "  Erreur : Ligne " + str( n + 2) + " : Le code externe dans le fichier excel ne correpond pas au code externe de la formation sur la quelle vous etes"

            mydata['date_debut'] = str(df['date_debut'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_debut'])
            if(local_status is False ):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne "+str(n+2)+"."
                              "La date debut n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne "+str(n+2)+". La date debut n'est pas au format jj/mm/aaaa "

            mydata['date_fin'] = str(df['date_fin'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_fin'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(n+2) + "."
                                                                                                                     "La date date_fin n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n+1) + ". La date fin n'est pas au format jj/mm/aaaa "


            ## Verification de la cohérence des dates. Date_du doit <= Date_au
            if (datetime.strptime(str(mydata['date_debut']).strip(), '%d/%m/%Y') > datetime.strptime(
                    str(mydata['date_fin']).strip(), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer la session de formation : La date debut " + str(mydata['date_debut']) +
                    " est postérieure à la date de fin " + str(mydata['date_fin']) + " pour la ligne  "+str(n+2)+" ")

                return False, " Impossible de créer la session de formation : La date debut " + str(mydata['date_debut'])[0:10] +\
                       " est postérieure à la date de fin " + str(mydata['date_fin'])[0:10] + " pour la ligne  "+str(n+2)+" "


            local_nb_participants = "1"
            if ("nb_participant" in df.keys()):
                if (str(df['nb_participant'].values[n])):
                    local_nb_participants = str(df['nb_participant'].values[n]).strip()

            local_status, new_participants = mycommon.IsInt(local_nb_participants)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'nb_participant' de la ligne " + str(n+2) + " est incorrecte.")
                return False, " Le champ nb_participant de la ligne " + str(n+2) + " est incorrecte. "

            mydata['nb_participant'] = str(new_participants)

            prix_session = "0"
            if ("prix_session" in df.keys()):
                if (str(df['prix_session'].values[n])):
                    prix_session = str(df['prix_session'].values[n]).strip()

            local_status, new_prix_session = mycommon.IsFloat(prix_session)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'prix_session' de la ligne " + str(n+2) + " est incorrecte.")
                return False, " Le champ prix_session de la ligne " + str(n+2) + " est incorrecte. "

            mydata['prix_session'] = str(new_prix_session)

            local_code_session = ""
            if ("code_session" in df.keys()):
                if (str(df['code_session'].values[n])):
                    local_code_session = str(df['code_session'].values[n]).strip()

            if (len(str(local_code_session).strip()) < 2):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'code_session' de la ligne " + str(
                        n + 2) + " doit faire plus de deux caractères.")
                return False, " Le champ code_session de la ligne " + str(
                    n + 2) + " doit faire plus de deux caractères. "

            mydata['code_session'] = local_code_session

            local_adresse = ""
            if ("adresse" in df.keys()):
                if (str(df['adresse'].values[n])):
                    local_adresse = str(df['adresse'].values[n]).strip()
            mydata['adresse'] = local_adresse

            """ lms_class_code = ""
            if ("lms_class_code" in df.keys()):
                if (str(df['lms_class_code'].values[n])):
                    lms_class_code = str(df['lms_class_code'].values[n]).strip()
            mydata['lms_class_code'] = lms_class_code """


            session_ondemande = "0"
            if ("session_ondemande" in df.keys()):
                if (str(df['session_ondemande'].values[n])):
                    session_ondemande =  str(mycommon.tryInt(str(df['session_ondemande'].values[n]).strip()))

                    if( session_ondemande != "1" and session_ondemande != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'session_ondemande' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'session_ondemande' de la ligne " + str(n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"


            mydata['session_ondemande'] = session_ondemande



            local_code_postal = ""
            if ("code_postal" in df.keys()):
                if (str(df['code_postal'].values[n])):
                    local_code_postal = str(df['code_postal'].values[n]).strip()
                    if ("." in str(local_code_postal)):
                        # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                        local_code_postal = str(local_code_postal).split(".")[0]
                    elif ("." in str(local_code_postal)):
                        # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                        local_code_postal = str(local_code_postal).split(",")[0]
                    else:
                        local_code_postal = str(local_code_postal)


            mydata['code_postal'] = local_code_postal

            distanciel = ""
            if ("distanciel" in df.keys()):
                if (str(df['distanciel'].values[n])):
                    distanciel = str(df['distanciel'].values[n]).strip()
                    distanciel = str(mycommon.tryInt(distanciel))
                    if (distanciel != "1" and distanciel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'distanciel' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'distanciel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"



            mydata['distantiel'] = distanciel

            presentiel = ""
            if ("presentiel" in df.keys()):
                if (str(df['presentiel'].values[n])):
                    presentiel = str(df['presentiel'].values[n]).strip()
                    presentiel = str(mycommon.tryInt(presentiel))

                    if (presentiel != "1" and presentiel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'presentiel' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'presentiel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"

            mydata['presentiel'] = presentiel

            #mydata['code_postal'] = str(df['code_postal'].values[n]).strip()

            local_ville = ""
            if ("ville" in df.keys()):
                if (str(df['ville'].values[n])):
                    local_ville = str(df['ville'].values[n]).strip()
            mydata['ville'] = local_ville

            local_pays = ""
            if ("pays" in df.keys()):
                if (str(df['pays'].values[n])):
                    local_pays = str(df['pays'].values[n]).strip()
            mydata['pays'] = local_pays

            contenu_ftion = ""
            if ("contenu_ftion" in df.keys()):
                if (str(df['contenu_ftion'].values[n])):
                    contenu_ftion = str(df['contenu_ftion'].values[n]).strip()
            mydata['contenu_ftion'] = contenu_ftion

            #mydata['ville'] = str(df['ville'].values[n]).strip()

            local_attestation_certif = ""
            if ("attestation" in df.keys()):
                if (str(df['attestation'].values[n])):
                    local_attestation_certif = str(df['attestation'].values[n]).strip()
            mydata['attestation_certif'] = local_attestation_certif

            #mydata['attestation_certif'] = str(df['attestation'].values[n]).strip()


            session_status = ""
            if ("session_status" in df.keys()):
                if (str(df['session_status'].values[n])):
                    session_status = str(df['session_status'].values[n]).strip()
            session_status = str(mycommon.tryInt(session_status))
            mydata['session_status'] = session_status


            session_etape = ""
            if ("session_etape" in df.keys()):
                if (str(df['session_etape'].values[n])):
                    session_etape = str(df['session_etape'].values[n]).strip()

            mydata['session_etape'] = session_etape

            """ 
            Update du 11/08/23 :
            - le status va etre geré en 0 (desactivé) et 1 (activé)
            - mise en commentaire du code ci-dessous
            
            local_session = str(df['session_status'].values[n]).strip()

            if( str(local_session) != "0" and  str(local_session) != "1" and  str(local_session) != "2"):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2")
                return False, " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2"

            if( str(local_session) == "1"):
                mydata['session_status'] = str("true")
            """

            mydata['date_debut_inscription'] = str(df['date_debut_inscription'].values[n]).strip().split(" ")[0]
            if( str(mydata['date_debut_inscription']).strip() != ""):
                local_status = mycommon.CheckisDate(mydata['date_debut_inscription'])
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(n+2) + "."
                                                                                                                         "La  date_debut_inscription n'est pas au format jj/mm/aaaa ")

                    return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n+2) + ". La date_debut_inscription n'est pas au format jj/mm/aaaa "


            mydata['date_fin_inscription'] = str(df['date_fin_inscription'].values[n]).strip().split(" ")[0]
            if (str(mydata['date_fin_inscription']).strip() != ""):
                local_status = mycommon.CheckisDate(mydata['date_fin_inscription'])
                if (local_status is False):
                    mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(n+2) + "."
                                                                                                                     "La date_fin_inscription n'est pas au format jj/mm/aaaa ")

                    return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n+1) + ". La date_fin_inscription n'est pas au format jj/mm/aaaa "

            ## Verification de la cohérence des dates. date_debut_inscription doit <= date_fin_inscription
            if( str(mydata['date_debut_inscription']).strip() != "" and str(mydata['date_fin_inscription']).strip() != "" ):
                if (datetime.strptime(str(mydata['date_debut_inscription']).strip(), '%d/%m/%Y') > datetime.strptime(
                        str(mydata['date_fin_inscription']).strip(), '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Impossible de créer la session de formation : La date debut des inscriptions " + str(
                            mydata['date_debut_inscription']) +
                        " est postérieure à la date de fin des inscriptions " + str(mydata['date_fin_inscription']) + " pour la ligne  "+str(n+2)+" ")

                    return False, " Impossible de créer la session de formation : La date de fin des inscriptions est antérieure à la date de début des inscriptions : Ligne  "+str(n+2)+" "

            mydata['token'] = str(my_token)
            mydata['class_internal_url'] = str(class_internal_url)

            #print(" ### mydata ", mydata)

            diction_for_session_id = {}
            diction_for_session_id['date_du'] = str(mydata['date_debut']).split(" ")[0]
            diction_for_session_id['date_au'] = str(mydata['date_fin']).split(" ")[0]
            diction_for_session_id['code_postal'] = str(mydata['code_postal'] )
            diction_for_session_id['adresse'] = str(mydata['adresse'])

            """
                       Verifier si la session existe deja en base, si c'est le cas récupérer le '_id'
                       la clé pour verifier l'existance d'une session est : 
                       - code_session
                       - class_internal_url
                       - partner_owner_recid
                       """

            existing_session = MYSY_GV.dbname['session_formation'].find_one(
                {'code_session': str(local_code_session), 'class_internal_url': str(class_internal_url),
                 'partner_owner_recid': str(partner_recid), 'valide': '1'})

            if (existing_session is not None):
                if ('_id' in existing_session.keys()):
                    mydata['session_id'] = existing_session['_id']

            clean_dict = {k: mydata[k] for k in mydata if (str(mydata[k]) != "nan")}

            #print("####  Add_Update_SessionFormation_mass : clean_dict ", clean_dict)
            status, retval = Add_Update_SessionFormation(clean_dict)

            if (status is False):
                return status, retval


        print(str(total_rows) + " sessions ont été inserées")

        message_ignored_line = ""
        if (ignored_line):
            message_ignored_line = "  ATTENTION -  Les lignes [" + str(
                ignored_line) + "] ont été ignorées. car les toutes informations obligatoires ne sont pas fournies"

        return True, str(nb_inserted_line) + " sessions ont été inserées / Mises à jour. " + str(message_ignored_line)


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'importer les sessions de formation  en masse "

"""
Cette fonction permet de faire des controles du fichier excel avant l'import.
cela permet d'eviter des imports partiels.
c'est soit le fichier est TOUT bon ou pas.
"""
def Controle_Add_Update_SessionFormation_mass(saved_file=None, Folder=None, diction=None):
    try:
        '''
               # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
               # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
               # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
               # field_list.
               '''
        field_list = ['token', 'class_internal_url']
        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'existe pas, Creation session annulée")
                return False, " Le champ  '" + val + "' n'existe pas, Creation session annulée "

        '''
        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 
        '''
        field_list_obligatoire = ['token', 'class_internal_url']

        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 liste ")
                return False, " La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_token = diction['token']

        # Verifier la validité du token
        retval = mycommon.check_partner_token_validity("", my_token)
        if retval is False:
            return "Err_Connexion", " La session de connexion n'est pas valide"

        class_internal_url = ""
        if ("class_internal_url" in diction.keys()):
            if diction['class_internal_url']:
                class_internal_url = diction['class_internal_url']

        if (len(str(class_internal_url).strip()) <= 0):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " Le code de la formation est vide : Impossible d'importer la liste des sessions ")
            return False, "Le code de la formation est vide. Impossible d'importer la liste des sessions"


        partner_recid = mycommon.get_parnter_recid_from_token(my_token)
        if (partner_recid is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - partner_recid KO : Impossible d'importer la liste des sessions ")
            return False, "les information de connexion sont incorrectes. Impossible d'importer la liste des sessions"

        nb_line = 0

        df = pd.read_csv(saved_file, encoding='utf8', on_bad_lines='skip', sep=';', encoding_errors='ignore')
        df = df.fillna('')
        # Dictionnaire des champs utilisables
        '''
        # Verification que les noms des colonne sont bien corrects"
        '''
        field_list = ['date_debut', 'date_fin', 'nb_participant', 'adresse', 'code_postal', 'ville', 'pays',
                      'session_status', 'date_debut_inscription', 'date_fin_inscription', 'attestation',
                      'code_session', "distanciel", "presentiel", "prix_session", 'contenu_ftion', 'lms_class_code',
                      'session_ondemande', 'session_etape', 'formation_code_externe','formateur_email', 'titre', 'location_type', 'is_bpf']

        # Controle du nombre de lignes dans le fichier.
        total_rows = len(df)
        if (total_rows > MYSY_GV.MAX_PARTICIPANT_BY_CSV):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le fichier comporte plus de " + str(
                    MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes.")
            return False, " Le fichier comporte plus de " + str(MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes."

        # print(df.columns)
        for val in df.columns:
            if str(val).lower() not in field_list:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " : entete du fichier csv. '" + val + "' n'est pas acceptée")
                return False, " Entete du fichier csv. La Colonne '" + val + "' n'est pas acceptée"

        # Verification des champs obligatoires dans le fichier
        field_list_obligatoire_file = ['date_debut', 'date_fin', 'session_status', 'code_session',
                                       'formation_code_externe']

        for val in field_list_obligatoire_file:
            if val not in df.columns:
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " : Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire")
                return False, " Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire "

        # Recuperation des info de la formation.
        formation_data = MYSY_GV.dbname['myclass'].find_one(
            {'internal_url': str(class_internal_url), 'valide': '1', 'locked': '0'})
        if (formation_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " La session de formation n'existe pas : Impossible d'importer la liste des participants ")
            return False, "la session de formation n'existe pas. Impossible d'importer la liste des participants"

        x = range(0, total_rows)
        ignored_line = ""
        nb_inserted_line = 0

        for n in x:
            mydata = {}

            nb_inserted_line = nb_inserted_line + 1
            # Si une ligne n'a aucune information obligatoire, alors on ignore la ligne
            if (str(df['code_session'].values[n]) == "nan" or str(df['session_status'].values[n]) == "nan" or
                    str(df['date_debut'].values[n]) == "nan" or str(df['date_fin'].values[n]) == "nan"):
                mycommon.myprint(str(
                    inspect.stack()[0][
                        3]) + " - La ligne " + str(n + 2) + " a été ignorée")
                ignored_line = str(n + 2) + " , " + str(ignored_line)

                nb_inserted_line = nb_inserted_line - 1
                continue

            external_code = ""
            if ("formation_code_externe" in df.keys()):
                if (str(df['formation_code_externe'].values[n])):
                    external_code = str(df['formation_code_externe'].values[n]).strip()

                    # On verifie l'existance de l'external code pour ce une des formations de ce partner
                    count_class = MYSY_GV.dbname['myclass'].count_documents(
                        {'external_code': str(external_code), 'valide': '1',
                         'locked': '0', 'partner_owner_recid': str(partner_recid)})

                    if (count_class < 0):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Ligne " + str(
                                n + 2) + " : Le code_externe n'est pas valide.")
                        return False, " Ligne " + str(n + 2) + " : Le code_externe n'est pas valide."

                    if (count_class > 1):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Erreur : Ligne " + str(
                                n + 2) + " : Le code_externe corresponds à plus d'une formation.")
                        return False, " Erreur : Ligne " + str(
                            n + 2) + " : Le code_externe corresponds à plus d'une formation."

                    class_date = MYSY_GV.dbname['myclass'].find_one(
                        {'external_code': str(external_code), 'valide': '1',
                         'locked': '0', 'partner_owner_recid': str(partner_recid)})

                    if (class_date['external_code'] != formation_data['external_code']):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Erreur : Ligne " + str(
                                n + 2) + " : Le code externe dans le fichier excel ne correpond pas au code externe de la formation sur la quelle vous etes")
                        return False, "  Erreur : Ligne " + str(
                            n + 2) + " : Le code externe dans le fichier excel ne correpond pas au code externe de la formation sur la quelle vous etes"

            mydata['date_debut'] = str(df['date_debut'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_debut'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date debut n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 2) + ". La date debut n'est pas au format jj/mm/aaaa "

            mydata['date_fin'] = str(df['date_fin'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_fin'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date date_fin n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 1) + ". La date fin n'est pas au format jj/mm/aaaa "

            # Verifier que l'adresse email du formateur est valide
            formateur_email = ""
            formateur_id = ""
            if ("formateur_email" in df.keys()):
                if (str(df['formateur_email'].values[n])):

                    formateur_email = str(df['formateur_email'].values[n]).strip()
                    if (mycommon.isEmailValide(formateur_email) is False):
                        mycommon.myprint(str(
                            inspect.stack()[0][3]) + " - L'email du formateur  '" + str(
                            formateur_email) + "' pour la formation à la ligne " + str(
                            n + 2) + " n'est pas valide.")
                        return False, " L'email du formateur '" + str(
                            formateur_email) + "' pour la formation à la ligne " + str(
                            n + 2) + " n'est pas valide."

                is_formateur_email_ok = MYSY_GV.dbname['ressource_humaine'].count_documents(
                    {'email': formateur_email,
                     'valide': '1',
                     'locked': '0',
                     'partner_recid': str(
                         partner_recid)})
                if (is_formateur_email_ok <= 0):
                    mycommon.myprint(str(
                        inspect.stack()[0][3]) + " - L'email du formateur  '" + str(
                        formateur_email) + "' pour la formation à la ligne " + str(
                        n + 2) + " n'est pas valide (2).")
                    return False, " L'email du formateur '" + str(
                        formateur_email) + "' pour la formation à la ligne " + str(
                        n + 2) + " n'est pas valide (2)."

                formateur_data = MYSY_GV.dbname['ressource_humaine'].find_one({'email': formateur_email,
                                                                               'valide': '1',
                                                                               'locked': '0',
                                                                               'partner_recid': str(
                                                                                   partner_recid)})

                formateur_id = str(formateur_data['_id'])

            mydata['formateur_id'] = formateur_id

            if ("titre" in df.keys()):
                mydata['titre'] =  str(df['titre'].values[n]).strip()

            if ("location_type" in df.keys()):
                mydata['location_type'] = str(df['location_type'].values[n]).strip().lower()
                if (str(df['location_type'].values[n]).strip().lower() not in MYSY_GV.TRAINING_LOCATION_TYPE):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le champ 'location_type' est incorrecte.")
                    return False, "Le champ 'location_type' est incorrect."

            if ("is_bpf" in df.keys()):
                if (str(df['is_bpf'].values[n]).strip() not in ['0', '1']):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le champ 'bpf' est incorrect.  Les valeurs acceptées sont : '1' ou '0' ")
                    return False, "Le champ 'bpf' est incorrect.  Les valeurs acceptées sont : '1' ou '0' "

                mydata['is_bpf'] = str(df['is_bpf'].values[n]).strip()


            ## Verification de la cohérence des dates. Date_du doit <= Date_au
            if (datetime.strptime(str(mydata['date_debut']).strip(), '%d/%m/%Y') > datetime.strptime(
                    str(mydata['date_fin']).strip(), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer la session de formation : La date debut " + str(
                        mydata['date_debut']) +
                    " est postérieure à la date de fin " + str(mydata['date_fin']) + " pour la ligne  " + str(
                        n + 2) + " ")

                return False, " Impossible de créer la session de formation : La date debut " + str(
                    mydata['date_debut'])[0:10] + \
                       " est postérieure à la date de fin " + str(mydata['date_fin'])[0:10] + " pour la ligne  " + str(
                    n + 2) + " "

            local_nb_participants = "1"
            if ("nb_participant" in df.keys()):
                if (str(df['nb_participant'].values[n])):
                    local_nb_participants = str(df['nb_participant'].values[n]).strip()

            local_status, new_participants = mycommon.IsInt(local_nb_participants)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'nb_participant' de la ligne " + str(
                        n + 2) + " est incorrecte.")
                return False, " Le champ nb_participant de la ligne " + str(n + 2) + " est incorrecte. Un nombre Entier Positif doit être fourni "

            mydata['nb_participant'] = str(new_participants)

            prix_session = "0"
            if ("prix_session" in df.keys()):
                if (str(df['prix_session'].values[n])):
                    prix_session = str(df['prix_session'].values[n]).strip()

            local_status, new_prix_session = mycommon.IsFloat(prix_session)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'prix_session' de la ligne " + str(
                        n + 2) + " est incorrecte.")
                return False, " Le champ prix_session de la ligne " + str(n + 2) + " est incorrecte. "

            mydata['prix_session'] = str(new_prix_session)

            local_code_session = ""
            if ("code_session" in df.keys()):
                if (str(df['code_session'].values[n])):
                    local_code_session = str(df['code_session'].values[n]).strip()
                    
            if(len(str(local_code_session).strip()) < 2 ):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'code_session' de la ligne " + str(
                        n + 2) + " doit faire plus de deux caractères.")
                return False, " Le champ code_session de la ligne " + str(n + 2) + " doit faire plus de deux caractères. "
                
            mydata['code_session'] = local_code_session

            local_adresse = ""
            if ("adresse" in df.keys()):
                if (str(df['adresse'].values[n])):
                    local_adresse = str(df['adresse'].values[n]).strip()
            mydata['adresse'] = local_adresse


            session_ondemande = "0"
            if ("session_ondemande" in df.keys()):
                if (str(df['session_ondemande'].values[n])):
                    session_ondemande = str(df['session_ondemande'].values[n]).strip()
                    session_ondemande = str(mycommon.tryInt(str(session_ondemande)))

                    if (session_ondemande != "1" and session_ondemande != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'session_ondemande' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'session_ondemande' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"

            mydata['session_ondemande'] = session_ondemande

            local_code_postal = ""
            if ("code_postal" in df.keys()):
                if (str(df['code_postal'].values[n])):
                    local_code_postal = str(df['code_postal'].values[n]).strip()

                    if ("." in str(local_code_postal)):
                        # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                        local_code_postal = str(local_code_postal).split(".")[0]
                    elif ("." in str(local_code_postal)):
                        # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                        local_code_postal = str(local_code_postal).split(",")[0]
                    else:
                        local_code_postal = str(local_code_postal)


            mydata['code_postal'] = local_code_postal

            distanciel = ""
            if ("distanciel" in df.keys()):
                if (str(df['distanciel'].values[n])):
                    distanciel = str(df['distanciel'].values[n]).strip()
                    distanciel = str(mycommon.tryInt(distanciel))

                    if (distanciel != "1" and distanciel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'distanciel' de la ligne " + str(
                                n + 2) + " est incorrecte. La valeur fournie est "+str(distanciel) )
                        return False, " Le champ 'distanciel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0'. La valeur fournie est "+str(distanciel)

            mydata['distantiel'] = distanciel

            presentiel = ""
            if ("presentiel" in df.keys()):
                if (str(df['presentiel'].values[n])):
                    presentiel = str(df['presentiel'].values[n]).strip()
                    presentiel = str(mycommon.tryInt(presentiel))

                    if (presentiel != "1" and presentiel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'presentiel' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'presentiel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"

            mydata['presentiel'] = presentiel

            # mydata['code_postal'] = str(df['code_postal'].values[n]).strip()

            local_ville = ""
            if ("ville" in df.keys()):
                if (str(df['ville'].values[n])):
                    local_ville = str(df['ville'].values[n]).strip()
            mydata['ville'] = local_ville

            local_pays = ""
            if ("pays" in df.keys()):
                if (str(df['pays'].values[n])):
                    local_pays = str(df['pays'].values[n]).strip()
            mydata['pays'] = local_pays

            contenu_ftion = ""
            if ("contenu_ftion" in df.keys()):
                if (str(df['contenu_ftion'].values[n])):
                    contenu_ftion = str(df['contenu_ftion'].values[n]).strip()
            mydata['contenu_ftion'] = contenu_ftion

            # mydata['ville'] = str(df['ville'].values[n]).strip()

            local_attestation_certif = ""
            if ("attestation" in df.keys()):
                if (str(df['attestation'].values[n])):
                    local_attestation_certif = str(df['attestation'].values[n]).strip()
            mydata['attestation_certif'] = local_attestation_certif

            # mydata['attestation_certif'] = str(df['attestation'].values[n]).strip()


            session_status = ""
            if ("session_status" in df.keys()):
                if (str(df['session_status'].values[n])):
                    session_status = str(df['session_status'].values[n]).strip()
            mydata['session_status'] = session_status

            session_etape = ""
            if ("session_etape" in df.keys()):
                if (str(df['session_etape'].values[n])):
                    session_etape = str(df['session_etape'].values[n]).strip()
            mydata['session_etape'] = session_etape

            """ 
            Update du 11/08/23 :
            - le status va etre geré en 0 (desactivé) et 1 (activé)
            - mise en commentaire du code ci-dessous

            local_session = str(df['session_status'].values[n]).strip()

            if( str(local_session) != "0" and  str(local_session) != "1" and  str(local_session) != "2"):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2")
                return False, " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2"

            if( str(local_session) == "1"):
                mydata['session_status'] = str("true")
            """

            mydata['date_debut_inscription'] = str(df['date_debut_inscription'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_debut_inscription'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La  date_debut_inscription n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 2) + ". La date_debut_inscription n'est pas au format jj/mm/aaaa "

            mydata['date_fin_inscription'] = str(df['date_fin_inscription'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_fin_inscription'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date_fin_inscription n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 1) + ". La date_fin_inscription n'est pas au format jj/mm/aaaa "

            ## Verification de la cohérence des dates. Date_du doit <= Date_au
            if (datetime.strptime(str(mydata['date_debut_inscription']).strip(), '%d/%m/%Y') > datetime.strptime(
                    str(mydata['date_fin_inscription']).strip(), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer la session de formation : La date debut des inscriptions " + str(
                        mydata['date_debut_inscription'])[0:10] +
                    " est postérieure à la date de fin des inscriptions " + str(
                        mydata['date_fin_inscription'])[0:10] + " pour la ligne  " + str(n + 2) + " ")

                return False, " Impossible de créer la session de formation : La date de fin des inscriptions est antérieure à la date de début des inscriptions : Ligne  " + str(
                    n + 2) + " "

            mydata['token'] = str(my_token)
            mydata['class_internal_url'] = str(class_internal_url)

            # print(" ### mydata ", mydata)

            diction_for_session_id = {}
            diction_for_session_id['date_du'] = str(mydata['date_debut']).split(" ")[0]
            diction_for_session_id['date_au'] = str(mydata['date_fin']).split(" ")[0]
            diction_for_session_id['code_postal'] = str(mydata['code_postal'])
            diction_for_session_id['adresse'] = str(mydata['adresse'])





        return True, str(total_rows)+" sessions dans le fichier"


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de controler le fichier des sessions de formation  en masse "


"""
import des sessions de formation en masse
pour plusieurs formation.

Cela veut dire qu'on fourni 'external_code' pour chaque ligne du fichier excel, mais on ne fourni pas de 'internal_url'
"""


def Add_Update_SessionFormation_mass_for_many_class(file=None, Folder=None, diction=None):
    try:
        '''
               # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
               # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
               # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
               # field_list.
               '''
        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'existe pas, Creation session annulée")
                return False, " Le champ  '" + val + "' n'existe pas, Creation session annulée "

        '''
        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 
        '''
        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 liste ")
                return False, " La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_token = diction['token']

        # Verifier la validité du token
        retval = mycommon.check_partner_token_validity("", my_token)
        if retval is False:
            return "Err_Connexion", " La session de connexion n'est pas valide"

        # Verifier la validité du token
        retval = mycommon.check_partner_token_validity("", my_token)

        if retval is False:
            return "Err_Connexion", " La session de connexion n'est pas valide"

        partner_recid = mycommon.get_parnter_recid_from_token(my_token)
        if (partner_recid is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - partner_recid KO : Impossible d'importer la liste des sessions ")
            return False, "les information de connexion sont incorrectes. Impossible d'importer la liste des sessions"

        status, saved_file = mycommon.Upload_Save_CSV_File(file, Folder)
        if (status == False):
            return False, "Impossible d'importer la liste des sessions, le nom du fichier est incorrect "

        # " Lecture du fichier "
        # print(" Lecture du fichier : "+saved_file)
        nb_line = 0

        """"
                update du 31/08/23 : Controle de l'integrité du fichier avant import
                """
        local_controle_status, local_controle_message = Controle_Add_Update_SessionFormation_mass_for_many_class(saved_file,
                                                                                                  Folder,
                                                                                                  diction)


        if (local_controle_status is False):
            return local_controle_status, local_controle_message

        print(" #### local_controle_message = ", local_controle_message)


        df = pd.read_csv(saved_file, encoding='utf8', on_bad_lines='skip', sep=';', encoding_errors='ignore')
        df = df.fillna('')
        # Dictionnaire des champs utilisables
        '''
        # Verification que les noms des colonne sont bien corrects"
        '''
        field_list = ['date_debut', 'date_fin', 'nb_participant', 'adresse', 'code_postal', 'ville', 'pays',
                      'session_status', 'date_debut_inscription', 'date_fin_inscription', 'attestation',
                      'code_session', "distanciel", "presentiel", "prix_session", 'contenu_ftion', 'lms_class_code',
                      'session_ondemande', 'session_etape', 'formation_code_externe', 'formateur_email', 'titre', 'location_type', 'is_bpf']

        # Controle du nombre de lignes dans le fichier.
        total_rows = len(df)
        if (total_rows > MYSY_GV.MAX_PARTICIPANT_BY_CSV):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le fichier comporte plus de " + str(
                    MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes.")
            return False, " Le fichier comporte plus de " + str(MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes."

        # print(df.columns)
        for val in df.columns:
            if str(val).lower() not in field_list:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " : entete du fichier csv. '" + val + "' n'est pas acceptée")
                return False, " Entete du fichier csv. La Colonne '" + val + "' n'est pas acceptée"

        # Verification des champs obligatoires dans le fichier
        field_list_obligatoire_file = ['date_debut', 'date_fin', 'session_status', 'code_session', 'formation_code_externe']

        for val in field_list_obligatoire_file:
            if val not in df.columns:
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " : Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire")
                return False, " Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire "



        x = range(0, total_rows)
        ignored_line = ""
        nb_inserted_line = 0


        for n in x:
            mydata = {}

            nb_inserted_line = nb_inserted_line + 1
            # Si une ligne n'a aucune information obligatoire, alors on ignore la ligne
            if (str(df['code_session'].values[n]) == "nan" or str(df['session_status'].values[n]) == "nan" or
                    str(df['date_debut'].values[n]) == "nan" or str(df['date_fin'].values[n]) == "nan"):
                mycommon.myprint(str(
                    inspect.stack()[0][
                        3]) + " - La ligne " + str(n + 2) + " a été ignorée")
                ignored_line = str(n + 2) + " , " + str(ignored_line)

                nb_inserted_line = nb_inserted_line - 1
                continue

            mydata['date_debut'] = str(df['date_debut'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_debut'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date debut n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 2) + ". La date debut n'est pas au format jj/mm/aaaa "

            mydata['date_fin'] = str(df['date_fin'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_fin'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date date_fin n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 1) + ". La date fin n'est pas au format jj/mm/aaaa "

            # Verifier que l'adresse email du formateur est valide
            formateur_email = ""
            formateur_id = ""
            if ("formateur_email" in df.keys()):
                if (str(df['formateur_email'].values[n])):

                    formateur_email = str(df['formateur_email'].values[n]).strip()
                    if (mycommon.isEmailValide(formateur_email) is False):
                        mycommon.myprint(str(
                            inspect.stack()[0][3]) + " - L'email du formateur  '" + str(
                            formateur_email) + "' pour la formation à la ligne " + str(
                            n + 2) + " n'est pas valide.")
                        return False, " L'email du formateur '" + str(
                            formateur_email) + "' pour la formation à la ligne " + str(
                            n + 2) + " n'est pas valide."

                is_formateur_email_ok = MYSY_GV.dbname['ressource_humaine'].count_documents(
                    {'email': formateur_email,
                     'valide': '1',
                     'locked': '0',
                     'partner_recid': str(
                         partner_recid)})
                if (is_formateur_email_ok <= 0):
                    mycommon.myprint(str(
                        inspect.stack()[0][3]) + " - L'email du formateur  '" + str(
                        formateur_email) + "' pour la formation à la ligne " + str(
                        n + 2) + " n'est pas valide (2).")
                    return False, " L'email du formateur '" + str(
                        formateur_email) + "' pour la formation à la ligne " + str(
                        n + 2) + " n'est pas valide (2)."

                formateur_data = MYSY_GV.dbname['ressource_humaine'].find_one({'email': formateur_email,
                                                                               'valide': '1',
                                                                               'locked': '0',
                                                                               'partner_recid': str(
                                                                                   partner_recid)})

                formateur_id = str(formateur_data['_id'])

            mydata['formateur_id'] = formateur_id

            if ("titre" in df.keys()):
                mydata['titre'] = str(df['titre'].values[n]).strip()

            if ("location_type" in df.keys()):
                mydata['location_type'] = str(df['location_type'].values[n]).strip().lower()
                if (str(df['location_type'].values[n]).strip().lower() not in MYSY_GV.TRAINING_LOCATION_TYPE):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le champ 'location_type' est incorrecte.")
                    return False, "Le champ 'location_type' est incorrect."

            if ("is_bpf" in df.keys()):
                if (str(df['is_bpf'].values[n]).strip() not in ['0', '1']):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le champ 'bpf' est incorrect.  Les valeurs acceptées sont : '1' ou '0' ")
                    return False, "Le champ 'bpf' est incorrect.  Les valeurs acceptées sont : '1' ou '0' "

                mydata['is_bpf'] =  str(df['is_bpf'].values[n]).strip()




            ## Verification de la cohérence des dates. Date_du doit <= Date_au
            if (datetime.strptime(str(mydata['date_debut']).strip(), '%d/%m/%Y') > datetime.strptime(
                    str(mydata['date_fin']).strip(), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer la session de formation : La date debut " + str(
                        mydata['date_debut']) +
                    " est postérieure à la date de fin " + str(mydata['date_fin']) + " pour la ligne  " + str(
                        n + 2) + " ")

                return False, " Impossible de créer la session de formation : La date debut " + str(
                    mydata['date_debut'])[0:10] + \
                       " est postérieure à la date de fin " + str(mydata['date_fin'])[0:10] + " pour la ligne  " + str(
                    n + 2) + " "

            local_nb_participants = "1"
            if ("nb_participant" in df.keys()):
                if (str(df['nb_participant'].values[n])):
                    local_nb_participants = str(df['nb_participant'].values[n]).strip()

            local_status, new_participants = mycommon.IsInt(local_nb_participants)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'nb_participant' de la ligne " + str(
                        n + 2) + " est incorrecte.")
                return False, " Le champ nb_participant de la ligne " + str(n + 2) + " est incorrecte. "

            mydata['nb_participant'] = str(new_participants)

            prix_session = "0"
            if ("prix_session" in df.keys()):
                if (str(df['prix_session'].values[n])):
                    prix_session = str(df['prix_session'].values[n]).strip()

            local_status, new_prix_session = mycommon.IsFloat(prix_session)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'prix_session' de la ligne " + str(
                        n + 2) + " est incorrecte.")
                return False, " Le champ prix_session de la ligne " + str(n + 2) + " est incorrecte. "

            mydata['prix_session'] = str(new_prix_session)

            class_internal_url = ""

            external_code = ""
            if ("formation_code_externe" in df.keys()):
                if (str(df['formation_code_externe'].values[n])):
                    external_code = str(df['formation_code_externe'].values[n]).strip()

                    #On verifie l'existance de l'external code pour ce une des formations de ce partner
                    count_class =  MYSY_GV.dbname['myclass'].count_documents({'external_code':str(external_code), 'valide':'1',
                                                                               'locked':'0', 'partner_owner_recid':str(partner_recid)})


                    if( count_class != 1 ):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'code_externe' de la ligne " + str(
                                n + 2) + " ne correspond pas à une formation valide.")
                        return False, " Le champ 'code_externe' de la ligne " + str(
                            n + 2) + " ne correspond pas à une formation valide."

                    class_from_external_code = MYSY_GV.dbname['myclass'].find({'external_code':str(external_code), 'valide':'1',
                                                                               'locked':'0', 'partner_owner_recid':str(partner_recid)})

                    if(class_from_external_code is None ):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'code_exyer' de la ligne " + str(
                                n + 2) + " ne correspond pas à une formation valide (2).")
                        return False, " Le champ 'code_exyer' de la ligne " + str( n + 2) + " ne correspond pas à une formation valide (2)."


                    class_internal_url = str(class_from_external_code[0]['internal_url'])


            local_code_session = ""
            if ("code_session" in df.keys()):
                if (str(df['code_session'].values[n])):
                    local_code_session = str(df['code_session'].values[n]).strip()

            if (len(str(local_code_session).strip()) < 2):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'code_session' de la ligne " + str(
                        n + 2) + " doit faire plus de deux caractères.")
                return False, " Le champ code_session de la ligne " + str(
                    n + 2) + " doit faire plus de deux caractères. "
            mydata['code_session'] = local_code_session

            local_adresse = ""
            if ("adresse" in df.keys()):
                if (str(df['adresse'].values[n])):
                    local_adresse = str(df['adresse'].values[n]).strip()
            mydata['adresse'] = local_adresse




            session_ondemande = ""
            if ("session_ondemande" in df.keys()):
                if (str(df['session_ondemande'].values[n])):
                    session_ondemande = str(df['session_ondemande'].values[n]).strip()

                    if (session_ondemande != "1" and session_ondemande != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'session_ondemande' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'session_ondemande' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"

            mydata['session_ondemande'] = session_ondemande

            local_code_postal = ""
            if ("code_postal" in df.keys()):
                if (str(df['code_postal'].values[n])):
                    local_code_postal = str(df['code_postal'].values[n]).strip()

            if ("." in str(local_code_postal)):
                # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                local_code_postal = str(local_code_postal).split(".")[0]
            elif ("." in str(local_code_postal)):
                # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                local_code_postal = str(local_code_postal).split(",")[0]
            else:
                local_code_postal = str(local_code_postal)

            mydata['code_postal'] = local_code_postal

            distanciel = ""
            if ("distanciel" in df.keys()):
                if (str(df['distanciel'].values[n])):
                    distanciel = str(df['distanciel'].values[n]).strip()
                    distanciel = str(mycommon.tryInt(distanciel))
                    if (distanciel != "1" and distanciel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'distanciel' de la ligne " + str(
                                n + 2) + " est incorrecte. Valeur reçue : "+str(distanciel))
                        return False, " Le champ 'distanciel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide. Valeur reçue : "+str(distanciel)

            mydata['distantiel'] = distanciel

            presentiel = ""
            if ("presentiel" in df.keys()):
                if (str(df['presentiel'].values[n])):
                    presentiel = str(df['presentiel'].values[n]).strip()
                    presentiel = str(mycommon.tryInt(presentiel))
                    if (presentiel != "1" and presentiel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'presentiel' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'presentiel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"

            mydata['presentiel'] = presentiel

            # mydata['code_postal'] = str(df['code_postal'].values[n]).strip()

            local_ville = ""
            if ("ville" in df.keys()):
                if (str(df['ville'].values[n])):
                    local_ville = str(df['ville'].values[n]).strip()
            mydata['ville'] = local_ville

            pays = ""
            if ("pays" in df.keys()):
                if (str(df['pays'].values[n])):
                    pays = str(df['pays'].values[n]).strip()
            mydata['pays'] = pays

            contenu_ftion = ""
            if ("contenu_ftion" in df.keys()):
                if (str(df['contenu_ftion'].values[n])):
                    contenu_ftion = str(df['contenu_ftion'].values[n]).strip()
            mydata['contenu_ftion'] = contenu_ftion

            # mydata['ville'] = str(df['ville'].values[n]).strip()
            """ 
            local_attestation_certif = ""
            if ("attestation" in df.keys()):
                if (str(df['attestation'].values[n])):
                    local_attestation_certif = str(df['attestation'].values[n]).strip()
            mydata['attestation_certif'] = local_attestation_certif
            
            # mydata['attestation_certif'] = str(df['attestation'].values[n]).strip()
            """

            session_status = ""
            if ("session_status" in df.keys()):
                if (str(df['session_status'].values[n])):
                    session_status = str(df['session_status'].values[n]).strip()

            session_status = str(mycommon.tryInt(session_status))
            mydata['session_status'] = session_status

            session_etape = ""
            if ("session_etape" in df.keys()):
                if (str(df['session_etape'].values[n])):
                    session_etape = str(df['session_etape'].values[n]).strip()


            mydata['session_etape'] = session_etape

            """ 
            Update du 11/08/23 :
            - le status va etre geré en 0 (desactivé) et 1 (activé)
            - mise en commentaire du code ci-dessous

            local_session = str(df['session_status'].values[n]).strip()

            if( str(local_session) != "0" and  str(local_session) != "1" and  str(local_session) != "2"):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2")
                return False, " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2"

            if( str(local_session) == "1"):
                mydata['session_status'] = str("true")
            """

            mydata['date_debut_inscription'] = str(df['date_debut_inscription'].values[n]).strip().split(" ")[0]
            if( str(mydata['date_debut_inscription']).strip() != ""):
                local_status = mycommon.CheckisDate(mydata['date_debut_inscription'])
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                            n + 2) + "."
                                     "La  date_debut_inscription n'est pas au format jj/mm/aaaa ")

                    return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + ". La date_debut_inscription n'est pas au format jj/mm/aaaa "

            mydata['date_fin_inscription'] = str(df['date_fin_inscription'].values[n]).strip().split(" ")[0]
            if (str(mydata['date_fin_inscription']).strip() != ""):
                local_status = mycommon.CheckisDate(mydata['date_fin_inscription'])
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                            n + 2) + "."
                                     "La date_fin_inscription n'est pas au format jj/mm/aaaa ")

                    return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 1) + ". La date_fin_inscription n'est pas au format jj/mm/aaaa "

            ## Verification de la cohérence des dates. Date_du doit <= Date_au
            if (str(mydata['date_debut_inscription']).strip() != "" and str(mydata['date_fin_inscription']).strip() != ""):
                if (datetime.strptime(str(mydata['date_debut_inscription']).strip(), '%d/%m/%Y') > datetime.strptime(
                        str(mydata['date_fin_inscription']).strip(), '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Impossible de créer la session de formation : La date debut des inscriptions " + str(
                            mydata['date_debut_inscription']) +
                        " est postérieure à la date de fin des inscriptions " + str(
                            mydata['date_fin_inscription']) + " pour la ligne  " + str(n + 2) + " ")

                    return False, " Impossible de créer la session de formation : La date de fin des inscriptions est antérieure à la date de début des inscriptions : Ligne  " + str(
                    n + 2) + " "

            mydata['token'] = str(my_token)
            mydata['class_internal_url'] = str(class_internal_url)

            #print(" ### mydata ", mydata)

            diction_for_session_id = {}
            diction_for_session_id['date_du'] = str(mydata['date_debut']).split(" ")[0]
            diction_for_session_id['date_au'] = str(mydata['date_fin']).split(" ")[0]
            diction_for_session_id['code_postal'] = str(mydata['code_postal'])
            diction_for_session_id['adresse'] = str(mydata['adresse'])

            """
            Verifier si la session existe deja en base, si c'est le cas récupérer le '_id'
            la clé pour verifier l'existance d'une session est : 
            - code_session
            - class_internal_url
            - partner_owner_recid
            """

            existing_session = MYSY_GV.dbname['session_formation'].find_one({'code_session':str(local_code_session), 'class_internal_url':str(class_internal_url),
                                                                             'partner_owner_recid':str(partner_recid), 'valide':'1'})

            if( existing_session is not None):
                if( '_id' in existing_session.keys()):
                    mydata['session_id'] = existing_session['_id']

            clean_dict = {k: mydata[k] for k in mydata if (str(mydata[k]) != "nan")}

            print("####  Add_Update_SessionFormation_mass_for_many_class : clean_dict ", clean_dict)
            status, retval = Add_Update_SessionFormation(clean_dict)

            if (status is False):
                return status, retval

        print(str(total_rows) + " sessions ont été inserées")

        message_ignored_line = ""
        if (ignored_line):
            message_ignored_line = "  ATTENTION -  Les lignes [" + str(
                ignored_line) + "] ont été ignorées. car les toutes informations obligatoires ne sont pas fournies"

        return True, str(nb_inserted_line) + " sessions ont été inserées / Mises à jour. " + str(message_ignored_line)


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'importer les sessions de formation  en masse "



"""
Controle fichier avant import
"""
def Controle_Add_Update_SessionFormation_mass_for_many_class(saved_file=None, Folder=None, diction=None):
    try:
        '''
               # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
               # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
               # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
               # field_list.
               '''
        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'existe pas, Creation session annulée")
                return False, " Le champ  '" + val + "' n'existe pas, Creation session annulée "

        '''
        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 
        '''
        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 liste ")
                return False, " La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_token = diction['token']

        # Verifier la validité du token
        retval = mycommon.check_partner_token_validity("", my_token)
        if retval is False:
            return "Err_Connexion", " La session de connexion n'est pas valide"


        partner_recid = mycommon.get_parnter_recid_from_token(my_token)
        if (partner_recid is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - partner_recid KO : Impossible d'importer la liste des sessions ")
            return False, "les information de connexion sont incorrectes. Impossible d'importer la liste des sessions"

        nb_line = 0

        df = pd.read_csv(saved_file, encoding='utf8', on_bad_lines='skip', sep=';', encoding_errors='ignore')
        df = df.fillna('')
        # Dictionnaire des champs utilisables
        '''
        # Verification que les noms des colonne sont bien corrects"
        '''
        field_list = ['date_debut', 'date_fin', 'nb_participant', 'adresse', 'code_postal', 'ville', 'pays',
                      'session_status', 'date_debut_inscription', 'date_fin_inscription', 'attestation',
                      'code_session', "distanciel", "presentiel", "prix_session", 'contenu_ftion', 'lms_class_code',
                      'session_ondemande', 'session_etape', 'formation_code_externe', 'formateur_email', 'titre', 'location_type', 'is_bpf']

        # Controle du nombre de lignes dans le fichier.
        total_rows = len(df)
        if (total_rows > MYSY_GV.MAX_PARTICIPANT_BY_CSV):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le fichier comporte plus de " + str(
                    MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes.")
            return False, " Le fichier comporte plus de " + str(MYSY_GV.MAX_PARTICIPANT_BY_CSV) + " lignes."

        # print(df.columns)
        for val in df.columns:
            if str(val).lower() not in field_list:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " : entete du fichier csv. '" + val + "' n'est pas acceptée")
                return False, " Entete du fichier csv. La Colonne '" + val + "' n'est pas acceptée"

        # Verification des champs obligatoires dans le fichier
        field_list_obligatoire_file = ['date_debut', 'date_fin', 'session_status', 'code_session',
                                       'formation_code_externe']

        for val in field_list_obligatoire_file:
            if val not in df.columns:
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " : Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire")
                return False, " Le champ '" + val + "' n'est pas présent dans le fichier. Il est obligatoire "


        x = range(0, total_rows)
        ignored_line = ""
        nb_inserted_line = 0

        for n in x:
            mydata = {}

            nb_inserted_line = nb_inserted_line + 1
            # Si une ligne n'a aucune information obligatoire, alors on ignore la ligne
            if (str(df['code_session'].values[n]) == "nan" or str(df['session_status'].values[n]) == "nan" or
                    str(df['date_debut'].values[n]) == "nan" or str(df['date_fin'].values[n]) == "nan"):
                mycommon.myprint(str(
                    inspect.stack()[0][
                        3]) + " - La ligne " + str(n + 2) + " a été ignorée")
                ignored_line = str(n + 2) + " , " + str(ignored_line)

                nb_inserted_line = nb_inserted_line - 1
                continue

            external_code = ""
            if ("formation_code_externe" in df.keys()):
                if (str(df['formation_code_externe'].values[n])):
                    external_code = str(df['formation_code_externe'].values[n]).strip()

                    # On verifie l'existance de l'external code pour ce une des formations de ce partner
                    count_class = MYSY_GV.dbname['myclass'].count_documents(
                        {'external_code': str(external_code), 'valide': '1',
                         'locked': '0', 'partner_owner_recid': str(partner_recid)})

                    if (count_class < 0):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Ligne " + str(
                                n + 2) + " : Le code_externe n'est pas valide.")
                        return False, " Ligne " + str(n + 2) + " : Le code_externe n'est pas valide."

                    if (count_class > 1):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Erreur : Ligne " + str(
                                n + 2) + " : Le code_externe corresponds à plus d'une formation.")
                        return False, " Erreur : Ligne " + str(
                            n + 2) + " : Le code_externe corresponds à plus d'une formation."

                    class_date = MYSY_GV.dbname['myclass'].find_one(
                        {'external_code': str(external_code), 'valide': '1',
                         'locked': '0', 'partner_owner_recid': str(partner_recid)})

                else:
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " Erreur : Ligne " + str(
                            n + 2) + " : Le code_externe de la formation  n'est pas invalide.")
                    return False, " Erreur : Ligne " + str(
                        n + 2) + " :  Le code_externe de la formation  n'est pas invalide."


            mydata['date_debut'] = str(df['date_debut'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_debut'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date debut n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 2) + ". La date debut n'est pas au format jj/mm/aaaa "

            mydata['date_fin'] = str(df['date_fin'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_fin'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date date_fin n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 1) + ". La date fin n'est pas au format jj/mm/aaaa "

            ## Verification de la cohérence des dates. Date_du doit <= Date_au
            if (datetime.strptime(str(mydata['date_debut']).strip(), '%d/%m/%Y') > datetime.strptime(
                    str(mydata['date_fin']).strip(), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer la session de formation : La date debut " + str(
                        mydata['date_debut']) +
                    " est postérieure à la date de fin " + str(mydata['date_fin']) + " pour la ligne  " + str(
                        n + 2) + " ")

                return False, " Impossible de créer la session de formation : La date debut " + str(
                    mydata['date_debut']) + \
                       " est postérieure à la date de fin " + str(mydata['date_fin'])[0:10] + " pour la ligne  " + str(
                    n + 2) + " "

            # Verifier que l'adresse email du formateur est valide
            formateur_email = ""
            formateur_id = ""
            if ("formateur_email" in df.keys()):
                if (str(df['formateur_email'].values[n])):

                    formateur_email = str(df['formateur_email'].values[n]).strip()
                    if (mycommon.isEmailValide(formateur_email) is False):
                        mycommon.myprint(str(
                            inspect.stack()[0][3]) + " - L'email du formateur  '" + str(
                            formateur_email) + "' pour la formation à la ligne " + str(
                            n + 2) + " n'est pas valide.")
                        return False, " L'email du formateur '" + str(
                            formateur_email) + "' pour la formation à la ligne " + str(
                            n + 2) + " n'est pas valide."

                is_formateur_email_ok = MYSY_GV.dbname['ressource_humaine'].count_documents(
                    {'email': formateur_email,
                     'valide': '1',
                     'locked': '0',
                     'partner_recid': str(
                         partner_recid)})
                if (is_formateur_email_ok <= 0):
                    mycommon.myprint(str(
                        inspect.stack()[0][3]) + " - L'email du formateur  '" + str(
                        formateur_email) + "' pour la formation à la ligne " + str(
                        n + 2) + " n'est pas valide (2).")
                    return False, " L'email du formateur '" + str(
                        formateur_email) + "' pour la formation à la ligne " + str(
                        n + 2) + " n'est pas valide (2)."

                formateur_data = MYSY_GV.dbname['ressource_humaine'].find_one({'email': formateur_email,
                                                                               'valide': '1',
                                                                               'locked': '0',
                                                                               'partner_recid': str(
                                                                                   partner_recid)})

                formateur_id = str(formateur_data['_id'])

            mydata['formateur_id'] = formateur_id

            if ("titre" in df.keys()):
                mydata['titre'] = str(df['titre'].values[n]).strip()

            if ("location_type" in df.keys()):
                mydata['location_type'] = str(df['location_type'].values[n]).strip().lower()
                if (str(df['location_type'].values[n]).strip().lower() not in MYSY_GV.TRAINING_LOCATION_TYPE):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le champ 'location_type' est incorrecte. Les valeurs acceptés sont : "+str(MYSY_GV.TRAINING_LOCATION_TYPE))
                    return False, "Le champ 'location_type' est incorrect. . Les valeurs acceptés sont : "+str(MYSY_GV.TRAINING_LOCATION_TYPE)+ " "

            if ("is_bpf" in df.keys()):
                if (str(df['is_bpf'].values[n]).strip() not in ['0', '1']):
                    mycommon.myprint(str(inspect.stack()[0][
                                             3]) + " - Le champ 'bpf' est incorrect.  Les valeurs acceptées sont : '1' ou '0' ")
                    return False, "Le champ 'bpf' est incorrect.  Les valeurs acceptées sont : '1' ou '0' "

                mydata['is_bpf'] = str(df['is_bpf'].values[n]).strip()

            local_nb_participants = "1"
            if ("nb_participant" in df.keys()):
                if (str(df['nb_participant'].values[n])):
                    local_nb_participants = str(df['nb_participant'].values[n]).strip()

            local_status, new_participants = mycommon.IsInt(local_nb_participants)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'nb_participant' de la ligne " + str(
                        n + 2) + " est incorrecte.")
                return False, " Le champ nb_participant de la ligne " + str(n + 2) + " est incorrecte. Un nombre Entier Positif doit être fourni "

            mydata['nb_participant'] = str(new_participants)

            prix_session = "0"
            if ("prix_session" in df.keys()):
                if (str(df['prix_session'].values[n])):
                    prix_session = str(df['prix_session'].values[n]).strip()

            local_status, new_prix_session = mycommon.IsFloat(prix_session)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'prix_session' de la ligne " + str(
                        n + 2) + " est incorrecte.")
                return False, " Le champ prix_session de la ligne " + str(n + 2) + " est incorrecte. "

            mydata['prix_session'] = str(new_prix_session)

            local_code_session = ""
            if ("code_session" in df.keys()):
                if (str(df['code_session'].values[n])):
                    local_code_session = str(df['code_session'].values[n]).strip()

            if (len(str(local_code_session).strip()) < 2):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'code_session' de la ligne " + str(
                        n + 2) + " doit faire plus de deux caractères.")
                return False, " Le champ code_session de la ligne " + str(
                    n + 2) + " doit faire plus de deux caractères. "

            mydata['code_session'] = local_code_session

            local_adresse = ""
            if ("adresse" in df.keys()):
                if (str(df['adresse'].values[n])):
                    local_adresse = str(df['adresse'].values[n]).strip()
            mydata['adresse'] = local_adresse


            session_ondemande = "0"
            if ("session_ondemande" in df.keys()):
                if (str(df['session_ondemande'].values[n])):
                    session_ondemande = str(df['session_ondemande'].values[n]).strip()
                    session_ondemande = str(mycommon.tryInt(str(session_ondemande)))

                    if (session_ondemande != "1" and session_ondemande != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'session_ondemande' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'session_ondemande' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"

            mydata['session_ondemande'] = session_ondemande

            local_code_postal = ""
            if ("code_postal" in df.keys()):
                if (str(df['code_postal'].values[n])):
                    local_code_postal = str(df['code_postal'].values[n]).strip()

                    if ("." in str(local_code_postal)):
                        # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                        local_code_postal = str(local_code_postal).split(".")[0]
                    elif ("." in str(local_code_postal)):
                        # /!\ : l'utilisateur envoie un code poster au format entier, plutot que string.
                        local_code_postal = str(local_code_postal).split(",")[0]
                    else:
                        local_code_postal = str(local_code_postal)


            mydata['code_postal'] = local_code_postal

            distanciel = ""
            if ("distanciel" in df.keys()):
                if (str(df['distanciel'].values[n])):
                    distanciel = str(df['distanciel'].values[n]).strip()
                    distanciel = str(mycommon.tryInt(distanciel))

                    if (distanciel != "1" and distanciel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'distanciel' de la ligne " + str(
                                n + 2) + " est incorrecte. La valeur fournie est "+str(distanciel) )
                        return False, " Le champ 'distanciel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0'. La valeur fournie est "+str(distanciel)

            mydata['distantiel'] = distanciel

            presentiel = ""
            if ("presentiel" in df.keys()):
                if (str(df['presentiel'].values[n])):
                    presentiel = str(df['presentiel'].values[n]).strip()
                    presentiel = str(mycommon.tryInt(presentiel))

                    if (presentiel != "1" and presentiel != "0"):
                        mycommon.myprint(
                            str(inspect.stack()[0][3]) + " Le champ 'presentiel' de la ligne " + str(
                                n + 2) + " est incorrecte.")
                        return False, " Le champ 'presentiel' de la ligne " + str(
                            n + 2) + " est incorrecte. Les valeurs acceptées sont '1' ou '0' ou vide"

            mydata['presentiel'] = presentiel

            # mydata['code_postal'] = str(df['code_postal'].values[n]).strip()

            local_ville = ""
            if ("ville" in df.keys()):
                if (str(df['ville'].values[n])):
                    local_ville = str(df['ville'].values[n]).strip()
            mydata['ville'] = local_ville

            local_pays = ""
            if ("pays" in df.keys()):
                if (str(df['pays'].values[n])):
                    local_pays = str(df['pays'].values[n]).strip()
            mydata['pays'] = local_pays

            contenu_ftion = ""
            if ("contenu_ftion" in df.keys()):
                if (str(df['contenu_ftion'].values[n])):
                    contenu_ftion = str(df['contenu_ftion'].values[n]).strip()
            mydata['contenu_ftion'] = contenu_ftion

            # mydata['ville'] = str(df['ville'].values[n]).strip()

            local_attestation_certif = ""
            if ("attestation" in df.keys()):
                if (str(df['attestation'].values[n])):
                    local_attestation_certif = str(df['attestation'].values[n]).strip()
            mydata['attestation_certif'] = local_attestation_certif

            # mydata['attestation_certif'] = str(df['attestation'].values[n]).strip()


            session_status = ""
            if ("session_status" in df.keys()):
                if (str(df['session_status'].values[n])):
                    session_status = str(df['session_status'].values[n]).strip()
            mydata['session_status'] = session_status

            session_etape = ""
            if ("session_etape" in df.keys()):
                if (str(df['session_etape'].values[n])):
                    session_etape = str(df['session_etape'].values[n]).strip()
            mydata['session_etape'] = session_etape

            """ 
            Update du 11/08/23 :
            - le status va etre geré en 0 (desactivé) et 1 (activé)
            - mise en commentaire du code ci-dessous

            local_session = str(df['session_status'].values[n]).strip()

            if( str(local_session) != "0" and  str(local_session) != "1" and  str(local_session) != "2"):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2")
                return False, " Le champ 'session_status' de la ligne " + str(n+2) + " est incorrecte. Les valeurs acceptées sont 0,1,2"

            if( str(local_session) == "1"):
                mydata['session_status'] = str("true")
            """

            mydata['date_debut_inscription'] = str(df['date_debut_inscription'].values[n]).strip().split(" ")[0]
            local_status = mycommon.CheckisDate(mydata['date_debut_inscription'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La  date_debut_inscription n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 2) + ". La date_debut_inscription n'est pas au format jj/mm/aaaa "

            mydata['date_fin_inscription'] = str(df['date_fin_inscription'].values[n]).strip().split(" ")[0]

            local_status = mycommon.CheckisDate(mydata['date_fin_inscription'])
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                        n + 2) + "."
                                 "La date_fin_inscription n'est pas au format jj/mm/aaaa ")

                return False, " - Impossible de créer/mettre à jour la session de formation à ligne " + str(
                    n + 1) + ". La date_fin_inscription n'est pas au format jj/mm/aaaa "

            ## Verification de la cohérence des dates. Date_du doit <= Date_au
            if (datetime.strptime(str(mydata['date_debut_inscription']).strip(), '%d/%m/%Y') > datetime.strptime(
                    str(mydata['date_fin_inscription']).strip(), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Impossible de créer la session de formation : La date debut des inscriptions " + str(
                        mydata['date_debut_inscription']) +
                    " est postérieure à la date de fin des inscriptions " + str(
                        mydata['date_fin_inscription']) + " pour la ligne  " + str(n + 2) + " ")

                return False, " Impossible de créer la session de formation : La date de fin des inscriptions est antérieure à la date de début des inscriptions : Ligne  " + str(
                    n + 2) + " "

            mydata['token'] = str(my_token)

            # print(" ### mydata ", mydata)

            diction_for_session_id = {}
            diction_for_session_id['date_du'] = str(mydata['date_debut']).split(" ")[0]
            diction_for_session_id['date_au'] = str(mydata['date_fin']).split(" ")[0]
            diction_for_session_id['code_postal'] = str(mydata['code_postal'])
            diction_for_session_id['adresse'] = str(mydata['adresse'])


        return True, str(total_rows)+" sessions dans le fichier"


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de controler le fichier des sessions de formation  en masse "


"""
Cette fonction supprime une session de formation.
/!\ : il faut s'assurer qu'il n'y a aucune inscription avant de supprimer valide.
Et la session est supprimé, alors supprimer toutes inscriptions (annulée) associés
Ensuite supprimer les affectations d'enseignants et de materiels associée

12/01/2024 : 
- Supprimer les sequences de cette session
- Dealloué les agenda 
"""
def Delete_SessionFormation(diction):
    try:

        field_list = ['token',  'session_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é, Creation partenaire annulée")
                return False, "de récupérer la liste des stagiaires . Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token', 'session_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 liste ")
                return False, "Impossible de récupérer la liste des stagiaires, Toutes les informations necessaires n'ont pas été fournies"

        # Recuperation du recid du partner
        mydata = {}
        mytoken = ""
        if ("token" in diction.keys()):
            if diction['token']:
                mytoken = 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

        partner_recid = str(my_partner['recid'])
        session_id = ""
        if ("session_id" in diction.keys()):
            if diction['session_id']:
                session_id = diction['session_id']



        # Verifier qu'il n'y a pas d'incription valide
        inscription_count_qry = {'session_id':str(session_id), 'status':{'$in':['0', '1', '2']} , 'partner_owner_recid':str(partner_recid)}
        print(" ####  inscription_count_qry aa =", inscription_count_qry)
        inscription_count = MYSY_GV.dbname['inscription'].count_documents(inscription_count_qry)
        if( inscription_count > 0 ):
            mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de supprimer la session. Vous avez "+str(inscription_count)+" inscription(s) associée(s) ")
            return False, "Impossible de supprimer la session. Vous avez "+str(inscription_count)+" inscription(s) associée(s)"

        # Suppression des insciption eventuellement annulées
        MYSY_GV.dbname['inscription'].delete_many({'session_id':str(session_id)})

        # Suppression des affectation de ressources associées
        delete_affectation_qry = {'related_target_collection':'session_formation', 'related_target_collection_id':str(session_id),
                                  'partner_owner_recid': str(partner_recid)
                                  }

        # Pour les Ressource Humaine
        MYSY_GV.dbname['ressource_humaine_affectation'].delete_many(delete_affectation_qry)

        # Pour le materiel
        MYSY_GV.dbname['ressource_materielle_affectation'].delete_many(delete_affectation_qry)

        # 12/01/2024 : Supprimer les sequences
        for sequence in MYSY_GV.dbname['session_formation_sequence'].find({'session_id':str(diction['session_id']),
                                                                           'partner_owner_recid':str(my_partner['recid'])},
                                                                          {'_id':1}):
            local_status, local_retval = Session_Formation_Sequence.Delete_Given_Session_Sequence({'token':str(diction['token']), '_id':str(sequence['_id']) })
            if( local_status is False):
                mycommon.myprint(str(inspect.stack()[0][3]) + " WARNING : Impossible de supprimer la sequence_id "+str(sequence['_id']))



        # Suppression de la session
        deleted_session_qry = {'_id':ObjectId(str(session_id)), 'partner_owner_recid':str(partner_recid)}
        deleted_data = MYSY_GV.dbname['session_formation'].delete_many(deleted_session_qry)

        mycommon.myprint(str(inspect.stack()[0][3]) + str(deleted_data.deleted_count)+" Document supprimé. La session_id " + str(
            session_id) + " a été correctement supprimée ")


        return True, "La session a été correctement supprimée"

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de supprimer la session de formation"


"""
Cette fonction prends une liste '_id' de session et effectue la suppresion
si les conditions sont remplie.

list_session_id = ['id1', 'id2', 'id3,]
"""
def Delete_List_SessionFormation(diction):
    try:

        field_list = ['token',  'list_session_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é, Creation partenaire annulée")
                return False, "de récupérer la liste des stagiaires . Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token', 'list_session_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 liste ")
                return False, "Impossible de récupérer la liste des stagiaires, Toutes les informations necessaires n'ont pas été fournies"

        # Recuperation du recid du partner
        mydata = {}
        mytoken = ""
        if ("token" in diction.keys()):
            if diction['token']:
                mytoken = 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

        partner_recid = my_partner['recid']

        list_session_id = []
        if ("list_session_id" in diction.keys()):
            if diction['list_session_id']:
                list_session_id = str(diction['list_session_id']).replace(",", ";").split(";")



        # Verifier qu'il n'y a pas d'incription valide
        for session_id in list_session_id :
            inscription_count_qry = {'session_id':str(session_id), 'status':{'$in':['0', '1', '2']} , 'partner_owner_recid':str(partner_recid)}
            #print(" ####  inscription_count_qry aa =", inscription_count_qry)
            inscription_count = MYSY_GV.dbname['inscription'].count_documents(inscription_count_qry)
            if( inscription_count > 0 ):
                session_formation_data = MYSY_GV.dbname['session_formation'].find_one({'_id':ObjectId(str(session_id)), 'partner_owner_recid':str(partner_recid)})
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de supprimer la session "+str(session_formation_data['code_session'])+". Vous avez "+str(inscription_count)+" inscriptions associées.Suppression en masse annulée ")
                return False, "Impossible de supprimer la session "+str(session_formation_data['code_session'])+". Vous avez "+str(inscription_count)+" inscriptions associées. Suppression en masse annulée"

        # Suppression des insciption eventuellement annulées
        MYSY_GV.dbname['inscription'].delete_many({'session_id':{'$in':list_session_id}})

        # Suppression des affectation de ressources associées
        delete_affectation_qry = {'related_target_collection':'session_formation', 'related_target_collection_id':{'$in':list_session_id},
                                  'partner_owner_recid': str(partner_recid)
                                  }

        # Pour les Ressource Humaine
        MYSY_GV.dbname['ressource_humaine_affectation'].delete_many(delete_affectation_qry)

        # Pour le materiel
        MYSY_GV.dbname['ressource_materielle_affectation'].delete_many(delete_affectation_qry)


        # Suppression des sessions
        cpt = 0
        for session_id in list_session_id:
            deleted_session_qry = {'_id':ObjectId(str(session_id)), 'partner_owner_recid':str(partner_recid)}
            deleted_data = MYSY_GV.dbname['session_formation'].delete_many(deleted_session_qry)

            mycommon.myprint(str(inspect.stack()[0][3]) + str(deleted_data.deleted_count)+" Document supprimé. La session_id " + str(
            session_id) + " a été correctement supprimée ")
            cpt = cpt + 1

        if( cpt > 1 ):
            return True, "("+str(cpt)+" sessions ont été correctement supprimées"
        else:
            return True, "La session a été correctement supprimée"


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de supprimer la liste des sessions de formation"


"""
Cette fonction verifier des données correspondent à une session : 
- internal_url
         - date_debut
         - date_fin
         - si presentiel : la ville
         - si distance, juste le a distance 

"""
def Is_Corresponding_SessionFormation(diction):
    try:

        field_list = ['token', 'class_url', 'date_debut','date_fin', 'distantiel', 'ville' ]
        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é, Creation partenaire annulée")
                return False, " Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token', 'class_url', 'date_debut','date_fin', 'distantiel', 'ville' ]
        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 liste ")
                return False, " Toutes les informations necessaires n'ont pas été fournies"

        # Recuperation du recid du partner
        mydata = {}
        mytoken = ""
        if ("token" in diction.keys()):
            if diction['token']:
                mytoken = diction['token']

        # Verifier la validité du token
        retval = mycommon.check_partner_token_validity("", mytoken)
        if retval is False:
            return "Err_Connexion", " La session de connexion n'est pas valide"

        partner_recid = mycommon.get_parnter_recid_from_token(mytoken)
        if (partner_recid is False):
            mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer la liste des stagiaires, ")
            return False, " Les informations d'identification sont incorrectes "


        class_url = ""
        if ("class_url" in diction.keys()):
            if diction['class_url']:
                class_url = diction['class_url']

        """
        Recuperation de l'internal url depuis l'url de la formation 
        """
        myclass_data = MYSY_GV.dbname['myclass'].find_one({'valide':"1", 'locked':'0',
                                                           'url':str(class_url)})


        if( myclass_data is None or "internal_url" not in myclass_data.keys()):
            mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer les données de la formation, ")
            return False, " Impossible de récupérer les données de la formation, "

        class_internal_url = str(myclass_data['internal_url'])

        coll_session = MYSY_GV.dbname['session_formation']

        myquery = [{'$match':{ 'class_internal_url':class_internal_url, 'partner_owner_recid':str(partner_recid)}},
            {'$lookup':
                {
                    'from': 'myclass',
                    'localField': 'class_internal_url',
                    'foreignField': 'internal_url',
                    'pipeline': [{'$project': {'title': 1, 'lms_class_code':1}}],
                    'as': 'myclass'
                }
            }
        ]

        print(" ##### myquery GetSessionFormation = "+str(myquery))
        RetObject = []

        nb_val = 0
        for retval in coll_session.aggregate(myquery):
            #print(" ##### Is_Corresponding_SessionFormation retval  a controle = " + str(retval))
            if (retval['distantiel'] == diction['distantiel'] and str(retval['date_debut'][0:10]) == diction[
                'date_debut']
                    and str(retval['date_fin'][0:10]) == diction['date_fin'] and retval['ville'] == diction['ville']):
                user = {}
                user = retval


                user['id'] = str(nb_val)
                nb_val = nb_val + 1
                title = ""
                lms_class_code = ""
                if ('myclass' in retval.keys() and len(retval['myclass']) > 0):

                    if( "title" in retval['myclass'][0].keys()):
                        title = retval['myclass'][0]['title']

                    if ("lms_class_code" in retval['myclass'][0].keys()):
                        lms_class_code = retval['myclass'][0]['lms_class_code']

                user['title'] = title
                user['lms_class_code'] = lms_class_code

                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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de verifier si la session correspond à une session existante"



"""
Cette fonction permet de dupliquer une session de formation.
par defaut lorqu'on duplique

- code_session = old_code_session+"_dup"

/!\ : Important : on prend une tab de session_id
"""

def Duplicate_List_Session_Formation(diction):
    try:

        field_list = ['token', 'tab_session_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é, Creation partenaire annulée")
                return False, " Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token', 'tab_session_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 liste ")
                return False, " Toutes les informations necessaires n'ont pas été fournies"

        # Recuperation du recid du partner
        mydata = {}
        mytoken = ""
        if ("token" in diction.keys()):
            if diction['token']:
                mytoken = diction['token']

        # Verifier la validité du token
        local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data({'token':mytoken})
        if (local_status is not True):
            return local_status, my_partner


        # Verification de la validité de toutes les session dans tab_session_id
        tab_session_id = str(diction['tab_session_id']).split(',')
        for session_id in tab_session_id :
            if( MYSY_GV.dbname['session_formation'].count_documents({'_id':ObjectId(str(session_id)),
                                                                     'valide':'1',
                                                                     'partner_owner_recid':str(my_partner['recid'])}) != 1):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " La session_id :"+str(session_id)+" n'est pas valide ")
                return False, " La session_id :"+str(session_id)+" n'est pas valide  "


        # Duplicata
        cpt = 0
        now = str(datetime.now())
        for session_id in tab_session_id:
            session_data = MYSY_GV.dbname['session_formation'].find_one({'_id':ObjectId(str(session_id)),
                                                                     'valide':'1',
                                                                     'partner_owner_recid':str(my_partner['recid'])})

            if( session_data is None):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " La session n'est pas valide ")
                return False, " La session n'est pas valide "



            duplicated_session = session_data
            del duplicated_session['_id']
            duplicated_session['code_session'] = str(session_data['code_session'])+"_dup"
            duplicated_session['date_update'] = now
            duplicated_session['update_by'] = str(my_partner['_id'])
            local_retval = MYSY_GV.dbname['session_formation'].insert_one(duplicated_session)

            """
                    # Ajout de l'evenement dans l'historique
                    """
            now = str(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
            history_event_dict = {}
            history_event_dict['token'] = diction['token']
            history_event_dict['related_collection'] = "session_formation"
            history_event_dict['related_collection_recid'] = str(local_retval.inserted_id)
            history_event_dict['action_date'] = str(now)
            history_event_dict['action_description'] = "Creation (Dupliqué depuis "+str(duplicated_session['code_session'])+" "
            local_status, local_retval = mycommon.Collection_Historique.Add_Historique_Event(history_event_dict)
            if (local_status is False):
                mycommon.myprint(
                    " WARNING : Impossible de logguer l'historique pour l'évènement : " + str(history_event_dict))

            cpt = cpt + 1

        if(cpt > 1 ):
            return True, "("+str(cpt)+" sessions ont été correctement dupliquées "
        else:
            return True, "La session a été correctement dupliquée "

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de dupliquer la session de formation"


"""
Cette fonction les convention par email de formation en partant de la session.

Algo :

On recuperer les stagaiaires qu'on groupe par client_rattachement_id 
Pour tous ceux qui on le meme, on envoie une convention groupée

pour les autres, on envoi des conventions individuelle
 
"""
def Prepare_and_Send_Convention_From_Session_By_Email(tab_files, Folder, diction):
    try:

        field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'email_test', 'email_production']

        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 liste ")
                return False, "  La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_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 que la session est valide
        is_session_valide = 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 != 1):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant de la session  est invalide ")
            return False, "  L'identifiant de la session  est invalide  "


        # Verifier qu'il ya bien des inscriptions valides dans la session pour le client
        liste_client_rattachement_id = MYSY_GV.dbname['inscription'].distinct("client_rattachement_id",
                                                                              {'session_id':str(diction['session_id']),
                                                                               'status': '1',
                                                                               'partner_owner_recid': str(
                                                                                   my_partner['recid']),
                                                                                  "client_rattachement_id": { '$ne': ''}
                                                                              }
                                                                              )


        print(" ### la liste des liste_client_rattachement_id = ", liste_client_rattachement_id)


        # Sauvegarde des fichiers joints depuis le front
        tab_saved_file_full_path = []
        for file in tab_files:
            status, saved_file_full_path = mycommon.Upload_Save_PDF_IMG_File(file, Folder)
            if (status is False):
                mycommon.myprint("Impossible de récupérer correctement le fichier à importer")
                return False, "Impossible de récupérer correctement le fichier à importer"

            tab_saved_file_full_path.append(saved_file_full_path)

        print(" #### tab_saved_file_full_path = ", tab_saved_file_full_path)

        # Recupération des données du modèle de document
        is_convention_by_client = "0"
        courrier_template_data = MYSY_GV.dbname['courrier_template'].find_one(
            {'_id': ObjectId(str(diction['courrier_template_id'])),
             'valide': '1',
             'locked': '0',
             'partner_owner_recid': str(my_partner['recid'])}
        )

        if( courrier_template_data and "edit_by_client" in  courrier_template_data.keys() and courrier_template_data['edit_by_client'] == "1"):
            is_convention_by_client = "1"

        if( str(is_convention_by_client) == "1" ):
            # Envoie des conventions pour les inscrits AVEC client_id  (conventions d'entreprise)
            for single_client in liste_client_rattachement_id :
                print(" Traintement du client_id = ", single_client)

                # Recuperation des contacts de communication du client
                local_diction = {}
                local_diction['token'] = diction['token']
                local_diction['_id'] = str(single_client)

                print(" ##### local_diction = ", local_diction)
                local_status, partner_client_contact_communication = partner_client.Get_Partner_Client_Communication_Contact(local_diction)


                if (local_status is False):
                    mycommon.myprint(" Impossible de récupérer les contacts de communication du client ")
                    return False, " Impossible de récupérer les contacts de communication du client "

                print("  ### partner_client_contact_communication = ", partner_client_contact_communication)
                tab_local_email_production = []
                for tmp in partner_client_contact_communication:
                    tmp_JSON = ast.literal_eval(tmp)
                    if ("email" in tmp_JSON.keys()):
                        tab_local_email_production.append(str(tmp_JSON["email"]))

                list_local_email_production = ",".join(tab_local_email_production)

                new_diction_client = {}
                new_diction_client['partner_client_id'] = single_client
                new_diction_client['token'] = diction['token']
                new_diction_client['courrier_template_id'] = diction['courrier_template_id']
                new_diction_client['email_test'] = diction['email_test']
                new_diction_client['email_production'] = str(list_local_email_production)
                new_diction_client['session_id'] = diction['session_id']

                print(" ##### new_diction_client = ", new_diction_client)
                print(" ##### tab_files = ", tab_files)
                local_status, local_retval = Inscription_mgt.Sent_Convention_Stagiaire_By_Email_By_Partner_client(tab_saved_file_full_path, Folder, new_diction_client)

                if( local_status is False):
                    mycommon.myprint("  WARNING : impossible d'envoyer la convention au client :  "+str( single_client))

        elif (str(is_convention_by_client) == "0"):
            liste_inscription_no_client = MYSY_GV.dbname['inscription'].find(
                {"$or": [{'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          "client_rattachement_id": ''
                          },
                         {'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          'client_rattachement_id': {'$exists': False}
                          }]
                 }
                )
            # Envoie des conventions pour les inscrits SANS client_id (conventions individuelles)
            print(" ### is_convention_by_client ==== 0 : ")
            print(" ### LIST traitement de l'inscrit : ", liste_inscription_no_client)


            for single_inscrit_no_client in liste_inscription_no_client :
                print(" ### traitement de l'inscrit : ",single_inscrit_no_client )
                #field_list_obligatoire = [ 'token', 'inscription_id', 'courrier_template_id', 'email_test', 'email_production' ]
                new_diction_no_client = {}
                new_diction_no_client['token'] = str(diction['token'])
                new_diction_no_client['inscription_id'] = str(single_inscrit_no_client['_id'])
                new_diction_no_client['courrier_template_id'] = diction['courrier_template_id']

                new_diction_no_client['session_id'] = diction['session_id']
                new_diction_no_client['email_test'] = diction['email_test']
                new_diction_no_client['email_production'] = diction['email_production']

                print(" ##### new_diction_no_client = ", new_diction_no_client)
                local_status, local_retval = Inscription_mgt.Sent_Convention_Stagiaire_By_Email(tab_saved_file_full_path, Folder, new_diction_no_client)

                if (local_status is False):
                    mycommon.myprint("  WARNING impossible d'envoyer la convention a l'apprenant :  " + str(single_inscrit_no_client['_id']) )

        else:
            return False, " Vous devez definir si la convention est individuelle ou par client"

        # Traitement de l'eventuel fichier joint
        tab_files_to_attache_to_mail = []


        return True, " Les conventions ont été correctement envoyées par emails"

    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'envoyer les conventions par email "



"""
Cette fonction envoie les convention cochées par 'default'.
La fonction va envoyer les convention par defaut pour les inscrit rattachés à une societé et ceux rattaché à une societe.

Regle de gestion des adresse email :
Si le champ 'email_test' est rempli, alors il prend le pas sur la recherche des emails par defaut. Cela signifie que le
client veux faire un test.

"""
def Prepare_and_Send_Default_Convention_From_Session_By_Email(tab_files, Folder, diction):
    try:

        field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'email_test', 'email_production']

        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 liste ")
                return False, "  La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_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_test_mode = "0"
        email_test = ""
        if( "email_test" in diction.keys() and diction['email_test']):
            email_test = diction['email_test']
            if( mycommon.isEmailValide(email_test) is False ):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " L'adresse email du test est invalide  ")
                return False, " L'adresse email du test est invalide "

            is_test_mode =  "1"



        # Verifier que la session est valide
        is_session_valide = 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 != 1):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant de la session  est invalide ")
            return False, "  L'identifiant de la session  est invalide  "


        # Verifier qu'il ya bien des inscriptions valides dans la session pour le client
        liste_client_rattachement_id = MYSY_GV.dbname['inscription'].distinct("client_rattachement_id",
                                                                              {'session_id':str(diction['session_id']),
                                                                               'status': '1',
                                                                               'partner_owner_recid': str(
                                                                                   my_partner['recid']),
                                                                                  "client_rattachement_id": { '$ne': ''}
                                                                              }
                                                                              )


        # Sauvegarde des fichiers joints depuis le front
        tab_saved_file_full_path = []
        for file in tab_files:
            status, saved_file_full_path = mycommon.Upload_Save_PDF_IMG_File(file, Folder)
            if (status is False):
                mycommon.myprint("Impossible de récupérer correctement le fichier à importer")
                return False, "Impossible de récupérer correctement le fichier à importer"

            tab_saved_file_full_path.append(saved_file_full_path)

        """
        On verifie s'il y a des convention d'entreprise à faire, si oui on verifie si il y a un document 
        qui a été configuré
        """

        if (len(liste_client_rattachement_id) > 0):
            """ 
            # Recupération de la convention d'entreprise par defaut de à envoyer par email :
            - ref_interne = "CONVENTION_STAGIAIRE"
            - default_version = "1"
            - edit_by_client = "1"
            - type_doc = "email"
            """

            default_courrier_template_client_count = MYSY_GV.dbname['courrier_template'].count_documents(
                {'valide': '1',
                 'locked': '0',
                 'ref_interne': 'CONVENTION_STAGIAIRE',
                 'default_version': '1',
                 'edit_by_client': '1',
                 'type_doc': 'email',
                 'partner_owner_recid': str(my_partner['recid'])}
            )

            if( default_courrier_template_client_count <= 0 ):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Aucune convention d'entreprise n'est configurée ")
                return False, " Aucune convention d'entreprise n'est configurée  "

            if (default_courrier_template_client_count > 1):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Il y a " + str(
                        default_courrier_template_client_count) + " conventions d'entreprise configurées. Il ne doit y avoir qu'une seule ")
                return False, " Il y a " + str(
                    default_courrier_template_client_count) + " conventions d'entreprise configurées. Il ne doit y avoir qu'une seule "

        nb_liste_inscription_no_client = MYSY_GV.dbname['inscription'].count_documents(
            {"$or": [{'session_id': str(diction['session_id']),
                      'status': '1',
                      'partner_owner_recid': str(my_partner['recid']),
                      "client_rattachement_id": ''
                      },
                     {'session_id': str(diction['session_id']),
                      'status': '1',
                      'partner_owner_recid': str(my_partner['recid']),
                      'client_rattachement_id': {'$exists': False}
                      }]
             }
        )

        """
        On verifie s'il y a des conventions individuelles à faire, si oui on verifie si il y a un document 
        qui a été configuré
        """

        if (nb_liste_inscription_no_client > 0):
            """ 
            # Recupération de la convention individuelle par defaut de à envoyer par email :
            - ref_interne = "CONVENTION_STAGIAIRE"
            - default_version = "1"
            - edit_by_client = "0"
            - type_doc = "email"
            """



            default_courrier_template_individuel_count = MYSY_GV.dbname['courrier_template'].count_documents(
                {"$or": [{'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': '0',
                          'type_doc': 'email',
                          'partner_owner_recid': str(my_partner['recid'])}
                    ,
                         {'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': {'$exists': False},
                          'type_doc': 'email',
                          'partner_owner_recid': str(my_partner['recid'])}

                         ]
                 }
            )

            if (default_courrier_template_individuel_count <= 0):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Aucune convention individuelle n'est configurée ")
                return False, " Aucune convention d'individuelle n'est configurée  "


            if (default_courrier_template_individuel_count > 1):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Il y a "+str(default_courrier_template_individuel_count)+" conventions individuelles par défaut configurées. Il ne doit y avoir qu'une seule ")
                return False, " Il y a "+str(default_courrier_template_individuel_count)+" conventions individuelles par défaut configurées. Il ne doit y avoir qu'une seule "



        # Envoi des conventions d'entreprise par default
        if( len(liste_client_rattachement_id) > 0 ):
            # Il y a bien de inscris rattachés à des client. on cherche et envoie les conventions d'entreprises)

            # Recuperer les datas de la convention par defautl
            default_courrier_template_client_data = MYSY_GV.dbname['courrier_template'].find_one(
                {'valide': '1',
                 'locked': '0',
                 'ref_interne': 'CONVENTION_STAGIAIRE',
                 'default_version': '1',
                 'edit_by_client': '1',
                 'type_doc': 'email',
                 'partner_owner_recid': str(my_partner['recid'])}
            )

            for single_client in liste_client_rattachement_id :

                # Recuperation des contacts de communication du client
                local_diction = {}
                local_diction['token'] = diction['token']
                local_diction['_id'] = str(single_client)

                print(" ## Traitement du client  id: ", str(single_client))
                local_status, partner_client_contact_communication = partner_client.Get_Partner_Client_Communication_Contact(local_diction)


                if (local_status is False):
                    mycommon.myprint(" Impossible de récupérer les contacts de communication du client ")
                    return False, " Impossible de récupérer les contacts de communication du client "


                tab_local_email_production = []
                for tmp in partner_client_contact_communication:
                    tmp_JSON = ast.literal_eval(tmp)
                    if ("email" in tmp_JSON.keys()):
                        tab_local_email_production.append(str(tmp_JSON["email"]))

                list_local_email_production = ",".join(tab_local_email_production)

                new_diction_client = {}
                new_diction_client['partner_client_id'] = single_client
                new_diction_client['token'] = diction['token']
                new_diction_client['courrier_template_id'] = default_courrier_template_client_data['_id']

                if( is_test_mode == "1"):
                    new_diction_client['email_test'] = email_test
                    new_diction_client['email_production'] = ""
                else:
                    new_diction_client['email_test'] = ""
                    new_diction_client['email_production'] = str(list_local_email_production)

                new_diction_client['session_id'] = diction['session_id']


                local_status, local_retval = Inscription_mgt.Sent_Convention_Stagiaire_By_Email_By_Partner_client(tab_saved_file_full_path, Folder, new_diction_client)

                if( local_status is False):
                    mycommon.myprint("  WARNING : impossible d'envoyer la convention au client :  "+str( single_client))


        # Envoi des conventions individuelles par defaut
        if (nb_liste_inscription_no_client > 0):
            liste_inscription_no_client = MYSY_GV.dbname['inscription'].find(
                {"$or": [{'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          "client_rattachement_id": ''
                          },
                         {'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          'client_rattachement_id': {'$exists': False}
                          }]
                 }
                )

            # Recuperer les datas de la convention par defautl
            default_courrier_template_individuel_data = MYSY_GV.dbname['courrier_template'].find_one(
                {"$or": [{'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': '0',
                          'type_doc': 'email',
                          'partner_owner_recid': str(my_partner['recid'])}
                    ,
                         {'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': {'$exists': False},
                          'type_doc': 'email',
                          'partner_owner_recid': str(my_partner['recid'])}

                         ]
                 }
            )

            # Envoie des conventions pour les inscrits SANS client_id (conventions individuelles)
            print(" ### is_convention_by_client ==== 0 : ")
            print(" ### LIST traitement de l'inscrit : ", liste_inscription_no_client)


            for single_inscrit_no_client in liste_inscription_no_client :
                print(" ### traitement de l'inscrit : ",single_inscrit_no_client )
                #field_list_obligatoire = [ 'token', 'inscription_id', 'courrier_template_id', 'email_test', 'email_production' ]
                new_diction_no_client = {}
                new_diction_no_client['token'] = str(diction['token'])
                new_diction_no_client['inscription_id'] = str(single_inscrit_no_client['_id'])
                new_diction_no_client['courrier_template_id'] = default_courrier_template_individuel_data['_id']

                new_diction_no_client['session_id'] = diction['session_id']
                if (is_test_mode == "1"):
                    new_diction_no_client['email_test'] = email_test
                    new_diction_no_client['email_production'] = ""
                else:
                    new_diction_no_client['email_test'] = ""
                    new_diction_no_client['email_production'] = ""

                print(" ##### new_diction_no_client = ", new_diction_no_client)
                local_status, local_retval = Inscription_mgt.Sent_Convention_Stagiaire_By_Email(tab_saved_file_full_path, Folder, new_diction_no_client)

                if (local_status is False):
                    mycommon.myprint("  WARNING impossible d'envoyer la convention a l'apprenant :  " + str(single_inscrit_no_client['_id']) )

        else:
            return False, " Vous devez definir si la convention est individuelle ou par client"

        # Traitement de l'eventuel fichier joint
        tab_files_to_attache_to_mail = []


        return True, " Les conventions ont été correctement envoyées par emails"

    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'envoyer les conventions par email "




"""
Cette fonction permet de telecharger PDF toutes les conventions d'une session.
Depuis la session, l'utilisateur choisi le modele PDF et
telecharge les conventions d'entreprise et les conventions individuelles.

On créé un fichier zip qui sera téléchargé avec toutes les pièces jointes

"""
def Prepare_and_Send_Convention_From_Session_By_PDF(diction):
    try:
        field_list_obligatoire = ['token', 'session_id', 'courrier_template_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 liste ")
                return False, "  La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_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 que la session est valide
        is_session_valide = 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 != 1):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant de la session  est invalide ")
            return False, "  L'identifiant de la session  est invalide  "

        # Stokage des nom de fichier à zipper
        list_file_name_to_zip = []

        # Verifier qu'il ya bien des inscriptions valides dans la session pour le client
        liste_client_rattachement_id = MYSY_GV.dbname['inscription'].distinct("client_rattachement_id",
                                                                              {'session_id':str(diction['session_id']),
                                                                               'status': '1',
                                                                               'partner_owner_recid': str(
                                                                                   my_partner['recid']),
                                                                                  "client_rattachement_id": { '$ne': ''}
                                                                              }
                                                                              )

        print(" ### la liste des liste_client_rattachement_id = ", liste_client_rattachement_id)

        # Recuperer inscriptions indépenantes, donc pas liée à un client


        liste_inscription_no_client = MYSY_GV.dbname['inscription'].find({"$or": [{'session_id': str(diction['session_id']),
                                                                                  'status': '1',
                                                                                  'partner_owner_recid': str(my_partner['recid']),
                                                                                  "client_rattachement_id": ''
                                                                                  },
                                                                                 {'session_id': str(diction['session_id']),
                                                                                  'status': '1',
                                                                                  'partner_owner_recid': str(my_partner['recid']),
                                                                                  'client_rattachement_id': {'$exists': False}
                                                                                  }]
                                                                         }
                                                                         )

        """
        for val in liste_inscription_no_client:
            print(" ### la liste des liste_inscription_no_client = ", str(val))
        """



        # Recupération des données du modèle de document
        is_convention_by_client = "0"
        courrier_template_data = MYSY_GV.dbname['courrier_template'].find_one(
            {'_id': ObjectId(str(diction['courrier_template_id'])),
             'valide': '1',
             'locked': '0',
             'partner_owner_recid': str(my_partner['recid'])}
        )

        if (courrier_template_data and "edit_by_client" in courrier_template_data.keys() and courrier_template_data[
            'edit_by_client'] == "1"):
            is_convention_by_client = "1"

        if (str(is_convention_by_client) == "1"):
            # Envoie des conventions pour les inscrits AVEC client_id
            for val in liste_client_rattachement_id:
                local_diction = {}
                # field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'client_id']
                local_diction['token'] = diction['token']
                local_diction['session_id'] = diction['session_id']
                local_diction['courrier_template_id'] = diction['courrier_template_id']
                local_diction['client_id'] = str(val)

                print(" #### Traitemnt de local_diction aaa = ", local_diction)
                local_status, local_full_file_name = Create_Convention_By_Client_PDF(local_diction)
                if( local_status is False):
                    return local_status, local_full_file_name
                else:
                    print(" ###  pdf_file_name = ", local_full_file_name)
                    list_file_name_to_zip.append(str(local_full_file_name))




        elif (str(is_convention_by_client) == "0"):
            liste_inscription_no_client = MYSY_GV.dbname['inscription'].find(
                {"$or": [{'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          "client_rattachement_id": ''
                          },
                         {'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          'client_rattachement_id': {'$exists': False}
                          }]
                 }
                )
            for val in liste_inscription_no_client:
                local_diction = {}
                # field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'client_id']
                local_diction['token'] = diction['token']
                local_diction['session_id'] = diction['session_id']
                local_diction['courrier_template_id'] = diction['courrier_template_id']
                local_diction['inscription_id'] = str(val['_id'])

                #print(" #### Traitemnt de local_diction bb = ", local_diction)
                local_status, local_full_file_name = Create_Convention_By_Stagiaire_PDF(local_diction)
                if( local_status is False):
                    return local_status, local_full_file_name
                else:
                    list_file_name_to_zip.append(str(local_full_file_name))


        # Create a ZipFile Object
        todays_date = str(date.today().strftime("%d/%m/%Y"))
        ts = datetime.now().timestamp()
        ts = str(ts).replace(".", "").replace(",", "")[-3:]
        zip_file_name = str(MYSY_GV.TEMPORARY_DIRECTORY_V2)+"List_Convention_session_"+str(diction['session_id'])+"_"+str(ts)+".zip"

        with ZipFile(zip_file_name, 'w') as zip_object:
            for pdf_files in list_file_name_to_zip :
                #print(" ### fichier a zipper = ", pdf_files)
                zip_object.write(str(pdf_files))


        if os.path.exists(zip_file_name):
            # print(" ### ok os.path.exists(outputFilename) "+str(outputFilename))
            return True, send_file(zip_file_name, as_attachment=True)

        return False, " Impossible de générer les conventions par pdf PDF (1) "



    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 générer les conventions par pdf PDF  "



"""
Cette fonction permet de telecharge les conventions par defaut pour les entreprises et les individuels
"""
def Prepare_and_Send_Default_Convention_From_Session_By_PDF(diction):
    try:
        field_list_obligatoire = ['token', 'session_id', 'courrier_template_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 liste ")
                return False, "  La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_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 que la session est valide
        is_session_valide = 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 != 1):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant de la session  est invalide ")
            return False, "  L'identifiant de la session  est invalide  "

        # Verifier qu'il ya bien des inscriptions valides dans la session pour le client
        liste_client_rattachement_id = MYSY_GV.dbname['inscription'].distinct("client_rattachement_id",
                                                                              {'session_id': str(
                                                                                  diction['session_id']),
                                                                               'status': '1',
                                                                               'partner_owner_recid': str(
                                                                                   my_partner['recid']),
                                                                               "client_rattachement_id": {'$ne': ''}
                                                                               }
                                                                              )



        # --------
        """
                On verifie s'il y a des convention d'entreprise à faire, si oui on verifie si il y a un document 
                qui a été configuré
                """

        if (len(liste_client_rattachement_id) > 0):
            """ 
            # Recupération de la convention d'entreprise par defaut de à envoyer par email :
            - ref_interne = "CONVENTION_STAGIAIRE"
            - default_version = "1"
            - edit_by_client = "1"
            - type_doc = "pdf"
            """

            default_courrier_template_client_count = MYSY_GV.dbname['courrier_template'].count_documents(
                {'valide': '1',
                 'locked': '0',
                 'ref_interne': 'CONVENTION_STAGIAIRE',
                 'default_version': '1',
                 'edit_by_client': '1',
                 'type_doc': 'pdf',
                 'partner_owner_recid': str(my_partner['recid'])}
            )

            if (default_courrier_template_client_count <= 0):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Aucune convention d'entreprise n'est configurée ")
                return False, " Aucune convention d'entreprise n'est configurée  "

            if (default_courrier_template_client_count > 1):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Il y a " + str(
                        default_courrier_template_client_count) + " conventions d'entreprise par défaut  configurées. Il ne doit y avoir qu'une seule ")
                return False, " Il y a " + str(
                    default_courrier_template_client_count) + " conventions d'entreprise par défaut  configurées. Il ne doit y avoir qu'une seule "

        nb_liste_inscription_no_client = MYSY_GV.dbname['inscription'].count_documents(
            {"$or": [{'session_id': str(diction['session_id']),
                      'status': '1',
                      'partner_owner_recid': str(my_partner['recid']),
                      "client_rattachement_id": ''
                      },
                     {'session_id': str(diction['session_id']),
                      'status': '1',
                      'partner_owner_recid': str(my_partner['recid']),
                      'client_rattachement_id': {'$exists': False}
                      }]
             }
        )

        """
        On verifie s'il y a des conventions individuelles à faire, si oui on verifie si il y a un document 
        qui a été configuré
        """

        if (nb_liste_inscription_no_client > 0):
            """ 
            # Recupération de la convention individuelle par defaut de à envoyer par email :
            - ref_interne = "CONVENTION_STAGIAIRE"
            - default_version = "1"
            - edit_by_client = "0"
            - type_doc = "pdf"
            """
            qry_indi = {"$or": [{'valide': '1',
                                 'locked': '0',
                                 'ref_interne': 'CONVENTION_STAGIAIRE',
                                 'default_version': '1',
                                 'edit_by_client': '0',
                                 'type_doc': 'pdf',
                                 'partner_owner_recid': str(my_partner['recid'])}
                ,
                                {'valide': '1',
                                 'locked': '0',
                                 'ref_interne': 'CONVENTION_STAGIAIRE',
                                 'default_version': '1',
                                 'edit_by_client': {'$exists': False},
                                 'type_doc': 'pdf',
                                 'partner_owner_recid': str(my_partner['recid'])}

                                ]
                        }

            print(" ### qry_indi = ", qry_indi)

            default_courrier_template_individuel_count = MYSY_GV.dbname['courrier_template'].count_documents(
                {"$or": [{'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': '0',
                          'type_doc': 'pdf',
                          'partner_owner_recid': str(my_partner['recid'])}
                    ,
                         {'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': {'$exists': False},
                          'type_doc': 'pdf',
                          'partner_owner_recid': str(my_partner['recid'])}

                         ]
                 }
            )

            if (default_courrier_template_individuel_count <= 0):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Aucune convention individuelle n'est configurée ")
                return False, " Aucune convention d'individuelle n'est configurée  "

            if (default_courrier_template_individuel_count > 1):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " Il y a " + str(
                        default_courrier_template_individuel_count) + " conventions individuelles configurées. Il ne doit y avoir qu'une seule ")
                return False, " Il y a " + str(
                    default_courrier_template_individuel_count) + " conventions individuelles configurées. Il ne doit y avoir qu'une seule "

        # -------------

        # Stokage des nom de fichier à zipper
        list_file_name_to_zip = []



        # Recuperer inscriptions indépenantes, donc pas liée à un client
        liste_inscription_no_client = MYSY_GV.dbname['inscription'].find(
            {"$or": [{'session_id': str(diction['session_id']),
                      'status': '1',
                      'partner_owner_recid': str(my_partner['recid']),
                      "client_rattachement_id": ''
                      },
                     {'session_id': str(diction['session_id']),
                      'status': '1',
                      'partner_owner_recid': str(my_partner['recid']),
                      'client_rattachement_id': {'$exists': False}
                      }]
             }
        )
        # Envoi des conventions d'entreprise par default
        if (len(liste_client_rattachement_id) > 0):

            # Recuperer les datas de la convention par defautl
            default_courrier_template_client_data = MYSY_GV.dbname['courrier_template'].find_one(
                {'valide': '1',
                 'locked': '0',
                 'ref_interne': 'CONVENTION_STAGIAIRE',
                 'default_version': '1',
                 'edit_by_client': '1',
                 'type_doc': 'pdf',
                 'partner_owner_recid': str(my_partner['recid'])}
            )


            for val in liste_client_rattachement_id:
                local_diction = {}
                # field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'client_id']
                local_diction['token'] = diction['token']
                local_diction['session_id'] = diction['session_id']
                local_diction['courrier_template_id'] = default_courrier_template_client_data['_id']
                local_diction['client_id'] = str(val)

                print(" #### Traitemnt de local_diction aaa = ", local_diction)
                local_status, local_full_file_name = Create_Convention_By_Client_PDF(local_diction)
                if( local_status is False):
                    return local_status, local_full_file_name
                else:
                    print(" ###  pdf_file_name = ", local_full_file_name)
                    list_file_name_to_zip.append(str(local_full_file_name))

                # Envoi des conventions individuelles par defaut

        # Envoi des conventions individuelles par defaut
        if (nb_liste_inscription_no_client > 0):
            liste_inscription_no_client = MYSY_GV.dbname['inscription'].find(
                {"$or": [{'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          "client_rattachement_id": ''
                          },
                         {'session_id': str(diction['session_id']),
                          'status': '1',
                          'partner_owner_recid': str(my_partner['recid']),
                          'client_rattachement_id': {'$exists': False}
                          }]
                 }
            )
            # Recuperer les datas de la convention par defautl
            default_courrier_template_individuel_data = MYSY_GV.dbname['courrier_template'].find_one(
                {"$or": [{'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': '0',
                          'type_doc': 'pdf',
                          'partner_owner_recid': str(my_partner['recid'])}
                    ,
                         {'valide': '1',
                          'locked': '0',
                          'ref_interne': 'CONVENTION_STAGIAIRE',
                          'default_version': '1',
                          'edit_by_client': {'$exists': False},
                          'type_doc': 'pdf',
                          'partner_owner_recid': str(my_partner['recid'])}

                         ]
                 }
            )

            for val in liste_inscription_no_client:
                local_diction = {}
                # field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'client_id']
                local_diction['token'] = diction['token']
                local_diction['session_id'] = diction['session_id']
                local_diction['courrier_template_id'] = default_courrier_template_individuel_data['_id']
                local_diction['inscription_id'] = str(val['_id'])

                #print(" #### Traitemnt de local_diction bb = ", local_diction)
                local_status, local_full_file_name = Create_Convention_By_Stagiaire_PDF(local_diction)
                if( local_status is False):
                    return local_status, local_full_file_name
                else:
                    list_file_name_to_zip.append(str(local_full_file_name))


        # Create a ZipFile Object
        todays_date = str(date.today().strftime("%d/%m/%Y"))
        ts = datetime.now().timestamp()
        ts = str(ts).replace(".", "").replace(",", "")[-3:]
        zip_file_name = str(MYSY_GV.TEMPORARY_DIRECTORY_V2)+"List_Convention_session_"+str(diction['session_id'])+"_"+str(ts)+".zip"

        with ZipFile(zip_file_name, 'w') as zip_object:
            for pdf_files in list_file_name_to_zip :
                #print(" ### fichier a zipper = ", pdf_files)
                zip_object.write(str(pdf_files))


        if os.path.exists(zip_file_name):
            # print(" ### ok os.path.exists(outputFilename) "+str(outputFilename))
            return True, send_file(zip_file_name, as_attachment=True)

        return False, " Impossible de générer les conventions par  PDF (1) "



    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 générer les conventions par pdf PDF  "




""" 
Cette fonction créer un PDF par client et retounr l'url complet du fichier pdf
pour les client (convention de type client)
"""

def Create_Convention_By_Client_PDF(diction):
    try:
        field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'client_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 liste ")
                return False, "  La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_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


        # 1 - Verifier que le modele de courrier est bien editable par client
        template_courrier_data = MYSY_GV.dbname['courrier_template'].find_one({'_id':ObjectId(str(diction['courrier_template_id'])),
                                                                               'valide':'1',
                                                                               'locked':'0',
                                                                               'partner_owner_recid':str(my_partner['recid'])})

        if( template_courrier_data is None or "edit_by_client" not in template_courrier_data.keys() or str(template_courrier_data['edit_by_client']) != "1" ):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  Le modèle de courrier n'est pas éditable par client ")
            return False, "  Le modèle de courrier n'est pas éditable par client  "

        # Verifier que le client est valide
        client_data = MYSY_GV.dbname['partner_client'].find_one({'_id':ObjectId(str(diction['client_id'])), 'valide':'1',
                                                                               'locked':'0',
                                                                               'partner_recid':str(my_partner['recid'])})

        if (client_data is None ):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant du client est invalide ")
            return False, "   L'identifiant du client est invalide   "

        tab_client = []
        tab_client.append(client_data['_id'])


        # Verifier que la session est valide
        session_data = MYSY_GV.dbname['session_formation'].find_one(
            {'_id': ObjectId(str(diction['session_id'])), 'valide': '1', 'partner_owner_recid': str(my_partner['recid'])})

        if (session_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant de la session  est invalide  ")
            return False, "  L'identifiant de la session  est invalide  "

        tab_session = []
        tab_session.append(session_data['_id'])

        # Recuperation du titre de la formation
        class_data = MYSY_GV.dbname['myclass'].find_one(
            {'internal_url': str(session_data['class_internal_url']), 'valide': '1',
             'partner_owner_recid': str(my_partner['recid']), 'locked': '0'})

        tab_class = []
        tab_class.append(class_data['_id'])

        # Recuperation des données du stagiaire
        inscription_data = MYSY_GV.dbname['inscription'].find({'session_id': str(diction['session_id']),
                                                               'status': '1',
                                                               'partner_owner_recid': str(my_partner['recid']),
                                                               'client_rattachement_id': str(
                                                                   diction['client_id'])})

        tab_participant = []
        for val in inscription_data:
            tab_participant.append(val['_id'])

        print(" ### tab_participant = ", tab_participant)
        # Creation du dictionnaire d'information à utiliser pour la creation du doc
        convention_dictionnary_data = {}
        new_diction = {}
        new_diction['token'] = diction['token']
        new_diction['list_stagiaire_id'] = tab_participant
        new_diction['list_session_id'] = tab_session
        new_diction['list_class_id'] = tab_class
        new_diction['list_client_id'] = tab_client

        local_status, local_retval = mycommon.Get_Dictionnary_data_For_Template(new_diction)

        if (local_status is False):
            return local_status, local_retval

        convention_dictionnary_data = local_retval

        body = {
            "params": convention_dictionnary_data,
        }

        """
         Creation du ficier PDF
        """
        contenu_doc_Template = jinja2.Template(str(template_courrier_data['contenu_doc']))


        sourceHtml = contenu_doc_Template.render(params=body["params"])

        todays_date = str(date.today().strftime("%d/%m/%Y"))
        ts = datetime.now().timestamp()
        ts = str(ts).replace(".", "").replace(",", "")[-5:]

        orig_file_name = "Convention_" + str(my_partner['recid']) + "_" + str(ts) + ".pdf"
        outputFilename = str(MYSY_GV.TEMPORARY_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, outputFilename

    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 créer le fichier pdf de convention client "


"""
Cette fonction créer un PDF par client et retounr l'url complet du fichier pdf pour les 
personnes sans rattachement client (convention indivisuelle)
"""
def Create_Convention_By_Stagiaire_PDF(diction):
    try:
        field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'inscription_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 liste ")
                return False, "  La valeur '" + val + "' n'est pas presente dans liste"

        my_token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                my_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


        # 1 - Verifier que le modele de courrier est bien editable par individu
        template_courrier_data = MYSY_GV.dbname['courrier_template'].find_one({'_id':ObjectId(str(diction['courrier_template_id'])),
                                                                               'valide':'1',
                                                                               'locked':'0',
                                                                               'ref_interne': 'CONVENTION_STAGIAIRE',
                                                                               'partner_owner_recid':str(my_partner['recid'])})

        if( template_courrier_data is None or ("edit_by_client" in template_courrier_data.keys() and str(template_courrier_data['edit_by_client']) == "1" ) ):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  Le modèle de courrier n'est pas éditable par stagiaire. ")
            return False, "  Le modèle de courrier n'est pas éditable par stagiaire  "

        # Verifier que le statgiaire est valide
        local_qry = {'_id':ObjectId(str(diction['inscription_id'])), 'status':'1',
                                                                               'partner_owner_recid':str(my_partner['recid'])}

        statgiaire_data = MYSY_GV.dbname['inscription'].find_one({'_id':ObjectId(str(diction['inscription_id'])), 'status':'1',
                                                                               'partner_owner_recid':str(my_partner['recid'])})

        if (statgiaire_data is None ):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant du stagiaire est invalide  ")
            return False, "   L'identifiant du stagiaire est invalide   "

        tab_stagiaire = []
        tab_stagiaire.append(statgiaire_data['_id'])


        # Verifier que la session est valide
        session_data = MYSY_GV.dbname['session_formation'].find_one(
            {'_id': ObjectId(str(diction['session_id'])), 'valide': '1', 'partner_owner_recid': str(my_partner['recid'])})

        if (session_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "  L'identifiant de la session  est invalide  ")
            return False, "  L'identifiant de la session  est invalide  "

        tab_session = []
        tab_session.append(session_data['_id'])

        # Recuperation du titre de la formation
        class_data = MYSY_GV.dbname['myclass'].find_one(
            {'internal_url': str(session_data['class_internal_url']), 'valide': '1',
             'partner_owner_recid': str(my_partner['recid']), 'locked': '0'})

        tab_class = []
        tab_class.append(class_data['_id'])



        # Creation du dictionnaire d'information à utiliser pour la creation du doc
        convention_dictionnary_data = {}
        new_diction = {}
        new_diction['token'] = diction['token']
        new_diction['list_stagiaire_id'] = tab_stagiaire
        new_diction['list_session_id'] = tab_session
        new_diction['list_class_id'] = tab_class
        new_diction['list_client_id'] = []

        local_status, local_retval = mycommon.Get_Dictionnary_data_For_Template(new_diction)

        if (local_status is False):
            return local_status, local_retval

        convention_dictionnary_data = local_retval

        body = {
            "params": convention_dictionnary_data,
        }

        """
         Creation du ficier PDF
        """
        contenu_doc_Template = jinja2.Template(str(template_courrier_data['contenu_doc']))

        sourceHtml = contenu_doc_Template.render(params=body["params"])

        todays_date = str(date.today().strftime("%d/%m/%Y"))
        ts = datetime.now().timestamp()
        ts = str(ts).replace(".", "").replace(",", "")[-5:]

        orig_file_name = "Convention_" + str(my_partner['recid']) + "_" + str(ts) + ".pdf"
        outputFilename = str(MYSY_GV.TEMPORARY_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, outputFilename

    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 créer le fichier pdf de convention par stagiaire "


