"""
Ce fichier permet de gerer les devis et les commandes d'un partenaires.
Pour précision, une commande a les status suivants :
- devis
- Commande
- Facturé
- Annulé

Une commande est defini par
order_header et order_lines comme suit :

order {order_header_ref:'xxx', order_header_amount:'yyyy',  order_line[ {order_line1}, {order_line2}, ....,{}] }
"""
import ast

import bson
import pymongo
from pymongo import MongoClient
import json
from bson import ObjectId
import re
from datetime import datetime, date, timedelta

import Contact
import E_Sign_Document
import Inscription_mgt
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
import ela_index_bdd_classes as eibdd
import email_mgt as email
import jinja2
from flask import send_file
from xhtml2pdf import pisa
from email.message import EmailMessage
from email.mime.text import MIMEText
from email import encoders
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

"""
Creation d'un commande client d'un partenaire
Order_type = 'commande'
"""
def Add_Partner_Order(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_client_id', 'order_header_description', 'order_header_comment', 'order_header_date_cmd', 'order_header_date_expiration',
                      'order_header_adr_fact_adresse', 'order_header_adr_fact_code_postal', 'order_header_adr_fact_ville','order_header_adr_fact_pays',
                      'order_header_adr_liv_adresse', 'order_header_adr_liv_code_postal', 'order_header_adr_liv_ville', 'order_header_adr_liv_pays',
                      'order_header_condition_paiement_id', 'order_header_ref_client', 'order_header_vendeur_id', 'order_header_email_client',
                      'order_header_ref_interne', 'order_header_total_ht', 'order_header_total_tax', 'order_header_total_ttc', 'order_header_status', 'order_header_type_reduction',
                      'order_header_type_reduction_valeur', 'order_header_montant_reduction', 'order_lines', 'order_header_type',
                      'order_header_location_type', 'order_header_origin', 'order_header_tax', 'order_header_tax_amount',
                      'total_header_hors_taxe_after_header_reduction', 'total_header_hors_taxe_before_header_reduction', 'total_header_toutes_taxes',
                      'total_lines_hors_taxe_after_lines_reduction', 'total_lines_hors_taxe_before_lines_reduction', 'total_lines_montant_reduction']

        """
        /!\ A noter que   "order_lines" est tableau [] qui peut contenir les keys suivantes : 'order_line_formation', 'order_line_qty', 'order_line_prix_unitaire', 'order_line_tax', 'order_line_type_reduction', 'order_line_type_valeur', 'order_line_montant_reduction'
        ainsi, order_lines sera du style  order_lines[ {order_line_formation:'xxx', order_line_qty:'2', etc },  {order_line_formation:'yyy', order_line_qty:'7', etc }, ....{}}
        
        """

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes", False

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', "order_header_client_id", "order_header_date_cmd"]

        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, " Les informations fournies sont incorrectes", False

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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


        # Recuperation des champs
        data = {}
        data['partner_owner_recid'] = my_partner['recid']

        data['order_header_type'] = "commande"


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



                # Verifier que le client existe bien pour ce partner
                is_client_exist_count = MYSY_GV.dbname['partner_client'].count_documents({'_id':ObjectId(str(order_header_client_id)), 'valide':'1',
                                                                                          'locked':'0', 'partner_recid':str(my_partner['recid'])})

                if( is_client_exist_count <= 0):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le client est invalide ")
                    return False, " - Le client est invalide  ", False
                data['order_header_client_id'] = diction['order_header_client_id']


        order_header_description = ""
        if ("order_header_description" in diction.keys()):
            if diction['order_header_description']:
                order_header_description = diction['order_header_description']
                if (len(str(order_header_description)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_description' fait plus de 500 caractères ")

                    return False, " - Le champ 'Description' fait plus de 500 caractères ", False
                data['order_header_description'] = diction['order_header_description']

        order_header_comment = ""
        if ("order_header_comment" in diction.keys()):
            if diction['order_header_comment']:
                order_header_comment = diction['order_header_comment']
                if (len(str(order_header_comment)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_comment' fait plus de 500 caractères ")

                    return False, " - Le champ 'Commentaire' fait plus de 500 caractères ", False
                data['order_header_comment'] = diction['order_header_comment']

        order_header_condition_paiement_id = ""
        if ("order_header_condition_paiement_id" in diction.keys()):
            if diction['order_header_condition_paiement_id']:
                order_header_condition_paiement_id = diction['order_header_condition_paiement_id']
                if (len(str(order_header_condition_paiement_id)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_condition_paiement' fait plus de 255 caractères ")

                    return False, " - Le champ 'Condition de paiement' fait plus de 255 caractères ", False
        data['order_header_condition_paiement_id'] = order_header_condition_paiement_id

        order_header_ref_interne = ""
        if ("order_header_ref_interne" in diction.keys()):
            if diction['order_header_ref_interne']:
                order_header_ref_interne = diction['order_header_ref_interne']
                if (len(str(order_header_ref_interne)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_ref_interne' fait plus de 255 caractères ")

                    return False, " - Le champ 'ref_interne' fait plus de 255 caractères ", False
        data['order_header_ref_interne'] = order_header_ref_interne


        order_header_email_client = ""
        if ("order_header_email_client" in diction.keys()):
            if diction['order_header_email_client']:
                order_header_email_client = diction['order_header_email_client']
                if (len(str(order_header_email_client)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_email_client' fait plus de 255 caractères ")

                    return False, " - Le champ 'email_client' fait plus de 255 caractères ", False

                if (mycommon.isEmailValide(order_header_email_client) is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_email_client' n'est pas valide ")

                    return False, " - Le champ 'email_client' n'est pas valide ", False


        data['order_header_email_client'] = order_header_email_client



        order_header_status = ""
        if ("order_header_status" in diction.keys()):
            order_header_status = diction['order_header_status']
            if (order_header_status not in MYSY_GV.PARTNER_ORDER_STATUS):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'Statut' est invalide. Les valeurs acceptées " + str(
                        MYSY_GV.PARTNER_ORDER_STATUS))

                return False, " - Le champ 'Statut' est invalide. Les valeurs acceptées " + str(
                    MYSY_GV.PARTNER_ORDER_STATUS), False
            data['order_header_status'] = diction['order_header_status']
        else:
            data['order_header_status'] = "0"


        order_header_origin = ""
        if ("order_header_origin" in diction.keys()):
            if diction['order_header_origin']:
                order_header_origin = diction['order_header_origin']
                if (len(str(order_header_origin)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_origin' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_origin' fait plus de 255 caractères ", False
                data['order_header_origin'] = diction['order_header_origin']

        order_header_ref_client = ""
        if ("order_header_ref_client" in diction.keys()):
            if diction['order_header_ref_client']:
                order_header_ref_client = diction['order_header_ref_client']
                if (len(str(order_header_ref_client)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_ref_client' fait plus de 255 caractères ")

                    return False, " - Le champ 'ref_externe' fait plus de 255 caractères ", False
                data['order_header_ref_client'] = diction['order_header_ref_client']



        order_header_location_type = ""
        if ("order_header_location_type" in diction.keys()):
            if diction['order_header_location_type']:
                order_header_location_type = diction['order_header_location_type']
                if (len(str(order_header_location_type)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_location_type' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_location_type' fait plus de 255 caractères ", False
                data['order_header_location_type'] = diction['order_header_location_type']

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

                # Verifier que l'employé vendeur existe bien pour ce partner
                is_employee_exist_count = MYSY_GV.dbname['ressource_humaine'].count_documents(
                    {'_id': ObjectId(str(order_header_vendeur_id)), 'valide': '1',
                     'locked': '0', 'partner_recid': str(my_partner['recid'])})

                if (is_employee_exist_count <= 0):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le vendeur est invalide ")
                    return False, " - Le vendeur est invalide  ", False
                
                data['order_header_vendeur_id'] = diction['order_header_vendeur_id']

        order_header_date_cmd = ""
        if ("order_header_date_cmd" in diction.keys()):
            if diction['order_header_date_cmd']:
                order_header_date_cmd = str(diction['order_header_date_cmd'])[0:10]
                local_status = mycommon.CheckisDate(order_header_date_cmd)
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date order_header_date_cmd n'est pas au format 'jj/mm/aaaa' ")
                    return False, "La date de la commande n'est pas au format 'jj/mm/aaaa'", False

                data['order_header_date_cmd'] = str(diction['order_header_date_cmd'])[0:10]
            else:
                # par defaut la date de la commande est la date du jour
                data['order_header_date_cmd'] = datetime.today().strftime("%d/%m/%Y")


        order_header_date_expiration = ""
        if ("order_header_date_expiration" in diction.keys()):
            if diction['order_header_date_expiration']:
                order_header_date_cmd = str(diction['order_header_date_expiration'])[0:10]
                local_status = mycommon.CheckisDate(order_header_date_cmd)
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date order_header_date_expiration n'est pas au format 'jj/mm/aaaa' ")
                    return False, "La date d'expiration de la commande n'est pas au format 'jj/mm/aaaa'", False

                data['order_header_date_expiration'] = str(diction['order_header_date_expiration'])[0:10]

                ## Verification de la cohérence des dates. order_header_date_cmd doit < order_header_date_expiration
                if (datetime.strptime(str(diction['order_header_date_cmd'])[0:10], '%d/%m/%Y') >= datetime.strptime(str(diction['order_header_date_expiration'])[0:10], '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - La date d'expiration  " + str(diction['order_header_date_expiration'])[0:10] +" doit etre postérieure à la date de la commande " + str(diction['order_header_date_cmd'])[0:10] + "  ")

                    return False, "  - La date d'expiration  " + str(diction['order_header_date_expiration'])[0:10] +" doit etre postérieure à la date de la commande " + str(diction['order_header_date_cmd'])[0:10] + "  ", False



        ## Recuperation de l'adresse de facturation
        order_header_adr_fact_adresse = ""
        if ("order_header_adr_fact_adresse" in diction.keys()):
            if diction['order_header_adr_fact_adresse']:
                order_header_adr_fact_adresse = diction['order_header_adr_fact_adresse']
                if (len(str(order_header_adr_fact_adresse)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_adresse' fait plus de 500 caractères ")

                    return False, " - Le champ 'adresse de facturation' fait plus de 500 caractères ", False
                data['order_header_adr_fact_adresse'] = diction['order_header_adr_fact_adresse']

        order_header_adr_fact_code_postal = ""
        if ("order_header_adr_fact_code_postal" in diction.keys()):
            if diction['order_header_adr_fact_code_postal']:
                order_header_adr_fact_code_postal = diction['order_header_adr_fact_code_postal']
                if (len(str(order_header_adr_fact_code_postal)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères ", False
                data['order_header_adr_fact_code_postal'] = diction['order_header_adr_fact_code_postal']

        order_header_adr_fact_ville = ""
        if ("order_header_adr_fact_ville" in diction.keys()):
            if diction['order_header_adr_fact_ville']:
                order_header_adr_fact_ville = diction['order_header_adr_fact_ville']
                if (len(str(order_header_adr_fact_ville)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères ", False
                data['order_header_adr_fact_ville'] = diction['order_header_adr_fact_ville']

        order_header_adr_fact_pays = ""
        if ("order_header_adr_fact_pays" in diction.keys()):
            if diction['order_header_adr_fact_pays']:
                order_header_adr_fact_pays = diction['order_header_adr_fact_pays']
                if (len(str(order_header_adr_fact_pays)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères ", False
                data['order_header_adr_fact_pays'] = diction['order_header_adr_fact_pays']



        ## Recuperation de l'adresse d'exécution de la formation
        order_header_adr_liv_adresse = ""
        if ("order_header_adr_liv_adresse" in diction.keys()):
            if diction['order_header_adr_liv_adresse']:
                order_header_adr_liv_adresse = diction['order_header_adr_liv_adresse']
                if (len(str(order_header_adr_liv_adresse)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_adresse' fait plus de 500 caractères ")

                    return False, " - Le champ 'adresse d'exécution' fait plus de 500 caractères ", False
                data['order_header_adr_liv_adresse'] = diction['order_header_adr_liv_adresse']

        order_header_adr_liv_code_postal = ""
        if ("order_header_adr_liv_code_postal" in diction.keys()):
            if diction['order_header_adr_liv_code_postal']:
                order_header_adr_liv_code_postal = diction['order_header_adr_liv_code_postal']
                if (len(str(order_header_adr_liv_code_postal)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères ", False
                data['order_header_adr_liv_code_postal'] = diction['order_header_adr_liv_code_postal']

        order_header_adr_liv_ville = ""
        if ("order_header_adr_liv_ville" in diction.keys()):
            if diction['order_header_adr_liv_ville']:
                order_header_adr_liv_ville = diction['order_header_adr_liv_ville']
                if (len(str(order_header_adr_liv_ville)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères ", False
                data['order_header_adr_liv_ville'] = diction['order_header_adr_liv_ville']

        order_header_adr_liv_pays = ""
        if ("order_header_adr_liv_pays" in diction.keys()):
            if diction['order_header_adr_liv_pays']:
                order_header_adr_liv_pays = diction['order_header_adr_liv_pays']
                if (len(str(order_header_adr_liv_pays)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères ", False
                data['order_header_adr_liv_pays'] = diction['order_header_adr_liv_pays']



        """
        Recuperation des lignes de commande
        """
        data_order_lines = []
        if( "order_lines" in diction.keys()):

            # JSON.loads prends les variable entre double quote. on va donc remplacer les eventuels simple quote par des doubles quotes
            data_order_lines = json.loads(str(diction['order_lines']).replace("'", '"'))

            for order_line in data_order_lines:
                # Verifier les champs acceptés et champs obligatoires pour une ligne de commande
                """
                        Verification des input acceptés
                        """
                field_list = ['order_line_formation', 'order_line_qty', 'order_line_prix_unitaire',
                              'order_line_tax','order_line_type_reduction', 'order_line_type_valeur', 'order_line_montant_reduction']

                print(" ### order_line = ", order_line)
                incom_keys = order_line.keys()
                for val in incom_keys:
                    if val not in field_list:
                        mycommon.myprint(str(
                            inspect.stack()[0][3]) + "   Line de commande : Le champ  '" + val + "' n'est pas autorisé")
                        return False, " Line de commande : Les informations fournies sont incorrectes", False

                """
                Verification des champs obligatoires
                """
                field_list_obligatoire = ['order_line_formation', "order_line_qty", "order_line_prix_unitaire"]

                for val in field_list_obligatoire:
                    if val not in order_line:
                        mycommon.myprint(
                            str(inspect.stack()[0][
                                    3]) + " -  Line de commande : La valeur '" + val + "' n'est pas presente dans liste ")
                        return False, " Line de commande :  Les informations fournies sont incorrectes", False


        """
        
        /!\ : A present que tous les controles sont ok, on va proceder à la creation dans les table.
        
        """

        ### 1 - Creation de l'entete
        """
                /!\ Update du 24/09/2023 : 
                Si on ne trouve pas une sequence propre au partenaire (partner_owner_recid), alors on va chercher 
                la sequence par defaut dont partner_owner_recid = 'default'
                """


        # Rcuperation de la sequence de l'objet "partner_order_header" dans la collection : "mysy_sequence"
        retval_sequence_order = MYSY_GV.dbname['mysy_sequence'].find_one({'related_mysy_object': 'partner_order_header',
                                                           'valide': '1', 'partner_owner_recid':str(my_partner['recid'])})

        if (retval_sequence_order is None):
            # Il n'y pas de sequence pour le partenaire, on va aller chercher la sequence par defaut
            retval_sequence_order = MYSY_GV.dbname['mysy_sequence'].find_one(
                {'related_mysy_object': 'partner_order_header',
                 'valide': '1', 'partner_owner_recid': 'default'})


        if (retval_sequence_order is None or "current_val" not in retval_sequence_order.keys()):
            # Il n'y aucune sequence meme par defaut.
            mycommon.myprint(" Impossible de récupérer la sequence 'retval_sequence_order' ")
            return False, "Impossible de récupérer la sequence 'retval_sequence_order'", False

        current_seq_value = str(retval_sequence_order['current_val'])
        new_sequence_value = int(mycommon.tryInt(current_seq_value)) + 1

        # /!\ Affectation de la reference interne de la commande
        data['order_header_ref_interne'] = retval_sequence_order['prefixe']+str(current_seq_value)

        print(" ####  diction['order_header_ref_interne'] = ", str( data['order_header_ref_interne']))


        ## Verifier qu'il n'y pas une commande avec la meme reference interne
        existe_cmd_ref_interne_count = MYSY_GV.dbname['partner_order_header'].count_documents({'order_header_ref_interne':str(data['order_header_ref_interne'])})
        if( existe_cmd_ref_interne_count > 0):
            mycommon.myprint(
                " Il existe déjà une commande avec la même reference interne "+str(data['order_header_ref_interne']))
            return False, " Il existe déjà une commande avec la même reference interne "+str(data['order_header_ref_interne'])+" ", False

        data['valide'] = '1'
        data['locked'] = '0'
        data['date_update'] = str(datetime.now())


        print(" ### add_partner_order data = ", data)
        inserted_id = ""
        inserted_id = MYSY_GV.dbname['partner_order_header'].insert_one(data).inserted_id
        if (not inserted_id):
            mycommon.myprint(
                " Impossible de créer l'entete de la commande ")
            return False, "Impossible de créer l'entete de la commande  ", False


        new_sequance_data_to_update = {'current_val': new_sequence_value}
        ret_val2 = MYSY_GV.dbname['mysy_sequence'].find_one_and_update(
            {'_id': ObjectId(str(retval_sequence_order['_id'])), 'valide': '1'},
            {"$set": new_sequance_data_to_update},
            return_document=ReturnDocument.AFTER,
            upsert=False,
        )

        tmp_val = str(inserted_id)
        print(" ### inserted_id = ", str(tmp_val))


        ### 2 - Creation des lignes
        data_order_lines = []

        if ("order_lines" in diction.keys()):
            # JSON.loads prends les variable entre double quote. on va donc remplacer les eventuels simple quote par des doubles quotes
            data_order_lines = json.loads(str(diction['order_lines']).replace("'", '"'))

            for order_line in data_order_lines:
                order_line['order_header_id'] = str(tmp_val)
                order_line['order_header_ref_interne'] = str(data['order_header_ref_interne'])
                order_line['valide'] = '1'
                order_line['locked'] = '0'
                order_line['date_update'] = str(datetime.now())
                order_line['partner_owner_recid'] = my_partner['recid']
                order_line['order_line_type'] = "commande"
                order_line['order_line_status'] = data['order_header_status']
                inserted_line_id = ""

                inserted_line_id = MYSY_GV.dbname['partner_order_line'].insert_one(order_line).inserted_id
                if (not inserted_line_id):
                    mycommon.myprint(
                        " Impossible de créer la ligne la commande ")
                    return False, " Impossible de créer la ligne la commande  ", False


        return True, " La commande a été correctement créée", str(data['order_header_ref_interne'])

    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 la commande ", False


"""
Creation d'un devis client d'un partenaire
Order_Type = 'devis'
"""

def Add_Partner_Quotation(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_client_id', 'order_header_description', 'order_header_comment',
                      'order_header_date_cmd', 'order_header_date_expiration',
                      'order_header_adr_fact_adresse', 'order_header_adr_fact_code_postal',
                      'order_header_adr_fact_ville', 'order_header_adr_fact_pays',
                      'order_header_adr_liv_adresse', 'order_header_adr_liv_code_postal', 'order_header_adr_liv_ville',
                      'order_header_adr_liv_pays', 'order_header_email_client',
                      'order_header_condition_paiement_id', 'order_header_ref_client', 'order_header_vendeur_id',
                      'order_header_ref_interne', 'order_header_total_ht', 'order_header_total_tax',
                      'order_header_total_ttc', 'order_header_status', 'order_header_type_reduction',
                      'order_header_type_reduction_valeur', 'order_header_montant_reduction', 'order_lines',
                      'order_header_type', 'order_header_location_type', 'order_header_tax', 'order_header_origin',
                      'order_header_tax_amount', 'total_header_hors_taxe_after_header_reduction',
                      'total_header_hors_taxe_before_header_reduction', 'total_header_toutes_taxes', 'total_lines_hors_taxe_after_lines_reduction',
                      'total_lines_hors_taxe_before_lines_reduction', 'total_lines_montant_reduction']

        """
        /!\ A noter que   "order_lines" est tableau [] qui peut contenir les keys suivantes : 'order_line_formation', 'order_line_qty', 'order_line_prix_unitaire', 'order_line_tax', 'order_line_type_reduction', 'order_line_type_valeur', 'order_line_montant_reduction'
        ainsi, order_lines sera du style  order_lines[ {order_line_formation:'xxx', order_line_qty:'2', etc },  {order_line_formation:'yyy', order_line_qty:'7', etc }, ....{}}

        """

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False and  val not in MYSY_GV.PARTNER_BASE_CONFIG_NAME :
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes", False

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', "order_header_client_id", "order_header_date_cmd"]

        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, " Les informations fournies sont incorrectes", False

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        # Recuperation des champs
        data = {}
        data['partner_owner_recid'] = my_partner['recid']
        data['order_header_type'] = "devis"

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

                # Verifier que le client existe bien pour ce partner
                is_client_exist_count = MYSY_GV.dbname['partner_client'].count_documents(
                    {'_id': ObjectId(str(order_header_client_id)), 'valide': '1',
                     'locked': '0', 'partner_recid': str(my_partner['recid'])})

                if (is_client_exist_count <= 0):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le client est invalide ")
                    return False, " - Le client est invalide  ", False
                data['order_header_client_id'] = diction['order_header_client_id']

        order_header_description = ""
        if ("order_header_description" in diction.keys()):
            if diction['order_header_description']:
                order_header_description = diction['order_header_description']
                if (len(str(order_header_description)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_description' fait plus de 500 caractères ")

                    return False, " - Le champ 'Description' fait plus de 500 caractères ", False
                data['order_header_description'] = diction['order_header_description']

        order_header_status = ""
        if ("order_header_status" in diction.keys()):
            order_header_status = diction['order_header_status']
            if (order_header_status not in MYSY_GV.PARTNER_QUOTATION_STATUS):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'Statut' est invalide. Les valeurs acceptées " + str(
                        MYSY_GV.PARTNER_QUOTATION_STATUS))

                return False, " - Le champ 'Statut' est invalide. Les valeurs acceptées " + str(
                    MYSY_GV.PARTNER_QUOTATION_STATUS), False
            data['order_header_status'] = diction['order_header_status']
        else:
            data['order_header_status'] = "0"


        order_header_location_type = ""
        if ("order_header_location_type" in diction.keys()):
            if diction['order_header_location_type']:
                order_header_location_type = diction['order_header_location_type']
                if (len(str(order_header_location_type)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_location_type' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_location_type' fait plus de 255 caractères ", False
                data['order_header_location_type'] = diction['order_header_location_type']


        # Ajout des point de setup des relances
        for val in MYSY_GV.PARTNER_BASE_CONFIG_NAME:
            if (val in diction.keys()):
                data[val] = diction[val]

        order_header_comment = ""
        if ("order_header_comment" in diction.keys()):
            if diction['order_header_comment']:
                order_header_comment = diction['order_header_comment']
                if (len(str(order_header_comment)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_comment' fait plus de 500 caractères ")

                    return False, " - Le champ 'Commentaire' fait plus de 500 caractères ", False
                data['order_header_comment'] = diction['order_header_comment']

        order_header_condition_paiement_id = ""
        if ("order_header_condition_paiement_id" in diction.keys()):
            if diction['order_header_condition_paiement_id']:
                order_header_condition_paiement_id = diction['order_header_condition_paiement_id']
                if (len(str(order_header_condition_paiement_id)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_condition_paiement' fait plus de 255 caractères ")

                    return False, " - Le champ 'Condition de paiement' fait plus de 255 caractères ", False
                data['order_header_condition_paiement_id'] = order_header_condition_paiement_id

        order_header_ref_interne = ""
        if ("order_header_ref_interne" in diction.keys()):
            if diction['order_header_ref_interne']:
                order_header_ref_interne = diction['order_header_ref_interne']
                if (len(str(order_header_ref_interne)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_ref_interne' fait plus de 255 caractères ")

                    return False, " - Le champ 'ref_interne' fait plus de 255 caractères ", False
                data['order_header_ref_interne'] = diction['order_header_ref_interne']

        order_header_ref_client = ""
        if ("order_header_ref_client" in diction.keys()):
            if diction['order_header_ref_client']:
                order_header_ref_client = diction['order_header_ref_client']
                if (len(str(order_header_ref_client)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_ref_client' fait plus de 255 caractères ")

                    return False, " - Le champ 'ref_externe' fait plus de 255 caractères ", False
                data['order_header_ref_client'] = diction['order_header_ref_client']

        order_header_email_client = ""
        if ("order_header_email_client" in diction.keys()):
            if diction['order_header_email_client']:
                order_header_email_client = diction['order_header_email_client']
                if (len(str(order_header_email_client)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_email_client' fait plus de 255 caractères ")

                    return False, " - Le champ 'email_client' fait plus de 255 caractères ", False

                if (mycommon.isEmailValide(order_header_email_client) is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_email_client' n'est pas valide ")

                    return False, " - Le champ 'email_client' n'est pas valide ", False

        data['order_header_email_client'] = order_header_email_client


        order_header_origin = ""
        if ("order_header_origin" in diction.keys()):
            if diction['order_header_origin']:
                order_header_origin = diction['order_header_origin']
                if (len(str(order_header_origin)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_origin' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_origin' fait plus de 255 caractères ", False
                data['order_header_origin'] = diction['order_header_origin']



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

                # Verifier que l'employé vendeur existe bien pour ce partner
                is_employee_exist_count = MYSY_GV.dbname['ressource_humaine'].count_documents(
                    {'_id': ObjectId(str(order_header_vendeur_id)), 'valide': '1',
                     'locked': '0', 'partner_recid': str(my_partner['recid'])})

                if (is_employee_exist_count <= 0):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Le vendeur est invalide ")
                    return False, " - Le vendeur est invalide  ", False

                data['order_header_vendeur_id'] = diction['order_header_vendeur_id']

        order_header_date_cmd = ""
        if ("order_header_date_cmd" in diction.keys()):
            if diction['order_header_date_cmd']:
                order_header_date_cmd = str(diction['order_header_date_cmd'])[0:10]
                local_status = mycommon.CheckisDate(order_header_date_cmd)
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date order_header_date_cmd n'est pas au format 'jj/mm/aaaa' ")
                    return False, "La date de la commande n'est pas au format 'jj/mm/aaaa'", False

                data['order_header_date_cmd'] = str(diction['order_header_date_cmd'])[0:10]
            else:
                # par defaut la date de la commande est la date du jour
                data['order_header_date_cmd'] = datetime.today().strftime("%d/%m/%Y")

        order_header_date_expiration = ""
        if ("order_header_date_expiration" in diction.keys()):
            if diction['order_header_date_expiration']:
                order_header_date_cmd = str(diction['order_header_date_expiration'])[0:10]
                local_status = mycommon.CheckisDate(order_header_date_cmd)
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date order_header_date_expiration n'est pas au format 'jj/mm/aaaa' ")
                    return False, "La date d'expiration de la commande n'est pas au format 'jj/mm/aaaa'", False

                data['order_header_date_expiration'] = str(diction['order_header_date_expiration'])[0:10]

                ## Verification de la cohérence des dates. order_header_date_cmd doit < order_header_date_expiration
                if (datetime.strptime(str(diction['order_header_date_cmd'])[0:10], '%d/%m/%Y') >= datetime.strptime(
                        str(diction['order_header_date_expiration'])[0:10], '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - La date d'expiration  " + str(diction['order_header_date_expiration'])[
                                                                    0:10] + " doit etre postérieure à la date de la commande " + str(
                            diction['order_header_date_cmd'])[0:10] + "  ")

                    return False, "  - La date d'expiration  " + str(diction['order_header_date_expiration'])[
                                                                 0:10] + " doit etre postérieure à la date de la commande " + str(
                        diction['order_header_date_cmd'])[0:10] + "  ", False

        ## Recuperation de l'adresse de facturation
        order_header_adr_fact_adresse = ""
        if ("order_header_adr_fact_adresse" in diction.keys()):
            if diction['order_header_adr_fact_adresse']:
                order_header_adr_fact_adresse = diction['order_header_adr_fact_adresse']
                if (len(str(order_header_adr_fact_adresse)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_adresse' fait plus de 500 caractères ")

                    return False, " - Le champ 'adresse de facturation' fait plus de 500 caractères ", False
                data['order_header_adr_fact_adresse'] = diction['order_header_adr_fact_adresse']

        order_header_adr_fact_code_postal = ""
        if ("order_header_adr_fact_code_postal" in diction.keys()):
            if diction['order_header_adr_fact_code_postal']:
                order_header_adr_fact_code_postal = diction['order_header_adr_fact_code_postal']
                if (len(str(order_header_adr_fact_code_postal)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères ", False
                data['order_header_adr_fact_code_postal'] = diction['order_header_adr_fact_code_postal']

        order_header_adr_fact_ville = ""
        if ("order_header_adr_fact_ville" in diction.keys()):
            if diction['order_header_adr_fact_ville']:
                order_header_adr_fact_ville = diction['order_header_adr_fact_ville']
                if (len(str(order_header_adr_fact_ville)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères ", False
                data['order_header_adr_fact_ville'] = diction['order_header_adr_fact_ville']

        order_header_adr_fact_pays = ""
        if ("order_header_adr_fact_pays" in diction.keys()):
            if diction['order_header_adr_fact_pays']:
                order_header_adr_fact_pays = diction['order_header_adr_fact_pays']
                if (len(str(order_header_adr_fact_pays)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères ", False
                data['order_header_adr_fact_pays'] = diction['order_header_adr_fact_pays']

        ## Recuperation de l'adresse d'exécution de la formation
        order_header_adr_liv_adresse = ""
        if ("order_header_adr_liv_adresse" in diction.keys()):
            if diction['order_header_adr_liv_adresse']:
                order_header_adr_liv_adresse = diction['order_header_adr_liv_adresse']
                if (len(str(order_header_adr_liv_adresse)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_adresse' fait plus de 500 caractères ")

                    return False, " - Le champ 'adresse d'exécution' fait plus de 500 caractères ", False
                data['order_header_adr_liv_adresse'] = diction['order_header_adr_liv_adresse']

        order_header_adr_liv_code_postal = ""
        if ("order_header_adr_liv_code_postal" in diction.keys()):
            if diction['order_header_adr_liv_code_postal']:
                order_header_adr_liv_code_postal = diction['order_header_adr_liv_code_postal']
                if (len(str(order_header_adr_liv_code_postal)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères ", False
                data['order_header_adr_liv_code_postal'] = diction['order_header_adr_liv_code_postal']

        order_header_adr_liv_ville = ""
        if ("order_header_adr_liv_ville" in diction.keys()):
            if diction['order_header_adr_liv_ville']:
                order_header_adr_liv_ville = diction['order_header_adr_liv_ville']
                if (len(str(order_header_adr_liv_ville)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères ", False
                data['order_header_adr_liv_ville'] = diction['order_header_adr_liv_ville']

        order_header_adr_liv_pays = ""
        if ("order_header_adr_liv_pays" in diction.keys()):
            if diction['order_header_adr_liv_pays']:
                order_header_adr_liv_pays = diction['order_header_adr_liv_pays']
                if (len(str(order_header_adr_liv_pays)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères ")

                    return False, " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères ", False
                data['order_header_adr_liv_pays'] = diction['order_header_adr_liv_pays']

        """
        Recuperation des lignes de commande
        """
        data_order_lines = []
        if ("order_lines" in diction.keys()):

            # JSON.loads prends les variable entre double quote. on va donc remplacer les eventuels simple quote par des doubles quotes
            data_order_lines = json.loads(str(diction['order_lines']).replace("'", '"'))

            for order_line in data_order_lines:
                # Verifier les champs acceptés et champs obligatoires pour une ligne de commande
                """
                        Verification des input acceptés
                        """
                field_list = ['order_line_formation', 'order_line_qty', 'order_line_prix_unitaire',
                              'order_line_tax', 'order_line_type_reduction', 'order_line_type_valeur',
                              'order_line_montant_reduction']

                #print(" ### order_line = ", order_line)
                incom_keys = order_line.keys()
                for val in incom_keys:
                    if val not in field_list:
                        mycommon.myprint(str(
                            inspect.stack()[0][3]) + "   Line de commande : Le champ  '" + val + "' n'est pas autorisé")
                        return False, " Line de commande : Les informations fournies sont incorrectes", False

                """
                Verification des champs obligatoires
                """
                field_list_obligatoire = ['order_line_formation', "order_line_qty", "order_line_prix_unitaire"]

                for val in field_list_obligatoire:
                    if val not in order_line:
                        mycommon.myprint(
                            str(inspect.stack()[0][
                                    3]) + " -  Line de commande : La valeur '" + val + "' n'est pas presente dans liste ")
                        return False, " Line de commande :  Les informations fournies sont incorrectes", False

        """

        /!\ : A present que tous les controles sont ok, on va proceder à la creation dans les table.

        """

        ### 1 - Creation de l'entete

        # Rcuperation de la sequence de l'objet "partner_quotation_header" dans la collection : "mysy_sequence"
        """
        /!\ Update du 24/09/2023 : 
        Si on ne trouve pas une sequence propre au partenaire (partner_owner_recid), alors on va chercher 
        la sequence par defaut dont partner_owner_recid = 'default'
        """

        retval_sequence_order = MYSY_GV.dbname['mysy_sequence'].find_one({'related_mysy_object': 'partner_quotation_header',
                                                                          'valide': '1', 'partner_owner_recid': str(
                my_partner['recid'])})


        if( retval_sequence_order is None ):
            # Il n'y pas de sequence pour le partenaire, on va aller chercher la sequence par defaut
            retval_sequence_order = MYSY_GV.dbname['mysy_sequence'].find_one(
                {'related_mysy_object': 'partner_quotation_header',
                 'valide': '1', 'partner_owner_recid': 'default'})

        if (retval_sequence_order is None or "current_val" not in retval_sequence_order.keys()):
            # Il n'y a aucune sequence, meme par defaut.
            mycommon.myprint(" Impossible de récupérer la sequence 'retval_sequence_order' ")
            return False, "Impossible de récupérer la sequence 'retval_sequence_order'", False

        current_seq_value = str(retval_sequence_order['current_val'])
        new_sequence_value = int(mycommon.tryInt(current_seq_value)) + 1

        # /!\ Affectation de la reference interne de la commande
        data['order_header_ref_interne'] = retval_sequence_order['prefixe'] + str(current_seq_value)

        #print(" ####  diction['order_header_ref_interne'] = ", str(data['order_header_ref_interne']))

        ## Verifier qu'il n'y pas une commande avec la meme reference interne
        existe_cmd_ref_interne_count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'order_header_ref_interne': str(data['order_header_ref_interne'])})
        if (existe_cmd_ref_interne_count > 0):
            mycommon.myprint(
                " Il existe déjà une commande avec la même reference interne " + str(data['order_header_ref_interne']))
            return False, " Il existe déjà une commande avec la même reference interne " + str(
                data['order_header_ref_interne']) + " ", False

        data['valide'] = '1'
        data['locked'] = '0'
        data['date_update'] = str(datetime.now())
        data['is_validated'] = '0'
        data['update_by'] = str(my_partner['recid'])



        #print(" ### add_partner_order data = ", data)
        inserted_id = ""
        inserted_id = MYSY_GV.dbname['partner_order_header'].insert_one(data).inserted_id
        if (not inserted_id):
            mycommon.myprint(
                " Impossible de créer l'entete de la commande ")
            return False, "Impossible de créer l'entete de la commande  ", False

        new_sequance_data_to_update = {'current_val': new_sequence_value}
        ret_val2 = MYSY_GV.dbname['mysy_sequence'].find_one_and_update(
            {'_id': ObjectId(str(retval_sequence_order['_id'])), 'valide': '1'},
            {"$set": new_sequance_data_to_update},
            return_document=ReturnDocument.AFTER,
            upsert=False,
        )

        tmp_val = str(inserted_id)
        print(" ### inserted_id = ", str(tmp_val))

        ### 2 - Creation des lignes
        data_order_lines = []

        if ("order_lines" in diction.keys()):
            # JSON.loads prends les variable entre double quote. on va donc remplacer les eventuels simple quote par des doubles quotes
            data_order_lines = json.loads(str(diction['order_lines']).replace("'", '"'))

            for order_line in data_order_lines:
                order_line['order_header_id'] = str(tmp_val)
                order_line['order_header_ref_interne'] = str(data['order_header_ref_interne'])
                order_line['valide'] = '1'
                order_line['locked'] = '0'
                order_line['date_update'] = str(datetime.now())
                order_line['partner_owner_recid'] = my_partner['recid']
                order_line['order_line_type'] = "devis"
                order_line['order_line_status'] = data['order_header_status']
                order_line['update_by'] = str(my_partner['recid'])
                inserted_line_id = ""

                inserted_line_id = MYSY_GV.dbname['partner_order_line'].insert_one(order_line).inserted_id
                if (not inserted_line_id):
                    mycommon.myprint(
                        " Impossible de créer la ligne la commande ")
                    return False, " Impossible de créer la ligne la commande  ", False

        return True, " La commande a été correctement créée", str(data['order_header_ref_interne'])

    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 la commande ", False


"""
Fonction de mise à jour d'une entete commande client d'un partner.
Les ligne sont mise à jour avec une fonction à part entière

On se base sur l' '_id' du header et le token pour faire la mise à jour
"""

def Update_Partner_Order_Header(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_client_id', 'order_header_description', 'order_header_comment',
                      'order_header_date_cmd', 'order_header_date_expiration',
                      'order_header_adr_fact_adresse', 'order_header_adr_fact_code_postal',
                      'order_header_adr_fact_ville', 'order_header_adr_fact_pays',
                      'order_header_adr_liv_adresse', 'order_header_adr_liv_code_postal', 'order_header_adr_liv_ville',
                      'order_header_adr_liv_pays', 'order_header_email_client',
                      'order_header_condition_paiement_id', 'order_header_ref_client', 'order_header_vendeur_id',
                      'order_header_ref_interne', 'order_header_total_ht', 'order_header_total_tax',
                      'order_header_total_ttc', 'order_header_status', 'order_header_type_reduction',
                      'order_header_type_reduction_valeur', 'order_header_montant_reduction',
                      'order_header_id', 'order_header_type', 'order_header_location_type', 'order_header_origin']



        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', "order_header_client_id", "order_header_date_cmd",
                                  'order_header_id', 'order_header_ref_interne', 'order_header_type']

        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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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

        """ 
        #  Verifier que la commande existe et qu'elle est modifiable.
        Pour les ligne, on fait pareil, on ne peut modifier que celles qui sont modifiable.
        
        Conditions pour modifier entete  : 
        1 - statut est : devis, cmd, MAIS PAS ANNULE ou FACTURE
        Pour un debut pas de facturation partielle. c'est tout ou rien.
        """
        my_order_data_count = MYSY_GV.dbname['partner_order_header'].count_documents({'partner_owner_recid':str(my_partner['recid']),
                                                                                      'valide':'1', 'locked':'0', 'order_header_type':'commande',
                                                                                      '_id':ObjectId(str(order_header_id))})

        if( my_order_data_count != 1 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la commande est invalide ")
            return False, " L'identifiant de la commande est invalide",

        """
        Recuperation et stockage des données de l'entete avant mise à jour
        """
        my_order_data_previous_information = MYSY_GV.dbname['partner_order_header'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0', 'order_header_type': 'commande',
             '_id': ObjectId(str(order_header_id))})

        # Recuperation des champs
        data = {}
        data['partner_owner_recid'] = my_partner['recid']

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

            # Verifier que le client existe bien pour ce partner
            is_client_exist_count = MYSY_GV.dbname['partner_client'].count_documents(
                {'_id': ObjectId(str(order_header_client_id)), 'valide': '1',
                 'locked': '0', 'partner_recid': str(my_partner['recid'])})

            if (is_client_exist_count <= 0):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Le client est invalide ")
                return False, " - Le client est invalide  "
            data['order_header_client_id'] = diction['order_header_client_id']

        order_header_description = ""
        if ("order_header_description" in diction.keys()):
            order_header_description = diction['order_header_description']
            if (len(str(order_header_description)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_description' fait plus de 500 caractères ")

                return False, " - Le champ 'Description' fait plus de 500 caractères "
            data['order_header_description'] = diction['order_header_description']

        order_header_status = ""
        if ("order_header_status" in diction.keys()):
            order_header_status = diction['order_header_status']
            if (order_header_status not in MYSY_GV.PARTNER_ORDER_STATUS):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'Statut' est invalide. Les valeurs acceptées "+str(MYSY_GV.PARTNER_ORDER_STATUS))

                return False, " - Le champ 'Statut' est invalide. Les valeurs acceptées "+str(MYSY_GV.PARTNER_ORDER_STATUS)
            data['order_header_status'] = diction['order_header_status']

        order_header_location_type = ""
        if ("order_header_location_type" in diction.keys()):
            order_header_location_type = diction['order_header_location_type']
            if (len(str(order_header_location_type)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_location_type' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_location_type' fait plus de 255 caractères "
            data['order_header_location_type'] = diction['order_header_location_type']


        order_header_comment = ""
        if ("order_header_comment" in diction.keys()):
            order_header_comment = diction['order_header_comment']
            if (len(str(order_header_comment)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_comment' fait plus de 500 caractères ")

                return False, " - Le champ 'Commentaire' fait plus de 500 caractères "
            data['order_header_comment'] = diction['order_header_comment']

        order_header_condition_paiement_id = ""
        if ("order_header_condition_paiement_id" in diction.keys() and diction['order_header_condition_paiement_id']):
            order_header_condition_paiement_id = diction['order_header_condition_paiement_id']
            if (len(str(order_header_condition_paiement_id)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_condition_paiement' fait plus de 255 caractères ")

                return False, " - Le champ 'Condition de paiement' fait plus de 255 caractères "
            data['order_header_condition_paiement_id'] = diction['order_header_condition_paiement_id']

        order_header_ref_interne = ""
        if ("order_header_ref_interne" in diction.keys()):
            if diction['order_header_ref_interne']:
                order_header_ref_interne = diction['order_header_ref_interne']
                if (len(str(order_header_ref_interne)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_ref_interne' fait plus de 255 caractères ")

                    return False, " - Le champ 'ref_interne' fait plus de 255 caractères "
                data['order_header_ref_interne'] = diction['order_header_ref_interne']
            else:
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - La reference interne de la commande est vide ")

                return False, " - La reference interne de la commande est vide "

        order_header_ref_client = ""
        if ("order_header_ref_client" in diction.keys()):
            order_header_ref_client = diction['order_header_ref_client']
            if (len(str(order_header_ref_client)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_ref_client' fait plus de 255 caractères ")

                return False, " - Le champ 'ref_externe' fait plus de 255 caractères "
            data['order_header_ref_client'] = diction['order_header_ref_client']

        order_header_email_client = ""
        if ("order_header_email_client" in diction.keys()):
            order_header_email_client = diction['order_header_email_client']
            if (len(str(order_header_email_client)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_email_client' fait plus de 255 caractères ")

                return False, " - Le champ 'email_client' fait plus de 255 caractères "
            data['order_header_email_client'] = order_header_email_client

        order_header_origin = ""
        if ("order_header_origin" in diction.keys()):
            order_header_origin = diction['order_header_origin']
            if (len(str(order_header_origin)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_origin' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_origin' fait plus de 255 caractères "
            data['order_header_origin'] = diction['order_header_origin']


        order_header_type_reduction = ""
        if ("order_header_type_reduction" in diction.keys()):
            order_header_type_reduction = diction['order_header_type_reduction']
            if ( order_header_type_reduction not in ['fixe', 'percent','']):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'type de reduction ' n'est pas valide ")

                return False, " - Le champ 'type de reduction ' n'est pas valide "
            data['order_header_type_reduction'] = diction['order_header_type_reduction']

            # On ne prend en charge la valeur de la reduction que si le type de reduction est 'fixe' ou 'percent'
            if ( order_header_type_reduction in ['fixe', 'percent']):
                order_header_type_reduction_valeur = ""
                if ("order_header_type_reduction_valeur" in diction.keys()):
                    order_header_type_reduction_valeur = diction['order_header_type_reduction_valeur']
                    local_status, local_retval = mycommon.IsFloat(order_header_type_reduction_valeur)
                    if (local_status is False):
                        mycommon.myprint(
                            str(inspect.stack()[0][
                                    3]) + " - Le champ 'valeur de reduction ' n'est pas valide ")

                        return False, " - Le champ 'valeur de reduction ' n'est pas valide "
                    data['order_header_type_reduction_valeur'] = str(local_retval)




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

            #local_qry = {'_id': ObjectId(str(order_header_vendeur_id)), 'valide': '1', 'locked': '0', 'partner_recid': str(my_partner['recid'])}
            #print(" #### local_qry = ", local_qry)

            # Verifier que l'employé vendeur existe bien pour ce partner
            is_employee_exist_count = MYSY_GV.dbname['ressource_humaine'].count_documents(
                {'_id': ObjectId(str(order_header_vendeur_id)), 'valide': '1',
                 'locked': '0', 'partner_recid': str(my_partner['recid'])})

            if (is_employee_exist_count <= 0):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Le vendeur est invalide ")
                return False, " - Le vendeur est invalide  "

            data['order_header_vendeur_id'] = diction['order_header_vendeur_id']

        order_header_date_cmd = ""
        if ("order_header_date_cmd" in diction.keys()):
            if diction['order_header_date_cmd']:
                order_header_date_cmd = str(diction['order_header_date_cmd'])[0:10]
                local_status = mycommon.CheckisDate(order_header_date_cmd)
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date order_header_date_cmd n'est pas au format 'jj/mm/aaaa' ")
                    return False, "La date de la commande n'est pas au format 'jj/mm/aaaa'"

                data['order_header_date_cmd'] = str(diction['order_header_date_cmd'])[0:10]

            else:
                # par defaut la date de la commande est la date du jour
                data['order_header_date_cmd'] = datetime.today().strftime("%d/%m/%Y")

        order_header_date_expiration = ""
        if ("order_header_date_expiration" in diction.keys()):
            order_header_date_cmd = str(diction['order_header_date_expiration'])[0:10]
            local_status = mycommon.CheckisDate(order_header_date_cmd)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " La date order_header_date_expiration n'est pas au format 'jj/mm/aaaa' ")
                return False, "La date d'expiration de la commande n'est pas au format 'jj/mm/aaaa'"

            data['order_header_date_expiration'] = str(diction['order_header_date_expiration'])[0:10]

            ## Verification de la cohérence des dates. order_header_date_cmd doit < order_header_date_expiration
            if (datetime.strptime(str(diction['order_header_date_cmd'])[0:10], '%d/%m/%Y') >= datetime.strptime(
                    str(diction['order_header_date_expiration'])[0:10], '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - La date d'expiration  " + str(diction['order_header_date_expiration'])[
                                                                0:10] + " doit etre postérieure à la date de la commande " + str(
                        diction['order_header_date_cmd'])[0:10] + "  ")

                return False, "  - La date d'expiration  " + str(diction['order_header_date_expiration'])[
                                                             0:10] + " doit etre postérieure à la date de la commande " + str(
                    diction['order_header_date_cmd'])[0:10] + "  "

        ## Recuperation de l'adresse de facturation
        order_header_adr_fact_adresse = ""
        if ("order_header_adr_fact_adresse" in diction.keys()):
            order_header_adr_fact_adresse = diction['order_header_adr_fact_adresse']
            if (len(str(order_header_adr_fact_adresse)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_adresse' fait plus de 500 caractères ")

                return False, " - Le champ 'adresse de facturation' fait plus de 500 caractères "
            data['order_header_adr_fact_adresse'] = diction['order_header_adr_fact_adresse']

        order_header_adr_fact_code_postal = ""
        if ("order_header_adr_fact_code_postal" in diction.keys()):
            order_header_adr_fact_code_postal = diction['order_header_adr_fact_code_postal']
            if (len(str(order_header_adr_fact_code_postal)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères "
            data['order_header_adr_fact_code_postal'] = diction['order_header_adr_fact_code_postal']

        order_header_adr_fact_ville = ""
        if ("order_header_adr_fact_ville" in diction.keys()):
            order_header_adr_fact_ville = diction['order_header_adr_fact_ville']
            if (len(str(order_header_adr_fact_ville)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères "
            data['order_header_adr_fact_ville'] = diction['order_header_adr_fact_ville']

        order_header_adr_fact_pays = ""
        if ("order_header_adr_fact_pays" in diction.keys()):
            order_header_adr_fact_pays = diction['order_header_adr_fact_pays']
            if (len(str(order_header_adr_fact_pays)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères "
            data['order_header_adr_fact_pays'] = diction['order_header_adr_fact_pays']

        ## Recuperation de l'adresse d'exécution de la formation
        order_header_adr_liv_adresse = ""
        if ("order_header_adr_liv_adresse" in diction.keys()):
            order_header_adr_liv_adresse = diction['order_header_adr_liv_adresse']
            if (len(str(order_header_adr_liv_adresse)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_adresse' fait plus de 500 caractères ")

                return False, " - Le champ 'adresse d'exécution' fait plus de 500 caractères "
            data['order_header_adr_liv_adresse'] = diction['order_header_adr_liv_adresse']

        order_header_adr_liv_code_postal = ""
        if ("order_header_adr_liv_code_postal" in diction.keys()):
            order_header_adr_liv_code_postal = diction['order_header_adr_liv_code_postal']
            if (len(str(order_header_adr_liv_code_postal)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères "
            data['order_header_adr_liv_code_postal'] = diction['order_header_adr_liv_code_postal']

        order_header_adr_liv_ville = ""
        if ("order_header_adr_liv_ville" in diction.keys()):
            order_header_adr_liv_ville = diction['order_header_adr_liv_ville']
            if (len(str(order_header_adr_liv_ville)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères "
            data['order_header_adr_liv_ville'] = diction['order_header_adr_liv_ville']

        order_header_adr_liv_pays = ""
        if ("order_header_adr_liv_pays" in diction.keys()):
            order_header_adr_liv_pays = diction['order_header_adr_liv_pays']
            if (len(str(order_header_adr_liv_pays)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères "
            data['order_header_adr_liv_pays'] = diction['order_header_adr_liv_pays']


        """

        /!\ : A present que tous les controles sont ok, on va proceder à la creation dans les table.

        """

        ### 1 - Mise à jour de l'entete

        data['date_update'] = str(datetime.now())
        data['update_by'] = str(my_partner['_id'])

        print(" ### Update_partner_order data = ", data)

        inserted_data = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0','order_header_type':'commande',
             '_id': ObjectId(str(order_header_id))},
            {"$set": data},
            return_document=ReturnDocument.AFTER,
            upsert=False,
        )

        if( inserted_data is None ):
            mycommon.myprint(
                " Impossible de mettre à jour l'entete de commande ")
            return False, "Impossible de mettre à jour l'entete de commande  "

        """
        Si le statut de l'entete de commande a bougé, alors on met à le statut de toutes les ligne
        Verification my_order_data_previous_information['order_header_status'] != order_header_status
        """
        local_qry = {'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0',
                     'order_header_id': str(order_header_id)
                     }
        #print(" #### COMMANDE local_qry = ", local_qry)

        if( "order_header_status" in my_order_data_previous_information.keys()):
            if( str(my_order_data_previous_information['order_header_status']) != str(order_header_status)):
                # Il y a eu une mise à jour du statut de l'entete, on va donc mettre à jour les statuts des lignes de commande
                inserted_data_line = MYSY_GV.dbname['partner_order_line'].update_many(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0',
                     'order_header_id': str(order_header_id)
                     },
                    {
                        "$set": {"order_line_status": str(order_header_status), "order_line_type": str(my_order_data_previous_information['order_header_type']),
                                 'date_update':str(data['date_update'])}
                    })
                """print("raw:", inserted_data_line.raw_result)
                print("acknowledged:", inserted_data_line.acknowledged)
                print("matched_count:", inserted_data_line.matched_count)"""
        else:
            inserted_data_line = MYSY_GV.dbname['partner_order_line'].update_many(
                {'partner_owner_recid': str(my_partner['recid']),
                 'valide': '1', 'locked': '0',
                 'order_header_id': str(order_header_id)
                 },
                {
                    "$set": {"order_line_status": str(order_header_status), "order_line_type": str(my_order_data_previous_information['order_header_type']),
                             'date_update': str(data['date_update'])}
                })
            """print("raw:", inserted_data_line.raw_result)
            print("acknowledged:", inserted_data_line.acknowledged)
            print("matched_count:", inserted_data_line.matched_count)"""

        return True, " La commande a été correctement mise à jour"

    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 mettre à jour la commande "


"""
Fonction de mise à jour d'un devis
"""
def Update_Partner_Quotation_Header(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_client_id', 'order_header_description', 'order_header_comment',
                      'order_header_date_cmd', 'order_header_date_expiration',
                      'order_header_adr_fact_adresse', 'order_header_adr_fact_code_postal',
                      'order_header_adr_fact_ville', 'order_header_adr_fact_pays',
                      'order_header_adr_liv_adresse', 'order_header_adr_liv_code_postal', 'order_header_adr_liv_ville',
                      'order_header_adr_liv_pays', 'order_header_email_client',
                      'order_header_condition_paiement_id', 'order_header_ref_client', 'order_header_vendeur_id',
                      'order_header_ref_interne', 'order_header_total_ht', 'order_header_total_tax',
                      'order_header_total_ttc', 'order_header_status', 'order_header_type_reduction',
                      'order_header_type_reduction_valeur', 'order_header_montant_reduction',
                      'order_header_id', 'order_header_type', 'order_header_location_type', 'order_header_origin']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False and  val not in MYSY_GV.PARTNER_BASE_CONFIG_NAME :
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', "order_header_client_id", "order_header_date_cmd",
                                  'order_header_id', 'order_header_ref_interne', 'order_header_type']

        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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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

        """ 
        #  Verifier que la commande existe et qu'elle est modifiable.
        Pour les ligne, on fait pareil, on ne peut modifier que celles qui sont modifiable.

        Conditions pour modifier entete  : 
        1 - statut est : devis, cmd, MAIS PAS ANNULE ou FACTURE
        Pour un debut pas de facturation partielle. c'est tout ou rien.
        """
        my_order_data_count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0', 'order_header_type':'devis',
             '_id': ObjectId(str(order_header_id))})

        if (my_order_data_count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la commande est invalide ")
            return False, " L'identifiant de la commande est invalide",

        """
        Recuperation et stockage des données de l'entete avant mise à jour
        """
        my_order_data_previous_information = MYSY_GV.dbname['partner_order_header'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0', 'order_header_type': 'devis',
             '_id': ObjectId(str(order_header_id))})



        # Recuperation des champs
        data = {}
        data['partner_owner_recid'] = my_partner['recid']

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

            # Verifier que le client existe bien pour ce partner
            is_client_exist_count = MYSY_GV.dbname['partner_client'].count_documents(
                {'_id': ObjectId(str(order_header_client_id)), 'valide': '1',
                 'locked': '0', 'partner_recid': str(my_partner['recid'])})

            if (is_client_exist_count <= 0):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Le client est invalide ")
                return False, " - Le client est invalide  "
            data['order_header_client_id'] = diction['order_header_client_id']


        # Ajout des point de setup des relances
        for val in MYSY_GV.PARTNER_BASE_CONFIG_NAME:
            if (val in diction.keys()):
                data[val] = diction[val]


        order_header_description = ""
        if ("order_header_description" in diction.keys()):
            order_header_description = diction['order_header_description']
            if (len(str(order_header_description)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_description' fait plus de 500 caractères ")

                return False, " - Le champ 'Description' fait plus de 500 caractères "
            data['order_header_description'] = diction['order_header_description']

        order_header_status = ""
        if ("order_header_status" in diction.keys()):
            order_header_status = diction['order_header_status']
            if (order_header_status not in MYSY_GV.PARTNER_QUOTATION_STATUS):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'Statut' est invalide. Les valeurs acceptées " + str(
                        MYSY_GV.PARTNER_QUOTATION_STATUS))

                return False, " - Le champ 'Statut' est invalide. Les valeurs acceptées " + str(
                    MYSY_GV.PARTNER_QUOTATION_STATUS)
            data['order_header_status'] = diction['order_header_status']


        order_header_location_type = ""
        if ("order_header_location_type" in diction.keys()):
            order_header_location_type = diction['order_header_location_type']
            if (len(str(order_header_location_type)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_location_type' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_location_type' fait plus de 255 caractères "
            data['order_header_location_type'] = diction['order_header_location_type']

        order_header_comment = ""
        if ("order_header_comment" in diction.keys()):
            order_header_comment = diction['order_header_comment']
            if (len(str(order_header_comment)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_comment' fait plus de 500 caractères ")

                return False, " - Le champ 'Commentaire' fait plus de 500 caractères "
            data['order_header_comment'] = diction['order_header_comment']

        order_header_condition_paiement_id = ""
        if ("order_header_condition_paiement_id" in diction.keys() and diction['order_header_condition_paiement_id']):
            order_header_condition_paiement_id = diction['order_header_condition_paiement_id']
            if (len(str(order_header_condition_paiement_id)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_condition_paiement' fait plus de 255 caractères ")

                return False, " - Le champ 'Condition de paiement' fait plus de 255 caractères "
            data['order_header_condition_paiement_id'] = diction['order_header_condition_paiement_id']

        order_header_ref_interne = ""
        if ("order_header_ref_interne" in diction.keys()):
            if diction['order_header_ref_interne']:
                order_header_ref_interne = diction['order_header_ref_interne']
                if (len(str(order_header_ref_interne)) > 255):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_header_ref_interne' fait plus de 255 caractères ")

                    return False, " - Le champ 'ref_interne' fait plus de 255 caractères "
                data['order_header_ref_interne'] = diction['order_header_ref_interne']
            else:
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - La reference interne de la commande est vide ")

                return False, " - La reference interne de la commande est vide "

        order_header_ref_client = ""
        if ("order_header_ref_client" in diction.keys()):
            order_header_ref_client = diction['order_header_ref_client']
            if (len(str(order_header_ref_client)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_ref_client' fait plus de 255 caractères ")

                return False, " - Le champ 'ref_externe' fait plus de 255 caractères "
            data['order_header_ref_client'] = diction['order_header_ref_client']

        order_header_email_client = ""
        if ("order_header_email_client" in diction.keys()):
            order_header_email_client = diction['order_header_email_client']
            if (len(str(order_header_email_client)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_email_client' fait plus de 255 caractères ")

                return False, " - Le champ 'email_client' fait plus de 255 caractères "
            data['order_header_email_client'] = diction['order_header_email_client']


        order_header_origin = ""
        if ("order_header_origin" in diction.keys()):
            order_header_origin = diction['order_header_origin']
            if (len(str(order_header_origin)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_origin' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_origin' fait plus de 255 caractères "
            data['order_header_origin'] = diction['order_header_origin']


        order_header_type_reduction = ""
        if ("order_header_type_reduction" in diction.keys()):
            order_header_type_reduction = diction['order_header_type_reduction']
            if (order_header_type_reduction not in ['fixe', 'percent', '']):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'type de reduction ' n'est pas valide ")

                return False, " - Le champ 'type de reduction ' n'est pas valide "
            data['order_header_type_reduction'] = diction['order_header_type_reduction']

             # On ne prend en charge la valeur de la reduction que si le type de reduction est 'fixe' ou 'percent'
            if (order_header_type_reduction in ['fixe', 'percent']):
                order_header_type_reduction_valeur = ""
                if ("order_header_type_reduction_valeur" in diction.keys()):
                    order_header_type_reduction_valeur = diction['order_header_type_reduction_valeur']
                    local_status, local_retval = mycommon.IsFloat(order_header_type_reduction_valeur)
                    if (local_status is False):
                        mycommon.myprint(
                            str(inspect.stack()[0][
                                    3]) + " - Le champ 'valeur de reduction ' n'est pas valide ")

                        return False, " - Le champ 'valeur de reduction ' n'est pas valide "
                    data['order_header_type_reduction_valeur'] = str(local_retval)



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

            # local_qry = {'_id': ObjectId(str(order_header_vendeur_id)), 'valide': '1', 'locked': '0', 'partner_recid': str(my_partner['recid'])}
            # print(" #### local_qry = ", local_qry)

            # Verifier que l'employé vendeur existe bien pour ce partner
            is_employee_exist_count = MYSY_GV.dbname['ressource_humaine'].count_documents(
                {'_id': ObjectId(str(order_header_vendeur_id)), 'valide': '1',
                 'locked': '0', 'partner_recid': str(my_partner['recid'])})

            if (is_employee_exist_count <= 0):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Le vendeur est invalide ")
                return False, " - Le vendeur est invalide  "

            data['order_header_vendeur_id'] = diction['order_header_vendeur_id']

        order_header_date_cmd = ""
        if ("order_header_date_cmd" in diction.keys()):
            if diction['order_header_date_cmd']:
                order_header_date_cmd = str(diction['order_header_date_cmd'])[0:10]
                local_status = mycommon.CheckisDate(order_header_date_cmd)
                if (local_status is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date order_header_date_cmd n'est pas au format 'jj/mm/aaaa' ")
                    return False, "La date de la commande n'est pas au format 'jj/mm/aaaa'"

                data['order_header_date_cmd'] = str(diction['order_header_date_cmd'])[0:10]

            else:
                # par defaut la date de la commande est la date du jour
                data['order_header_date_cmd'] = datetime.today().strftime("%d/%m/%Y")

        order_header_date_expiration = ""
        if ("order_header_date_expiration" in diction.keys()):
            order_header_date_cmd = str(diction['order_header_date_expiration'])[0:10]
            local_status = mycommon.CheckisDate(order_header_date_cmd)
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " La date order_header_date_expiration n'est pas au format 'jj/mm/aaaa' ")
                return False, "La date d'expiration de la commande n'est pas au format 'jj/mm/aaaa'"

            data['order_header_date_expiration'] = str(diction['order_header_date_expiration'])[0:10]

            ## Verification de la cohérence des dates. order_header_date_cmd doit < order_header_date_expiration
            if (datetime.strptime(str(diction['order_header_date_cmd'])[0:10], '%d/%m/%Y') >= datetime.strptime(
                    str(diction['order_header_date_expiration'])[0:10], '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - La date d'expiration  " + str(diction['order_header_date_expiration'])[
                                                                0:10] + " doit etre postérieure à la date de la commande " + str(
                        diction['order_header_date_cmd'])[0:10] + "  ")

                return False, "  - La date d'expiration  " + str(diction['order_header_date_expiration'])[
                                                             0:10] + " doit etre postérieure à la date de la commande " + str(
                    diction['order_header_date_cmd'])[0:10] + "  "

        ## Recuperation de l'adresse de facturation
        order_header_adr_fact_adresse = ""
        if ("order_header_adr_fact_adresse" in diction.keys()):
            order_header_adr_fact_adresse = diction['order_header_adr_fact_adresse']
            if (len(str(order_header_adr_fact_adresse)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_adresse' fait plus de 500 caractères ")

                return False, " - Le champ 'adresse de facturation' fait plus de 500 caractères "
            data['order_header_adr_fact_adresse'] = diction['order_header_adr_fact_adresse']

        order_header_adr_fact_code_postal = ""
        if ("order_header_adr_fact_code_postal" in diction.keys()):
            order_header_adr_fact_code_postal = diction['order_header_adr_fact_code_postal']
            if (len(str(order_header_adr_fact_code_postal)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_fact_code_postal' fait plus de 255 caractères "
            data['order_header_adr_fact_code_postal'] = diction['order_header_adr_fact_code_postal']

        order_header_adr_fact_ville = ""
        if ("order_header_adr_fact_ville" in diction.keys()):
            order_header_adr_fact_ville = diction['order_header_adr_fact_ville']
            if (len(str(order_header_adr_fact_ville)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_fact_ville' fait plus de 255 caractères "
            data['order_header_adr_fact_ville'] = diction['order_header_adr_fact_ville']

        order_header_adr_fact_pays = ""
        if ("order_header_adr_fact_pays" in diction.keys()):
            order_header_adr_fact_pays = diction['order_header_adr_fact_pays']
            if (len(str(order_header_adr_fact_pays)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_fact_pays' fait plus de 255 caractères "
            data['order_header_adr_fact_pays'] = diction['order_header_adr_fact_pays']

        ## Recuperation de l'adresse d'exécution de la formation
        order_header_adr_liv_adresse = ""
        if ("order_header_adr_liv_adresse" in diction.keys()):
            order_header_adr_liv_adresse = diction['order_header_adr_liv_adresse']
            if (len(str(order_header_adr_liv_adresse)) > 500):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_adresse' fait plus de 500 caractères ")

                return False, " - Le champ 'adresse d'exécution' fait plus de 500 caractères "
            data['order_header_adr_liv_adresse'] = diction['order_header_adr_liv_adresse']

        order_header_adr_liv_code_postal = ""
        if ("order_header_adr_liv_code_postal" in diction.keys()):
            order_header_adr_liv_code_postal = diction['order_header_adr_liv_code_postal']
            if (len(str(order_header_adr_liv_code_postal)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_liv_code_postal' fait plus de 255 caractères "
            data['order_header_adr_liv_code_postal'] = diction['order_header_adr_liv_code_postal']

        order_header_adr_liv_ville = ""
        if ("order_header_adr_liv_ville" in diction.keys()):
            order_header_adr_liv_ville = diction['order_header_adr_liv_ville']
            if (len(str(order_header_adr_liv_ville)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_liv_ville' fait plus de 255 caractères "
            data['order_header_adr_liv_ville'] = diction['order_header_adr_liv_ville']

        order_header_adr_liv_pays = ""
        if ("order_header_adr_liv_pays" in diction.keys()):
            order_header_adr_liv_pays = diction['order_header_adr_liv_pays']
            if (len(str(order_header_adr_liv_pays)) > 255):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères ")

                return False, " - Le champ 'order_header_adr_liv_pays' fait plus de 255 caractères "
            data['order_header_adr_liv_pays'] = diction['order_header_adr_liv_pays']

        """

        /!\ : A present que tous les controles sont ok, on va proceder à la creation dans les table.

        """

        ### 1 - Mise à jour de l'entete

        data['date_update'] = str(datetime.now())
        data['update_by'] = str(my_partner['_id'])

        print(" ### Update_partner_order data = ", data)

        inserted_data = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0','order_header_type':'devis',
             '_id': ObjectId(str(order_header_id))},
            {"$set": data},
            return_document=ReturnDocument.AFTER,
            upsert=False,
        )

        if (inserted_data is None):
            mycommon.myprint(
                " Impossible de mettre à jour l'entete du devis ")
            return False, "Impossible de mettre à jour l'entete du devis  "

        """
                Si le statut de l'entete de commande a bougé, alors on met à le statut de toutes les ligne
                Verification my_order_data_previous_information['order_header_status'] != order_header_status
                """

        local_qry = {'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0',
                     'order_header_id': str(order_header_id)
                     },

        #print(" #### DEVIS local_qry = ",local_qry )

        if( "order_header_status" in my_order_data_previous_information.keys()):
            if (str(my_order_data_previous_information['order_header_status']) != str(order_header_status)):
                # Il y a eu une mise à jour du statut de l'entete, on va donc mettre à jour les statuts des lignes de commande
                inserted_data_line = MYSY_GV.dbname['partner_order_line'].update_many(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0',
                     'order_header_id': str(order_header_id)
                     },
                    {
                        "$set": {"order_line_status": str(order_header_status), "order_line_type": str(my_order_data_previous_information['order_header_type']),
                                 'date_update': str(data['date_update'])}
                    })
                """print("raw:", inserted_data_line.raw_result)
                print("acknowledged:", inserted_data_line.acknowledged)
                print("matched_count:", inserted_data_line.matched_count)"""

        else:
            inserted_data_line = MYSY_GV.dbname['partner_order_line'].update_many(
                {'partner_owner_recid': str(my_partner['recid']),
                 'valide': '1', 'locked': '0',
                 'order_header_id': str(order_header_id)
                 },
                {
                    "$set": {"order_line_status": str(order_header_status), "order_line_type": str(my_order_data_previous_information['order_header_type']),
                             'date_update': str(data['date_update'])}
                })
            """print("raw:", inserted_data_line.raw_result)
            print("acknowledged:", inserted_data_line.acknowledged)
            print("matched_count:", inserted_data_line.matched_count)"""

        return True, " Le devis a été correctement mis à jour"

    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 mettre à jour le devis "


"""
Fonction ajoute des lignes à une commande qui existe.
Clé : 
 - order_header_id
 - order_header_ref_interne
 - partner_owner_recid
 """
def Add_Update_Partner_Order_Line(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_line_formation', 'order_line_session_id', 'order_line_qty', 'order_line_prix_unitaire',
                      'order_line_tax', 'order_line_type_reduction', 'order_line_type_valeur',
                      'order_line_montant_reduction', 'order_line_id', 'order_header_ref_interne',
                      'order_header_id', 'order_line_status', 'order_line_type', 'order_line_comment',
                      'order_line_montant_hors_taxes', 'order_line_tax_amount', 'order_line_montant_toutes_taxes']



        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")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'order_line_formation', "order_line_qty", "order_line_prix_unitaire",
                                  'order_line_id', 'order_header_ref_interne', 'order_header_id',
                                  'order_line_status', 'order_line_type']

        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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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


        data = {}

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


        # Si l'utilisateur a choisi une session, verifier qu'elle est valide
        order_line_session_id = ""
        if( "order_line_session_id" in diction.keys() and diction['order_line_session_id']):
            is_valide_session_id_count = MYSY_GV.dbname['session_formation'].count_documents({'_id':ObjectId(str(diction['order_line_session_id'])),
                                                                                        'partner_owner_recid':str(my_partner['recid']),
                                                                                        'valide':'1'})

            if( is_valide_session_id_count <= 0 ):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " L'identifiant de session de formation  "+str(diction['order_line_session_id'])+" n'est pas valide ")
                return False, " L'identifiant de session de formation  "+str(diction['order_line_session_id'])+" n'est pas valide "

            order_line_session_id = str(diction['order_line_session_id'])
            data['order_line_session_id'] = order_line_session_id


        order_line_type = ""
        if ("order_line_type" in diction.keys()):
            if diction['order_line_type']:
                order_line_type = diction['order_line_type']
                data['order_line_type'] = order_line_type
                if( order_line_type not in MYSY_GV.PARTNER_ORDER_TYPE):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " - La valeur du champ 'order_line_type' est invalide. Les valeurs acceptées :"+str(MYSY_GV.PARTNER_ORDER_TYPE))
                    return False, "  La valeur du champ 'order_line_type' est invalide. Les valeurs acceptées :"+str(MYSY_GV.PARTNER_ORDER_TYPE)

        order_line_status = ""
        if ("order_line_status" in diction.keys()):
            if diction['order_line_status']:
                order_line_status = diction['order_line_status']
                data['order_line_status'] = order_line_status
                if( order_line_type == "commande"):
                    if (order_line_status not in MYSY_GV.PARTNER_ORDER_STATUS):
                        mycommon.myprint(
                            str(inspect.stack()[0][
                                    3]) + " - La valeur du champ 'order_line_type' est invalide. Les valeurs acceptées :" + str(
                                MYSY_GV.PARTNER_ORDER_STATUS))
                        return False, "  La valeur du champ 'order_line_type' est invalide. Les valeurs acceptées :" + str(
                            MYSY_GV.PARTNER_ORDER_STATUS)

                if (order_line_type == "devis"):
                    if (order_line_status not in MYSY_GV.PARTNER_QUOTATION_STATUS):
                        mycommon.myprint(
                            str(inspect.stack()[0][
                                    3]) + " - La valeur du champ 'order_line_type' est invalide. Les valeurs acceptées :" + str(
                                MYSY_GV.PARTNER_QUOTATION_STATUS))
                        return False, "  La valeur du champ 'order_line_type' est invalide. Les valeurs acceptées :" + str(
                            MYSY_GV.PARTNER_QUOTATION_STATUS)



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

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

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

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

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

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


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

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

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

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

        order_line_comment = ""
        if ("order_line_comment" in diction.keys()):
            if diction['order_line_comment']:
                order_line_comment = diction['order_line_comment']
                data['order_line_comment'] = order_line_comment
                if(len(str(order_line_comment)) > 500):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " - Le champ 'order_line_comment' fait plus de 500 caractères ")

                    return False, " - Le champ 'Commentaire de la ligne' fait plus de 500 caractères "

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


        order_line_id = ""
        if ("order_line_id" in diction.keys() and len(str(diction['order_line_id'])) > 0 ) :
            # il s'agit de mettre à jour la ligne. Il faut verifier que la ligne existe et est modifiable
            order_line_id = diction['order_line_id']
            existe_order_line_count = MYSY_GV.dbname['partner_order_line'].count_documents({'_id':ObjectId(str(order_line_id)), 'valide':'1', 'locked':'0',
                                                                                            'partner_owner_recid':str(my_partner['recid'])})

            if( existe_order_line_count != 1 ):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - La ligne à mettre à jour est invalide")
                return False, "La ligne à mettre à jour est invalide",

            data['date_update'] = str(datetime.now())
            data['update_by'] = str(my_partner['_id'])

            inserted_data = MYSY_GV.dbname['partner_order_line'].find_one_and_update(
                {'_id': ObjectId(str(order_line_id)), 'valide': '1', 'locked': '0',
                 'partner_owner_recid': str(my_partner['recid'])},
                {"$set": data},
                return_document=ReturnDocument.AFTER,
                upsert=False,
            )

            if (inserted_data is None):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la ligne (3)")
                return False, " Impossible de mettre à jour la ligne (3) "

            """
            Une fois qu'on a modifier une ligne, il faut remettre les statuts d'entete et de ligne à 'brouillon'
            pour obligier l'utilisateur à revalider le devis
            """

            local_update_data = {}
            local_update_data['date_update'] = str(datetime.now())
            local_update_data['update_by'] = str(my_partner['_id'])
            local_update_data['order_header_status'] = "0"

            upadate_header = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
                {'_id': ObjectId(str(diction['order_header_id'])), 'valide': '1', 'locked': '0',
                 'partner_owner_recid': str(my_partner['recid'])},
                {"$set": local_update_data},
                return_document=ReturnDocument.AFTER,
                upsert=False,
            )

            local_update_data = {}
            local_update_data['date_update'] = str(datetime.now())
            local_update_data['update_by'] = str(my_partner['_id'])
            local_update_data['order_line_status'] = "0"

            upadate_line = MYSY_GV.dbname['partner_order_line'].find_one_and_update(
                {'order_header_id': str(diction['order_header_id']), 'valide': '1', 'locked': '0',
                 'partner_owner_recid': str(my_partner['recid'])},
                {"$set": local_update_data},
                return_document=ReturnDocument.AFTER,
                upsert=False,
            )

        else:
            # Il s'agit d'une creation d'une nouvelle ligne
            data['valide'] = '1'
            data['locked'] = '0'
            data['date_update'] = str(datetime.now())
            data['partner_owner_recid'] = my_partner['recid']
            data['update_by'] = str(my_partner['_id'])

            inserted_line_id = ""

            inserted_line_id = MYSY_GV.dbname['partner_order_line'].insert_one(data).inserted_id
            if (not inserted_line_id):
                mycommon.myprint(
                    " Impossible de créer la ligne la commande ")
                return False, " Impossible de créer la ligne la commande  "

            """
                        Une fois qu'on a modifier une ligne, il faut remettre les statuts d'entete et de ligne à 'brouillon'
                        pour obligier l'utilisateur à revalider le devis
                        """


            local_update_data = {}
            local_update_data['date_update'] = str(datetime.now())
            local_update_data['update_by'] = str(my_partner['_id'])
            local_update_data['order_header_status'] = "0"

            upadate_header = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
                {'_id': ObjectId(str(diction['order_header_id'])), 'valide': '1', 'locked': '0',
                 'partner_owner_recid': str(my_partner['recid'])},
                {"$set": local_update_data},
                return_document=ReturnDocument.AFTER,
                upsert=False,
            )

            local_update_data = {}
            local_update_data['date_update'] = str(datetime.now())
            local_update_data['update_by'] = str(my_partner['_id'])
            local_update_data['order_line_status'] = "0"

            upadate_line = MYSY_GV.dbname['partner_order_line'].find_one_and_update(
                {'order_header_id': str(diction['order_header_id']), 'valide': '1', 'locked': '0',
                 'partner_owner_recid': str(my_partner['recid'])},
                {"$set": local_update_data},
                return_document=ReturnDocument.AFTER,
                upsert=False,
            )



        return True, " La ligne de commande a été correctement ajoutée/mise à jour"

    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 / mettre à jour la ligne de commande "



""" 
Fonction qui permet de confirmer un document, passer du statut brouillon, au statut confirmé, 
pour devis et pr commande.

Seules order au statut : Brouillon ou En cours, sont confirmables.

/!\ : Apres la confirmation, on procede au calcul des totaux (compute Order)
"""
def Confirm_Partner_Order_Header_And_Lines(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token',  'order_header_id', ]

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token',  'order_header_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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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


        my_order_data_count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})

        if (my_order_data_count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la commande est invalide ")
            return False, " L'identifiant de la commande est invalide",

        """
        Recuperation et stockage des données de l'entete avant mise à jour
        """
        my_order_data_previous_information = MYSY_GV.dbname['partner_order_header'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})



        if( str(my_order_data_previous_information['order_header_status']) != "0" and str(my_order_data_previous_information['order_header_status']) != "1"):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Le document doit être au statut 'en cours' ou 'brouillon' pour avant d'être confirmé ")
            return False, " Le document doit être au statut 'en cours' ou 'brouillon' avant d'être confirmé  ",


        # Si la l'order est un devis, on verifie s'il n'a pas expiré
        mytoday = datetime.today().strftime("%d/%m/%Y")
        if ( str(my_order_data_previous_information['order_header_date_expiration']) == "devis" and "order_header_date_expiration" in my_order_data_previous_information.keys() and len(
                str(my_order_data_previous_information['order_header_date_expiration']).strip()) > 0):
            if (datetime.strptime(str(my_order_data_previous_information['order_header_date_expiration']).strip(),
                                  '%d/%m/%Y') < datetime.strptime(str(mytoday), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - Le devis a expiré ")
                return False, " Le devis a expiré", False

        """

        /!\ : A present que tous les controles sont ok, on va proceder à la creation dans les table.

        """

        ### 1 - Mise à jour de l'entete
        # Recuperation des champs
        data = {}
        data['date_update'] = str(datetime.now())
        data['order_header_status'] = "1"
        data['update_by'] = str(my_partner['_id'])

        print(" ### Update_partner_order data = ", data)

        inserted_data = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))},
            {"$set": data},
            return_document=ReturnDocument.AFTER,
            upsert=False,
        )

        if (inserted_data is None):
            mycommon.myprint(
                " Impossible de mettre à jour l'entete de commande ")
            return False, "Impossible de mettre à jour l'entete de commande  "

        """
       Mise à jour des lignes (partner_order_line) dont les status sont à 0 (brouillon) 
        """
        local_qry = {'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0',
                     'order_header_id': str(order_header_id)
                     }
        # print(" #### COMMANDE local_qry = ", local_qry)

        inserted_data_line = MYSY_GV.dbname['partner_order_line'].update_many(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             'order_header_id': str(order_header_id),
             'order_line_status':'0'
             },
            {
                "$set": {"order_line_status": "1",
                         'date_update': str(data['date_update'])}
            })
        """print("raw:", inserted_data_line.raw_result)
        print("acknowledged:", inserted_data_line.acknowledged)
        print("matched_count:", inserted_data_line.matched_count)"""

        comput_diction = {}
        comput_diction['token'] = diction['token']
        comput_diction['_id'] = diction['order_header_id']

        local_retval, local_message = Compute_Order_Header(comput_diction)
        if( local_retval is False) :
            mycommon.myprint(" WARNING : Apres la confirmation, La fonction compute pour l'ordre : "+str(comput_diction)+" n'a pas fonctionnée, ")

        return True, " Le document a été correctement mise à jour"

    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 confirmer le document  "

"""
Fonction qui annulle un order. Seules order au statut : Brouillon ou En cours, sont annulables.
"""
def Annule_Partner_Order_Header_And_Lines(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token',  'order_header_id', ]

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token',  'order_header_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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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


        my_order_data_count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})

        if (my_order_data_count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la commande est invalide ")
            return False, " L'identifiant de la commande est invalide",

        """
        Recuperation et stockage des données de l'entete avant mise à jour
        """
        my_order_data_previous_information = MYSY_GV.dbname['partner_order_header'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})



        if( str(my_order_data_previous_information['order_header_status']) != "0" and str(my_order_data_previous_information['order_header_status']) != "1"):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Le document doit être au statut 'en cours' ou 'brouillon' pour avant d'être annulé ")
            return False, " Le document doit être au statut 'en cours' ou 'brouillon' pour avant d'être annulé  ",


        """

        /!\ : A present que tous les controles sont ok, on va proceder à la creation dans les table.

        """

        ### 1 - Mise à jour de l'entete
        # Recuperation des champs
        data = {}
        data['date_update'] = str(datetime.now())
        data['order_header_status'] = "-1"

        print(" ### Update_partner_order data = ", data)

        inserted_data = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))},
            {"$set": data},
            return_document=ReturnDocument.AFTER,
            upsert=False,
        )

        if (inserted_data is None):
            mycommon.myprint(
                " Impossible de mettre à jour l'entete de commande ")
            return False, "Impossible de mettre à jour l'entete de commande  "

        """
       Mise à jour des lignes (partner_order_line) dont les status sont à 0 (brouillon) 
        """
        local_qry = {'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0',
                     'order_header_id': str(order_header_id)
                     }
        # print(" #### COMMANDE local_qry = ", local_qry)

        inserted_data_line = MYSY_GV.dbname['partner_order_line'].update_many(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             'order_header_id': str(order_header_id),
             'order_line_status':'0'
             },
            {
                "$set": {"order_line_status": "-1",
                         'date_update': str(data['date_update'])}
            })
        """print("raw:", inserted_data_line.raw_result)
        print("acknowledged:", inserted_data_line.acknowledged)
        print("matched_count:", inserted_data_line.matched_count)"""


        return True, " Le document a été correctement annulé"

    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'annuler le document  "



"""
Fonction de suppression d'une commande client (entete et ligne) si son statut le permet en prenant le '_id'

un devis est supprimable à tout moment, mais une commande FACTURE ou TRAITE n'est pas supprimable
•	2 => Traité (prêt à être facturée)
•	3 => Facturé (la facture est traitée dans un autre document).
"""
def Delete_Partner_Order_Header_And_Lines(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_id']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'order_header_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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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

        """ 
        #  Verifier que la commande existe et qu'elle est supprimable.
        Pour les ligne, on fait pareil, on ne peut modifier que celles qui sont modifiable.

        
        """
        my_order_data_count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})

        if (my_order_data_count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la commande est invalide ")
            return False, " L'identifiant de la commande est invalide",


        # Verifier que la commande / devis  est supprimable :
        my_order_data = MYSY_GV.dbname['partner_order_header'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})

        if( my_order_data['order_header_type'] == "commande" and my_order_data['order_header_status'] == "2"):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Cette commande a été traitée, impossible de la supprimer")
            return False, " Cette commande a été traitée, impossible de la supprimer",

        if (my_order_data['order_header_type'] == "commande" and my_order_data[
            'order_header_status'] == "3"):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Cette commande a été facturée, impossible de la supprimer")
            return False, " Cette commande a été facturée, impossible de la supprimer",


        # Verifier qu'il n'y pas des lignes (partner_order_line) traitée ou facturé... (cas des facturations partielles à venir)

        qry_line_count_cancel =  {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             'order_header_id': str(order_header_id),
             'order_header_ref_interne':str(my_order_data['order_header_ref_interne']),
             'order_line_status':{'$in':['2', '3']}}

        print(" #### qry_line_count_cancel = ", qry_line_count_cancel)

        my_order_line_not_cancel_data_count = MYSY_GV.dbname['partner_order_line'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             'order_header_id': str(order_header_id),
             'order_header_ref_interne':str(my_order_data['order_header_ref_interne']),
             'order_line_status':{'$in':['2', '3']}})

        if( my_order_line_not_cancel_data_count > 0 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Cette commande contient des lignes traitées ou facturées. Impossible de supprimer le document ")
            return False, " Cette commande contient des lignes traitées ou facturées. Impossible de supprimer le document ",

        # Recuperation des champs
        data = {}
        data['partner_owner_recid'] = my_partner['recid']



        delete_data = MYSY_GV.dbname['partner_order_header'].delete_one(
            {'partner_owner_recid': str(my_partner['recid']),
             '_id': ObjectId(str(order_header_id))}, )


        if( delete_data is None or delete_data.deleted_count < 0 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Impossible de supprimer la commande (2) ")
            return False, "  - Impossible de supprimer la commande (2)  ",


        # A present,suppression des lignes de la commande

        delete_data_order_lines = MYSY_GV.dbname['partner_order_line'].delete_many(
            {'partner_owner_recid': str(my_partner['recid']),
             'order_header_id': str(order_header_id)}, )


        return True, " La commande 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de supprimer la commande "



"""
Fonction de suppression d'une commande client (entete et ligne) si son statut le permet, en prenant le 'order_header_ref_interne'
"""
def Delete_Partner_Order_Header_And_Lines_From_order_reference(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_ref_interne']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'order_header_ref_interne', ]

        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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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

        """ 
        #  Verifier que la commande existe et qu'elle est supprimable.
        Pour les ligne, on fait pareil, on ne peut modifier que celles qui sont modifiable.

        Conditions pour modifier entete  : 
        1 - statut est : annulé, devis, cmd, MAIS PAS  FACTURE
        Pour un debut pas de facturation partielle. c'est tout ou rien.
        """
        my_order_data_count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             'order_header_ref_interne': str(order_header_ref_interne)})

        if (my_order_data_count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la commande est invalide ")
            return False, " L'identifiant de la commande est invalide",



        delete_data = MYSY_GV.dbname['partner_order_header'].delete_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'order_header_ref_interne': str(order_header_ref_interne)}, )


        if( delete_data is None or delete_data.deleted_count < 0 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Impossible de supprimer la commande (2) ")
            return False, "  - Impossible de supprimer la commande (2)  ",


        # A present,suppression des lignes de la commande

        delete_data_order_lines = MYSY_GV.dbname['partner_order_line'].delete_many(
            {'partner_owner_recid': str(my_partner['recid']),
             'order_header_ref_interne': str(order_header_ref_interne)}, )


        return True, " La commande 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de supprimer la commande "



"""
Fonction de suppression d'une ligne d'une commande
"""
def Delete_Partner_Order_Line(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_id', 'order_line_id']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'order_header_id', 'order_line_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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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

        """ 
        #  Verifier que la commande existe et qu'elle est supprimable.
        Pour les ligne, on fait pareil, on ne peut modifier que celles qui sont modifiable.

        Conditions pour modifier entete  : 
        1 - statut est : annulé, devis, cmd, MAIS PAS  FACTURE
        Pour un debut pas de facturation partielle. c'est tout ou rien.
        """
        my_order_data_count = MYSY_GV.dbname['partner_order_line'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']), 'order_header_id':str(diction['order_header_id']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_line_id))})

        if (my_order_data_count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la ligne est invalide ")
            return False, " L'identifiant de la ligne est invalide",



        delete_data = MYSY_GV.dbname['partner_order_line'].delete_one(
            {'partner_owner_recid': str(my_partner['recid']), 'order_header_id':str(diction['order_header_id']),
             '_id': ObjectId(str(order_line_id))} )


        if( delete_data is None or delete_data.deleted_count < 0 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Impossible de supprimer la ligne de commande (2) ")
            return False, "  - Impossible de supprimer la ligne de commande (2)  ",



        return True, " La ligne de la commande 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de supprimer la ligne de la commande"


"""
Recuperation d'une commande donnée à partir du '_id'
"""
def Get_Given_Partner_Order(diction):
    try:

        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', '_id']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'existe pas")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', '_id']
        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        """
        Clés de mise à jour 
        """
        data_cle = {}
        data_cle['partner_owner_recid'] = str(my_partner['recid'])
        data_cle['_id'] = ObjectId(str(diction['_id']))

        data_cle['valide'] = "1"
        data_cle['locked'] = "0"

        RetObject = []
        val_tmp = 1

        #print(" ### data_cle = ", data_cle)
        for retval in MYSY_GV.dbname['partner_order_header'].find(data_cle):
            user = retval
            user['id'] = str(val_tmp)
            val_tmp = val_tmp + 1

            # Si le champ 'order_header_condition_paiement_id' alors on va chercher le code de la condition de paiement
            paiement_ction_code = ""
            if ('order_header_condition_paiement_id' in retval.keys() and retval['order_header_condition_paiement_id'] ):
                paiement_ction_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
                    {'_id': ObjectId(str(retval['order_header_condition_paiement_id'])), 'valide': '1', 'locked': '0',
                     'partner_owner_recid': str(my_partner['recid'])})

                if (paiement_ction_data and 'code' in paiement_ction_data.keys()):
                    paiement_ction_code = str(paiement_ction_data['code'])
            user['order_header_paiement_condition_code'] = paiement_ction_code
            #print(" #### paiement_ction_code = ", paiement_ction_code)
            #print(" #### retval['order_header_condition_paiement_id'] = ", retval['order_header_condition_paiement_id'])


            # Si le champ 'order_header_client_id' alors on va chercher le nom du client
            order_header_client_nom = ""
            if ('order_header_client_id' in retval.keys() and retval['order_header_client_id']):
                Client_data = MYSY_GV.dbname['partner_client'].find_one(
                    {'_id': ObjectId(str(retval['order_header_client_id'])), 'valide': '1', 'locked': '0',
                     'partner_recid': str(my_partner['recid'])})

                if (Client_data and 'nom' in Client_data.keys()):
                    order_header_client_nom = str(Client_data['nom'])
            user['order_header_client_nom'] = order_header_client_nom


            # Si le champ 'order_header_vendeur_id' alors on va chercher le nom et prenom du vendeur (employe)
            order_header_vendeur_nom_prenom = ""
            if ('order_header_vendeur_id' in retval.keys() and retval['order_header_vendeur_id']):
                Employee_data = MYSY_GV.dbname['ressource_humaine'].find_one(
                    {'_id': ObjectId(str(retval['order_header_vendeur_id'])), 'valide': '1', 'locked': '0',
                     'partner_recid': str(my_partner['recid'])})

                order_header_vendeur_nom_prenom = ""
                if (Employee_data and 'nom' in Employee_data.keys()):
                    order_header_vendeur_nom_prenom = str(Employee_data['nom'])

                if (Employee_data and 'prenom' in Employee_data.keys()):
                    order_header_vendeur_nom_prenom = str(order_header_vendeur_nom_prenom) + " " + str(
                        Employee_data['prenom'])

                order_header_vendeur_nom_prenom = str(order_header_vendeur_nom_prenom)

            user['order_header_vendeur_nom_prenom'] = order_header_vendeur_nom_prenom

            # Recuperation des ligne associées
            retval_line_data = []
            for retval_line in MYSY_GV.dbname['partner_order_line'].find({'order_header_id':str(retval['_id']), 'partner_owner_recid':str(my_partner['recid']),
                                                                          'valide':'1', 'locked':'0'}):

                retval_line_data.append(retval_line)


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

        print(" ### RetObject Get_Given_Partner_Order = ", 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de récupérer les données de la commande "


"""
Recuperation des lignes d'une commande à partir de l'order_header_id, sans entete
"""
def Get_Given_Partner_Order_Lines(diction):
    try:

        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_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'existe pas")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'order_header_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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        """
        Clés de mise à jour 
        """
        data_cle = {}
        data_cle['partner_owner_recid'] = str(my_partner['recid'])
        data_cle['order_header_id'] = str(diction['order_header_id'])

        data_cle['valide'] = "1"
        data_cle['locked'] = "0"

        RetObject = []
        val_tmp = 1

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

        query = [{'$match': {'$and': [ filt_order_header_id,
                                      {'partner_owner_recid': str(my_partner['recid'])}]}},
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'order_line_formation',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'$and': [ filt_class_partner_recid]}},
                                      {'$project': {'title': 1, 'domaine': 1, '_id':1,
                                                    'duration': 1,
                                                    'duration_unit': 1,'external_code':1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]
        #print("#### Get_Given_Partner_Order_Lines  : query pip= ", query)

        for retval in MYSY_GV.dbname['partner_order_line'].aggregate(query):
            if ('myclass_collection' in retval.keys() and len(retval['myclass_collection']) > 0):
                user = {}
                user['id'] = str(val_tmp)
                val_tmp = val_tmp + 1
                user['_id'] = retval['_id']
                user['order_line_formation'] = retval['order_line_formation']
                user['order_line_qty'] = retval['order_line_qty']
                user['order_line_prix_unitaire'] = retval['order_line_prix_unitaire']
                user['order_header_id'] = retval['order_header_id']
                user['order_header_ref_interne'] = retval['order_header_ref_interne']
                user['valide'] = retval['valide']
                user['locked'] = retval['locked']

                if( "order_line_session_id" in retval.keys() ):
                    user['order_line_session_id'] = retval['order_line_session_id']

                    # Recuperation du code de la session
                    local_session_data = MYSY_GV.dbname['session_formation'].find_one({'_id':ObjectId(str(retval['order_line_session_id'])),
                                                                                       'partner_owner_recid':str(my_partner['recid']),
                                                                                       'valide':'1'})
                    if( local_session_data and "code_session" in local_session_data.keys() ):
                        user['order_line_session_code_session'] = local_session_data['code_session']
                    else:
                        user['order_line_session_code_session'] = ""
                else:
                    user['order_line_session_id'] = ""
                    user['order_line_session_code_session'] = ""


                if ("order_line_montant_reduction" in retval.keys()):
                    user['order_line_montant_reduction'] = retval['order_line_montant_reduction']
                else:
                    user['order_line_montant_reduction'] = "0"

                if ("order_line_montant_toutes_taxes" in retval.keys()):
                    user['order_line_montant_toutes_taxes'] = retval['order_line_montant_toutes_taxes']
                else:
                    user['order_line_montant_toutes_taxes'] = "0"

                if ("order_line_tax" in retval.keys()):
                    user['order_line_tax'] = retval['order_line_tax']
                else:
                    user['order_line_tax'] = ""

                if ("order_line_tax_amount" in retval.keys()):
                    user['order_line_tax_amount'] = retval['order_line_tax_amount']
                else:
                    user['order_line_tax_amount'] = "0"

                if ("order_line_type_reduction" in retval.keys()):
                    user['order_line_type_reduction'] = retval['order_line_type_reduction']
                else:
                    user['order_line_montant_reduction'] = ""

                if ("order_line_type_valeur" in retval.keys()):
                    user['order_line_type_valeur'] = retval['order_line_type_valeur']
                else:
                    user['order_line_type_valeur'] = "0"


                if ("order_line_montant_hors_taxes" in retval.keys()):
                    user['order_line_montant_hors_taxes'] = retval['order_line_montant_hors_taxes']
                else:
                    user['order_line_montant_hors_taxes'] = "0"


                user['date_update'] = retval['date_update']
                user['partner_owner_recid'] = retval['partner_owner_recid']
                user['order_line_type'] = retval['order_line_type']
                user['order_line_status'] = retval['order_line_status']

                if( "order_line_comment" in retval.keys()):
                    user['order_line_comment'] = retval['order_line_comment']
                else:
                    user['order_line_comment'] = ""

                user['title'] = retval['myclass_collection'][0]['title']
                user['order_line_formation_external_code'] = retval['myclass_collection'][0]['external_code']

                if( "domaine" in retval['myclass_collection'][0].keys() ):
                    user['domaine'] = retval['myclass_collection'][0]['domaine']
                else:
                    user['domaine'] = ""

                user['duration'] = retval['myclass_collection'][0]['duration']
                user['duration_unit'] = retval['myclass_collection'][0]['duration_unit']

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

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

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

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

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

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

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

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



        #print(" ### RetObject = ", 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de récupérer les lignes de commande "


"""
Recuperation des lignes d'une commande à partir de l' order_header_ref_interne, sans entete
"""
def Get_Given_Partner_Order_Lines_From_order_ref_interne(diction):
    try:

        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_header_ref_interne']

        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")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'order_header_ref_interne']
        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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        """
        Clés de mise à jour 
        """
        data_cle = {}
        data_cle['partner_owner_recid'] = str(my_partner['recid'])
        data_cle['order_header_ref_interne'] = str(diction['order_header_ref_interne'])

        data_cle['valide'] = "1"
        data_cle['locked'] = "0"

        RetObject = []
        val_tmp = 1

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

        query = [{'$match': {'$and': [filt_order_header_ref_interne,
                                      {'partner_owner_recid': str(my_partner['recid'])}]}},
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'order_line_formation',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'$and': [ filt_class_partner_recid]}},
                                      {'$project': {'title': 1, 'domaine': 1,
                                                    'duration': 1,
                                                    'duration_unit': 1,'external_code':1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]
        #print("#### Get_Given_Partner_Order_Lines_From_order_ref_interne  : query pip= ", query)

        for retval in MYSY_GV.dbname['partner_order_line'].aggregate(query):
            if ('myclass_collection' in retval.keys() and len(retval['myclass_collection']) > 0):
                user = {}
                user['id'] = str(val_tmp)
                val_tmp = val_tmp + 1
                user['_id'] = retval['_id']
                user['order_line_formation'] = retval['order_line_formation']
                user['order_line_qty'] = retval['order_line_qty']
                user['order_line_prix_unitaire'] = retval['order_line_prix_unitaire']
                user['order_header_id'] = retval['order_header_id']
                user['order_header_ref_interne'] = retval['order_header_ref_interne']
                user['valide'] = retval['valide']
                user['locked'] = retval['locked']

                if ("order_line_session_id" in retval.keys()):
                    user['order_line_session_id'] = retval['order_line_session_id']

                    # Recuperation du code de la session
                    local_session_data = MYSY_GV.dbname['session_formation'].find_one(
                        {'_id': ObjectId(str(retval['order_line_session_id'])),
                         'partner_owner_recid': str(my_partner['recid']),
                         'valide': '1'})
                    if (local_session_data and "code_session" in local_session_data.keys()):
                        user['order_line_session_code_session'] = local_session_data['code_session']
                    else:
                        user['order_line_session_code_session'] = ""
                else:
                    user['order_line_session_id'] = ""
                    user['order_line_session_code_session'] = ""


                if( "order_line_montant_reduction" in retval.keys()):
                    user['order_line_montant_reduction'] = retval['order_line_montant_reduction']
                else:
                    user['order_line_montant_reduction'] = "0"

                if ("order_line_montant_toutes_taxes" in retval.keys()):
                    user['order_line_montant_toutes_taxes'] = retval['order_line_montant_toutes_taxes']
                else:
                    user['order_line_montant_toutes_taxes'] = "0"

                if( "order_line_tax" in retval.keys()):
                    user['order_line_tax'] = retval['order_line_tax']
                else:
                    user['order_line_tax'] = ""

                if( "order_line_tax_amount" in retval.keys()):
                    user['order_line_tax_amount'] = retval['order_line_tax_amount']
                else:
                    user['order_line_tax_amount'] = "0"

                if( "order_line_type_reduction" in retval.keys()):
                    user['order_line_type_reduction'] = retval['order_line_type_reduction']
                else:
                    user['order_line_montant_reduction'] = ""

                if( "order_line_type_valeur" in retval.keys()):
                    user['order_line_type_valeur'] = retval['order_line_type_valeur']
                else:
                    user['order_line_type_valeur'] = "0"

                if ("order_line_montant_hors_taxes" in retval.keys()):
                    user['order_line_montant_hors_taxes'] = retval['order_line_montant_hors_taxes']
                else:
                    user['order_line_montant_hors_taxes'] = "0"


                user['date_update'] = retval['date_update']
                user['partner_owner_recid'] = retval['partner_owner_recid']
                user['order_line_type'] = retval['order_line_type']
                user['order_line_status'] = retval['order_line_status']
                if ("order_line_comment" in retval.keys()):
                    user['order_line_comment'] = retval['order_line_comment']
                else:
                    user['order_line_comment'] = ""

                user['title'] = retval['myclass_collection'][0]['title']
                user['order_line_formation_external_code'] = retval['myclass_collection'][0]['external_code']

                if ("domaine" in retval['myclass_collection'][0].keys()):
                    user['domaine'] = retval['myclass_collection'][0]['domaine']
                else:
                    user['domaine'] = ""

                user['duration'] = retval['myclass_collection'][0]['duration']
                user['duration_unit'] = retval['myclass_collection'][0]['duration_unit']

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

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

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

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

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

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

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


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


        #print(" ### RetObject = ", 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de récupérer les lignes de commande "



"""
Recuperation d'un commande en partant de la reference interne et du token
"""

def Get_Given_Partner_Order_From_Internal_ref(diction):
    try:

        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'internal_ref']

        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")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'internal_ref']
        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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        """
        Clés de mise à jour 
        """
        data_cle = {}
        data_cle['partner_owner_recid'] = str(my_partner['recid'])
        data_cle['order_header_ref_interne'] = str(diction['internal_ref'])

        data_cle['valide'] = "1"
        data_cle['locked'] = "0"

        RetObject = []
        val_tmp = 1

        # print(" ### data_cle = ", data_cle)
        for retval in MYSY_GV.dbname['partner_order_header'].find(data_cle):
            user = retval
            user['id'] = str(val_tmp)
            val_tmp = val_tmp + 1

            # Si le champ 'order_header_condition_paiement_id' alors on va chercher le code de la condition de paiement
            paiement_ction_code = ""
            if ('order_header_condition_paiement_id' in retval.keys() and retval['order_header_condition_paiement_id']):
                paiement_ction_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
                    {'_id': ObjectId(str(retval['order_header_condition_paiement_id'])), 'valide': '1', 'locked': '0',
                     'partner_owner_recid': str(my_partner['recid'])})

                if (paiement_ction_data and 'code' in paiement_ction_data.keys()):
                    paiement_ction_code = str(paiement_ction_data['code'])
            user['order_header_paiement_condition_code'] = paiement_ction_code

            # Si le champ 'order_header_client_id' alors on va chercher le nom du client
            order_header_client_nom = ""
            if ('order_header_client_id' in retval.keys() and retval['order_header_client_id']):
                Client_data = MYSY_GV.dbname['partner_client'].find_one(
                    {'_id': ObjectId(str(retval['order_header_client_id'])), 'valide': '1', 'locked': '0',
                     'partner_recid': str(my_partner['recid'])})

                if (Client_data and 'nom' in Client_data.keys()):
                    order_header_client_nom = str(Client_data['nom'])
            user['order_header_client_nom'] = order_header_client_nom

            # Si le champ 'order_header_vendeur_id' alors on va chercher le nom et prenom du vendeur (employe)
            order_header_vendeur_nom_prenom = ""
            if ('order_header_vendeur_id' in retval.keys() and retval['order_header_vendeur_id']):
                Employee_data = MYSY_GV.dbname['ressource_humaine'].find_one(
                    {'_id': ObjectId(str(retval['order_header_vendeur_id'])), 'valide': '1', 'locked': '0',
                     'partner_recid': str(my_partner['recid'])})

                order_header_vendeur_nom_prenom = ""
                if (Employee_data and 'nom' in Employee_data.keys()):
                    order_header_vendeur_nom_prenom = str(Employee_data['nom'])

                if (Employee_data and 'prenom' in Employee_data.keys()):
                    order_header_vendeur_nom_prenom = str(order_header_vendeur_nom_prenom) + " " + str(
                        Employee_data['prenom'])

                order_header_vendeur_nom_prenom = str(order_header_vendeur_nom_prenom)

            user['order_header_vendeur_nom_prenom'] = order_header_vendeur_nom_prenom

            # Recuperation des ligne associées
            retval_line_data = []
            for retval_line in MYSY_GV.dbname['partner_order_line'].find(
                    {'order_header_id': str(retval['_id']), 'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0'}):
                retval_line_data.append(retval_line)

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

        # print(" ### RetObject = ", 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de récupérer les données de la commande "



"""
Recuperation de la liste des commandes d'un partner
"""
def Get_List_Partner_Order_no_filter(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', ]

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'existe pas")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', ]
        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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



        find_qry = {'$and': [{'partner_owner_recid': str(my_partner['recid']), 'valide': '1', 'locked': '0'}, {}, ]}

        new_myquery_find_order = [{'$match': find_qry},
                                  { '$sort': {'_id': -1}},
                                  {"$addFields": {"partner_order_header_Id": {"$toString": "$_id"}}},
                                  {'$lookup':
                                      {
                                          'from': 'partner_order_line',
                                          'localField': "partner_order_header_Id",
                                          'foreignField': 'order_header_id',
                                          'pipeline': [{'$match': {'$and': [{}, {
                                              'partner_owner_recid': str(my_partner['recid'])}, {'valide': '1'}]}}, ],
                                          'as': 'partner_order_line_collection'
                                      }
                                  }
                                  ]


        print(" ### orders  new_myquery_find_order = ", new_myquery_find_order)
        RetObject = []
        val_tmp = 1

        for New_retVal in MYSY_GV.dbname['partner_order_header'].aggregate(new_myquery_find_order):
            user = New_retVal
            user['id'] = str(val_tmp)
            val_tmp = val_tmp + 1

            # Si le champ 'order_header_condition_paiement_id' alors on va chercher le code de la condition de paiement
            paiement_ction_code = ""
            if ('order_header_condition_paiement_id' in New_retVal.keys() and New_retVal['order_header_condition_paiement_id']):
                paiement_ction_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
                    {'_id': ObjectId(str(New_retVal['order_header_condition_paiement_id'])), 'valide': '1', 'locked': '0',
                     'partner_owner_recid': str(my_partner['recid'])})

                if (paiement_ction_data and 'code' in paiement_ction_data.keys()):
                    paiement_ction_code = str(paiement_ction_data['code'])
            user['order_header_paiement_condition_code'] = paiement_ction_code

            # Si le champ 'order_header_client_id' alors on va chercher le nom du client
            if( 'order_header_client_id' in New_retVal.keys()):
                Client_data = MYSY_GV.dbname['partner_client'].find_one({'_id':ObjectId(str(New_retVal['order_header_client_id'])), 'valide':'1', 'locked':'0',
                                                                         'partner_recid':str(my_partner['recid'])})

                if( Client_data and 'nom' in Client_data.keys() ):
                    user['order_header_client_nom'] = str(Client_data['nom'])

            # Si le champ 'order_header_vendeur_id' alors on va chercher le nom et prenom du vendeur (employe)
            if ('order_header_vendeur_id' in New_retVal.keys()):
                Employee_data = MYSY_GV.dbname['ressource_humaine'].find_one(
                    {'_id': ObjectId(str(New_retVal['order_header_vendeur_id'])), 'valide': '1', 'locked': '0',
                     'partner_recid': str(my_partner['recid'])})

                order_header_vendeur_nom_prenom = ""
                if (Employee_data and 'nom' in Employee_data.keys()):
                    order_header_vendeur_nom_prenom = str(Employee_data['nom'])

                if (Employee_data and 'prenom' in Employee_data.keys()):
                    order_header_vendeur_nom_prenom = str(order_header_vendeur_nom_prenom)+" "+str(Employee_data['prenom'])

                user['order_header_vendeur_nom_prenom'] = str(order_header_vendeur_nom_prenom)

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

        return True, RetObject


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de récupérer la liste des commandes "


"""
Recuperation de la liste des commandes avec des filtres.
les filtres acceptés sont : 
- ref_interne
- ref_externe
- date_cmd entre date_debut et date_fin  
- nom_client
"""
def Get_List_Partner_Order_with_filter(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés. les filtres accepté sont : 
        - ref_interne, 
        """
        field_list = ['token', 'date_cmd_debut', 'date_cmd_fin', 'client_nom', 'ref_interne', 'ref_externe',
                      'formation', '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'existe pas")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', ]
        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        filt_client_nom = {}
        sub_filt_client_nom = {}
        Lists_partner_client_id = []
        if ("client_nom" in diction.keys()):
            sub_filt_client_nom = {'nom': {'$regex': str(diction['client_nom']), "$options": "i"}, 'partner_recid':str(my_partner['recid']), 'valide':'1', 'locked':'0'}
            # Recuperation des '_id' des clients dont le nom match en regexp
            #print(" ### sub_filt_client_nom = ", sub_filt_client_nom)
            for List_Client_Data in MYSY_GV.dbname['partner_client'].find(sub_filt_client_nom, {'_id':1}):
                Lists_partner_client_id.append(str(List_Client_Data['_id']))

            filt_client_nom =  {'order_header_client_id': {'$in': Lists_partner_client_id, }}
            #print(' ### filt_client_nom = ', filt_client_nom)



        filt_formation_external_code = {}
        sub_filt_formation_external_code = {}
        Lists_partner_formation_internal_url = []
        if ("formation" in diction.keys()):
            sub_filt_formation_external_code = {'external_code': {'$regex': str(diction['formation']), "$options": "i"},
                                   'partner_owner_recid': str(my_partner['recid']), 'valide': '1', 'locked': '0'}

            # Recuperation des '_id' des formation dont le nom match en regexp
            print(" ### sub_filt_formation_external_code = ", sub_filt_formation_external_code)
            for Lists_partner_formation_Data in MYSY_GV.dbname['myclass'].find(sub_filt_formation_external_code, {'internal_url': 1}):
                Lists_partner_formation_internal_url.append(str(Lists_partner_formation_Data['internal_url']))

            filt_formation_external_code = {'order_line_formation': {'$in': Lists_partner_formation_internal_url }}

        filt_code_session_id = {}
        sub_filt_code_session = {}
        Lists_partner_session_id = []
        if ("code_session" in diction.keys()):
            sub_filt_code_session = {'code_session': {'$regex': str(diction['code_session']), "$options": "i"},
                                                'partner_owner_recid': str(my_partner['recid']), 'valide': '1',}

            # Recuperation des '_id' des formation dont le nom match en regexp
            print(" ### sub_filt_code_session = ", sub_filt_code_session)
            for Lists_partner_session_Data in MYSY_GV.dbname['session_formation'].find(sub_filt_code_session,
                                                                               {'_id': 1}):
                Lists_partner_session_id.append(str(Lists_partner_session_Data['_id']))

            filt_code_session_id = {'order_line_session_id': {'$in': Lists_partner_session_id}}


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

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



        find_qry = {'$and': [{'partner_owner_recid': str(my_partner['recid']), 'valide': '1', 'locked': '0'}, filt_client_nom, filt_ref_interne, filt_ref_externe]}

        new_myquery_find_order = [{'$match': find_qry},
                                  {"$addFields": {"partner_order_header_Id": {"$toString": "$_id"}}},
                                  {'$lookup':
                                      {
                                          'from': 'partner_order_line',
                                          'localField': "partner_order_header_Id",
                                          'foreignField': 'order_header_id',
                                          'pipeline': [{'$match': {'$and': [filt_formation_external_code, filt_code_session_id,
                                                                            {
                                              'partner_owner_recid': str(my_partner['recid'])}, {'valide': '1'}]}}, ],
                                          'as': 'partner_order_line_collection'
                                      }
                                  }
                                  ]


        print(" ### Get_List_Partner_Order_with_filter orders  new_myquery_find_order = ", new_myquery_find_order)
        RetObject = []
        val_tmp = 1

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

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



        for New_retVal in MYSY_GV.dbname['partner_order_header'].aggregate(new_myquery_find_order):
            if ('partner_order_line_collection' in New_retVal.keys() and len( New_retVal['partner_order_line_collection']) > 0):
                user = New_retVal

                # Si le champ 'order_header_condition_paiement_id' alors on va chercher le code de la condition de paiement
                paiement_ction_code = ""
                if ('order_header_condition_paiement_id' in New_retVal.keys() and New_retVal[
                    'order_header_condition_paiement_id']):
                    paiement_ction_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
                        {'_id': ObjectId(str(New_retVal['order_header_condition_paiement_id'])), 'valide': '1',
                         'locked': '0',
                         'partner_owner_recid': str(my_partner['recid'])})

                    if (paiement_ction_data and 'code' in paiement_ction_data.keys()):
                        paiement_ction_code = str(paiement_ction_data['code'])
                user['order_header_paiement_condition_code'] = paiement_ction_code

                # Si le champ 'order_header_client_id' alors on va chercher le nom du client
                if ('order_header_client_id' in New_retVal.keys()):
                    Client_data = MYSY_GV.dbname['partner_client'].find_one(
                        {'_id': ObjectId(str(New_retVal['order_header_client_id'])), 'valide': '1', 'locked': '0',
                         'partner_recid': str(my_partner['recid'])})

                    if (Client_data and 'nom' in Client_data.keys()):
                        user['order_header_client_nom'] = str(Client_data['nom'])

                # Si le champ 'order_header_vendeur_id' alors on va chercher le nom et prenom du vendeur (employe)
                if ('order_header_vendeur_id' in New_retVal.keys()):
                    Employee_data = MYSY_GV.dbname['ressource_humaine'].find_one(
                        {'_id': ObjectId(str(New_retVal['order_header_vendeur_id'])), 'valide': '1', 'locked': '0',
                         'partner_recid': str(my_partner['recid'])})

                    order_header_vendeur_nom_prenom = ""
                    if (Employee_data and 'nom' in Employee_data.keys()):
                        order_header_vendeur_nom_prenom = str(Employee_data['nom'])

                    if (Employee_data and 'prenom' in Employee_data.keys()):
                        order_header_vendeur_nom_prenom = str(order_header_vendeur_nom_prenom) + " " + str(
                            Employee_data['prenom'])

                    user['order_header_vendeur_nom_prenom'] = str(order_header_vendeur_nom_prenom)


                if( filter_date_debut and filter_date_fin ):
                    if ( datetime.strptime(str(New_retVal['order_header_date_cmd'])[0:10], '%d/%m/%Y') >= datetime.strptime(str(filter_date_debut)[0:10], '%d/%m/%Y') and
                    datetime.strptime(str(New_retVal['order_header_date_cmd'])[0:10], '%d/%m/%Y') <= datetime.strptime(str(filter_date_fin)[0:10], '%d/%m/%Y') ):
                        user['id'] = str(val_tmp)
                        val_tmp = val_tmp + 1

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

                elif ( filter_date_debut ):
                    if ( datetime.strptime(str(New_retVal['order_header_date_cmd'])[0:10], '%d/%m/%Y') >= datetime.strptime(str(filter_date_debut)[0:10], '%d/%m/%Y')  ):
                        user['id'] = str(val_tmp)
                        val_tmp = val_tmp + 1
                        RetObject.append(mycommon.JSONEncoder().encode(user))

                elif ( filter_date_fin ):
                    if ( datetime.strptime(str(New_retVal['order_header_date_cmd'])[0:10], '%d/%m/%Y') <= datetime.strptime(str(filter_date_fin)[0:10], '%d/%m/%Y') ):
                        user['id'] = str(val_tmp)
                        val_tmp = val_tmp + 1
                        RetObject.append(mycommon.JSONEncoder().encode(user))

                else:
                    user['id'] = str(val_tmp)
                    val_tmp = val_tmp + 1
                    RetObject.append(mycommon.JSONEncoder().encode(user))


        #print(" ####  nb_result = ", val_tmp)
        return True, RetObject


    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de récupérer la liste des commandes "

"""
Cette fonction permet de récupérer une ligne de detail de commande donnée
c'est a dire, une ligne de la collection 'partner_order_line' 
"""
def Get_Given_Line_Of_Partner_Order_Lines(diction):
    try:

        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'order_line_id', 'order_header_ref_interne']

        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")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', 'order_line_id', 'order_header_ref_interne']
        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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        """
        Clés de mise à jour 
        """
        data_cle = {}
        data_cle['partner_owner_recid'] = str(my_partner['recid'])
        data_cle['order_line_id'] = str(diction['order_line_id'])
        data_cle['order_header_ref_interne'] = str(diction['order_header_ref_interne'])

        data_cle['valide'] = "1"
        data_cle['locked'] = "0"

        RetObject = []
        val_tmp = 1

        filt_class_partner_recid = {'partner_owner_recid': str(my_partner['recid'])}
        filt_order_line_id = {'_id': ObjectId(str(diction['order_line_id']))}
        filt_order_line_header_ref_interne = {'order_header_ref_interne': str(diction['order_header_ref_interne'])}

        query = [{'$match': {'$and': [ filt_order_line_id,filt_order_line_header_ref_interne,
                                      {'partner_owner_recid': str(my_partner['recid'])}]}},
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'order_line_formation',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'$and': [ filt_class_partner_recid]}},
                                      {'$project': {'title': 1, 'domaine': 1,
                                                    'duration': 1,
                                                    'duration_unit': 1,
                                                    'external_code':1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]
        print("#### Get_Given_Partner_Order_Lines  : query pip= ", query)

        for retval in MYSY_GV.dbname['partner_order_line'].aggregate(query):
            if ('myclass_collection' in retval.keys() and len(retval['myclass_collection']) > 0):
                user = {}
                user['id'] = str(val_tmp)
                val_tmp = val_tmp + 1
                user['_id'] = retval['_id']
                user['order_line_formation'] = retval['order_line_formation']
                user['order_line_qty'] = retval['order_line_qty']
                user['order_line_prix_unitaire'] = retval['order_line_prix_unitaire']
                user['order_header_id'] = retval['order_header_id']
                user['order_header_ref_interne'] = retval['order_header_ref_interne']

                if ("order_line_session_id" in retval.keys()):
                    user['order_line_session_id'] = retval['order_line_session_id']

                    # Recuperation du code de la session
                    local_session_data = MYSY_GV.dbname['session_formation'].find_one(
                        {'_id': ObjectId(str(retval['order_line_session_id'])),
                         'partner_owner_recid': str(my_partner['recid']),
                         'valide': '1'})
                    if (local_session_data and "code_session" in local_session_data.keys()):
                        user['order_line_session_code_session'] = local_session_data['code_session']
                    else:
                        user['order_line_session_code_session'] = ""
                else:
                    user['order_line_session_id'] = ""
                    user['order_line_session_code_session'] = ""


                if ("order_line_montant_reduction" in retval.keys()):
                    user['order_line_montant_reduction'] = retval['order_line_montant_reduction']
                else:
                    user['order_line_montant_reduction'] = "0"

                if ("order_line_montant_toutes_taxes" in retval.keys()):
                    user['order_line_montant_toutes_taxes'] = retval['order_line_montant_toutes_taxes']
                else:
                    user['order_line_montant_toutes_taxes'] = "0"

                if ("order_line_tax" in retval.keys()):
                    user['order_line_tax'] = retval['order_line_tax']
                else:
                    user['order_line_tax'] = ""

                if ("order_line_tax_amount" in retval.keys()):
                    user['order_line_tax_amount'] = retval['order_line_tax_amount']
                else:
                    user['order_line_tax_amount'] = "0"

                if ("order_line_type_reduction" in retval.keys()):
                    user['order_line_type_reduction'] = retval['order_line_type_reduction']
                else:
                    user['order_line_montant_reduction'] = ""

                if ("order_line_type_valeur" in retval.keys()):
                    user['order_line_type_valeur'] = retval['order_line_type_valeur']
                else:
                    user['order_line_type_valeur'] = "0"

                if ("order_line_montant_hors_taxes" in retval.keys()):
                    user['order_line_montant_hors_taxes'] = retval['order_line_montant_hors_taxes']
                else:
                    user['order_line_montant_hors_taxes'] = "0"


                user['valide'] = retval['valide']
                user['locked'] = retval['locked']
                user['date_update'] = retval['date_update']
                user['partner_owner_recid'] = retval['partner_owner_recid']
                user['order_line_type'] = retval['order_line_type']
                user['order_line_status'] = retval['order_line_status']

                if( "order_line_comment" in retval.keys()):
                    user['order_line_comment'] = retval['order_line_comment']
                else:
                    user['order_line_comment'] = ""

                user['title'] = retval['myclass_collection'][0]['title']
                user['order_line_formation_external_code'] = retval['myclass_collection'][0]['external_code']

                if ("domaine" in retval['myclass_collection'][0].keys()):
                    user['domaine'] = retval['myclass_collection'][0]['domaine']
                else:
                    user['domaine'] = ""


                user['duration'] = retval['myclass_collection'][0]['duration']
                user['duration_unit'] = retval['myclass_collection'][0]['duration_unit']

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

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

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

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

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

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

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

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



        #print(" ### RetObject = ", 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) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " Impossible de récupérer les lignes de commande "


""""
Cette fonction calcul les totaux (reduction,HT, TTC, TAXES, etc) d'un commande / devis et met à jour ces info
"""
def Compute_Order_Header(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', '_id']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'existe pas")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token', '_id']
        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

        # Recuperation de la valeur de la TVA (taux tva)
        partner_taux_tva = 20

        if( "invoice_taux_vat" in my_partner.keys()):
            IsInt_status, IsInt_retval = mycommon.IsInt(str(my_partner['invoice_taux_vat']))
            if( IsInt_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - La valeur '" + str(my_partner['invoice_taux_vat']) + "' n'est pas un taux de TVA correcte ")
                return False, "  La valeur '" + str(my_partner['invoice_taux_vat']) + "' n'est pas un taux de TVA correcte ",

            partner_taux_tva = IsInt_retval


        print(" ### COMPUTE : le taux de TVA = ", str(partner_taux_tva))

        # Verification de la validité de l'order
        qry = {'_id':ObjectId(str(diction['_id'])), 'valide':'1', 'locked':'0', 'partner_owner_recid':str(my_partner['recid'])}
        print( " ### qry = ", qry)

        is_Order_Existe_Count = MYSY_GV.dbname['partner_order_header'].count_documents({'_id':ObjectId(str(diction['_id'])),
                                                                                        'valide':'1', 'locked':'0',
                                                                                        'partner_owner_recid':str(my_partner['recid'])})

        if( is_Order_Existe_Count != 1 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - La commande n'est pas valide ")
            return False, " La commande n'est pas valide",

        Order_header_data =  MYSY_GV.dbname['partner_order_header'].find_one({'_id':ObjectId(str(diction['_id'])),
                                                                                        'valide':'1', 'locked':'0',
                                                                                        'partner_owner_recid':str(my_partner['recid'])})

        """
        Algo :
        1 - récupérer toutes les lignes valides, créer des sous totaux
        2 - Appliquer les eventels reductions d'entete 
        """

        nb_line = 0
        line_sum_order_line_tax_amount = 0
        line_sum_order_line_montant_reduction = 0
        line_sum_order_line_montant_hors_taxes_before_reduction = 0
        line_sum_order_line_montant_hors_taxes_after_reduction = 0
        line_sum_order_line_montant_toutes_taxes = 0



        for local_retval in MYSY_GV.dbname['partner_order_line'].find({'order_header_id':str(diction['_id']), 'valide':'1', 'locked':'0',
                                                                       'partner_owner_recid':str(my_partner['recid']) }):

            #print(" ------------------- Pour la ligne numero : ", nb_line)
            ligne_montant_reduction = 0
            if ("order_line_montant_reduction" in local_retval.keys()):
                line_sum_order_line_montant_reduction = line_sum_order_line_montant_reduction + mycommon.tryFloat(
                    local_retval['order_line_montant_reduction'])
                ligne_montant_reduction = mycommon.tryFloat(local_retval['order_line_montant_reduction'])

            #    print(" #### order_line_montant_reduction = ",
            #          str(mycommon.tryFloat(local_retval['order_line_montant_reduction'])))


            if( "order_line_tax_amount" in local_retval.keys()):
                line_sum_order_line_tax_amount = line_sum_order_line_tax_amount + mycommon.tryFloat(local_retval['order_line_tax_amount'])
            #    print(" #### order_line_tax_amount = ", str(mycommon.tryFloat(local_retval['order_line_tax_amount'])))



            if ("order_line_montant_hors_taxes" in local_retval.keys()):
                line_sum_order_line_montant_hors_taxes_before_reduction = line_sum_order_line_montant_hors_taxes_before_reduction + mycommon.tryFloat(
                    local_retval['order_line_montant_hors_taxes'])
            #    print(" #### order_line_montant_hors_taxes = ", str(mycommon.tryFloat(local_retval['order_line_montant_hors_taxes'])))

                order_line_montant_hors_taxes_APRES_REDUCTION = mycommon.tryFloat(local_retval['order_line_montant_hors_taxes']) - ligne_montant_reduction
            #    print(" #### order_line_montant_hors_taxes_APRES_REDUCTION = ", str(order_line_montant_hors_taxes_APRES_REDUCTION))


            if ("order_line_montant_toutes_taxes" in local_retval.keys()):
                line_sum_order_line_montant_toutes_taxes = line_sum_order_line_montant_toutes_taxes + mycommon.tryFloat(
                    local_retval['order_line_montant_toutes_taxes'])
            #    print(" #### order_line_montant_toutes_taxes = ",
            #          str(mycommon.tryFloat(local_retval['order_line_montant_toutes_taxes'])))


            #print(" ----------- FIN DES LIGNES ")

            nb_line = nb_line + 1

        line_sum_order_line_montant_hors_taxes_after_reduction = line_sum_order_line_montant_hors_taxes_before_reduction - line_sum_order_line_montant_reduction
        """ 
        print(" ######  Apres compute des lignes : NB_LINE = ", nb_line)
        print(" ######  line_sum_order_line_montant_reduction =  ", line_sum_order_line_montant_reduction)
        print(" ######  line_sum_order_line_tax_amount =  ", line_sum_order_line_tax_amount)
        print(" ######  line_sum_order_line_montant_hors_taxes_before_reduction =  ", line_sum_order_line_montant_hors_taxes_before_reduction)
        print(" ######  line_sum_order_line_montant_hors_taxes_after_reduction =  ", line_sum_order_line_montant_hors_taxes_after_reduction)
        print(" ######  line_sum_order_line_montant_toutes_taxes =  ", line_sum_order_line_montant_toutes_taxes)
        """


        header_reduction_type = ""
        header_reduction_type_value = ""
        if( "order_header_type_reduction" in Order_header_data.keys()):
            header_reduction_type = Order_header_data['order_header_type_reduction']

        if ("order_header_type_reduction_valeur" in Order_header_data.keys()):
            header_reduction_type_value = Order_header_data['order_header_type_reduction_valeur']

        """
        print(" ### les reduction d'entete ")
        print(" ######  header_reduction_type =  ", header_reduction_type)
        print(" ######  header_reduction_type_value =  ", header_reduction_type_value)
        """


        global_order_taxe_amount = 0
        global_order_amount_ht_before_header_reduction = line_sum_order_line_montant_hors_taxes_after_reduction
        global_order_amount_ht_after_header_reduction = 0
        header_reduction_type_value_total_amount = 0

        if( str(header_reduction_type) == "fixe" ):
            header_reduction_type_value_total_amount = mycommon.tryFloat(header_reduction_type_value)
            global_order_amount_ht_after_header_reduction = line_sum_order_line_montant_hors_taxes_after_reduction - mycommon.tryFloat(header_reduction_type_value)

            """print(" GRRRR 022 header_reduction_type_value_total_amount = ",
                  header_reduction_type_value_total_amount)

            print(" GRRRR 022 global_order_amount_ht_after_header_reduction = ",
                  global_order_amount_ht_after_header_reduction)
            """

        elif( str(header_reduction_type) == "percent" ):
            #print(" GRRRR line_sum_order_line_montant_hors_taxes_after_reduction = ", line_sum_order_line_montant_hors_taxes_after_reduction)
            #print(" GRRRR mycommon.tryFloat(header_reduction_type_value)/100 = ",
            #      line_sum_order_line_montant_hors_taxes_after_reduction*mycommon.tryFloat(header_reduction_type_value)/100)
            #print(" GRRRR mycommon.tryFloat(header_reduction_type_value)/100 = ",
            #      (line_sum_order_line_montant_hors_taxes_after_reduction - (line_sum_order_line_montant_hors_taxes_after_reduction*mycommon.tryFloat(header_reduction_type_value)/100)) )

            header_reduction_type_value_total_amount = line_sum_order_line_montant_hors_taxes_after_reduction * mycommon.tryFloat(header_reduction_type_value)/100
            global_order_amount_ht_after_header_reduction = line_sum_order_line_montant_hors_taxes_after_reduction - ((line_sum_order_line_montant_hors_taxes_after_reduction *mycommon.tryFloat(header_reduction_type_value)/100 ))
            #print(" GRRRR global_order_amount_ht_after_header_reduction = ",global_order_amount_ht_after_header_reduction)

        else:
            header_reduction_type_value_total_amount = 0
            global_order_amount_ht_before_header_reduction = line_sum_order_line_montant_hors_taxes_after_reduction
            global_order_amount_ht_after_header_reduction = line_sum_order_line_montant_hors_taxes_after_reduction


        global_order_amount_ttc = global_order_amount_ht_after_header_reduction * 1.2

        """print(" ######  header_reduction_type_value_total_amount =  ", header_reduction_type_value_total_amount)
        print(" ######  global_order_amount_ht_before_header_reduction =  ", line_sum_order_line_montant_hors_taxes_after_reduction)
        print(" ######  global_order_amount_ht_after_header_reduction =  ", global_order_amount_ht_after_header_reduction)

        print(" ######  global_order_amount_ttc =  ", global_order_amount_ttc)
        """
        """
        Tous les calculs, ok, on met à l'entete de de l'order
        """
        header_computed_data = {}
        header_computed_data['total_lines_montant_reduction'] = str(round(line_sum_order_line_montant_reduction, 3))
        header_computed_data['total_lines_hors_taxe_before_lines_reduction'] = str(round(line_sum_order_line_montant_hors_taxes_before_reduction, 3))
        header_computed_data['total_lines_hors_taxe_after_lines_reduction'] = str(round(line_sum_order_line_montant_hors_taxes_after_reduction, 3))
        header_computed_data['order_header_montant_reduction'] = str(round(header_reduction_type_value_total_amount, 3))
        header_computed_data['total_header_hors_taxe_before_header_reduction'] = str(round(line_sum_order_line_montant_hors_taxes_after_reduction, 3))
        header_computed_data['total_header_hors_taxe_after_header_reduction'] = str(round(global_order_amount_ht_after_header_reduction, 3))
        header_computed_data['order_header_tax'] = "TVA "+str(partner_taux_tva)+"%"
        header_computed_data['order_header_tax_amount'] = str(round(line_sum_order_line_tax_amount, 3))
        header_computed_data['total_header_toutes_taxes'] = str(round(global_order_amount_ttc, 3))

        header_computed_data['date_update'] = str(datetime.now())


        print(" ### header_computed_data = ", header_computed_data)

        local_retval = MYSY_GV.dbname['partner_order_header'].find_one_and_update({'_id':ObjectId(str(diction['_id'])),
                                                                                        'valide':'1', 'locked':'0',
                                                                                        'partner_owner_recid':str(my_partner['recid'])},
                                                                   {"$set": header_computed_data
                                                                    },
                                                                          upsert=False,
                                                                          return_document=ReturnDocument.AFTER
                                                                          )

        if( local_retval is None ):
            mycommon.myprint(str(inspect.stack()[0][3]) + "  Impossible de finaliser la mise à jour" )
            return False, " Impossible de finaliser la mise à jour "

        return True, 'La mise à jour des prix a été correctement faite.'


    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 generer les calculs de mise à jour "



"""
Impression PDF d'une commande / devis 
"""


def GerneratePDF_Partner_Order(diction):
    try:
        field_list = ['order_id', '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]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " Les informations fournies sont incorrectes"

        """
                Verification de la liste des champs obligatoires
                """
        field_list_obligatoire = ['order_id', '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, "Les informations fournies sont incorrectes"

        query_get_data = {}
        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

        # Verification de la validité de l'order
        qry = {'_id': ObjectId(str(diction['order_id'])), 'valide': '1', 'locked': '0',
               'partner_owner_recid': str(my_partner['recid'])}
        #print(" ### qry = ", qry)

        is_Order_Existe_Count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'_id': ObjectId(str(diction['order_id'])),
             'valide': '1', 'locked': '0',
             'partner_owner_recid': str(my_partner['recid'])})

        if (is_Order_Existe_Count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - La commande n'est pas valide ")
            return False, " La commande n'est pas valide",

        Order_header_data = MYSY_GV.dbname['partner_order_header'].find_one({'_id': ObjectId(str(diction['order_id'])),
                                                                             'valide': '1', 'locked': '0',
                                                                             'partner_owner_recid': str(
                                                                                 my_partner['recid'])})

        partner_document_CONF_ORDER_data_qry = {'partner_owner_recid': str(my_partner['recid']),
                                                      'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'pdf'}

        print(" ### partner_document_CONF_ORDER_data_qry = ", partner_document_CONF_ORDER_data_qry)
        partner_document_CONF_ORDER_data = MYSY_GV.dbname['courrier_template'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'pdf'})

        if (partner_document_CONF_ORDER_data is None):
            # Il n'existe pas de personnalisation de la preinscription pour ce partenaire, on va aller récupérer la presinscription pa defaut
            partner_document_CONF_ORDER_data = MYSY_GV.dbname['courrier_template'].find_one(
                {'partner_owner_recid': 'default',
                 'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'pdf'})

        if (partner_document_CONF_ORDER_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "Aucun document paramétré ")
            return False, "Aucun document paramétré  "

        if ("contenu_doc" not in partner_document_CONF_ORDER_data or len(
                str(partner_document_CONF_ORDER_data['contenu_doc'])) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Le parametrage du document  est invalide")
            return False, " Le parametrage du document  est invalide "

        # Recuperation des données du client
        if ("order_header_client_id" in Order_header_data.keys()):
            Order_header_client_data = MYSY_GV.dbname['partner_client'].find_one(
                {'_id': ObjectId(str(Order_header_data['order_header_client_id'])),
                 'partner_recid': str(my_partner['recid']), 'valide': '1', 'locked': '0'})

            if (Order_header_client_data is None):
                mycommon.myprint(str(inspect.stack()[0][
                                         3]) + " - Le client est invalide")
                return False, " Le client est invalide"

        ### Ajout des données du client sur l'entete de la commande, exemple : le nom, email, etc
        if("raison_sociale" in Order_header_client_data.keys() ):
            Order_header_data['client_raison_sociale'] = Order_header_client_data['raison_sociale']

        if ("nom" in Order_header_client_data.keys()):
            Order_header_data['client_nom'] = Order_header_client_data['nom']

        if ("email" in Order_header_client_data.keys()):
            Order_header_data['client_email'] = Order_header_client_data['email']

        """
        Recup condition paiement id 
        """
        cdtion_paiement_code = ""
        cdtion_paiement_id = ""
        if( "order_header_condition_paiement_id" in Order_header_data.keys() and Order_header_data['order_header_condition_paiement_id']):
            cdtion_paiement_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one({'_id':ObjectId(str(Order_header_data['order_header_condition_paiement_id'])),
                                                                                            'valide':'1',
                                                                                            'locked':'0',
                                                                                               }
                                                                                              )

            if( cdtion_paiement_data and 'code' in cdtion_paiement_data.keys() ):
                cdtion_paiement_code = str(cdtion_paiement_data['code'])
                cdtion_paiement_id = str(cdtion_paiement_data['_id'])

        Order_header_data['order_header_condition_paiement_code'] = cdtion_paiement_code
        Order_header_data['order_header_condition_paiement_id'] = cdtion_paiement_id


        # Recuperation des details de lignes de : partner_order_line
        filt_class_partner_recid = {'partner_owner_recid': str(my_partner['recid'])}
        filt_order_header_order_id = {'order_header_id': str(diction['order_id'])}

        query = [{'$match': {'$and': [filt_order_header_order_id,
                                      {'partner_owner_recid': str(my_partner['recid'])}]}},
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'order_line_formation',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'$and': [filt_class_partner_recid]}},
                                      {'$project': {'title': 1, 'domaine': 1,
                                                    'duration': 1,
                                                    'duration_unit': 1,
                                                    'external_code':1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]
        #print("#### Get_Given_Partner_Order_Lines_From_order_ref_interne  : query pip= ", query)
        val_tmp = 0
        Order_header_lines_data = []
        for retval in MYSY_GV.dbname['partner_order_line'].aggregate(query):
            if ('myclass_collection' in retval.keys() and len(retval['myclass_collection']) > 0):
                user = {}
                user['id'] = str(val_tmp)
                val_tmp = val_tmp + 1
                user['_id'] = retval['_id']
                user['order_line_formation'] = retval['order_line_formation']
                user['order_line_qty'] = retval['order_line_qty']
                user['order_line_prix_unitaire'] = retval['order_line_prix_unitaire']
                user['order_header_id'] = retval['order_header_id']
                user['order_header_ref_interne'] = retval['order_header_ref_interne']
                user['valide'] = retval['valide']
                user['locked'] = retval['locked']

                if ("order_line_session_id" in retval.keys()):
                    local_session_data = MYSY_GV.dbname['session_formation'].find_one(
                        {'_id': ObjectId(str(retval['order_line_session_id'])),
                         'valide': '1',
                         'partner_owner_recid': my_partner['recid']})

                    if (local_session_data):

                        if ("code_session" in local_session_data.keys()):
                            user['code_session'] = local_session_data['code_session']
                        else:
                            user['code_session'] = ""

                        if ("date_debut" in local_session_data.keys() and "date_fin" in local_session_data.keys()):
                            user['session_date_debut'] = local_session_data['date_debut']
                            user['session_date_fin'] = local_session_data['date_fin']
                        else:
                            user['session_date_debut'] = ""
                            user['session_date_fin'] = ""
                else:
                    user['order_line_session_id'] = ""
                    user['code_session'] = ""
                    user['session_date_debut'] = ""
                    user['session_date_fin'] = ""

                if ("order_line_montant_reduction" in retval.keys()):
                    user['order_line_montant_reduction'] = retval['order_line_montant_reduction']
                else:
                    user['order_line_montant_reduction'] = "0"

                if ("order_line_montant_toutes_taxes" in retval.keys()):
                    user['order_line_montant_toutes_taxes'] = retval['order_line_montant_toutes_taxes']
                else:
                    user['order_line_montant_toutes_taxes'] = "0"

                if ("order_line_tax" in retval.keys()):
                    user['order_line_tax'] = retval['order_line_tax']
                else:
                    user['order_line_tax'] = ""

                if ("order_line_tax_amount" in retval.keys()):
                    user['order_line_tax_amount'] = retval['order_line_tax_amount']
                else:
                    user['order_line_tax_amount'] = "0"

                if ("order_line_type_reduction" in retval.keys()):
                    user['order_line_type_reduction'] = retval['order_line_type_reduction']
                else:
                    user['order_line_montant_reduction'] = ""

                if ("order_line_type_valeur" in retval.keys()):
                    user['order_line_type_valeur'] = retval['order_line_type_valeur']
                else:
                    user['order_line_type_valeur'] = "0"

                if ("order_line_montant_hors_taxes" in retval.keys()):
                    user['order_line_montant_hors_taxes'] =  str(round(mycommon.tryFloat(str(retval['order_line_montant_hors_taxes'])), 2))
                else:
                    user['order_line_montant_hors_taxes'] = "0"

                user['date_update'] = retval['date_update']
                user['partner_owner_recid'] = retval['partner_owner_recid']
                user['order_line_type'] = retval['order_line_type']
                user['order_line_status'] = retval['order_line_status']
                if ("order_line_comment" in retval.keys()):
                    user['order_line_comment'] = retval['order_line_comment']
                else:
                    user['order_line_comment'] = ""

                user['title'] = retval['myclass_collection'][0]['title']
                user['order_line_formation_external_code'] = retval['myclass_collection'][0]['external_code']

                if( "domaine" in retval['myclass_collection'][0].keys() ):
                    user['domaine'] = retval['myclass_collection'][0]['domaine']
                else:
                    user['domaine'] = ""

                user['duration'] = retval['myclass_collection'][0]['duration']
                user['duration_unit'] = retval['myclass_collection'][0]['duration_unit']

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

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

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

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

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

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

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

                Order_header_lines_data.append(user)

        if (len(Order_header_lines_data) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Aucune ligne de détail pour cette commande ")
            return False, " Aucune ligne de détail pour cette commande "

        #print(" ### Order_header_lines_data =  ", Order_header_lines_data)
        # Creation du dictionnaire d'information à utiliser pour la creation du doc

        tab_client = []
        tab_client.append(ObjectId(str(Order_header_data['order_header_client_id'])))

        convention_dictionnary_data = {}
        new_diction = {}
        new_diction['token'] = diction['token']
        new_diction['list_stagiaire_id'] = []
        new_diction['list_session_id'] = []
        new_diction['list_class_id'] = []
        new_diction['list_client_id'] = tab_client
        new_diction['list_apprenant_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

        convention_dictionnary_data['order_header'] = Order_header_data
        convention_dictionnary_data['order_lines'] = Order_header_lines_data

        body = {
            "params": convention_dictionnary_data,
        }

        contenu_doc_Template = jinja2.Template(str(partner_document_CONF_ORDER_data['contenu_doc']))

        #print(" #### Order_header_data = ", Order_header_data)
        #sourceHtml = contenu_doc_Template.render(params=Order_header_data)
        Order_header_data['order_header_type'] = str(Order_header_data['order_header_type']).capitalize()

        #sourceHtml = contenu_doc_Template.render(params=Order_header_data, param_order_lines=Order_header_lines_data)
        sourceHtml = contenu_doc_Template.render(params=body['params'], )

        orig_file_name = "Partner_Order_"+str(Order_header_data['order_header_ref_interne'])+".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()

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

        # return True on success and False on errors
        print(pisaStatus.err, type(pisaStatus.err))



        return True, " le fichier generé "
    except  Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, False



"""
Cette fonction créer un fichier PDF, stock le fichier en local et retour le nom complet du fichier
"""

def Gernerate_Stock_PDF_Partner_Order(diction):
    try:
        field_list = ['order_id', '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]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " Les informations fournies sont incorrectes", False

        """
                Verification de la liste des champs obligatoires
                """
        field_list_obligatoire = ['order_id', '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, "Les informations fournies sont incorrectes", False

        query_get_data = {}
        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, False

        # Verification de la validité de l'order
        qry = {'_id': ObjectId(str(diction['order_id'])), 'valide': '1', 'locked': '0',
               'partner_owner_recid': str(my_partner['recid'])}
        #print(" ### qry = ", qry)

        is_Order_Existe_Count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'_id': ObjectId(str(diction['order_id'])),
             'valide': '1', 'locked': '0',
             'partner_owner_recid': str(my_partner['recid'])})

        if (is_Order_Existe_Count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - La commande n'est pas valide ")
            return False, " La commande n'est pas valide", False

        Order_header_data = MYSY_GV.dbname['partner_order_header'].find_one({'_id': ObjectId(str(diction['order_id'])),
                                                                             'valide': '1', 'locked': '0',
                                                                             'partner_owner_recid': str(
                                                                                 my_partner['recid'])})

        partner_document_CONF_ORDER_data_qry = {'partner_owner_recid': str(my_partner['recid']),
                                                      'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'pdf'}

        print(" ### partner_document_CONF_ORDER_data_qry = ", partner_document_CONF_ORDER_data_qry)
        partner_document_CONF_ORDER_data = MYSY_GV.dbname['courrier_template'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'pdf'})

        if (partner_document_CONF_ORDER_data is None):
            # Il n'existe pas de personnalisation de la preinscription pour ce partenaire, on va aller récupérer la presinscription pa defaut
            partner_document_CONF_ORDER_data = MYSY_GV.dbname['courrier_template'].find_one(
                {'partner_owner_recid': 'default',
                 'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'pdf'})

        if (partner_document_CONF_ORDER_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "Aucun document paramétré ")
            return False, "Aucun document paramétré  ", False

        if ("contenu_doc" not in partner_document_CONF_ORDER_data or len(
                str(partner_document_CONF_ORDER_data['contenu_doc'])) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Le parametrage du document  est invalide")
            return False, " Le parametrage du document  est invalide "

        # Recuperation des données du client
        if ("order_header_client_id" in Order_header_data.keys()):
            Order_header_client_data = MYSY_GV.dbname['partner_client'].find_one(
                {'_id': ObjectId(str(Order_header_data['order_header_client_id'])),
                 'partner_recid': str(my_partner['recid']), 'valide': '1', 'locked': '0'})

            if (Order_header_client_data is None):
                mycommon.myprint(str(inspect.stack()[0][
                                         3]) + " - Le client est invalide")
                return False, " Le client est invalide", False

        ### Ajout des données du client sur l'entete de la commande, exemple : le nom, email, etc
        if("raison_sociale" in Order_header_client_data.keys() ):
            Order_header_data['client_raison_sociale'] = Order_header_client_data['raison_sociale']

        if ("nom" in Order_header_client_data.keys()):
            Order_header_data['client_nom'] = Order_header_client_data['nom']

        if ("email" in Order_header_client_data.keys()):
            Order_header_data['client_email'] = Order_header_client_data['email']

        """
              Recup condition paiement id 
              """
        cdtion_paiement_code = ""
        cdtion_paiement_id = ""
        if ("order_header_condition_paiement_id" in Order_header_data.keys() and Order_header_data[
            'order_header_condition_paiement_id']):
            cdtion_paiement_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
                {'_id': ObjectId(str(Order_header_data['order_header_condition_paiement_id'])),
                 'valide': '1',
                 'locked': '0',
                 }
                )

            if (cdtion_paiement_data and 'code' in cdtion_paiement_data.keys()):
                cdtion_paiement_code = str(cdtion_paiement_data['code'])
                cdtion_paiement_id = str(cdtion_paiement_data['_id'])

        Order_header_data['order_header_condition_paiement_code'] = cdtion_paiement_code
        Order_header_data['order_header_condition_paiement_id'] = cdtion_paiement_id

        # Recuperation des details de lignes de : partner_order_line
        filt_class_partner_recid = {'partner_owner_recid': str(my_partner['recid'])}
        filt_order_header_order_id = {'order_header_id': str(diction['order_id'])}

        query = [{'$match': {'$and': [filt_order_header_order_id,
                                      {'partner_owner_recid': str(my_partner['recid'])}]}},
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'order_line_formation',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'$and': [filt_class_partner_recid]}},
                                      {'$project': {'title': 1, 'domaine': 1,
                                                    'duration': 1,
                                                    'duration_unit': 1,
                                                    'external_code':1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]
        #print("#### Get_Given_Partner_Order_Lines_From_order_ref_interne  : query pip= ", query)
        val_tmp = 0
        Order_header_lines_data = []
        for retval in MYSY_GV.dbname['partner_order_line'].aggregate(query):
            if ('myclass_collection' in retval.keys() and len(retval['myclass_collection']) > 0):
                user = {}
                user['id'] = str(val_tmp)
                val_tmp = val_tmp + 1
                user['_id'] = retval['_id']
                user['order_line_formation'] = retval['order_line_formation']
                user['order_line_qty'] = retval['order_line_qty']
                user['order_line_prix_unitaire'] = retval['order_line_prix_unitaire']
                user['order_header_id'] = retval['order_header_id']
                user['order_header_ref_interne'] = retval['order_header_ref_interne']
                user['valide'] = retval['valide']
                user['locked'] = retval['locked']

                if ("order_line_session_id" in retval.keys()):
                    local_session_data = MYSY_GV.dbname['session_formation'].find_one(
                        {'_id': ObjectId(str(retval['order_line_session_id'])),
                         'valide': '1',
                         'partner_owner_recid': my_partner['recid']})

                    if (local_session_data):

                        if ("code_session" in local_session_data.keys()):
                            user['code_session'] = local_session_data['code_session']
                        else:
                            user['code_session'] = ""

                        if ("date_debut" in local_session_data.keys() and "date_fin" in local_session_data.keys()):
                            user['session_date_debut'] = local_session_data['date_debut']
                            user['session_date_fin'] = local_session_data['date_fin']
                        else:
                            user['session_date_debut'] = ""
                            user['session_date_fin'] = ""
                else:
                    user['order_line_session_id'] = ""
                    user['code_session'] = ""
                    user['session_date_debut'] = ""
                    user['session_date_fin'] = ""

                if ("order_line_montant_reduction" in retval.keys()):
                    user['order_line_montant_reduction'] = retval['order_line_montant_reduction']
                else:
                    user['order_line_montant_reduction'] = "0"

                if ("order_line_montant_toutes_taxes" in retval.keys()):
                    user['order_line_montant_toutes_taxes'] = retval['order_line_montant_toutes_taxes']
                else:
                    user['order_line_montant_toutes_taxes'] = "0"

                if ("order_line_tax" in retval.keys()):
                    user['order_line_tax'] = retval['order_line_tax']
                else:
                    user['order_line_tax'] = ""

                if ("order_line_tax_amount" in retval.keys()):
                    user['order_line_tax_amount'] = retval['order_line_tax_amount']
                else:
                    user['order_line_tax_amount'] = "0"

                if ("order_line_type_reduction" in retval.keys()):
                    user['order_line_type_reduction'] = retval['order_line_type_reduction']
                else:
                    user['order_line_montant_reduction'] = ""

                if ("order_line_type_valeur" in retval.keys()):
                    user['order_line_type_valeur'] = retval['order_line_type_valeur']
                else:
                    user['order_line_type_valeur'] = "0"

                if ("order_line_montant_hors_taxes" in retval.keys()):
                    user['order_line_montant_hors_taxes'] =  str(round(mycommon.tryFloat(str(retval['order_line_montant_hors_taxes'])), 2))
                else:
                    user['order_line_montant_hors_taxes'] = "0"

                user['date_update'] = retval['date_update']
                user['partner_owner_recid'] = retval['partner_owner_recid']
                user['order_line_type'] = retval['order_line_type']
                user['order_line_status'] = retval['order_line_status']
                if ("order_line_comment" in retval.keys()):
                    user['order_line_comment'] = retval['order_line_comment']
                else:
                    user['order_line_comment'] = ""

                user['title'] = retval['myclass_collection'][0]['title']
                user['order_line_formation_external_code'] = retval['myclass_collection'][0]['external_code']

                if( "domaine" in retval['myclass_collection'][0].keys() ):
                    user['domaine'] = retval['myclass_collection'][0]['domaine']
                else:
                    user['domaine'] = ""

                user['duration'] = retval['myclass_collection'][0]['duration']
                user['duration_unit'] = retval['myclass_collection'][0]['duration_unit']

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

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

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

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

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

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

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

                Order_header_lines_data.append(user)

        if (len(Order_header_lines_data) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Aucune ligne de détail pour cette commande ")
            return False, " Aucune ligne de détail pour cette commande ", False

        #print(" ### Order_header_lines_data =  ", Order_header_lines_data)
        # Creation du dictionnaire d'information à utiliser pour la creation du doc

        tab_client = []
        tab_client.append(ObjectId(str(Order_header_data['order_header_client_id'])))

        convention_dictionnary_data = {}
        new_diction = {}
        new_diction['token'] = diction['token']
        new_diction['list_stagiaire_id'] = []
        new_diction['list_session_id'] = []
        new_diction['list_class_id'] = []
        new_diction['list_client_id'] = tab_client
        new_diction['list_apprenant_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

        convention_dictionnary_data['order_header'] = Order_header_data
        convention_dictionnary_data['order_lines'] = Order_header_lines_data

        body = {
            "params": convention_dictionnary_data,
        }

        contenu_doc_Template = jinja2.Template(str(partner_document_CONF_ORDER_data['contenu_doc']))

        #print(" #### Order_header_data = ", Order_header_data)
        #sourceHtml = contenu_doc_Template.render(params=Order_header_data)
        Order_header_data['order_header_type'] = str(Order_header_data['order_header_type']).capitalize()

        #sourceHtml = contenu_doc_Template.render(params=Order_header_data, param_order_lines=Order_header_lines_data)
        sourceHtml = contenu_doc_Template.render(params=body['params'], )


        orig_file_name = "Partner_Order_"+str(Order_header_data['order_header_ref_interne'])+".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, sourceHtml
    except  Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, False, False


"""
Envoie de la commande par email
"""
def Send_Partner_Order_By_Email(diction):
    try:
        field_list = ['order_id', 'token', 'request_digital_signature']
        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]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, "Les informations fournies sont incorrectes"

        """
                Verification de la liste des champs obligatoires
                """
        field_list_obligatoire = ['order_id', '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, " Les informations fournies sont incorrectes "

        query_get_data = {}
        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

        """
               20/03/2024 : Creation du E-Document à signer
               On verifier si le partenaire dispose de l'option "signature_digital" dans la collection base_partner_setup

               ET SI DEPUIS LE FRONT, L'UTILISATEUR DECIDE DE L'UTILISER
               """
        is_partner_digital_signature = ""
        if ("request_digital_signature" in diction.keys() and diction['request_digital_signature'] == "1"):

            is_signature_digital_count = MYSY_GV.dbname['base_partner_setup'].count_documents(
                {'partner_owner_recid': str(my_partner['recid']),
                 'config_name': 'signature_digital',
                 'valide': '1',
                 'locked': '0',
                 'config_value': '1'})
            if (is_signature_digital_count == 1):
                is_partner_digital_signature = "1"


        # Verification de la validité de l'order
        qry = {'_id': ObjectId(str(diction['order_id'])), 'valide': '1', 'locked': '0',
               'partner_owner_recid': str(my_partner['recid'])}
        #print(" ### qry = ", qry)

        is_Order_Existe_Count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'_id': ObjectId(str(diction['order_id'])),
             'valide': '1', 'locked': '0',
             'partner_owner_recid': str(my_partner['recid'])})

        if (is_Order_Existe_Count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - La commande n'est pas valide ")
            return False, " La commande n'est pas valide",

        Order_header_data = MYSY_GV.dbname['partner_order_header'].find_one({'_id': ObjectId(str(diction['order_id'])),
                                                                             'valide': '1', 'locked': '0',
                                                                             'partner_owner_recid': str(
                                                                                 my_partner['recid'])})


        #print(" ### partner_document_CONF_ORDER_data_qry = ", partner_document_CONF_ORDER_data_qry)
        partner_document_CONF_ORDER_data = MYSY_GV.dbname['courrier_template'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'email'})

        if (partner_document_CONF_ORDER_data is None):
            # Il n'existe pas de personnalisation de la preinscription pour ce partenaire, on va aller récupérer la presinscription pa defaut
            partner_document_CONF_ORDER_data = MYSY_GV.dbname['courrier_template'].find_one(
                {'partner_owner_recid': 'default',
                 'valide': '1', 'locked': '0', 'ref_interne': 'PART_ORDER', 'type_doc':'email'})

        if (partner_document_CONF_ORDER_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + "Aucun document parametré ")
            return False, "Aucun document parametré "

        if ("contenu_doc" not in partner_document_CONF_ORDER_data or len(
                str(partner_document_CONF_ORDER_data['contenu_doc'])) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Le parametrage du document  est invalide")
            return False, " Le parametrage du document  est invalide "



        # Recuperation des données du client
        if( "order_header_client_id" in Order_header_data.keys() ):
            Order_header_client_data = MYSY_GV.dbname['partner_client'].find_one({'_id':ObjectId(str(Order_header_data['order_header_client_id'])),
                                                                                  'partner_recid':str(my_partner['recid']), 'valide':'1', 'locked':'0'})

            if( Order_header_client_data is None):
                mycommon.myprint(str(inspect.stack()[0][
                                         3]) + " - Le client est invalide")
                return False, " Le client est invalide"

        """
              Recup condition paiement id 
              """
        cdtion_paiement_code = ""
        cdtion_paiement_id = ""
        if ("order_header_condition_paiement_id" in Order_header_data.keys() and Order_header_data[
            'order_header_condition_paiement_id']):
            cdtion_paiement_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
                {'_id': ObjectId(str(Order_header_data['order_header_condition_paiement_id'])),
                 'valide': '1',
                 'locked': '0',
                 }
                )

            if (cdtion_paiement_data and 'code' in cdtion_paiement_data.keys()):
                cdtion_paiement_code = str(cdtion_paiement_data['code'])
                cdtion_paiement_id = str(cdtion_paiement_data['_id'])

        Order_header_data['order_header_condition_paiement_code'] = cdtion_paiement_code
        Order_header_data['order_header_condition_paiement_id'] = cdtion_paiement_id


        # Recuperation des details de lignes de : partner_order_line
        filt_class_partner_recid = {'partner_owner_recid': str(my_partner['recid'])}
        filt_order_header_order_id= {'order_header_id': str(diction['order_id'])}

        query = [{'$match': {'$and': [filt_order_header_order_id,
                                      {'partner_owner_recid': str(my_partner['recid'])}]}},
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'order_line_formation',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'$and': [filt_class_partner_recid]}},
                                      {'$project': {'title': 1, 'domaine': 1,
                                                    'duration': 1,
                                                    'duration_unit': 1,
                                                    'external_code':1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]
        #print("#### Get_Given_Partner_Order_Lines_From_order_ref_interne  : query pip= ", query)
        val_tmp = 0
        Order_header_lines_data = []
        for retval in MYSY_GV.dbname['partner_order_line'].aggregate(query):
            if ('myclass_collection' in retval.keys() and len(retval['myclass_collection']) > 0):
                user = {}
                user['id'] = str(val_tmp)
                val_tmp = val_tmp + 1
                user['_id'] = retval['_id']
                user['order_line_formation'] = retval['order_line_formation']
                user['order_line_qty'] = retval['order_line_qty']
                user['order_line_prix_unitaire'] = retval['order_line_prix_unitaire']
                user['order_header_id'] = retval['order_header_id']
                user['order_header_ref_interne'] = retval['order_header_ref_interne']
                user['valide'] = retval['valide']
                user['locked'] = retval['locked']

                if ("order_line_session_id" in retval.keys()):
                    local_session_data = MYSY_GV.dbname['session_formation'].find_one({'_id':ObjectId(str(retval['order_line_session_id'])),
                                                                                       'valide':'1',
                                                                                       'partner_owner_recid':my_partner['recid']})

                    if( local_session_data ):

                        if( "code_session" in local_session_data.keys() ):
                            user['code_session'] = local_session_data['code_session']
                        else:
                            user['code_session'] = ""

                        if ("date_debut" in local_session_data.keys() and "date_fin" in local_session_data.keys() ):
                            user['session_date_debut'] = local_session_data['date_debut']
                            user['session_date_fin'] = local_session_data['date_fin']
                        else:
                            user['session_date_debut'] = ""
                            user['session_date_fin'] = ""
                else:
                    user['order_line_session_id'] = ""
                    user['code_session'] = ""
                    user['session_date_debut'] = ""
                    user['session_date_fin'] = ""



                if ("order_line_montant_reduction" in retval.keys()):
                    user['order_line_montant_reduction'] = retval['order_line_montant_reduction']
                else:
                    user['order_line_montant_reduction'] = "0"

                if ("order_line_montant_toutes_taxes" in retval.keys()):
                    user['order_line_montant_toutes_taxes'] = retval['order_line_montant_toutes_taxes']
                else:
                    user['order_line_montant_toutes_taxes'] = "0"

                if ("order_line_tax" in retval.keys()):
                    user['order_line_tax'] = retval['order_line_tax']
                else:
                    user['order_line_tax'] = ""

                if ("order_line_tax_amount" in retval.keys()):
                    user['order_line_tax_amount'] = retval['order_line_tax_amount']
                else:
                    user['order_line_tax_amount'] = "0"

                if ("order_line_type_reduction" in retval.keys()):
                    user['order_line_type_reduction'] = retval['order_line_type_reduction']
                else:
                    user['order_line_montant_reduction'] = ""

                if ("order_line_type_valeur" in retval.keys()):
                    user['order_line_type_valeur'] = retval['order_line_type_valeur']
                else:
                    user['order_line_type_valeur'] = "0"

                if ("order_line_montant_hors_taxes" in retval.keys()):
                    user['order_line_montant_hors_taxes'] = str(round(mycommon.tryFloat(str(retval['order_line_montant_hors_taxes'])), 2))
                else:
                    user['order_line_montant_hors_taxes'] = "0"

                user['date_update'] = retval['date_update']
                user['partner_owner_recid'] = retval['partner_owner_recid']
                user['order_line_type'] = retval['order_line_type']
                user['order_line_status'] = retval['order_line_status']
                if ("order_line_comment" in retval.keys()):
                    user['order_line_comment'] = retval['order_line_comment']
                else:
                    user['order_line_comment'] = ""

                user['title'] = retval['myclass_collection'][0]['title']
                user['order_line_formation_external_code'] = retval['myclass_collection'][0]['external_code']

                if ("domaine" in retval['myclass_collection'][0].keys()):
                    user['domaine'] = retval['myclass_collection'][0]['domaine']
                else:
                    user['domaine'] = ""

                user['duration'] = retval['myclass_collection'][0]['duration']
                user['duration_unit'] = retval['myclass_collection'][0]['duration_unit']

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

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

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

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

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

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

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

                Order_header_lines_data.append(user)


        if(len(Order_header_lines_data) <= 0 ):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Aucune ligne de détail pour cette commande ")
            return False, " Aucune ligne de détail pour cette commande "

        # Creation du dictionnaire d'information à utiliser pour la creation du doc

        tab_client = []
        tab_client.append(ObjectId(str(Order_header_data['order_header_client_id'])))

        convention_dictionnary_data = {}
        new_diction = {}
        new_diction['token'] = diction['token']
        new_diction['list_stagiaire_id'] = []
        new_diction['list_session_id'] = []
        new_diction['list_class_id'] = []
        new_diction['list_client_id'] = tab_client
        new_diction['list_apprenant_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

        convention_dictionnary_data['order_header'] = Order_header_data
        convention_dictionnary_data['order_lines'] = Order_header_lines_data

        body = {
            "params": convention_dictionnary_data,
        }

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

        # Verifier s'il s'agit d'un document à envoyer avec une version de pièce jointe.
        if ("joint_pdf" in partner_document_CONF_ORDER_data.keys() and str(partner_document_CONF_ORDER_data['joint_pdf']) == "1"):
            # Il s'agit bien d'un envoie avec 'contenu_doc' en pièce jointe PDF
            """
            1 - Creation du PDF
            """
            contenu_doc_Template = jinja2.Template(str(partner_document_CONF_ORDER_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 = str(Order_header_data['order_header_type']) +"_"+ str(my_partner['recid'])[0:5] + "_" + 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()

            # Attachement du fichier joint
            file_to_attache_to_mail = MIMEBase('application', "octet-stream")
            file_to_attache_to_mail.set_payload(open(outputFilename, "rb").read())

            encoders.encode_base64(file_to_attache_to_mail)
            file_to_attache_to_mail.add_header('Content-Disposition',
                                               'attachment; filename="{0}"'.format(os.path.basename(outputFilename)))

            new_node = {"attached_file": file_to_attache_to_mail}
            tab_files_to_attache_to_mail.append(new_node)

            contenu_pdf_doc_Template = jinja2.Template(str(partner_document_CONF_ORDER_data['contenu_doc']))
            corps_mail_doc_Template = jinja2.Template(str(partner_document_CONF_ORDER_data['corps_mail']))
            sujet_doc_Template_subject = jinja2.Template(str(partner_document_CONF_ORDER_data['sujet']))

            #print(" #### Order_header_data = ", Order_header_data)
            Order_header_data['order_header_type'] = str(Order_header_data['order_header_type']).capitalize()

            sourceHtml = corps_mail_doc_Template.render(params=body['params'], )
            sujetHtml = sujet_doc_Template_subject.render(params=body['params'], )
            contenu_pdf_html = contenu_pdf_doc_Template.render(params=body['params'], )


            html_mime = MIMEText(sourceHtml, 'html')

            # Creation de l'email à enoyer
            msg = MIMEMultipart("alternative")



            new_model_courrier_with_code_tag = "	 <div style='width: 100%'> <div style = 'width: 100%; text-align: center;' >" \
                                               " <img style = 'height:60px; width:60px;'   src = '{{ params.mysy_qrcode_securite }}' > <br/>" \
                                                                  "  <nav  style = 'font-size: 10px; font-style: italic;' > Sécurisé  par MySy Training  Technology </nav>" \
                                                                  "  <br/> </div> </div>" +\
                                               str( contenu_pdf_html) + "	 <div style='width: 100%'> <div style = 'width: 100%; text-align: center;' >" \
                                                                  "  Signature Client <br/> <img style = 'height:100px; width:100px' " \
                                                                  " src = '{{ params.mysy_manual_signature_img }}' >  <br/> " \
                                                                        "  </div> </div>"

            todays_date = str(date.today().strftime("%d_%m_%Y"))
            ts = datetime.now().timestamp()
            ts = str(ts).replace(".", "").replace(",", "")[-2:]

            orig_file_name = "Devis_" + str(my_partner['recid'])[0:5] + "_" + str(todays_date)+"_"+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=contenu_pdf_html,  # the HTML to convert
                dest=resultFile)  # file handle to receive result

            # close output file
            resultFile.close()

        else:
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " Le paramétrage du modèle de courrier 'PART_ORDER' ne comporte pas de 'joint_pdf' ")
            return False, " Le paramétrage du modèle de courrier 'PART_ORDER' ne comporte pas de 'joint_pdf' "


        """
                       Recuperation des parametre SMTP du partner si le client a decidé d'utiliser son propre smpt
                       """
        partner_own_smtp_value = "0"
        partner_own_smtp = MYSY_GV.dbname['base_partner_setup'].find_one(
            {'partner_owner_recid':str(my_partner['recid']),
             'config_name': 'partner_smtp',
             'valide': '1',
             'locked': '0'})

        if (partner_own_smtp and "config_value" in partner_own_smtp.keys()):
            partner_own_smtp_value = partner_own_smtp['config_value']

            if (str(partner_own_smtp_value) == "1"):
                partner_SMTP_COUNT_password = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_user_pwd',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_smtpsrv = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_server',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_user = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_user',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_From_User = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_count_from_name',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_port = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_count_port',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

        if (str(partner_own_smtp_value) == "1"):
            print("debut envoi mail de test ")
            # Creation de l'email à enoyer
            msg = MIMEMultipart("alternative")
            msg.attach(html_mime)

            smtpserver = smtplib.SMTP(partner_SMTP_COUNT_smtpsrv, partner_SMTP_COUNT_port)

            """
            La commande est envoyée à l'adresse email qui se trouve sur la commande, le champ : 'order_header_email_client'.

            Si ce champ est vide alors on regarde si il y a un email sur la fiche client.
            """
            client_main_mail_tmp = ""

            if ("order_header_email_client" in Order_header_data.keys() and Order_header_data[
                'order_header_email_client']):
                client_main_mail_tmp = str(Order_header_data['order_header_email_client'])

                if (mycommon.isEmailValide(client_main_mail_tmp) is True):
                    msg['To'] = client_main_mail_tmp

                else:
                    mycommon.myprint(str(inspect.stack()[0][
                                             3]) + " - L'adresse email sur la commande n'est pas valide ")
                    return False, " L'adresse email sur la commande n'est pas valide "

            else:
                mycommon.myprint(str(inspect.stack()[0][
                                         3]) + " - Aucune adresse email  sur la commande ")
                return False, " Aucune adresse email  sur la commande "

            msg['From'] = partner_SMTP_COUNT_From_User
            msg['Bcc'] = 'contact@mysy-training.com'
            msg['Subject'] = sujetHtml

            # Attacher l'eventuelle pièces jointes
            for myfile in tab_files_to_attache_to_mail:
                msg.attach(myfile['attached_file'])

            smtpserver.ehlo()
            smtpserver.starttls()
            smtpserver.login(partner_SMTP_COUNT_user, partner_SMTP_COUNT_password)
            val = smtpserver.send_message(msg)
            smtpserver.close()
            print(" Email envoyé " + str(val))


        else:

            print("debut envoi mail de test ")
            # Creation de l'email à enoyer
            msg = MIMEMultipart("alternative")

            msg.attach(html_mime)
            smtpserver = smtplib.SMTP(MYSY_GV.O365_SMTP_COUNT_smtpsrv, MYSY_GV.O365_SMTP_COUNT_port)

            """
            La commande est envoyée à l'adresse email qui se trouve sur la commande, le champ : 'order_header_email_client'.
            
            Si ce champ est vide alors on regarde si il y a un email sur la fiche client.
            """
            client_main_mail_tmp = ""


            if( "order_header_email_client" in Order_header_data.keys() and Order_header_data['order_header_email_client']):
                client_main_mail_tmp = str(Order_header_data['order_header_email_client'])


                if (mycommon.isEmailValide(client_main_mail_tmp) is True):
                    msg['To'] = client_main_mail_tmp

                else:
                    mycommon.myprint(str(inspect.stack()[0][
                                             3]) + " - L'adresse email sur la commande n'est pas valide ")
                    return False, " L'adresse email sur la commande n'est pas valide "

            else:
                mycommon.myprint(str(inspect.stack()[0][
                                         3]) + " - Aucune adresse email  sur la commande ")
                return False, " Aucune adresse email  sur la commande "


            msg['From'] = MYSY_GV.O365_SMTP_COUNT_From_User
            msg['Bcc'] = 'contact@mysy-training.com'
            msg['Subject'] = sujetHtml

            # Attacher l'eventuelle pièces jointes
            for myfile in tab_files_to_attache_to_mail:
                msg.attach(myfile['attached_file'])

            smtpserver.ehlo()
            smtpserver.starttls()
            smtpserver.login(MYSY_GV.O365_SMTP_COUNT_user, MYSY_GV.O365_SMTP_COUNT_password)
            val = smtpserver.send_message(msg)
            smtpserver.close()
            print(" Email envoyé " + str(val))


        """
            Gestion de la E-Signature 

            20/03/2024 : la convention pdf a été créée. 
            Si le partenaire a l'option de signature digitale, alors on créé le e-document
            """
        if (is_partner_digital_signature == "1"):

            tab_client = []
            tab_client.append(ObjectId(str(Order_header_data['order_header_client_id'])))

            new_diction = {}
            new_diction['token'] = diction['token']
            new_diction['list_stagiaire_id'] = []
            new_diction['list_session_id'] = []
            new_diction['list_class_id'] = []
            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

            client_data = convention_dictionnary_data['list_client_data']

            # print(client_data[0]['list_contact_communication'] )

            tab_emails_destinataire = []
            for tmp in client_data[0]['list_contact_communication']:
                if ("email" in tmp.keys() and tmp['email']):
                    tab_emails_destinataire.append(tmp['email'])

            new_e_document_diction = {}
            new_e_document_diction['token'] = diction['token']
            new_e_document_diction['file_name'] = outputFilename
            toaddrs = ", ".join(tab_emails_destinataire)
            new_e_document_diction['email_destinataire'] = str(toaddrs)
            new_e_document_diction['source_document'] = new_model_courrier_with_code_tag

            new_e_document_diction['type'] = "quotation"
            new_e_document_diction['related_collection'] = "quotation"
            new_e_document_diction['related_collection_id'] = str(diction['order_id'])



            if( "order_header_ref_interne" in Order_header_data.keys() ):
                new_e_document_diction['file_cononical_name'] = str(Order_header_data['order_header_ref_interne'])
            else:
                new_e_document_diction['file_cononical_name'] = ""

            local_status_e_doc, local_retval_e_doc = E_Sign_Document.Create_E_Document(new_e_document_diction)

            if (local_status_e_doc is False):
                return local_status_e_doc, local_retval_e_doc

            """
           Apres la creation du document electronique, on envoie la demande de validation
           /!\ on envoie le mail  à chaque destinataire
           """

            for email in tab_emails_destinataire:
                print(" ### traitement du mail : ", email)
                new_send_e_document_diction = {}
                new_send_e_document_diction['token'] = diction['token']
                new_send_e_document_diction['e_doc_id'] = str(local_retval_e_doc)
                new_send_e_document_diction['user_email'] = str(email)

                local_status_send_e_doc, local_send_retval_e_doc = E_Sign_Document.Sent_E_Document_Signature_Request(
                    new_send_e_document_diction)
                if (local_status_send_e_doc is False):
                    return local_status_send_e_doc, local_send_retval_e_doc


        """
        Mettre à jour la commande /devis pour dire que quand le document a été envoyé
        """
        updata_data = {}
        updata_data['date_update'] = str(datetime.now())
        updata_data['update_by'] = str(my_partner['recid'])
        updata_data['date_envoi_quotation'] = str(datetime.now())

        todays_date = str(date.today().strftime("%d/%m/%Y"))

        updata_data['date_dernier_relance_auto'] = str(todays_date)

        MYSY_GV.dbname['partner_order_header'].find_one_and_update(
            {'_id': ObjectId(str(Order_header_data['_id'])),
             'partner_owner_recid': str(Order_header_data['partner_owner_recid'])},
            {'$set': updata_data})


        return True, " Le document a été envoyé par email à : '"+str(client_main_mail_tmp)+"' "

    except  Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'envoyer la commande par email"



"""
Conversion un devis en commande.
Cette fonction prends uniquement un devis, le duplique avec en mettant le type = commande


condition de conversion : 
- Commande type = devis
- status devis = En cours => valeur 1
- Devis pas expiré


"""
def Convert_Quotation_to_Order(diction):
    try:
        field_list = ['order_id', '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]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, "Les informations fournies sont incorrectes", False

        """
                Verification de la liste des champs obligatoires
                """
        field_list_obligatoire = ['order_id', '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, " Les informations fournies sont incorrectes ", False

        query_get_data = {}
        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, False

        # Verification de la validité du devis à convertir
        qry = {'_id': ObjectId(str(diction['order_id'])), 'valide': '1', 'locked': '0','order_header_type':'devis',
               'partner_owner_recid': str(my_partner['recid'])}
        #print(" ### qry = ", qry)

        is_Order_Existe_Count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'_id': ObjectId(str(diction['order_id'])),
             'valide': '1', 'locked': '0','order_header_type':'devis',
             'partner_owner_recid': str(my_partner['recid'])})

        if (is_Order_Existe_Count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - La commande n'est pas valide ")
            return False, " La commande n'est pas valide", False

        Quotation_header_data_tmp = MYSY_GV.dbname['partner_order_header'].find_one(
            {'_id': ObjectId(str(diction['order_id'])),
             'valide': '1', 'locked': '0',
             'order_header_type': 'devis',
             'partner_owner_recid': str(
                 my_partner['recid'])},
            )

        if( Quotation_header_data_tmp['order_header_status'] != '1'):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Le statut du devis n'est pas 'en cours'")
            return False, "  Le statut du devis n'est pas 'en cours'", False

        mytoday = datetime.today().strftime("%d/%m/%Y")
        if( "order_header_date_expiration" in Quotation_header_data_tmp.keys() and len(str(Quotation_header_data_tmp['order_header_date_expiration']).strip()) > 0):
            if (datetime.strptime(str(Quotation_header_data_tmp['order_header_date_expiration']).strip(), '%d/%m/%Y') < datetime.strptime(str(mytoday), '%d/%m/%Y')  ):
                mycommon.myprint(
                str(inspect.stack()[0][3]) + " - Le devis a expiré ")
                return False, " Le devis a expiré", False




        Quotation_header_data = MYSY_GV.dbname['partner_order_header'].find_one({'_id': ObjectId(str(diction['order_id'])),
                                                                             'valide': '1', 'locked': '0',
                                                                             'order_header_type':'devis',
                                                                             'partner_owner_recid': str(
                                                                                 my_partner['recid'])},
                                                                            {'order_header_comment':0, '_id':0, 'date_update':0,
                                                                             'order_header_type':0, 'order_header_ref_interne':0,
                                                                             'partner_owner_recid':0,
                                                                             'valide':0, 'locked':0})

        New_Order_Header = Quotation_header_data
        New_Order_Header['order_header_origin'] = Quotation_header_data_tmp['order_header_ref_interne']
        New_Order_Header['order_header_type'] = "commande"
        New_Order_Header['order_header_status'] = "0"
        New_Order_Header['token'] = mytoken

        """
        Supprimer les data qui ne concernent pas la commande
        comme la date de validation du devis, la date reservation, etc
        """
        list_champ_to_delete = ['validation_by', 'date_validation', 'mode_reservation', 'date_reservation',
                                'date_envoi_quotation', 'date_dernier_relance_auto', 'nb_relance',
                                'list_relance', 'frequence_relance_auto', 'relance_auto', 'nb_relance_auto',
                                'is_validated', 'reservation_by', 'update_by']

        for val in list_champ_to_delete :
            if( val in New_Order_Header.keys() ):
                del New_Order_Header[val]


        local_status, local_message, local_retval = Add_Partner_Order(New_Order_Header)

        if( local_status is False ):
            return  local_status, local_message, False


        new_created_order = MYSY_GV.dbname['partner_order_header'].find_one({'order_header_ref_interne':str(local_retval)})
        #print(" ### La nouvelle Entete a été créer le num_order = ", new_created_order['order_header_ref_interne'])


        # Traitement des lignes
        cpt_line = 0
        qyr_convert = {'order_header_id': str(diction['order_id']),
                                                                             'valide': '1', 'locked': '0',
                                                                             'order_line_type':'devis',
                                                                             'partner_owner_recid': str(
                                                                                 my_partner['recid'])}



        #print( " #### qry convert = ", qyr_convert)

        for Quotation_line_data in MYSY_GV.dbname['partner_order_line'].find({'order_header_id': str(diction['order_id']),
                                                                             'valide': '1', 'locked': '0',
                                                                             'order_line_type':'devis',
                                                                             'partner_owner_recid': str(
                                                                                 my_partner['recid'])},
                                                                            {'order_header_comment':0, '_id':0, 'date_update':0,
                                                                             'order_line_status':0, 'order_line_type':0,
                                                                             'order_header_ref_interne':0, 'partner_owner_recid':0,
                                                                             'valide':0, 'locked':0}):
            New_Order_Line = Quotation_line_data
            New_Order_Line['order_header_ref_interne'] = new_created_order['order_header_ref_interne']
            New_Order_Line['order_header_id'] = str(new_created_order['_id'])
            New_Order_Line['order_line_type'] = "commande"
            New_Order_Line['token'] = mytoken
            New_Order_Line['order_line_id'] = ""
            New_Order_Line['order_line_status'] = "0"


            list_champ_to_delete = ['validation_by', 'date_validation', 'mode_reservation', 'date_reservation',
                                    'date_envoi_quotation', 'date_dernier_relance_auto', 'nb_relance',
                                    'list_relance', 'frequence_relance_auto', 'relance_auto', 'nb_relance_auto',
                                    'is_validated', 'reservation_by', 'update_by']

            for val in list_champ_to_delete:
                if (val in New_Order_Line.keys()):
                    del New_Order_Line[val]

            ##print(" ### New_Order_Line = ",New_Order_Line)
            local_add_line_status, local_add_line_retval = Add_Update_Partner_Order_Line(New_Order_Line)

            #print(" Ligne = ", cpt_line)
            cpt_line = cpt_line + 1


            """
            Apres la convertion, on met à jour le devis (entete et lignes)  pour dire qu'il a été gagné, 
            On met la ref de nouvelle commande dans le champs 'related_order_internal_ref' = new_created_order['order_header_ref_interne']
            """
            data_update = {}
            data_update['date_update'] = str(datetime.now())
            data_update['update_by'] = str(my_partner['_id'])
            data_update['order_header_status'] = "3"
            data_update['related_order_internal_ref'] = new_created_order['order_header_ref_interne']


            result = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
                {'_id': ObjectId(str(diction['order_id'])),
                 'valide': '1', 'locked': '0',
                 'order_header_type': 'devis',
                 'partner_owner_recid': str(
                     my_partner['recid'])}
                ,
                {"$set": data_update},
                upsert=False,
                return_document=ReturnDocument.AFTER
            )

            data_update = {}
            data_update['date_update'] = str(datetime.now())
            data_update['update_by'] = str(my_partner['_id'])
            data_update['order_line_status'] = "3"
            data_update['related_order_internal_ref'] = new_created_order['order_header_ref_interne']

            result = MYSY_GV.dbname['partner_order_line'].update_many(
                {'order_header_id': str(diction['order_id']),
                 'valide': '1', 'locked': '0',
                 'order_header_type': 'devis',
                 'partner_owner_recid': str(
                     my_partner['recid'])}
                ,
                {"$set": data_update},
            )




        mycommon.myprint(
            str(inspect.stack()[0][3]) + " Le devis "+str(Quotation_header_data_tmp['order_header_ref_interne'])+" a été correctement convertie en commande avec le numero : "+ new_created_order['order_header_ref_interne'])
        return True, " Le devis a été correctement convertit en commande. Ref. Commande est : "+str(str(new_created_order['order_header_ref_interne'])), str(new_created_order['order_header_ref_interne'])


    except  Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de convertir le devis en commande", False


"""
Cette fonction met une commande et lignes associées au statuts = '2', c'est a dire : pret à etre facturé
"""
def Order_Ready_To_Invoice(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token',  'order_header_id', ]

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list  and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes",

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['token',  'order_header_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, " Les informations fournies sont incorrectes",

        """
        Verification de l'identité et autorisation de l'entité qui
        appelle cette API
        """
        token = ""
        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']

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

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


        my_order_data_count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})

        if (my_order_data_count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - L'identifiant de la commande est invalide ")
            return False, " L'identifiant de la commande est invalide",


        """
                Recuperation et stockage des données de l'entete avant mise à jour
                """
        my_order_data_previous_information = MYSY_GV.dbname['partner_order_header'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))})

        if ( str(my_order_data_previous_information['order_header_status']) != "1" or  str(my_order_data_previous_information['order_header_type']) != "commande"):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " - La commande doit être au statut 'en cours'   avant d'être confirmé mise en facture ")
            return False, " La commande doit être au statut 'en cours'   avant d'être confirmé mise en facture"

        ### 1 - Mise à jour de l'entete
        # Recuperation des champs
        data = {}
        data['date_update'] = str(datetime.now())
        data['order_header_status'] = "2"

        print(" ### Update_partner_order data = ", data)

        inserted_data = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             '_id': ObjectId(str(order_header_id))},
            {"$set": data},
            return_document=ReturnDocument.AFTER,
            upsert=False,
        )

        if (inserted_data is None):
            mycommon.myprint(
                " Impossible de mettre à jour l'entete de commande ")
            return False, "Impossible de mettre à jour l'entete de commande  "

        """
               Mise à jour des lignes (partner_order_line) dont les status sont à 0 (brouillon) 
                """
        local_qry = {'partner_owner_recid': str(my_partner['recid']),
                     'valide': '1', 'locked': '0',
                     'order_header_id': str(order_header_id)
                     }
        # print(" #### COMMANDE local_qry = ", local_qry)

        inserted_data_line = MYSY_GV.dbname['partner_order_line'].update_many(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0',
             'order_header_id': str(order_header_id),
             'order_line_status': '1'
             },
            {
                "$set": {"order_line_status": "2",
                         'date_update': str(data['date_update'])}
            })

        """print("raw:", inserted_data_line.raw_result)
        print("acknowledged:", inserted_data_line.acknowledged)
        print("matched_count:", inserted_data_line.matched_count)"""

        comput_diction = {}
        comput_diction['token'] = diction['token']
        comput_diction['_id'] = diction['order_header_id']

        local_retval, local_message = Compute_Order_Header(comput_diction)
        if (local_retval is False):
            mycommon.myprint(" WARNING : Apres la confirmation, La fonction compute pour l'ordre : " + str(
                comput_diction) + " n'a pas fonctionnée, ")

        return True, " Le document a été correctement mise à jour"

    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 mettre à jour le document  "
    
    
    
"""
Cette fonction permet qu'a la validation d'un devis ayant une session associée
de d'aller reserver les place dans la session.

ceci n'est possible que si la session n'est pas depassée et
qu'on ne parle de que personne "preinscrit"

algo : 
A la validation, pour chaque ligne du devis,
1 - On supprimer toutes les preinscriptions dans la session ayant la valeur du devis
2 - On insert de nouvelles lignes qui auront : 
  nom = num_devis_Nom_cpt 
  prenom = num_devis_Prenom_cpt
  email = num_devis_cpt@email.com

3 - Apres la reservation, si le partenaire a activer et demandé d'appliquer la signature electronique
alors on declenche le processus de signature electronique

/!\ : lorsqu'on fait la reservation de place dans la session, on doit ajouter le client facturer = au client normal
  
"""
def Insert_Quotation_To_Session(diction):
    try:
        # Dictionnaire des champs utilisables
        '''
        # 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', 'quotation_id', 'request_digital_signature' ]

        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, "Impossible de créer le stagiaire. Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['token', 'quotation_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 créer le stagiaire. La valeur '" + val + "' n'est pas presente dans liste"

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


        """
        Verifier la validité du devis
        """
        is_valide_qotation = MYSY_GV.dbname['partner_order_header'].count_documents({'_id':ObjectId(str(diction['quotation_id'])),
                                                                                     'partner_owner_recid':str(my_partner['recid']),
                                                                                     'order_header_type':'devis',
                                                                                     'valide':'1',
                                                                                     'locked':'0'})

        if(is_valide_qotation != 1 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " L'identifiant du devis n'est pas valide ")
            return False, " L'identifiant du devis n'est pas valide "


        is_valide_qotation_data = MYSY_GV.dbname['partner_order_header'].find_one(
            {'_id': ObjectId(str(diction['quotation_id'])),
             'partner_owner_recid': str(my_partner['recid']),
             'order_header_type': 'devis',
             'valide': '1',
             'locked': '0'})

        if ("order_header_date_expiration" in is_valide_qotation_data.keys() and is_valide_qotation_data['order_header_date_expiration']):

            qotation_date_expiration = str(is_valide_qotation_data['order_header_date_expiration']).strip()[0:10]
            if (mycommon.CheckisDate(qotation_date_expiration) is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " La date d'expiration du devis n'est pas au format jj/mm/aaaa ")
                return False, "  La date d'expiration du devis n'est pas au format jj/mm/aaaa "

            date_today = datetime.now().strftime("%d/%m/%Y")

            if (datetime.strptime(str(qotation_date_expiration), '%d/%m/%Y') <= datetime.strptime(str(date_today), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " La date d'expiration du devis " + str(qotation_date_expiration) + "  est déjà dépassée ")

                return False, "  La date d'expiration du devis " + str(qotation_date_expiration) + "  est déjà dépassée  "



        warning_msg = ""
        is_warning = ""
        """
        Recuperer les lignes du devis 
        """

        nb_resa_line = 0

        for qotation_line in MYSY_GV.dbname['partner_order_line'].find({'order_header_id':str(diction['quotation_id']),
                                                                                     'partner_owner_recid':str(my_partner['recid']),
                                                                                     'order_line_type':'devis',
                                                                                     'valide':'1',
                                                                                     'locked':'0'}):

            if( "order_line_session_id" in qotation_line.keys() and  qotation_line['order_line_session_id']):
                print(" ### la ligne suivant a une order_line_session_id : ", qotation_line)

                # Verifier la validité de la session
                is_order_line_session_id_valide = MYSY_GV.dbname['session_formation'].count_documents({'_id':ObjectId(str(qotation_line['order_line_session_id'])),
                                                                                                       'valide':'1',
                                                                                                       'partner_owner_recid':str(my_partner['recid'])})

                if( is_order_line_session_id_valide != 1 ):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " L'identifiant de la session de formation  n'est pas valide ")
                    return False, " L'identifiant de la session de formation  n'est pas valide "

                is_order_line_session_id_data = MYSY_GV.dbname['session_formation'].find_one(
                    {'_id': ObjectId(str(qotation_line['order_line_session_id'])),
                     'valide': '1',
                     'partner_owner_recid': str(my_partner['recid'])})

                session_date_du = str(is_order_line_session_id_data['date_debut']).strip()[0:10]
                if( mycommon.CheckisDate(session_date_du) is False ):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " La date de debut de session n'est pas au format jj/mm/aaaa ")
                    return False, " La date de debut de session n'est pas au format jj/mm/aaaa "


                date_today =  datetime.now().strftime("%d/%m/%Y")

                if (datetime.strptime(str(session_date_du), '%d/%m/%Y') <= datetime.strptime( str(date_today), '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date de debut de session "+str(session_date_du)+"  est déjà dépassée ")

                    return False, " La date de debut de session "+str(session_date_du)+"  est déjà dépassée "



                """
                1 - Suppression des eventuelles preinscrit dans cette session ayant le meme devis
                """
                MYSY_GV.dbname['inscription'].delete_many({'partner_owner_recid':str(my_partner['recid']),
                                                           'session_id':str(qotation_line['order_line_session_id']),
                                                           'status':'0',
                                                           'quotation_id':str(diction['quotation_id'])})

                """
                2 - Inserer les nouvelles lignes 
                """
                line_qotation_qty = mycommon.tryInt(str(qotation_line['order_line_qty']))

                cpt = 0

                while( cpt < line_qotation_qty ):
                    cpt = cpt + 1

                    new_data = {}
                    new_data['nom'] = str(qotation_line['order_header_ref_interne'])+"_Resa_nom_"+str(cpt)
                    new_data['prenom'] = str(qotation_line['order_header_ref_interne']) + "_Resa_prenom_" + str(cpt)
                    new_data['email'] = str(qotation_line['order_header_ref_interne']) + "_Resa_mail_" + str(cpt)+"@mail.com"
                    new_data['telephone'] = "01010101"
                    new_data['modefinancement'] = ""
                    new_data['class_internal_url'] = str(is_order_line_session_id_data['class_internal_url'])
                    new_data['session_id'] = str(qotation_line['order_line_session_id'])
                    new_data['token'] = str(diction['token'])
                    new_data['client_rattachement_id'] = str(is_valide_qotation_data['order_header_client_id'])
                    new_data['facture_client_rattachement_id'] = str(is_valide_qotation_data['order_header_client_id'])
                    new_data['civilite'] = "neutre"
                    new_data['quotation_id'] = str(qotation_line['order_header_id'])
                    new_data['status'] = "0"

                    local_insert_status, local_insert_retval = Inscription_mgt.AddStagiairetoClass(new_data)

                    if( local_insert_status is False ):
                        is_warning = "1"
                        warning_msg = warning_msg + "\n" + str(local_insert_retval)

                    else:
                        nb_resa_line = nb_resa_line + 1

        """
        Mettre à jour du devis avec la date de validation et de reservation
        """
        now = str(datetime.now())
        update_data = {}
        update_data['date_update'] = now
        update_data['update_by'] = str(my_partner['_id'])
        update_data['date_validation'] = now
        update_data['date_reservation'] = now
        update_data['is_validated'] = "1"
        update_data['mode_reservation'] = "automatique"
        update_data['validation_by'] = str(my_partner['_id'])
        update_data['reservation_by'] = str(my_partner['_id'])

        MYSY_GV.dbname['partner_order_header'].update_many({'_id': ObjectId(str(diction['quotation_id'])),
                                                                'partner_owner_recid': str(my_partner['recid']),
                                                                'order_header_type': 'devis',
                                                                'valide': '1',
                                                                'locked': '0'},
                                                           {"$set": update_data},
                                                           )



        # Verification si le process de e-signature doit etre declenché
        if( "request_digital_signature" in diction.keys() and str(diction['request_digital_signature']) == "1"):

            """
            Verifier que le partenaire a bien le droit à l'option de e-signature
            """
            is_partner_digital_signature = ""

            is_signature_digital_count = MYSY_GV.dbname['base_partner_setup'].count_documents(
                {'partner_owner_recid': str(my_partner['recid']),
                 'config_name': 'signature_digital',
                 'valide': '1',
                 'locked': '0',
                 'config_value': '1'})
            if (is_signature_digital_count == 1):
                is_partner_digital_signature = "1"

                """
                On va generer le fichier PDF
                """
                local_diction = {}
                local_diction['token'] = diction['token']
                local_diction['order_id'] = str(diction['quotation_id'])


                local_file_status,  local_file_retaval_PDF, local_file_retaval_SourceHtml= Gernerate_Stock_PDF_Partner_Order(local_diction)
                if( local_file_status is False ):
                    return local_file_status, local_file_retaval_PDF

                outputFilename = local_file_retaval_PDF
                sourceHtml = local_file_retaval_SourceHtml

                new_model_courrier_with_code_tag = str(
                    sourceHtml) + " <p  style='width: 300px;  text-align: right;'> Signature Client <br/> <img style='height:150px; width:150px' src='{{ params.mysy_manual_signature_img }}'>&nbsp;</p> <br/> " \
                                  " <p  style='width: 300px;  text-align: center;'> <img style='height:150px; width:150px;' src='{{ params.mysy_qrcode_securite }}'>&nbsp;</p> "


                if (is_partner_digital_signature == "1"):

                    print("is_valide_qotation_data =  ", is_valide_qotation_data)

                    tab_client = []
                    tab_client.append(ObjectId(str(is_valide_qotation_data['order_header_client_id'])))

                    print("tab_client =  ", tab_client)

                    new_diction = {}
                    new_diction['token'] = diction['token']
                    new_diction['list_stagiaire_id'] = []
                    new_diction['list_session_id'] = []
                    new_diction['list_class_id'] = []
                    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


                    client_data = convention_dictionnary_data['list_client_data']


                    #print(client_data[0]['list_contact_communication'] )

                    tab_emails_destinataire = []
                    for tmp in client_data[0]['list_contact_communication'] :
                        if( "email" in tmp.keys() and tmp['email']):
                            tab_emails_destinataire.append(tmp['email'])


                    new_e_document_diction = {}
                    new_e_document_diction['token'] = diction['token']
                    new_e_document_diction['file_name'] = outputFilename
                    toaddrs = ", ".join(tab_emails_destinataire)
                    new_e_document_diction['email_destinataire'] = str(toaddrs)
                    new_e_document_diction['source_document'] = new_model_courrier_with_code_tag
                    new_e_document_diction['type'] = "quotation"
                    new_e_document_diction['related_collection'] = "quotation"
                    new_e_document_diction['related_collection_id'] = str(diction['quotation_id'])

                    local_status_e_doc, local_retval_e_doc = E_Sign_Document.Create_E_Document(new_e_document_diction)

                    if (local_status_e_doc is False):
                        return local_status_e_doc, local_retval_e_doc

                    """
                   Apres la creation du document electronique, on envoie la demande de validation
                   /!\ on envoie le mail  à chaque destinataire
                   """

                    for email in tab_emails_destinataire:
                        print(" ### traitement du mail : ", email)
                        new_send_e_document_diction = {}
                        new_send_e_document_diction['token'] = diction['token']
                        new_send_e_document_diction['e_doc_id'] = str(local_retval_e_doc)
                        new_send_e_document_diction['user_email'] = str(email)

                        local_status_send_e_doc, local_send_retval_e_doc = E_Sign_Document.Sent_E_Document_Signature_Request(
                            new_send_e_document_diction)
                        if (local_status_send_e_doc is False):
                            return local_status_send_e_doc, local_send_retval_e_doc




        if (is_warning == "1"):
            return True, str(warning_msg)

        return True, " Le devis a été correctement mis à jour. ("+str(nb_resa_line)+") réservation(s) faite(s)"


    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"



"""
Inser quotation from partner_owner_recid
"""
def Insert_Quotation_To_Session_From_Partner_Owner_Recid(diction):
    try:
        # Dictionnaire des champs utilisables
        '''
        # 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 = ['partner_owner_recid', 'quotation_id', 'request_digital_signature' ]

        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, "Impossible de créer le stagiaire. Toutes les informations fournies ne sont pas valables"

        """
        Verification de la liste des champs obligatoires
        """
        field_list_obligatoire = ['partner_owner_recid', 'quotation_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 créer le stagiaire. La valeur '" + val + "' n'est pas presente dans liste"



        my_partner = {}
        my_partner['recid'] = diction['partner_owner_recid']
        """
        Verifier la validité du devis
        """

        qry = {'_id':ObjectId(str(diction['quotation_id'])),
                                                                                     'partner_owner_recid':str(my_partner['recid']),
                                                                                     'order_header_type':'devis',
                                                                                     'valide':'1',
                                                                                     'locked':'0'}

        print(" ### qty = ", qry )
        is_valide_qotation = MYSY_GV.dbname['partner_order_header'].count_documents({'_id':ObjectId(str(diction['quotation_id'])),
                                                                                     'partner_owner_recid':str(my_partner['recid']),
                                                                                     'order_header_type':'devis',
                                                                                     'valide':'1',
                                                                                     'locked':'0'})

        if(is_valide_qotation != 1 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " L'identifiant du devis n'est pas valide ")
            return False, " L'identifiant du devis n'est pas valide "


        is_valide_qotation_data = MYSY_GV.dbname['partner_order_header'].find_one(
            {'_id': ObjectId(str(diction['quotation_id'])),
             'partner_owner_recid': str(my_partner['recid']),
             'order_header_type': 'devis',
             'valide': '1',
             'locked': '0'})

        if ("order_header_date_expiration" in is_valide_qotation_data.keys() and is_valide_qotation_data['order_header_date_expiration']):

            qotation_date_expiration = str(is_valide_qotation_data['order_header_date_expiration']).strip()[0:10]
            if (mycommon.CheckisDate(qotation_date_expiration) is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " La date d'expiration du devis n'est pas au format jj/mm/aaaa ")
                return False, "  La date d'expiration du devis n'est pas au format jj/mm/aaaa "

            date_today = datetime.now().strftime("%d/%m/%Y")

            if (datetime.strptime(str(qotation_date_expiration), '%d/%m/%Y') <= datetime.strptime(str(date_today), '%d/%m/%Y')):
                mycommon.myprint(
                    str(inspect.stack()[0][
                            3]) + " La date d'expiration du devis " + str(qotation_date_expiration) + "  est déjà dépassée ")

                return False, "  La date d'expiration du devis " + str(qotation_date_expiration) + "  est déjà dépassée  "



        warning_msg = ""
        is_warning = ""
        """
        Recuperer les lignes du devis 
        """

        nb_resa_line = 0

        for qotation_line in MYSY_GV.dbname['partner_order_line'].find({'order_header_id':str(diction['quotation_id']),
                                                                                     'partner_owner_recid':str(my_partner['recid']),
                                                                                     'order_line_type':'devis',
                                                                                     'valide':'1',
                                                                                     'locked':'0'}):

            if( "order_line_session_id" in qotation_line.keys() and  qotation_line['order_line_session_id']):
                print(" ### la ligne suivant a une order_line_session_id : ", qotation_line)

                # Verifier la validité de la session
                is_order_line_session_id_valide = MYSY_GV.dbname['session_formation'].count_documents({'_id':ObjectId(str(qotation_line['order_line_session_id'])),
                                                                                                       'valide':'1',
                                                                                                       'partner_owner_recid':str(my_partner['recid'])})

                if( is_order_line_session_id_valide != 1 ):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " L'identifiant de la session de formation  n'est pas valide ")
                    return False, " L'identifiant de la session de formation  n'est pas valide "

                is_order_line_session_id_data = MYSY_GV.dbname['session_formation'].find_one(
                    {'_id': ObjectId(str(qotation_line['order_line_session_id'])),
                     'valide': '1',
                     'partner_owner_recid': str(my_partner['recid'])})

                session_date_du = str(is_order_line_session_id_data['date_debut']).strip()[0:10]
                if( mycommon.CheckisDate(session_date_du) is False ):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + " La date de debut de session n'est pas au format jj/mm/aaaa ")
                    return False, " La date de debut de session n'est pas au format jj/mm/aaaa "


                date_today =  datetime.now().strftime("%d/%m/%Y")

                if (datetime.strptime(str(session_date_du), '%d/%m/%Y') <= datetime.strptime( str(date_today), '%d/%m/%Y')):
                    mycommon.myprint(
                        str(inspect.stack()[0][
                                3]) + " La date de debut de session "+str(session_date_du)+"  est déjà dépassée ")

                    return False, " La date de debut de session "+str(session_date_du)+"  est déjà dépassée "



                """
                1 - Suppression des eventuelles preinscrit dans cette session ayant le meme devis
                """
                MYSY_GV.dbname['inscription'].delete_many({'partner_owner_recid':str(my_partner['recid']),
                                                           'session_id':str(qotation_line['order_line_session_id']),
                                                           'status':'0',
                                                           'quotation_id':str(diction['quotation_id'])})

                """
                2 - Inserer les nouvelles lignes 
                """
                line_qotation_qty = mycommon.tryInt(str(qotation_line['order_line_qty']))

                cpt = 0

                while( cpt < line_qotation_qty ):
                    cpt = cpt + 1

                    new_data = {}
                    new_data['nom'] = str(qotation_line['order_header_ref_interne'])+"_Reservation_Nom_"+str(cpt)
                    new_data['prenom'] = str(qotation_line['order_header_ref_interne']) + "_Reservation_Prenom_" + str(cpt)
                    new_data['email'] = str(qotation_line['order_header_ref_interne']) + "_Reservation_mail_" + str(cpt)+"@mail.com"
                    new_data['telephone'] = "01010101"
                    new_data['modefinancement'] = ""
                    new_data['class_internal_url'] = str(is_order_line_session_id_data['class_internal_url'])
                    new_data['session_id'] = str(qotation_line['order_line_session_id'])

                    new_data['client_rattachement_id'] = str(is_valide_qotation_data['order_header_client_id'])
                    new_data['civilite'] = "neutre"
                    new_data['quotation_id'] = str(qotation_line['order_header_id'])
                    new_data['status'] = "0"

                    """
                    /!\
                    22/04/2024 :On a besoin du token pour utiliser la fonction standard.
                    On va aller recuperer le token du compte principale du partner
                     /!\
                    """
                    main_account_data = MYSY_GV.dbname['partnair_account'].find_one({'recid':str(diction['partner_owner_recid']),
                                                                                     'active':'1', 'is_partner_admin_account':'1'})
                    new_data['token'] = str(main_account_data['token'])

                    local_insert_status, local_insert_retval = Inscription_mgt.AddStagiairetoClass(new_data)

                    if( local_insert_status is False ):
                        is_warning = "1"
                        warning_msg = warning_msg + "\n" + str(local_insert_retval)

                    else:
                        nb_resa_line = nb_resa_line + 1



        """
        Mettre à jour du devis avec la date de validation et de reservation
        """
        now = str(datetime.now())
        update_data = {}
        update_data['date_update'] = now
        update_data['update_by'] = "client"
        update_data['date_validation'] = now
        update_data['date_reservation'] = now
        update_data['is_validated'] = "1"
        update_data['mode_reservation'] = "automatique"
        update_data['validation_by'] = "client"
        update_data['reservation_by'] = "client"

        MYSY_GV.dbname['partner_order_header'].update_many({'_id': ObjectId(str(diction['quotation_id'])),
                                                                'partner_owner_recid': str(my_partner['recid']),
                                                                'order_header_type': 'devis',
                                                                'valide': '1',
                                                                'locked': '0'},
                                                           {"$set": update_data},
                                                           )



        # Verification si le process de e-signature doit etre declenché
        if( "request_digital_signature" in diction.keys() and str(diction['request_digital_signature']) == "1"):

            """
            Verifier que le partenaire a bien le droit à l'option de e-signature
            """
            is_partner_digital_signature = ""

            is_signature_digital_count = MYSY_GV.dbname['base_partner_setup'].count_documents(
                {'partner_owner_recid': str(my_partner['recid']),
                 'config_name': 'signature_digital',
                 'valide': '1',
                 'locked': '0',
                 'config_value': '1'})
            if (is_signature_digital_count == 1):
                is_partner_digital_signature = "1"

                """
                On va generer le fichier PDF
                """
                local_diction = {}
                local_diction['token'] = diction['token']
                local_diction['order_id'] = str(diction['quotation_id'])


                local_file_status,  local_file_retaval_PDF, local_file_retaval_SourceHtml= Gernerate_Stock_PDF_Partner_Order(local_diction)
                if( local_file_status is False ):
                    return local_file_status, local_file_retaval_PDF

                outputFilename = local_file_retaval_PDF
                sourceHtml = local_file_retaval_SourceHtml

                new_model_courrier_with_code_tag = str(
                    sourceHtml) + " <p  style='width: 300px;  text-align: right;'> Signature Client <br/> <img style='height:150px; width:150px' src='{{ params.mysy_manual_signature_img }}'>&nbsp;</p> <br/> " \
                                  " <p  style='width: 300px;  text-align: center;'> <img style='height:150px; width:150px;' src='{{ params.mysy_qrcode_securite }}'>&nbsp;</p> "

                if (is_partner_digital_signature == "1"):

                    print("is_valide_qotation_data =  ", is_valide_qotation_data)

                    tab_client = []
                    tab_client.append(ObjectId(str(is_valide_qotation_data['order_header_client_id'])))

                    print("tab_client =  ", tab_client)

                    new_diction = {}
                    new_diction['token'] = diction['token']
                    new_diction['list_stagiaire_id'] = []
                    new_diction['list_session_id'] = []
                    new_diction['list_class_id'] = []
                    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


                    client_data = convention_dictionnary_data['list_client_data']


                    #print(client_data[0]['list_contact_communication'] )

                    tab_emails_destinataire = []
                    for tmp in client_data[0]['list_contact_communication'] :
                        if( "email" in tmp.keys() and tmp['email']):
                            tab_emails_destinataire.append(tmp['email'])


                    new_e_document_diction = {}
                    new_e_document_diction['token'] = diction['token']
                    new_e_document_diction['file_name'] = outputFilename
                    toaddrs = ", ".join(tab_emails_destinataire)
                    new_e_document_diction['email_destinataire'] = str(toaddrs)
                    new_e_document_diction['source_document'] = new_model_courrier_with_code_tag
                    new_e_document_diction['type'] = "quotation"
                    new_e_document_diction['related_collection'] = "quotation"
                    new_e_document_diction['related_collection_id'] = str(diction['quotation_id'])

                    local_status_e_doc, local_retval_e_doc = E_Sign_Document.Create_E_Document(new_e_document_diction)

                    if (local_status_e_doc is False):
                        return local_status_e_doc, local_retval_e_doc

                    """
                   Apres la creation du document electronique, on envoie la demande de validation
                   /!\ on envoie le mail  à chaque destinataire
                   """

                    for email in tab_emails_destinataire:
                        print(" ### traitement du mail : ", email)
                        new_send_e_document_diction = {}
                        new_send_e_document_diction['token'] = diction['token']
                        new_send_e_document_diction['e_doc_id'] = str(local_retval_e_doc)
                        new_send_e_document_diction['user_email'] = str(email)

                        local_status_send_e_doc, local_send_retval_e_doc = E_Sign_Document.Sent_E_Document_Signature_Request(
                            new_send_e_document_diction)
                        if (local_status_send_e_doc is False):
                            return local_status_send_e_doc, local_send_retval_e_doc




        if (is_warning == "1"):
            return True, str(warning_msg)

        return True, " Le devis a été correctement mis à jour. ("+str(nb_resa_line)+") réservation(s) faite(s)"


    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"


"""
Cette fonction envoie une relance d'email, niveau 1
"""
def Send_Quotation_Remind_Level1(diction):
    try:
        field_list = ['order_id', '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]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, "Les informations fournies sont incorrectes"

        """
                Verification de la liste des champs obligatoires
                """
        field_list_obligatoire = ['order_id', '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, " Les informations fournies sont incorrectes "

        query_get_data = {}
        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



        # Verification de la validité de l'order
        qry = {'_id': ObjectId(str(diction['order_id'])), 'valide': '1', 'locked': '0',
               'partner_owner_recid': str(my_partner['recid'])}
        # print(" ### qry = ", qry)

        is_Order_Existe_Count = MYSY_GV.dbname['partner_order_header'].count_documents(
            {'_id': ObjectId(str(diction['order_id'])),
             'valide': '1', 'locked': '0', 'order_header_type':'devis',
             'partner_owner_recid': str(my_partner['recid'])})

        if (is_Order_Existe_Count != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " - La commande n'est pas valide ")
            return False, " La commande n'est pas valide",

        Order_header_data = MYSY_GV.dbname['partner_order_header'].find_one({'_id': ObjectId(str(diction['order_id'])),
                                                                             'valide': '1', 'locked': '0','order_header_type':'devis',
                                                                             'partner_owner_recid': str(
                                                                                 my_partner['recid'])})

        # Creation du dictionnaire d'information à utiliser pour la creation du doc

        tab_client = []
        tab_client.append(ObjectId(str(Order_header_data['order_header_client_id'])))

        convention_dictionnary_data = {}
        new_diction = {}
        new_diction['token'] = diction['token']
        new_diction['list_stagiaire_id'] = []
        new_diction['list_session_id'] = []
        new_diction['list_class_id'] = []
        new_diction['list_client_id'] = tab_client
        new_diction['list_apprenant_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


        """
        # Recuperer le modele de courrier pour la relance niveau 1 des devis :        
        ref_interne = 'QUOTATION_REMINDER_LEVEL_1'
        """

        # print(" ### partner_document_CONF_ORDER_data_qry = ", partner_document_CONF_ORDER_data_qry)
        partner_document_QUOTATION_REMIND_data = MYSY_GV.dbname['courrier_template'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'valide': '1', 'locked': '0', 'ref_interne': 'QUOTATION_REMINDER_LEVEL_1',
             'type_doc': 'email'})

        if (partner_document_QUOTATION_REMIND_data is None):
            # Il n'existe pas de personnalisation de la preinscription pour ce partenaire, on va aller récupérer la presinscription pa defaut
            partner_document_QUOTATION_REMIND_data = MYSY_GV.dbname['courrier_template'].find_one(
                {'partner_owner_recid': 'default',
                 'valide': '1', 'locked': '0', 'ref_interne': 'QUOTATION_REMINDER_LEVEL_1',
                 'type_doc': 'email'})

        if (partner_document_QUOTATION_REMIND_data is None):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " Aucun document de type 'partner_document_QUOTATION_REMIND_data' paramétrer ")
            return False, " Aucun document de type 'partner_document_QUOTATION_REMIND_data' paramétrer "

        if ("contenu_doc" not in partner_document_QUOTATION_REMIND_data or len(
                str(partner_document_QUOTATION_REMIND_data['contenu_doc'])) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Le paramétrage du document  est invalide -contenu_doc- ")
            return False, " Le paramétrage du document  est invalide -contenu_doc- "

        if ("corps_mail" not in partner_document_QUOTATION_REMIND_data or len(
                str(partner_document_QUOTATION_REMIND_data['corps_mail'])) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Le paramétrage du document  est invalide -corps_mail- ")
            return False, " Le paramétrage du document  est invalide -corps_mail- "

        # Recuperation des données du client
        if ("order_header_client_id" in Order_header_data.keys()):
            Order_header_client_data = MYSY_GV.dbname['partner_client'].find_one(
                {'_id': ObjectId(str(Order_header_data['order_header_client_id'])),
                 'partner_recid': str(my_partner['recid']), 'valide': '1', 'locked': '0'})

            if (Order_header_client_data is None):
                mycommon.myprint(str(inspect.stack()[0][
                                         3]) + " - Le client est invalide")
                return False, " Le client est invalide"

        # Recuperation des contacts de communication du client

        tab_emails_destinataire = []

        local_diction = {}
        local_diction['token'] = diction['token']
        local_diction['_id'] = str(Order_header_data['order_header_client_id'])

        local_status, partner_client_contact_communication = partner_client.Get_Partner_Client_Communication_Contact(
            local_diction)

        if (local_status is True):
            # print(" partner_client_contact_communication = ", partner_client_contact_communication)
            for contact_communication_str in partner_client_contact_communication:
                contact_communication = ast.literal_eval(contact_communication_str)
                if( "email" in contact_communication.keys() and contact_communication['email']):
                    tab_emails_destinataire.append(str(contact_communication['email']))

        """
              Recup condition paiement id 
              """
        cdtion_paiement_code = ""
        cdtion_paiement_id = ""
        if ("order_header_condition_paiement_id" in Order_header_data.keys() and Order_header_data[
            'order_header_condition_paiement_id']):
            cdtion_paiement_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
                {'_id': ObjectId(str(Order_header_data['order_header_condition_paiement_id'])),
                 'valide': '1',
                 'locked': '0',
                 }
                )

            if (cdtion_paiement_data and 'code' in cdtion_paiement_data.keys()):
                cdtion_paiement_code = str(cdtion_paiement_data['code'])
                cdtion_paiement_id = str(cdtion_paiement_data['_id'])

        Order_header_data['order_header_condition_paiement_code'] = cdtion_paiement_code
        Order_header_data['order_header_condition_paiement_id'] = cdtion_paiement_id

        # Recuperation des details de lignes de : partner_order_line
        filt_class_partner_recid = {'partner_owner_recid': str(my_partner['recid'])}
        filt_order_header_order_id = {'order_header_id': str(diction['order_id'])}

        query = [{'$match': {'$and': [filt_order_header_order_id,
                                      {'partner_owner_recid': str(my_partner['recid'])}]}},
                 {'$lookup':
                     {
                         'from': 'myclass',
                         'localField': 'order_line_formation',
                         'foreignField': 'internal_url',
                         'pipeline': [{'$match': {'$and': [filt_class_partner_recid]}},
                                      {'$project': {'title': 1, 'domaine': 1,
                                                    'duration': 1,
                                                    'duration_unit': 1,
                                                    'external_code': 1}}],
                         'as': 'myclass_collection'
                     }
                 }
                 ]
        # print("#### Get_Given_Partner_Order_Lines_From_order_ref_interne  : query pip= ", query)
        val_tmp = 0
        Order_header_lines_data = []
        for retval in MYSY_GV.dbname['partner_order_line'].aggregate(query):
            if ('myclass_collection' in retval.keys() and len(retval['myclass_collection']) > 0):
                user = {}
                user['id'] = str(val_tmp)
                val_tmp = val_tmp + 1
                user['_id'] = retval['_id']
                user['order_line_formation'] = retval['order_line_formation']
                user['order_line_qty'] = retval['order_line_qty']
                user['order_line_prix_unitaire'] = retval['order_line_prix_unitaire']
                user['order_header_id'] = retval['order_header_id']
                user['order_header_ref_interne'] = retval['order_header_ref_interne']
                user['valide'] = retval['valide']
                user['locked'] = retval['locked']

                if ("order_line_session_id" in retval.keys()):
                    local_session_data = MYSY_GV.dbname['session_formation'].find_one(
                        {'_id': ObjectId(str(retval['order_line_session_id'])),
                         'valide': '1',
                         'partner_owner_recid': my_partner['recid']})

                    if (local_session_data):

                        if ("code_session" in local_session_data.keys()):
                            user['code_session'] = local_session_data['code_session']
                        else:
                            user['code_session'] = ""

                        if ("date_debut" in local_session_data.keys() and "date_fin" in local_session_data.keys()):
                            user['session_date_debut'] = local_session_data['date_debut']
                            user['session_date_fin'] = local_session_data['date_fin']
                        else:
                            user['session_date_debut'] = ""
                            user['session_date_fin'] = ""
                else:
                    user['order_line_session_id'] = ""
                    user['code_session'] = ""
                    user['session_date_debut'] = ""
                    user['session_date_fin'] = ""

                if ("order_line_montant_reduction" in retval.keys()):
                    user['order_line_montant_reduction'] = retval['order_line_montant_reduction']
                else:
                    user['order_line_montant_reduction'] = "0"

                if ("order_line_montant_toutes_taxes" in retval.keys()):
                    user['order_line_montant_toutes_taxes'] = retval['order_line_montant_toutes_taxes']
                else:
                    user['order_line_montant_toutes_taxes'] = "0"

                if ("order_line_tax" in retval.keys()):
                    user['order_line_tax'] = retval['order_line_tax']
                else:
                    user['order_line_tax'] = ""

                if ("order_line_tax_amount" in retval.keys()):
                    user['order_line_tax_amount'] = retval['order_line_tax_amount']
                else:
                    user['order_line_tax_amount'] = "0"

                if ("order_line_type_reduction" in retval.keys()):
                    user['order_line_type_reduction'] = retval['order_line_type_reduction']
                else:
                    user['order_line_montant_reduction'] = ""

                if ("order_line_type_valeur" in retval.keys()):
                    user['order_line_type_valeur'] = retval['order_line_type_valeur']
                else:
                    user['order_line_type_valeur'] = "0"

                if ("order_line_montant_hors_taxes" in retval.keys()):
                    user['order_line_montant_hors_taxes'] = str(
                        round(mycommon.tryFloat(str(retval['order_line_montant_hors_taxes'])), 2))
                else:
                    user['order_line_montant_hors_taxes'] = "0"

                user['date_update'] = retval['date_update']
                user['partner_owner_recid'] = retval['partner_owner_recid']
                user['order_line_type'] = retval['order_line_type']
                user['order_line_status'] = retval['order_line_status']
                if ("order_line_comment" in retval.keys()):
                    user['order_line_comment'] = retval['order_line_comment']
                else:
                    user['order_line_comment'] = ""

                user['title'] = retval['myclass_collection'][0]['title']
                user['order_line_formation_external_code'] = retval['myclass_collection'][0]['external_code']

                if ("domaine" in retval['myclass_collection'][0].keys()):
                    user['domaine'] = retval['myclass_collection'][0]['domaine']
                else:
                    user['domaine'] = ""

                user['duration'] = retval['myclass_collection'][0]['duration']
                user['duration_unit'] = retval['myclass_collection'][0]['duration_unit']

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

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

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

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

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

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

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

                Order_header_lines_data.append(user)

        if (len(Order_header_lines_data) <= 0):
            mycommon.myprint(str(inspect.stack()[0][
                                     3]) + " - Aucune ligne de détail pour cette commande ")
            return False, " Aucune ligne de détail pour cette commande "

        convention_dictionnary_data['order_header'] = Order_header_data
        convention_dictionnary_data['order_lines'] = Order_header_lines_data

        body = {
            "params": convention_dictionnary_data,
        }

        #print(" #### BODY = ", body) zzzz

        # print(" ### Order_header_lines_data =  ", Order_header_lines_data)

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

        #######
        # Verifier s'il s'agit d'un document à envoyer avec une version de pièce jointe.
        if ("joint_pdf" in partner_document_QUOTATION_REMIND_data.keys() and str(partner_document_QUOTATION_REMIND_data['joint_pdf']) == "1"):
            # Il s'agit bien d'un envoie avec 'contenu_doc' en pièce jointe PDF
            """
            1 - Creation du PDF
            """


            contenu_doc_Template = jinja2.Template(str(partner_document_QUOTATION_REMIND_data['contenu_doc']))

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

            ###
            # print(" #### Order_header_data = ", Order_header_data)
            Order_header_data['order_header_type'] = str(Order_header_data['order_header_type']).capitalize()

            sourceHtml = contenu_doc_Template.render(params=body['params'],)

            sujet_doc_Template = jinja2.Template(str(partner_document_QUOTATION_REMIND_data['sujet']))
            sujetHtml = sujet_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 = "Devis_" + str(my_partner['recid'])[0:5] + "_" + 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()

            # Attachement du fichier joint
            file_to_attache_to_mail = MIMEBase('application', "octet-stream")
            file_to_attache_to_mail.set_payload(open(outputFilename, "rb").read())

            encoders.encode_base64(file_to_attache_to_mail)
            file_to_attache_to_mail.add_header('Content-Disposition',
                                               'attachment; filename="{0}"'.format(
                                                   os.path.basename(outputFilename)))

            new_node = {"attached_file": file_to_attache_to_mail}
            tab_files_to_attache_to_mail.append(new_node)

            ## Creation du  mail au format email

            corps_mail_Template = jinja2.Template(str(partner_document_QUOTATION_REMIND_data['corps_mail']))

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

            html_mime = MIMEText(sourceHtml, 'html')

            # Creation de l'email à enoyer
            msg = MIMEMultipart("alternative")




        """
                       Recuperation des parametre SMTP du partner si le client a decidé d'utiliser son propre smpt
                       """
        partner_own_smtp_value = "0"
        partner_own_smtp = MYSY_GV.dbname['base_partner_setup'].find_one(
            {'partner_owner_recid': str(my_partner['recid']),
             'config_name': 'partner_smtp',
             'valide': '1',
             'locked': '0'})

        if (partner_own_smtp and "config_value" in partner_own_smtp.keys()):
            partner_own_smtp_value = partner_own_smtp['config_value']

            if (str(partner_own_smtp_value) == "1"):
                partner_SMTP_COUNT_password = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_user_pwd',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_smtpsrv = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_server',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_user = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_user',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_From_User = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_count_from_name',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

                partner_SMTP_COUNT_port = str(MYSY_GV.dbname['base_partner_setup'].find_one(
                    {'partner_owner_recid': str(my_partner['recid']),
                     'config_name': 'smtp_count_port',
                     'valide': '1',
                     'locked': '0'}, {'config_value': 1})['config_value'])

        if (str(partner_own_smtp_value) == "1"):
            print("debut envoi mail de test ")
            #msg = EmailMessage()
            msg = MIMEMultipart("alternative")

            smtpserver = smtplib.SMTP(partner_SMTP_COUNT_smtpsrv, partner_SMTP_COUNT_port)

            """
            La commande est envoyée à l'adresse email qui se trouve sur la commande, le champ : 'order_header_email_client'.

            Si ce champ est vide alors on regarde si il y a un email sur la fiche client.
            """


            msg.attach(html_mime)
            msg['From'] = partner_SMTP_COUNT_From_User
            msg['Bcc'] = 'contact@mysy-training.com'
            msg['Subject'] = sujetHtml
            toaddrs = ", ".join(tab_emails_destinataire)
            msg['to'] = str(toaddrs)

            # Attacher l'eventuelle pièces jointes
            for myfile in tab_files_to_attache_to_mail:
                msg.attach(myfile['attached_file'])

            smtpserver.ehlo()
            smtpserver.starttls()
            smtpserver.login(partner_SMTP_COUNT_user, partner_SMTP_COUNT_password)
            val = smtpserver.send_message(msg)
            smtpserver.close()
            print(" Email envoyé " + str(val))



        else:

            print("debut envoi mail de test ")
            #msg = EmailMessage()
            msg = MIMEMultipart("alternative")


            msg.attach(html_mime)
            smtpserver = smtplib.SMTP(MYSY_GV.O365_SMTP_COUNT_smtpsrv, MYSY_GV.O365_SMTP_COUNT_port)

            msg['From'] = MYSY_GV.O365_SMTP_COUNT_From_User
            msg['Bcc'] = 'contact@mysy-training.com'
            msg['Subject'] = sujetHtml
            toaddrs = ", ".join(tab_emails_destinataire)
            msg['to'] = str(toaddrs)

            # Attacher l'eventuelle pièces jointes
            for myfile in tab_files_to_attache_to_mail:
                msg.attach(myfile['attached_file'])

            smtpserver.ehlo()
            smtpserver.starttls()
            smtpserver.login(MYSY_GV.O365_SMTP_COUNT_user, MYSY_GV.O365_SMTP_COUNT_password)
            val = smtpserver.send_message(msg)
            smtpserver.close()
            print(" Email envoyé " + str(val))


        return True, " Relance envoyé à : '" + str(toaddrs) + "' "

    except  Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de faire la relance du devis "



"""
Cette fonction créé automatiquement un devis
avec l'_id du lead concerée.
si besoin on créer le prospect
"""
def Create_Automatic_Quotation(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['partner_owner_recid', 'lead_website_id']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list and val.startswith('my_') is False:
                mycommon.myprint(str(
                    inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'est pas autorisé")
                return False, " Les informations fournies sont incorrectes", False

        """
        Verification des champs obligatoires
        """
        field_list_obligatoire = ['partner_owner_recid', 'lead_website_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, " Les informations fournies sont incorrectes", False



        local_status, my_partner = mycommon.Get_Connected_User_Partner_Data_From_RecID(str(diction['partner_owner_recid']))
        if (local_status is not True):
            return local_status, my_partner

        """
        Verifier la validité du lead_website
        """
        is_valide_lead_website = MYSY_GV.dbname['lead_website'].count_documents({'_id':ObjectId(str(diction['lead_website_id'])),
                                                                                 'valide':'1',
                                                                                 'locked':'0',
                                                                                 'partner_owner_recid':str(diction['partner_owner_recid'])})

        if( is_valide_lead_website != 1 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " L'identifiant du leads est invalide ")
            return False, " L'identifiant du leads est invalide ", False



        valide_lead_website_data = MYSY_GV.dbname['lead_website'].find_one({'_id':ObjectId(str(diction['lead_website_id'])),
                                                                                 'valide':'1',
                                                                                 'locked':'0',
                                                                                 'partner_owner_recid':str(diction['partner_owner_recid'])})

        """
        Verifier si le client existe
        """
        client_connu = "0"
        client_blocked = "0"

        is_client_exist_count = MYSY_GV.dbname['partner_client'].count_documents({'partner_recid':str(valide_lead_website_data['partner_owner_recid']),
                                                                 'siret':str(valide_lead_website_data['siret'])})


        if( is_client_exist_count == 1 ):
            is_client_exist_data = MYSY_GV.dbname['partner_client'].find_one(
                {'partner_recid': str(valide_lead_website_data['partner_owner_recid']),
                 'siret': str(valide_lead_website_data['siret'])})


            if( is_client_exist_data['locked'] == "1" or is_client_exist_data['valide'] == "0"):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Ce client est verrouillé, impossible de créer un devis ")
                return False, " Ce client est verrouillé, impossible de créer un devis ", False

            else:
                client_connu = "1"


        if( str(client_connu) != "1"):
            ## Le client est inconnu, il faut créer le client
            new_client_diction = {}
            new_client_diction['token'] = my_partner['token']

            new_client_diction['raison_sociale'] = valide_lead_website_data['raison_sociale']
            new_client_diction['nom'] = valide_lead_website_data['raison_sociale']
            new_client_diction['email'] = valide_lead_website_data['email_requester']
            new_client_diction['telephone'] = valide_lead_website_data['telephone_requester']
            new_client_diction['siret'] = valide_lead_website_data['siret']
            new_client_diction['is_company'] = "1"

            # Pour les données de facturation
            new_client_diction['invoice_nom'] = valide_lead_website_data['raison_sociale']
            new_client_diction['invoice_email'] = valide_lead_website_data['email_requester']


            local_prospect_status, local_prospect_retval = partner_client.Add_Partner_Prospect(new_client_diction)

            if( local_prospect_status is False ):
                return local_prospect_status, local_prospect_retval, False

            is_client_exist_data = MYSY_GV.dbname['partner_client'].find_one(
                {'partner_recid': str(valide_lead_website_data['partner_owner_recid']),
                 'siret': str(valide_lead_website_data['siret'])})

            """
            Apres la creation du client, on ajoute un contact de communication
            par defaut
            """
            prospect_contact_data = {}
            prospect_contact_data['related_collection'] = "partner_client"
            prospect_contact_data['related_collection_owner_id'] = str(is_client_exist_data['_id'])
            prospect_contact_data['email'] = str(valide_lead_website_data['email_requester'])
            prospect_contact_data['nom'] = str(valide_lead_website_data['nom_requester'])
            prospect_contact_data['civilite'] = "neutre"
            prospect_contact_data['telephone'] = str(valide_lead_website_data['telephone_requester'])
            prospect_contact_data['include_com'] = "1"
            prospect_contact_data['fonction'] = ""
            prospect_contact_data['token'] = str(my_partner['token'])


            #print(" ### prospect_contact_data data = ", prospect_contact_data)
            retval_status_add_contact, retval_retval_add_contact = Contact.Add_Contact(prospect_contact_data)

            if( retval_status_add_contact is False ):
                return retval_status_add_contact, retval_retval_add_contact

            #print(" ### retval_retval_add_contact = ", retval_retval_add_contact)

        todays_date = str(date.today().strftime("%d/%m/%Y"))
        expirate_date = datetime.today() + timedelta(days=90)
        expirate_date = str(expirate_date.strftime("%d/%m/%Y"))



        # Creation du devis
        new_quotation_header = {}
        new_quotation_header['token'] = my_partner['token']
        new_quotation_header['order_header_client_id'] = str(is_client_exist_data['_id'])
        new_quotation_header['order_header_date_cmd'] = todays_date
        new_quotation_header['order_header_date_expiration'] = expirate_date
        new_quotation_header['order_header_type'] = "devis"
        new_quotation_header['order_header_status'] = "0"
        new_quotation_header['order_header_email_client'] = str(valide_lead_website_data['email_requester'])


        new_quotation_header['order_lines'] = []

        """
        Recuperation des données de config pour la relance des devis
        """
        for tmp_val in MYSY_GV.dbname['base_partner_setup'].find(
                {'partner_owner_recid': str(my_partner['recid']), 'valide': '1', 'locked': '0',
                 'related_collection': 'quotation'}):
            new_quotation_header[str(tmp_val['config_name'])] = str(tmp_val['config_value'])


        local_create_quotation_status, local_create_quotation_retval, local_create_quotation_ref_interne = Add_Partner_Quotation(
            new_quotation_header)

        if (local_create_quotation_status is False):
            return local_create_quotation_status, local_create_quotation_retval, False

        quotation_id = MYSY_GV.dbname['partner_order_header'].find_one({"order_header_ref_interne":str(local_create_quotation_ref_interne),
                                                                        'partner_owner_recid':str(valide_lead_website_data['partner_owner_recid'])})

        # Recuperation de la valeur de la TVA (taux tva)
        partner_taux_tva = 20

        if ("invoice_taux_vat" in my_partner.keys()):
            IsInt_status, IsInt_retval = mycommon.IsInt(str(my_partner['invoice_taux_vat']))
            if (IsInt_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " - La valeur '" + str(
                        my_partner['invoice_taux_vat']) + "' n'est pas un taux de TVA correcte ")
                return False, "  La valeur '" + str(
                    my_partner['invoice_taux_vat']) + "' n'est pas un taux de TVA correcte ", False

            partner_taux_tva = IsInt_retval

        #print(" ### COMPUTE : le taux de TVA = ", str(partner_taux_tva))

        prix_total_ht = mycommon.tryFloat( str(valide_lead_website_data['nb_person_info'])) * mycommon.tryFloat(str(valide_lead_website_data['class_sales_price']))
        line_taxe = (prix_total_ht * partner_taux_tva)/100

        lines_node = {}
        lines_node['token'] = my_partner['token']
        lines_node['order_line_id'] = ""


        lines_node['order_line_status'] = "0"
        lines_node['order_line_type'] = "devis"
        lines_node['order_header_ref_interne'] = str(local_create_quotation_ref_interne)
        lines_node['order_header_id'] = str(quotation_id['_id'])
        lines_node['order_line_formation'] = valide_lead_website_data['class_internal_url']
        lines_node['order_line_qty'] = valide_lead_website_data['nb_person_info']
        lines_node['order_line_prix_unitaire'] = valide_lead_website_data['class_sales_price']
        lines_node['order_line_tax'] = str(partner_taux_tva)
        lines_node['order_line_type_reduction'] = ""
        lines_node['order_line_type_valeur'] = ""
        lines_node['order_line_montant_reduction'] = "0"

        lines_node['order_line_tax_amount'] = str(line_taxe)
        lines_node['order_line_montant_hors_taxes'] = str(prix_total_ht)
        lines_node['order_line_montant_toutes_taxes'] = str(prix_total_ht + line_taxe)




        local_create_quotation_line_status, local_create_quotation_line_retval  = Add_Update_Partner_Order_Line(lines_node)

        if(local_create_quotation_line_status is False ):
            return  local_create_quotation_line_status, local_create_quotation_line_retval, False


        comput_diction = {}
        comput_diction['token'] = my_partner['token']
        comput_diction['_id'] = str(quotation_id['_id'])

        local_retval, local_message = Compute_Order_Header(comput_diction)
        if (local_retval is False):
            mycommon.myprint(" WARNING : Apres la confirmation, La fonction compute pour l'ordre : " + str(
                comput_diction) + " n'a pas fonctionnée, ")


        """
        Mettre à jour le lead pour dire qu'il a été convertie en devis
        """
        update_data = {}
        update_data['valide'] = "0"
        update_data['quotation_ref'] = str(local_create_quotation_ref_interne)



        MYSY_GV.dbname['lead_website'].update_many({'_id':ObjectId(str(valide_lead_website_data['_id']))},
                                                   {'$set':update_data})

        return True, "Le devis a été crée avec la référence "+str(local_create_quotation_ref_interne), str(local_create_quotation_ref_interne)

    except  Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible de faire la relance du devis ", False


