Elyos_FI_Back_Office/Relance_client_facture.py

1168 lines
46 KiB
Python

"""
Ce fichier permet de gerer la relance des factures des client
"""
import ast
import smtplib
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import dateutil
import pymongo
import xlsxwriter
from flask import send_file
from pandas.io.formats.style import jinja2
from pymongo import MongoClient
import json
from bson import ObjectId
import re
from datetime import datetime, timezone, date
from xhtml2pdf import pisa
import attached_file_mgt
import prj_common as mycommon
import secrets
import inspect
import sys, os
import csv
import pandas as pd
from pymongo import ReturnDocument
import GlobalVariable as MYSY_GV
from math import isnan
import GlobalVariable as MYSY_GV
from datetime import timedelta
from datetime import timedelta
import Dashbord_queries.formation_tbd_qries as formation_tbd_qries
from dateutil.relativedelta import relativedelta
"""
Creation d'une relance client
"""
def Create_Relance_Client_Facture_Given_Client_PDF(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token', 'client_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', 'client_id' ]
for val in field_list_obligatoire:
if val not in diction:
mycommon.myprint(
str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans la liste des arguments ")
return False, " Les informations fournies sont incorrectes",
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 client
"""
is_clien_valide = MYSY_GV.dbname['partner_client'].count_documents({'_id':ObjectId(str(diction['client_id'])),
'partner_owner_recid':str(my_partner['recid']),
'valide':'1',
'locked':'0'})
if( is_clien_valide != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant du client est invalide ")
return False, " L'identifiant du client est invalide "
"""
Recuperer le modèle de document
"""
local_diction = {}
local_diction['ref_interne'] = "RELANCE_FACTURE_CLIENT"
local_diction['type_doc'] = "pdf"
local_diction['partner_owner_recid'] = str(my_partner['recid'])
courrier_data_status, courrier_data_retval = mycommon.Get_Courrier_Template_Include_Default_Data(local_diction)
if (courrier_data_status is False):
return courrier_data_status, courrier_data_retval
if ("contenu_doc" not in courrier_data_retval.keys() or str(courrier_data_retval['contenu_doc']) == ""):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Le modèle de courrier 'RELANCE_FACTURE_CLIENT' n'est pas correctement configuré ")
return False, " Le modèle de courrier 'RELANCE_FACTURE_CLIENT' n'est pas correctement configuré "
"""
Recuperation du dictionnaire des info
"""
tab_client = []
tab_client.append(ObjectId(str(diction['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
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
"""
Algo :
1 - recuperer toutes les facture du client arrivée a échangé et non payées
2 - Parcours les factures pour :
- recuperer le total du reste à payer
- le plus haut degré de relance
3 - Faire le courrier
4 - Mettre à jour chaque facutre pour mettre à jour la date de relance et le niveau de relance
- tab_relance = [ {date_relance:'xxx', relance_id:'xxx'} ]
5 - Ajouter l'action dans l'historique du client
"""
todays_date = str(date.today().strftime("%d/%m/%Y"))
todays_date_ISO_Date = datetime.strptime(str(todays_date).strip(), '%d/%m/%Y')
find_qry = {
'mysy_invoice_reste_to_paye_num': { '$gt': 0},
'mysy_invoice_du_date': {'$lt': todays_date_ISO_Date},
'order_header_client_id': str(diction['client_id']),
'invoice_litige': {'$ne':'1'},
}
query_invoice_echance_depace = [
{"$addFields":
{
"partner_invoice_header_Id": {"$toString": "$_id"},
"mysy_total_header_toutes_taxes": {"$convert": {
'input': "$total_header_toutes_taxes",
'to': "double",
'onError': {'error': 0},
'onNull': {'isnull': 0}
}
},
"mysy_invoice_du_date": {
'$dateFromString': {
"dateString": {
"$substr": [
{"$ifNull": ["$invoice_date_echeance", ""]},
0,
10
]
},
"format": "%d/%m/%Y",
"onError": "null",
"onNull": "null"
}
},
"mysy_invoice_date": {
"$dateFromString": {
"dateString": {
"$substr": [
{"$ifNull": ["$invoice_date", ""]},
0,
10
]
},
"format": "%d/%m/%Y",
"onError": 'null',
"onNull": 'null'
}
},
"mysy_invoice_reste_to_paye_num": {
"$convert": {
"input": {
"$replaceAll": {
"input": {
"$replaceAll": {
"input": {
"$ifNull": ["$reste_to_paye", "0"]
},
"find": " ",
"replacement": ""
}
},
"find": ",",
"replacement": "."
}
},
"to": "double",
"onError": 0,
"onNull": 0
}
}
},
},
{'$match': find_qry},
{
"$sort": {
"mysy_invoice_reste_to_paye_num": 1
}
},
{
"$project": {
"_id": 1,
"invoice_header_ref_interne": 1,
"invoice_header_type": 1,
"invoice_date": 1,
"invoice_date_echeance": 1,
"order_header_client_id": 1,
"order_header_email_client": 1,
"partner_owner_recid": 1,
"total_header_toutes_taxes": 1,
"invoice_paiement_status": 1,
"reste_to_paye": 1,
"mysy_invoice_reste_to_paye_num": 1,
'tab_relance':1,
}
}
]
print(" ### query_invoice_echance_depace = ", query_invoice_echance_depace)
RetObject = []
val_tmp = 0
total_reste_to_paye = 0
max_relance_done = 0
tab_invoice_a_relancer = []
mytoday22 = datetime.today().strftime("%d/%m/%Y")
for retval in MYSY_GV.dbname['partner_invoice_header'].aggregate(query_invoice_echance_depace):
user = retval
user['id'] = str(val_tmp)
node_tab_relance = {}
node_tab_relance['invoice_id'] = str(retval['_id'])
node_tab_relance['invoice_header_ref_interne'] = retval['invoice_header_ref_interne']
node_tab_relance['total_header_toutes_taxes'] = str(round(float(retval['total_header_toutes_taxes']), 2))
node_tab_relance['reste_to_paye'] = str(round(float(retval['reste_to_paye']), 2))
node_tab_relance['invoice_date_echeance'] = retval['invoice_date_echeance']
node_tab_relance['invoice_date'] = retval['invoice_date']
retard = ( datetime.strptime( str(mytoday22),'%d/%m/%Y') - datetime.strptime(str(retval['invoice_date_echeance'])[0:10], '%d/%m/%Y')).days
node_tab_relance['paiement_retard'] = str(retard)
tab_invoice_a_relancer.append(node_tab_relance)
total_reste_to_paye = total_reste_to_paye + float(retval['mysy_invoice_reste_to_paye_num'])
"""
Recuperer le niveau de relance à faire
"""
if( "tab_relance" in retval.keys()):
if( len(retval['tab_relance']) > max_relance_done ):
max_relance_done = len(retval['tab_relance'])
val_tmp = val_tmp + 1
RetObject.append(mycommon.JSONEncoder().encode(user))
total_reste_to_paye = f"{float(total_reste_to_paye):,.2f}"
total_reste_to_paye = total_reste_to_paye.replace(",", " ").replace(".", ",")
print(" TOTAL DU = ", total_reste_to_paye)
print(" Niveau relance = ", max_relance_done)
new_relance_level = 0
if( max_relance_done < 3 ):
new_relance_level = max_relance_done + 1
else:
new_relance_level = 3
convention_dictionnary_data['tab_invoice_a_relancer'] = tab_invoice_a_relancer
convention_dictionnary_data['total_reste_to_paye'] = str(total_reste_to_paye)
convention_dictionnary_data['new_relance_level'] = str(new_relance_level)
company_data = {
"params": convention_dictionnary_data,
}
#print(" ###company_data = ", company_data)
# read css file
css_file = "./css_document/elyos_css.css"
from xhtml2pdf.default import DEFAULT_CSS
if css_file is not None:
with open(css_file) as f:
DEFAULT_CSS += f.read()
contenu_doc_Template = jinja2.Template(str(courrier_data_retval['contenu_doc']))
sourceHtml = contenu_doc_Template.render(params=company_data['params'])
ts = datetime.now().timestamp()
ts = str(ts).replace(".", "").replace(",", "")[-5:]
orig_file_name = "Relance_Fact_Client_" + str(my_partner['recid'])[0:2] + "_" + 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,
default_css=DEFAULT_CSS) # file handle to receive result
# close output file
resultFile.close()
"""
Inserter la relance dans la collection : 'relance_client_invoice'
"""
new_relance_data = {}
new_relance_data['client_id'] = diction['client_id']
new_relance_data['tab_invoice'] = tab_invoice_a_relancer
new_relance_data['relance_date'] = str(datetime.now().strftime("%d/%m/%Y %H:%M"))
new_relance_data['relance_level'] = str(new_relance_level)
new_relance_data['relance_by'] = str(my_partner['_id'])
new_relance_data['total_reste_to_paye'] = str(total_reste_to_paye)
new_relance_data['partner_owner_recid'] = str(my_partner['recid'])
new_relance_data['update_date'] = str(datetime.now())
new_relance_data['update_by'] = str(my_partner['_id'])
new_relance_data['valide'] = "1"
new_relance_data['locked'] = "0"
new_relance_data['mode_envoi'] = "pdf"
relance_insert = MYSY_GV.dbname['relance_client_invoice'].insert_one(new_relance_data)
if( relance_insert and relance_insert.inserted_id):
"""
Mettre à jour la relance des factures
"""
todays_date_heure = datetime.now().strftime("%d/%m/%Y %H:%M")
for fact in tab_invoice_a_relancer:
new_data = {}
new_data['date_relance'] = str(todays_date_heure)
new_data['relance_id'] = str(relance_insert.inserted_id)
create = MYSY_GV.dbname['partner_invoice_header'].update_one({
'_id': ObjectId(str(fact['invoice_id'])),
'partner_owner_recid': str(my_partner['recid']),
},
{
'$push': {
"tab_relance": {
'$each': [new_data]
}
}
},
)
"""
Aller stocker le document PDF de relance et le rattacher a la relance
"""
saved_outputFilename = outputFilename
if (orig_file_name and outputFilename):
new_file = {}
new_file['token'] = diction['token']
type_document = "relance_facture"
new_file['file_business_object'] = str(orig_file_name)
new_file['file_name'] = str(orig_file_name)
new_file['status'] = "1"
new_file['type_document'] = str(type_document)
new_file['object_owner_collection'] = "partner_client"
new_file['object_owner_id'] = str(diction['client_id'])
new_file['file_name_to_store'] = outputFilename
tab_key_word = ""
new_file['tab_key_word'] = tab_key_word
tab_related_collection = []
node_class = {}
node_class['related_collection'] = 'relance_client_invoice'
node_class['related_collection_id'] = str(relance_insert.inserted_id)
tab_related_collection.append(node_class)
print(" ### new_file new_file = ", new_file)
local_status, local_retval = attached_file_mgt.Internal_Usage_Store_User_Downloaded_File(
MYSY_GV.upload_folder, new_file, tab_related_collection)
if (local_status is False):
print(" ## WARINNGGG Impossible de stocker le fichier de Convocation ")
if(local_retval ):
saved_outputFilename = local_retval
"""
# Ajout de l'evenement sur la fiche client
"""
now = str(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
history_event_dict = {}
history_event_dict['token'] = diction['token']
history_event_dict['related_collection'] = "partnair_account"
history_event_dict['related_collection_recid'] = str(diction['client_id'])
history_event_dict['action_date'] = str(now)
history_event_dict['action_description'] = "Relance facture client _id = "+str(str(relance_insert.inserted_id))
local_status, local_retval = mycommon.Collection_Historique.Add_Historique_Event(history_event_dict)
if (local_status is False):
mycommon.myprint(
" WARNING : Impossible de logguer l'historique pour l'évènement : " + str(history_event_dict))
# print(" ### outputFilename = "+str(outputFilename))
if os.path.exists(saved_outputFilename):
print(" ### ok os.path.exists(outputFilename) "+str(saved_outputFilename))
return True, send_file(saved_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()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible de faire la relance client "
def Create_Relance_Client_Facture_Given_Client_Email(tab_files, Folder, diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token', 'client_id', 'courrier_template_id', 'email_test', 'email_production' ]
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', 'client_id']
for val in field_list_obligatoire:
if val not in diction:
mycommon.myprint(
str(inspect.stack()[0][
3]) + " - La valeur '" + val + "' n'est pas presente dans la liste des arguments ")
return False, " Les informations fournies sont incorrectes",
local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
if (local_status is not True):
return local_status, my_partner
courrier_template_count = MYSY_GV.dbname['courrier_template'].count_documents(
{'_id': ObjectId(str(diction['courrier_template_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': str(my_partner['recid'])}
)
if (courrier_template_count != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant du modèle de courrier est invalide ")
return False, " L'identifiant du modèle de courrier est invalide "
"""
Verifier la validité du client
"""
is_clien_valide = MYSY_GV.dbname['partner_client'].count_documents({'_id': ObjectId(str(diction['client_id'])),
'partner_owner_recid': str(
my_partner['recid']),
'valide': '1',
'locked': '0'})
if (is_clien_valide != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant du client est invalide ")
return False, " L'identifiant du client est invalide "
"""
Recuperer le modèle de document
"""
courrier_data_retval = MYSY_GV.dbname['courrier_template'].find_one(
{'_id': ObjectId(str(diction['courrier_template_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': str(my_partner['recid'])}
)
if ("contenu_doc" not in courrier_data_retval.keys() or str(courrier_data_retval['contenu_doc']) == ""):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Le modèle de courrier 'RELANCE_FACTURE_CLIENT' n'est pas correctement configuré ")
return False, " Le modèle de courrier 'RELANCE_FACTURE_CLIENT' n'est pas correctement configuré "
#print(" IIIIIIIIIIIIIIIIIII courrier_data_retval[_id] = ", str(courrier_data_retval['_id']))
"""
Recuperation du dictionnaire des info
"""
tab_client = []
tab_client.append(ObjectId(str(diction['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
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
"""
Algo :
1 - recuperer toutes les facture du client arrivée a échangé et non payées
2 - Parcours les factures pour :
- recuperer le total du reste à payer
- le plus haut degré de relance
3 - Faire le courrier
4 - Mettre à jour chaque facutre pour mettre à jour la date de relance et le niveau de relance
- tab_relance = [ {date_relance:'xxx', relance_id:'xxx'} ]
5 - Ajouter l'action dans l'historique du client
"""
todays_date = str(date.today().strftime("%d/%m/%Y"))
todays_date_ISO_Date = datetime.strptime(str(todays_date).strip(), '%d/%m/%Y')
find_qry = {
'mysy_invoice_reste_to_paye_num': {'$gt': 0},
'mysy_invoice_du_date': {'$lt': todays_date_ISO_Date},
'order_header_client_id': str(diction['client_id']),
'invoice_litige': {'$ne': '1'},
}
query_invoice_echance_depace = [
{"$addFields":
{
"partner_invoice_header_Id": {"$toString": "$_id"},
"mysy_total_header_toutes_taxes": {"$convert": {
'input': "$total_header_toutes_taxes",
'to': "double",
'onError': {'error': 0},
'onNull': {'isnull': 0}
}
},
"mysy_invoice_du_date": {
'$dateFromString': {
"dateString": {
"$substr": [
{"$ifNull": ["$invoice_date_echeance", ""]},
0,
10
]
},
"format": "%d/%m/%Y",
"onError": "null",
"onNull": "null"
}
},
"mysy_invoice_date": {
"$dateFromString": {
"dateString": {
"$substr": [
{"$ifNull": ["$invoice_date", ""]},
0,
10
]
},
"format": "%d/%m/%Y",
"onError": 'null',
"onNull": 'null'
}
},
"mysy_invoice_reste_to_paye_num": {
"$convert": {
"input": {
"$replaceAll": {
"input": {
"$replaceAll": {
"input": {
"$ifNull": ["$reste_to_paye", "0"]
},
"find": " ",
"replacement": ""
}
},
"find": ",",
"replacement": "."
}
},
"to": "double",
"onError": 0,
"onNull": 0
}
}
},
},
{'$match': find_qry},
{
"$sort": {
"mysy_invoice_reste_to_paye_num": 1
}
},
{
"$project": {
"_id": 1,
"invoice_header_ref_interne": 1,
"invoice_header_type": 1,
"invoice_date": 1,
"invoice_date_echeance": 1,
"order_header_client_id": 1,
"order_header_email_client": 1,
"partner_owner_recid": 1,
"total_header_toutes_taxes": 1,
"invoice_paiement_status": 1,
"reste_to_paye": 1,
"mysy_invoice_reste_to_paye_num": 1,
'tab_relance': 1,
}
}
]
print(" ### query_invoice_echance_depace = ", query_invoice_echance_depace)
RetObject = []
val_tmp = 0
total_reste_to_paye = 0
max_relance_done = 0
tab_invoice_a_relancer = []
mytoday22 = datetime.today().strftime("%d/%m/%Y")
for retval in MYSY_GV.dbname['partner_invoice_header'].aggregate(query_invoice_echance_depace):
user = retval
user['id'] = str(val_tmp)
node_tab_relance = {}
node_tab_relance['invoice_id'] = str(retval['_id'])
node_tab_relance['invoice_header_ref_interne'] = retval['invoice_header_ref_interne']
node_tab_relance['total_header_toutes_taxes'] = str(round(float(retval['total_header_toutes_taxes']), 2))
node_tab_relance['reste_to_paye'] = str(round(float(retval['reste_to_paye']), 2))
node_tab_relance['invoice_date_echeance'] = retval['invoice_date_echeance']
node_tab_relance['invoice_date'] = retval['invoice_date']
retard = (datetime.strptime(str(mytoday22), '%d/%m/%Y') - datetime.strptime(
str(retval['invoice_date_echeance'])[0:10], '%d/%m/%Y')).days
node_tab_relance['paiement_retard'] = str(retard)
tab_invoice_a_relancer.append(node_tab_relance)
total_reste_to_paye = total_reste_to_paye + float(retval['mysy_invoice_reste_to_paye_num'])
"""
Recuperer le niveau de relance à faire
"""
if ("tab_relance" in retval.keys()):
if (len(retval['tab_relance']) > max_relance_done):
max_relance_done = len(retval['tab_relance'])
val_tmp = val_tmp + 1
RetObject.append(mycommon.JSONEncoder().encode(user))
total_reste_to_paye = f"{float(total_reste_to_paye):,.2f}"
total_reste_to_paye = total_reste_to_paye.replace(",", " ").replace(".", ",")
print(" TOTAL DU = ", total_reste_to_paye)
print(" Niveau relance = ", max_relance_done)
new_relance_level = 0
if (max_relance_done < 3):
new_relance_level = max_relance_done + 1
else:
new_relance_level = 3
convention_dictionnary_data['tab_invoice_a_relancer'] = tab_invoice_a_relancer
convention_dictionnary_data['total_reste_to_paye'] = str(total_reste_to_paye)
convention_dictionnary_data['new_relance_level'] = str(new_relance_level)
company_data = {
"params": convention_dictionnary_data,
}
###############################
# Traitement de l'eventuel fichier joint
# Sauvegarde des fichiers joints depuis le front
tab_saved_file_full_path = []
for file in tab_files:
status, saved_file_full_path = mycommon.Upload_Save_PDF_IMG_File(file, Folder)
if (status is False):
mycommon.myprint("Impossible de récupérer correctement le fichier à importer")
return False, "Impossible de récupérer correctement le fichier à importer"
tab_saved_file_full_path.append(saved_file_full_path)
tab_files_to_attache_to_mail = []
tab_list_file_for_queu_mail_and_internal_mail = []
for saved_file in tab_saved_file_full_path:
file_to_attache_to_mail = MIMEBase('application', "octet-stream")
file_to_attache_to_mail.set_payload(open(saved_file, "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(saved_file)))
new_node = {"attached_file": file_to_attache_to_mail}
tab_files_to_attache_to_mail.append(new_node)
tab_list_file_for_queu_mail_and_internal_mail.append(saved_file)
orig_file_name = None
outputFilename = None
# Verifier s'il s'agit d'un document à envoyer avec une version de pièce jointe.
if ("joint_pdf" in courrier_data_retval.keys() and str(courrier_data_retval['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(courrier_data_retval['contenu_doc']))
sourceHtml = contenu_doc_Template.render(params=company_data["params"])
ts = datetime.now().timestamp()
ts = str(ts).replace(".", "").replace(",", "")[-5:]
orig_file_name = "Relance_Fact_Client_" + str(my_partner['recid'])[0:2] + "_" + 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(courrier_data_retval['corps_mail']))
sourceHtml = corps_mail_Template.render(params=company_data["params"])
html_mime = MIMEText(sourceHtml, 'html')
# Creation de l'email à enoyer
msg = MIMEMultipart("alternative")
# Attacher l'eventuelle pièces jointes
for myfile in tab_files_to_attache_to_mail:
msg.attach(myfile['attached_file'])
else:
# Il s'agit d'une simple email
## Creation du mail au format email
contenu_doc_Template = jinja2.Template(str(courrier_data_retval['contenu_doc']))
sourceHtml = contenu_doc_Template.render(params=company_data["params"])
html_mime = MIMEText(sourceHtml, 'html')
# Creation de l'email à enoyer
msg = MIMEMultipart("alternative")
# Traitement du sujet du mail
sujet_mail_Template = jinja2.Template(str(courrier_data_retval['sujet']))
sujetHtml = sujet_mail_Template.render(params=company_data["params"])
# Recuperation des donnes smpt
local_stpm_status, partner_SMTP_COUNT_smtpsrv, partner_own_smtp_value, partner_SMTP_COUNT_password, partner_SMTP_COUNT_user, partner_SMTP_COUNT_From_User, partner_SMTP_COUNT_port = mycommon.Get_Partner_SMTP_Param(
my_partner['recid'])
if (local_stpm_status is False):
return local_stpm_status, partner_SMTP_COUNT_smtpsrv
msg.attach(html_mime)
if (str(partner_own_smtp_value) == "1"):
msg['From'] = partner_SMTP_COUNT_From_User
else:
msg['From'] = str(partner_SMTP_COUNT_From_User)
msg['Bcc'] = 'contact@mysy-training.com'
msg['Subject'] = sujetHtml
# msg['to'] = "billardman01@hotmail.com"
"""
Important :
L'email est envoyé
- au client principale,
- au mail du invoiced
- en copie le responsable du compte chez OF
"""
tab_email_contact_client_destinataire = []
client_data = MYSY_GV.dbname['partner_client'].find_one({'_id': ObjectId(str(diction['client_id'])),
'partner_owner_recid': str(
my_partner['recid']),
'valide': '1',
'locked': '0'}, {'email':1, 'invoice_email':1, 'responsable_compte_id':1})
if( client_data and "email" in client_data.keys()):
tab_email_contact_client_destinataire.append(client_data['email'])
if (client_data and "invoice_email" in client_data.keys()):
tab_email_contact_client_destinataire.append(client_data['invoice_email'])
responsable_compte_email = ""
if (client_data and "responsable_compte_id" in client_data.keys()):
responsable_compte_data = MYSY_GV.dbname['ressource_humaine'].find_one({'_id': ObjectId(str(client_data['responsable_compte_id'])),
'partner_recid': str(
my_partner['recid']),
'valide': '1',
'locked': '0'}, {'email':1, 'nom':1, 'prenom':1})
if( responsable_compte_data and 'email' in responsable_compte_data.keys()):
responsable_compte_email = responsable_compte_data['email']
toaddrs = ",".join(tab_email_contact_client_destinataire)
msg['to'] = str(toaddrs)
msg['cc'] = str(responsable_compte_email)
smtpserver = smtplib.SMTP(partner_SMTP_COUNT_smtpsrv, partner_SMTP_COUNT_port)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.login(partner_SMTP_COUNT_user, partner_SMTP_COUNT_password)
val = smtpserver.send_message(msg)
smtpserver.close()
print(" Email envoyé icii" + str(val))
################################
"""
Inserter la relantion dans la collection : 'relance_client_invoice'
"""
new_relance_data = {}
new_relance_data['client_id'] = diction['client_id']
new_relance_data['tab_invoice'] = tab_invoice_a_relancer
new_relance_data['relance_date'] = str(datetime.now().strftime("%d/%m/%Y %H:%M"))
new_relance_data['relance_level'] = str(new_relance_level)
new_relance_data['relance_by'] = str(my_partner['_id'])
new_relance_data['total_reste_to_paye'] = str(total_reste_to_paye)
new_relance_data['partner_owner_recid'] = str(my_partner['recid'])
new_relance_data['update_date'] = str(datetime.now())
new_relance_data['update_by'] = str(my_partner['_id'])
new_relance_data['valide'] = "1"
new_relance_data['locked'] = "0"
new_relance_data['mode_envoi'] = "email"
relance_insert = MYSY_GV.dbname['relance_client_invoice'].insert_one(new_relance_data)
if (relance_insert and relance_insert.inserted_id):
"""
Mettre à jour la relance des factures
"""
todays_date_heure = datetime.now().strftime("%d/%m/%Y %H:%M")
for fact in tab_invoice_a_relancer:
new_data = {}
new_data['date_relance'] = str(todays_date_heure)
new_data['relance_id'] = str(relance_insert.inserted_id)
create = MYSY_GV.dbname['partner_invoice_header'].update_one({
'_id': ObjectId(str(fact['invoice_id'])),
'partner_owner_recid': str(my_partner['recid']),
},
{
'$push': {
"tab_relance": {
'$each': [new_data]
}
}
},
)
"""
Aller stocker le document PDF de relance et le rattacher a la relance
"""
saved_outputFilename = outputFilename
if (orig_file_name and outputFilename):
new_file = {}
new_file['token'] = diction['token']
type_document = "relance_facture"
new_file['file_business_object'] = str(orig_file_name)
new_file['file_name'] = str(orig_file_name)
new_file['status'] = "1"
new_file['type_document'] = str(type_document)
new_file['object_owner_collection'] = "partner_client"
new_file['object_owner_id'] = str(diction['client_id'])
new_file['file_name_to_store'] = outputFilename
tab_key_word = ""
new_file['tab_key_word'] = tab_key_word
tab_related_collection = []
node_class = {}
node_class['related_collection'] = 'relance_client_invoice'
node_class['related_collection_id'] = str(relance_insert.inserted_id)
tab_related_collection.append(node_class)
#print(" ### new_file new_file = ", new_file)
local_status, local_retval = attached_file_mgt.Internal_Usage_Store_User_Downloaded_File(
MYSY_GV.upload_folder, new_file, tab_related_collection)
if (local_status is False):
print(" ## WARINNGGG Impossible de stocker le fichier de Convocation ")
if (local_retval):
saved_outputFilename = local_retval
"""
# Ajout de l'evenement sur la fiche client
"""
now = str(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
history_event_dict = {}
history_event_dict['token'] = diction['token']
history_event_dict['related_collection'] = "partnair_account"
history_event_dict['related_collection_recid'] = str(diction['client_id'])
history_event_dict['action_date'] = str(now)
history_event_dict['action_description'] = "Relance facture client "
local_status, local_retval = mycommon.Collection_Historique.Add_Historique_Event(history_event_dict)
if (local_status is False):
mycommon.myprint(
" WARNING : Impossible de logguer l'historique pour l'évènement : " + str(history_event_dict))
return True, " La relance client a été correctement envoyée par email "
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible d'envoyer la relance client par email"
"""
Recuperer la liste des relances avec un filter
"""
def Get_List_Relance_with_filter(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = ['token', 'client_id', 'invoice_id', 'invoice_ref', 'client_info']
incom_keys = diction.keys()
for val in incom_keys:
if val not in field_list and val.startswith('my_') is False:
mycommon.myprint(str(
inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé")
return False, " Les informations fournies sont incorrectes"
"""
Verification des champs obligatoires
"""
field_list_obligatoire = ['token',]
for val in field_list_obligatoire:
if val not in diction:
mycommon.myprint(
str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans la liste des arguments ")
return False, " Les informations fournies sont incorrectes"
"""
Verification de l'identité et autorisation de l'entité qui
appelle cette API
"""
token = ""
if ("token" in diction.keys()):
if diction['token']:
token = diction['token']
local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
if (local_status is not True):
return local_status, my_partner
"""
Filtre général sur le client (raison_sociale, nom, email, telephone
"""
filt_gle_client = {}
tab_client_id = []
if ("client_info" in diction.keys() and diction['client_info']):
local_myquery_gle = {
"partner_owner_recid": str(my_partner['recid']),
"valide": "1",
"locked": "0",
"$or": [
{'raison_sociale': {'$regex': mycommon.regex_replace_cartere(str(diction['client_info'])),
"$options": "i"}},
{'nom': {'$regex': mycommon.regex_replace_cartere(str(diction['client_info'])),
"$options": "i"}},
{'email': {'$regex': mycommon.regex_replace_cartere(str(diction['client_info'])),
"$options": "i"}},
{'telephone': {'$regex': mycommon.regex_replace_cartere(str(diction['client_info'])),
"$options": "i"}},
]
}
for tmp in MYSY_GV.dbname['partner_client'].find(local_myquery_gle):
tab_client_id.append(str(tmp['_id']))
if ("client_id" in diction.keys() and diction['client_id']):
if (diction['client_id'] not in tab_client_id):
tab_client_id.append(str(diction['client_id']))
filt_gle_client = {'client_id': {'$in': tab_client_id}}
filter_invoice_id = {}
if ("invoice_id" in diction.keys() and diction['invoice_id']):
filter_invoice_id = {'tab_invoice.invoice_id': str(diction['invoice_id'])}
filter_invoice_ref = {}
if ("invoice_ref" in diction.keys() and diction['invoice_ref']):
filter_invoice_ref = {'tab_invoice.invoice_header_ref_interne': str(diction['invoice_ref'])}
qery_match = {'$and': [{"partner_owner_recid": str(my_partner['recid']), 'valide': '1',
'locked': '0'},
filter_invoice_id, filter_invoice_ref, filt_gle_client]}
#print(" ### relance list : qery_match = ", qery_match)
RetObject = []
val_tmp = 0
for New_retVal in MYSY_GV.dbname['relance_client_invoice'].find(qery_match).sort([("_id", pymongo.DESCENDING), ]):
user = New_retVal
user['id'] = str(val_tmp)
if( "mode_envoi" not in user.keys() ):
user['mode_envoi'] = ""
strored_document_id = ""
strored_document_file_extention = ""
strored_document_file_business_object = ""
"""
Aller recuperer l'_id du document de relance associé
"""
qry_get_document = {}
qry_get_document['type_document'] = "relance_facture"
qry_get_document['partner_owner_recid'] = str(my_partner['recid'])
qry_get_document['valide'] = "1"
qry_get_document['locked'] = "0"
qry_get_document['tab_related_collection'] = {
'$elemMatch': {
'related_collection': "relance_client_invoice",
'related_collection_id': str(user['_id'])
}
}
#print(" QRY gry download_files_relance = ", qry_get_document)
download_files_relance = MYSY_GV.dbname['download_files'].find_one(qry_get_document, {'_id':1, 'file_extention':1, 'file_business_object':1})
if( download_files_relance and '_id' in download_files_relance.keys()):
strored_document_id = str(download_files_relance['_id'])
if (download_files_relance and 'file_extention' in download_files_relance.keys()):
strored_document_file_extention = str(download_files_relance['file_extention'])
if (download_files_relance and 'file_business_object' in download_files_relance.keys()):
strored_document_file_business_object = str(download_files_relance['file_business_object'])
user['stored_document_id'] = str(strored_document_id)
user['strored_document_file_extention'] = str(strored_document_file_extention)
user['strored_document_file_business_object'] = str(strored_document_file_business_object)
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 la liste des relances "