"""
Ce fichier permet de gerer le paiement des factures editer par mysy

Un paiement est defini par :
 - num_facture
 - paiement_ref
 - paiement_mode
 - montant payé
 - date paiement
 - commentaire

 regles :
 si montant payé != montant du :
  - option :
    - laisser ouvert
    - marquer entièrement payé
"""
import ast

import bson
import pymongo
from pymongo import MongoClient
import json
from bson import ObjectId
import re
from datetime import datetime
import prj_common as mycommon
import secrets
import inspect
import sys, os
import csv
import pandas as pd
from pymongo import ReturnDocument
import GlobalVariable as MYSY_GV
from math import isnan
import GlobalVariable as MYSY_GV
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

"""
Ajoute un paiement 
"""
def Add_Invoice_Paiement(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'invoice_id', 'paiement_amount', 'paiement_mode', 'paiement_ref',
                      'paiement_date', 'commentaire']

        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', 'invoice_id', 'paiement_amount', 'paiement_mode',
                      'paiement_date', ]

        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


        """
        Verifier que la date de paiement est au format jj/mm/aaaa
        """
        local_status = mycommon.CheckisDate(str(diction['paiement_date'])[0:10])
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " La date de paiement  n'est pas au format jj/mm/aaaa ")

            return False, "  La date de paiement  n'est pas au format jj/mm/aaaa "


        """
        Verifier que le payement est bien un float
        """
        local_status, local_retval = mycommon.IsFloat(str(diction['paiement_amount']))
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le montant payé  n'est convertible en Float ")
            return False, "  Le montant payé  n'est convertible en Float "




        # Verifier que la facture existe et est valide
        is_existe_invoice = MYSY_GV.dbname['partner_invoice_header'].count_documents({'_id':ObjectId(str(diction['invoice_id'])),
                                                                                                       'valide':'1',
                                                                                      'locked': '0',
                                                                                                       'partner_owner_recid':str(my_partner['recid'])})


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


        """
        Recuperer les données de facture et traiter le relicat à à payer
        """
        is_existe_invoice_data = MYSY_GV.dbname['partner_invoice_header'].find_one(
            {'_id': ObjectId(str(diction['invoice_id'])),
             'valide': '1', 'locked':'0',
             'partner_owner_recid': str(my_partner['recid'])})


        invoice_paiement_status = "0"
        if("invoice_paiement_status" in is_existe_invoice_data and is_existe_invoice_data['invoice_paiement_status']):
            invoice_paiement_status = is_existe_invoice_data['invoice_paiement_status']

        if( invoice_paiement_status not in MYSY_GV.INVOICE_PAIEMENT_STATUS ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Impossible d'analyser le statut de paiement de la facture ")
            return False, " Impossible d'analyser le statut de paiement de la facture  "

        if( invoice_paiement_status == "2" ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " La facture a déjà été payée ")
            return False, " La facture a déjà été payée "

        total_invoice_amount = "0"
        if( "total_header_toutes_taxes"  in is_existe_invoice_data.keys() ):
             total_invoice_amount = is_existe_invoice_data['total_header_toutes_taxes']

        local_status, local_retval = mycommon.IsFloat(total_invoice_amount)
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le champ 'total_header_toutes_taxes' n'est convertible en Float ")
            return False, " Le champ 'total_header_toutes_taxes' n'est convertible en Float "

        total_invoice_amount_float = local_retval


        """
        Récuprer les paiement déjà effectué 
        """
        local_diction = {"token": str(diction['token']), "invoice_id": str(diction['invoice_id'])}
        local_list_paiement_status, local_list_paiement_retval = Get_Invoice_Liste_Payement_And_Total_Amount(local_diction)
        if( local_list_paiement_status is False ):
            return local_list_paiement_status, local_list_paiement_retval

        #print(" Les payement = ", local_list_paiement_retval)

        list_payment =  ast.literal_eval(local_list_paiement_retval[0])

        #print(" Les payement JSON = ", list_payment)


        total_payed_amount = "0"
        if( "total_payed"  in list_payment.keys() ):
            total_payed_amount = list_payment['total_payed']

        local_status, local_retval = mycommon.IsFloat(total_payed_amount)
        if( local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le total payé n'est pas convertible en Float ")
            return False, " Le total payé n'est pas convertible en Float  "

        total_payed_amount_float = local_retval

        total_relicat = total_invoice_amount_float - total_payed_amount_float

        if( total_relicat < 0 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le montant du  "+str(total_relicat)+" est supérieur au montant payé "+str(total_payed_amount_float))
            return False, " Le montant du  "+str(total_relicat)+" est supérieur au montant payé "+str(total_payed_amount_float)


        """
        Tout est ok, alors on enregistre le paiement 
        """

        new_data = diction
        del diction['token']

        # Initialisation des champs non envoyés à vide
        for val in field_list:
            if val not in diction.keys():
                new_data[str(val)] = ""

        new_data['paiement_date'] = str(diction['paiement_date'])[0:10]

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

        new_data['date_update'] = str(datetime.now())
        new_data['update_by'] = str(my_partner['_id'])
        new_data['partner_owner_recid'] = str(my_partner['recid'])

        inserted_id = MYSY_GV.dbname['invoice_paiement'].insert_one(new_data).inserted_id
        if (not inserted_id):
            mycommon.myprint(
                " Impossible de créer le paiement  (2) ")
            return False, "Impossible de créer le paiement (2)  "


        """
        Mettre à jour la facture pour dire si elle est completement payée ou pas
        """
        update_data = {}
        update_data['date_update'] = str(datetime.now())
        update_data['update_by'] = str(my_partner['_id'])
        update_data['partner_owner_recid'] = str(my_partner['recid'])


        if( total_relicat == 0):
            update_data['invoice_paiement_status'] = "2"
        else:
            update_data['invoice_paiement_status'] = "1"

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

        return True, " Le paiement a été correctement cré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 créer le paiement "


"""
Mettre à jour un paiement
"""
def Update_Invoice_Paiement(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'invoice_id', 'paiement_amount', 'paiement_mode', 'paiement_ref',
                      'paiement_date', 'commentaire', '_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', 'invoice_id', 'paiement_amount', 'paiement_mode',
                      'paiement_date', '_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


        """
        Verifier que la date de paiement est au format jj/mm/aaaa
        """
        local_status = mycommon.CheckisDate(str(diction['paiement_date'])[0:10])
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][
                        3]) + " La date de paiement  n'est pas au format jj/mm/aaaa ")

            return False, "  La date de paiement  n'est pas au format jj/mm/aaaa "



        """
        Verifier que le paiement existe et est valide 
        """
        is_existe_invoice_paiement = MYSY_GV.dbname['invoice_paiement'].count_documents(
            {'_id': ObjectId(str(diction['_id'])),
             'valide': '1',
             'locked': '0',
             'partner_owner_recid': str(my_partner['recid'])})

        if (is_existe_invoice_paiement != 1):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " L'identifiant du paiement est invalide ")
            return False, " L'identifiant du paiement est invalide  "

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


        """
        Verifier que l'_id de la facture fourni dans diction est bien l'_id de la facture contenu dans le paiement
        """
        is_same_invoice_id = 0
        if( "invoice_id" in is_existe_invoice_paiement_data.keys() and is_existe_invoice_paiement_data['invoice_id']
        and is_existe_invoice_paiement_data['invoice_id'] == str(diction['invoice_id'])):
            is_same_invoice_id = 1

        if( is_same_invoice_id == "0"):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " L'identifiant de la facture ne correspond pas à la facture enregistrée dans le paiement ")
            return False, " L'identifiant de la facture ne correspond pas à la facture enregistrée dans le paiement "


        # Verifier que la facture existe et est valide
        is_existe_invoice = MYSY_GV.dbname['partner_invoice_header'].count_documents({'_id':ObjectId(str(diction['invoice_id'])),
                                                                                                       'valide':'1',
                                                                                      'locked': '0',
                                                                                                       'partner_owner_recid':str(my_partner['recid'])})


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


        """
        Recuperer les données de facture et traiter le relicat à à payer
        """
        is_existe_invoice_data = MYSY_GV.dbname['partner_invoice_header'].find_one(
            {'_id': ObjectId(str(diction['invoice_id'])),
             'valide': '1', 'locked':'0',
             'partner_owner_recid': str(my_partner['recid'])})



        invoice_paiement_status = "0"
        if("invoice_paiement_status" in is_existe_invoice_data and is_existe_invoice_data['invoice_paiement_status']):
            invoice_paiement_status = is_existe_invoice_data['invoice_paiement_status']

        if( invoice_paiement_status not in MYSY_GV.INVOICE_PAIEMENT_STATUS ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Impossible d'analyser le statut de paiement de la facture ")
            return False, " Impossible d'analyser le statut de paiement de la facture  "

        if( invoice_paiement_status == "2" ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " La facture a déjà été payée ")
            return False, " La facture a déjà été payée "

        total_invoice_amount = "0"
        if( "total_header_toutes_taxes"  in is_existe_invoice_data.keys() ):
             total_invoice_amount = is_existe_invoice_data['total_header_toutes_taxes']

        local_status, local_retval = mycommon.IsFloat(total_invoice_amount)
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le champ 'total_header_toutes_taxes' n'est convertible en Float ")
            return False, " Le champ 'total_header_toutes_taxes' n'est convertible en Float "

        total_invoice_amount_float = local_retval


        """
        Récuprer les paiement déjà effectué 
        """
        local_diction = {"token":str(diction['token']), "invoice_id":str(diction['invoice_id'])}
        local_list_paiement_status, local_list_paiement_retval = Get_Invoice_Liste_Payement_And_Total_Amount(local_diction)
        if( local_list_paiement_status is False ):
            return local_list_paiement_status, local_list_paiement_retval

        #print(" Les payement = ", local_list_paiement_retval)

        list_payment =  ast.literal_eval(local_list_paiement_retval[0])

        #print(" Les payement JSON = ", list_payment)


        total_payed_amount = "0"
        if( "total_payed"  in list_payment.keys() ):
            total_payed_amount = list_payment['total_payed']

        local_status, local_retval = mycommon.IsFloat(total_payed_amount)
        if( local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le total payé n'est pas convertible en Float ")
            return False, " Le total payé n'est pas convertible en Float  "

        total_payed_amount_float = local_retval

        total_relicat = total_invoice_amount_float - total_payed_amount_float

        if( total_relicat < 0 ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le montant du  "+str(total_relicat)+" est supérieur au montant payé "+str(total_payed_amount_float))
            return False, " Le montant du  "+str(total_relicat)+" est supérieur au montant payé "+str(total_payed_amount_float)


        """
        Tout est ok, alors on enregistre le paiement 
        """

        local_paiement_id = diction['_id']
        new_data = diction
        del diction['token']
        del diction['_id']

        new_data['paiement_date'] = str(diction['paiement_date'])[0:10]

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

        new_data['date_update'] = str(datetime.now())
        new_data['update_by'] = str(my_partner['_id'])
        new_data['partner_owner_recid'] = str(my_partner['recid'])

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


        """
        Mettre à jour la facture pour dire si elle est completement payée ou pas
        """
        update_data = {}
        update_data['date_update'] = str(datetime.now())
        update_data['update_by'] = str(my_partner['_id'])
        update_data['partner_owner_recid'] = str(my_partner['recid'])


        if( total_relicat == 0):
            update_data['invoice_paiement_status'] = "2"
        else:
            update_data['invoice_paiement_status'] = "1"

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

        return True, " Le paiement 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 paiement "


"""
Cette fonction permet de retourner la liste des payements valides
avec le total associé.

"""
def Get_Invoice_Liste_Payement(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'invoice_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', 'invoice_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


        # Verifier que la facture existe et est valide
        is_existe_invoice = MYSY_GV.dbname['partner_invoice_header'].count_documents({'_id':ObjectId(str(diction['invoice_id'])),
                                                                                                       'valide':'1',
                                                                                      'locked':'0',
                                                                                                       'partner_owner_recid':str(my_partner['recid'])})


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


        RetObject = []
        val_tmp = 0
        payed_amount = 0


        for retval in MYSY_GV.dbname['invoice_paiement'].find({'invoice_id':str(diction['invoice_id']),
                                                            'partner_owner_recid':str(my_partner['recid']),
                                                            'valide':'1',
                                                            'locked':'0'}).sort([("_id", pymongo.DESCENDING), ]):
            user = retval
            user['id'] = str(val_tmp)

            local_status, local_retval = mycommon.IsFloat(str(retval['paiement_amount']))
            if(local_status is False ):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Impossible d'évaluer les paiements effectués ")
                return False, " Impossible d'évaluer les paiements effectués  "

            payed_amount = payed_amount + local_retval

            val_tmp = val_tmp + 1
            RetObject.append(mycommon.JSONEncoder().encode(user))



        return True, RetObject

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
        return False, " IImpossible de récuperer les paiements de la facture "





"""
Cette fonction permet de retourner la liste des payements valides
avec le total associé.

"""
def Get_Invoice_Liste_Payement_And_Total_Amount(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'invoice_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', 'invoice_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


        # Verifier que la facture existe et est valide
        is_existe_invoice = MYSY_GV.dbname['partner_invoice_header'].count_documents({'_id':ObjectId(str(diction['invoice_id'])),
                                                                                                       'valide':'1',
                                                                                      'locked':'0',
                                                                                                       'partner_owner_recid':str(my_partner['recid'])})


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


        RetObject = []
        val_tmp = 0
        payed_amount = 0


        for retval in MYSY_GV.dbname['invoice_paiement'].find({'invoice_id':str(diction['invoice_id']),
                                                            'partner_owner_recid':str(my_partner['recid']),
                                                            'valide':'1',
                                                            'locked':'0'}).sort([("_id", pymongo.DESCENDING), ]):
            user = retval
            user['id'] = str(val_tmp)

            local_status, local_retval = mycommon.IsFloat(str(retval['paiement_amount']))
            if(local_status is False ):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Impossible d'évaluer les paiements effectués ")
                return False, " Impossible d'évaluer les paiements effectués  "

            payed_amount = payed_amount + local_retval

            val_tmp = val_tmp + 1
            RetObject.append(mycommon.JSONEncoder().encode(user))


        total_node = {"total_payed":str(payed_amount)}
        RetObject.append(mycommon.JSONEncoder().encode(total_node))


        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, " IImpossible de récuperer les paiements de la facture "


"""
Cette fonction retounne le montant total payé dans une facture ainsi que 
le reste à payer
"""
def Get_Invoice_Total_Amount_Payed_And_Remaining_Amount(diction):
    try:
        diction = mycommon.strip_dictionary(diction)

        """
        Verification des input acceptés
        """
        field_list = ['token', 'invoice_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', 'invoice_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


        # Verifier que la facture existe et est valide
        is_existe_invoice = MYSY_GV.dbname['partner_invoice_header'].count_documents({'_id':ObjectId(str(diction['invoice_id'])),
                                                                                                       'valide':'1',
                                                                                      'locked':'0',
                                                                                                       'partner_owner_recid':str(my_partner['recid'])})


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

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



        if( "total_header_toutes_taxes" in is_existe_invoice_data.keys() and  is_existe_invoice_data['total_header_toutes_taxes']):
            local_status, local_retval = mycommon.IsFloat(str(is_existe_invoice_data['total_header_toutes_taxes']))
            if (local_status is False):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Impossible d'évaluer le montant de la facture ")
                return False, " Impossible d'évaluer le montant de la facture "

        total_header_toutes_taxes_float = local_retval

        RetObject = []
        val_tmp = 0
        payed_amount = 0


        for retval in MYSY_GV.dbname['invoice_paiement'].find({'invoice_id':str(diction['invoice_id']),
                                                            'partner_owner_recid':str(my_partner['recid']),
                                                            'valide':'1',
                                                            'locked':'0'}).sort([("_id", pymongo.DESCENDING), ]):


            local_status, local_retval = mycommon.IsFloat(str(retval['paiement_amount']))
            if(local_status is False ):
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + " Impossible d'évaluer les paiements effectués ")
                return False, " Impossible d'évaluer les paiements effectués  "

            payed_amount = payed_amount + local_retval


        remain_amount = total_header_toutes_taxes_float - payed_amount

        payed_amount_str = str(payed_amount)
        if( payed_amount == 0 ):
            payed_amount_str = "0.0"

        total_node = {"total_amount":str(total_header_toutes_taxes_float), "payed_amount":str(payed_amount_str), "remaining_amount":str(remain_amount) }

        #print(" ### total_node = ",total_node)

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

        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, " IImpossible de récuperer les montants de la facture "




"""
Recuperer les données d'un paiement données
"""
def Get_Given_Invoice_Paiement(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['valide'] = "1"
        data_cle['locked'] = "0"
        data_cle['_id'] = ObjectId(str(diction['_id']))


        RetObject = []
        val_tmp = 0

        for retval in MYSY_GV.dbname['invoice_paiement'].find(data_cle):
            user = retval
            user['id'] = str(val_tmp)
            val_tmp = val_tmp + 1
            RetObject.append(mycommon.JSONEncoder().encode(user))

        return True, RetObject


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


"""
Cette fonction permet de supprimer un paiement
"""
def Delete_Given_Invoice_Paiement(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


        is_invoice_ok = 0
        invoice_data = None

        # Verifier les données du payement
        paiement_data = MYSY_GV.dbname['invoice_paiement'].find_one({'_id':ObjectId(str(diction['_id'])),
                                                                     'valide':'1',
                                                                     'locked':'0',
                                                                     'partner_owner_recid':my_partner['recid']})

        if( paiement_data and "invoice_id" in paiement_data.keys() ):
            # Verification des données de la facture
            invoice_data = MYSY_GV.dbname['partner_invoice_header'].find_one({'_id':ObjectId(str(paiement_data['invoice_id'])),
                                                                     'valide':'1',
                                                                     'locked':'0',
                                                                     'partner_owner_recid':my_partner['recid']})

        if( invoice_data and "total_header_toutes_taxes" in invoice_data.keys() ):
            is_invoice_ok = 1
        else:
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Les données de la factures sont incohérentes ")
            return False, " Les données de la factures sont incohérentes  "


        local_float_status, local_float_retval = mycommon.IsFloat(invoice_data['total_header_toutes_taxes'])
        if( local_float_status is False ):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Impossible de convertir le montant de la facture en Float ")
            return False, "  Impossible de convertir le montant de la facture en Float  "

        total_header_toutes_taxes_float = local_float_retval

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

        delete = MYSY_GV.dbname['invoice_paiement'].delete_one({'_id': ObjectId(str(diction['_id'])),
                                                               'partner_owner_recid': str(my_partner['recid']),
                                                               }, )


        """
        Apres suppression du paiement, on recalcul et met à jour l'etat de la facture
        """
        """
                Récuprer les paiement déjà effectué 
                """
        local_diction = {"token": str(diction['token']), "invoice_id": str(invoice_data['_id'])}
        local_list_paiement_status, local_list_paiement_retval = Get_Invoice_Liste_Payement_And_Total_Amount(
            local_diction)
        if (local_list_paiement_status is False):
            return local_list_paiement_status, local_list_paiement_retval

        # print(" Les payement = ", local_list_paiement_retval)

        list_payment = ast.literal_eval(local_list_paiement_retval[0])

        # print(" Les payement JSON = ", list_payment)

        total_payed_amount = "0"
        if ("total_payed" in list_payment.keys()):
            total_payed_amount = list_payment['total_payed']

        local_status, local_retval = mycommon.IsFloat(total_payed_amount)
        if (local_status is False):
            mycommon.myprint(
                str(inspect.stack()[0][3]) + " Le total payé n'est pas convertible en Float ")
            return False, " Le total payé n'est pas convertible en Float  "

        total_payed_amount_float = local_retval

        total_relicat = total_header_toutes_taxes_float - total_payed_amount_float

        update_data = {}
        update_data['date_update'] = str(datetime.now())
        update_data['update_by'] = str(my_partner['_id'])
        update_data['partner_owner_recid'] = str(my_partner['recid'])

        # Cette fois-ci on gere autrement. que les precdent
        if (total_payed_amount_float == 0):
            update_data['invoice_paiement_status'] = "0"
        else:
            update_data['invoice_paiement_status'] = "1"


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

        return True, "Le paiement a été correctement supprimé "


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