diff --git a/GlobalVariable.py b/GlobalVariable.py index b3edc8b..a194cc5 100644 --- a/GlobalVariable.py +++ b/GlobalVariable.py @@ -142,4 +142,11 @@ SENDINBLUE_API_KEY = "xkeysib-082bdb7bda0295a93f0b3bbc597e92fc4a91f9b52803fb1d1d ''' Taux de TVA ''' -TVA_TAUX = 0.2 \ No newline at end of file +TVA_TAUX = 0.2 + + +""" +Repertoire de depot des factures +""" +#INVOICE_DIRECTORY = "/tmp/Invoices/" +INVOICE_DIRECTORY = "C:/Users/ChérifBALDE/Desktop/Tmp_New/" \ No newline at end of file diff --git a/articles_avis.py b/articles_avis.py index a062126..82ac82a 100644 --- a/articles_avis.py +++ b/articles_avis.py @@ -62,7 +62,7 @@ def get_all_articles_avis(diction): insertObject = [] for x in coll_name.find({'valide': '1', 'locked': '0'}, { "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, - "valide": 0, "locked": 0, "url_formation": 0, }).sort( + "valide": 0, "locked": 0, }).sort( [("title_formation",pymongo.ASCENDING), ("date_avis",pymongo.ASCENDING)]): # mycommon.myprint("AVANT ==> "+str(x['description'])) val = x['qualite'] diff --git a/ela_factures_mgt.py b/ela_factures_mgt.py index c0e23f2..d2f686f 100644 --- a/ela_factures_mgt.py +++ b/ela_factures_mgt.py @@ -11,6 +11,7 @@ import prj_common as mycommon import secrets import inspect import sys, os +import shutil import csv import pandas as pd from pymongo import ReturnDocument @@ -19,6 +20,8 @@ import GlobalVariable as MYSY_GV import email_mgt as email from dateutil import tz import pytz +from xhtml2pdf import pisa +import jinja2 class JSONEncoder(json.JSONEncoder): @@ -81,13 +84,17 @@ def get_invoice_by_customer(diction): RetObject = [] coll_facture = MYSY_GV.dbname['factures'] - for retVal in coll_facture.find({'client_recid':user_recid, 'valide': '1'} )\ + for retVal in coll_facture.find({'client_recid':user_recid, 'valide': '1'}, + {'invoice_nom':1, 'total_ht':1, 'total_tva':1, 'total_ttc':1, + 'order_id':1, 'invoice_id':1, 'due_date':1, 'invoice_date':1, + } + )\ .sort([("date_facture", pymongo.ASCENDING), ("num_facture", pymongo.DESCENDING), ]): user = retVal if ("_id" in user.keys()): user['class_id'] = user.pop('_id') RetObject.append(JSONEncoder().encode(user)) - + print(" les facture du client = "+str(RetObject)) return True, RetObject except Exception as e: @@ -456,56 +463,13 @@ def createOrder(diction): new_data['invoice_telephone'] = part_account[0]['invoice_telephone'] total_ht = 0 - new_data['total_ht'] = total_ht - new_data['total_tva'] = mycommon.tryFloat(str(total_ht)) * MYSY_GV.TVA_TAUX - new_data['total_ttc'] = mycommon.tryFloat(str(total_ht)) + mycommon.tryFloat(str(new_data['total_tva'])) # Recuperation ds données de payement coll_part_payment = MYSY_GV.dbname['payement_mode'] part_account = coll_part_payment.find({'client_recid': user_recid, 'valide': '1'}) - total_ttc_float = mycommon.tryFloat(str(new_data['total_ttc'])) - print( "str(new_data['total_ttc']) === "+str(total_ttc_float)) - if( part_account.count() <= 0 and total_ttc_float > 0): - mycommon.myprint( - str(inspect.stack()[0][3]) + " Aucune donnée de payement, Impossible de créer la commande ") - return False, " Aucune donnée de payement,, Impossible de créer la commande ", None - - # Les données de payement ne sont utilisées que si le montatn > 0 - if( total_ttc_float > 0 ): - if ("type" in part_account[0].keys()): - if part_account[0]['type']: - new_data['type_payment'] = part_account[0]['type'] - - if ("bic" in part_account[0].keys()): - if part_account[0]['bic']: - new_data['bic_payment'] = part_account[0]['bic'] - - if ("cvv_carte" in part_account[0].keys()): - if part_account[0]['cvv_carte']: - new_data['cvv_carte_payment'] = part_account[0]['cvv_carte'] - - if ("date_exp_carte" in part_account[0].keys()): - if part_account[0]['date_exp_carte']: - new_data['date_exp_carte_payment'] = part_account[0]['date_exp_carte'] - - if ("iban" in part_account[0].keys()): - if part_account[0]['iban']: - new_data['iban_payment'] = part_account[0]['iban'] - - if ("nom_carte" in part_account[0].keys()): - if part_account[0]['nom_carte']: - new_data['nom_carte_payment'] = part_account[0]['nom_carte'] - - if ("nom_compte" in part_account[0].keys()): - if part_account[0]['nom_compte']: - new_data['nom_compte_payment'] = part_account[0]['nom_compte'] - - if ("num_carte" in part_account[0].keys()): - if part_account[0]['num_carte']: - new_data['num_carte_payment'] = part_account[0]['num_carte'] new_data['nb_product'] = str(nb_line) i = 0 @@ -536,10 +500,57 @@ def createOrder(diction): i = i + 1 + new_data['total_ht'] = total_ht + new_data['total_tva'] = mycommon.tryFloat(str(total_ht)) * MYSY_GV.TVA_TAUX + new_data['total_ttc'] = mycommon.tryFloat(str(total_ht)) + mycommon.tryFloat(str(new_data['total_tva'])) + + total_ttc_float = mycommon.tryFloat(str(new_data['total_ttc'])) + print("str(new_data['total_ttc']) === " + str(total_ttc_float)) + + if (part_account.count() <= 0 and total_ttc_float > 0): + mycommon.myprint( + str(inspect.stack()[0][3]) + " Aucune donnée de payement, Impossible de créer la commande ") + return False, " Aucune donnée de payement,, Impossible de créer la commande ", None + print(" new_data['total_ht'] = "+str(new_data['total_ht']) + " -- new_data['total_tva'] " +str(new_data['total_tva'])+ " -- new_data['total_ttc'] = "+ str(new_data['total_ttc'])) + # Les données de payement ne sont utilisées que si le montant > 0 + if (total_ttc_float > 0): + if ("type" in part_account[0].keys()): + if part_account[0]['type']: + new_data['type_payment'] = part_account[0]['type'] + + if ("bic" in part_account[0].keys()): + if part_account[0]['bic']: + new_data['bic_payment'] = part_account[0]['bic'] + + if ("cvv_carte" in part_account[0].keys()): + if part_account[0]['cvv_carte']: + new_data['cvv_carte_payment'] = part_account[0]['cvv_carte'] + + if ("date_exp_carte" in part_account[0].keys()): + if part_account[0]['date_exp_carte']: + new_data['date_exp_carte_payment'] = part_account[0]['date_exp_carte'] + + if ("iban" in part_account[0].keys()): + if part_account[0]['iban']: + new_data['iban_payment'] = part_account[0]['iban'] + + if ("nom_carte" in part_account[0].keys()): + if part_account[0]['nom_carte']: + new_data['nom_carte_payment'] = part_account[0]['nom_carte'] + + if ("nom_compte" in part_account[0].keys()): + if part_account[0]['nom_compte']: + new_data['nom_compte_payment'] = part_account[0]['nom_compte'] + + if ("num_carte" in part_account[0].keys()): + if part_account[0]['num_carte']: + new_data['num_carte_payment'] = part_account[0]['num_carte'] + + new_data['valide'] = "1" now = datetime.now() @@ -572,7 +583,10 @@ def createOrder(diction): return_document=ReturnDocument.AFTER ) - + # Facturation de la commande + print(" ######## lancement de la facturation total_ttc_float = " + str(total_ttc_float)) + if (total_ttc_float > 0): + CreateInvoice(new_data) return True, "la commande été correctement créee", str(new_data['order_id']) else: @@ -586,3 +600,177 @@ def createOrder(diction): return False, " Impossible de créer la facture" + +""" +Cette fontion recuperer l'id de la dernière facture +""" +def Get_Last_Invoice_ID(): + try: + last_invoice_id = 0 + coll_invoice = MYSY_GV.dbname["factures"] + tmp_val = coll_invoice.count_documents({}) + if( tmp_val ): + last_invoice_id = tmp_val + + return True, last_invoice_id + 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 recuperer l'ID de la dernière facture " + + +""" +Cette fonction créer une facture +""" +def CreateInvoice(diction): + try: + field_list_obligatoire = ['client_recid', 'invoice_nom', 'order_id', 'order_date', 'total_ttc','total_tva','total_ht','item_0'] + + for val in field_list_obligatoire: + if val not in diction: + mycommon.myprint(str(inspect.stack()[0][ + 3]) + " - Le champ '" + val + "' n'existe pas, Creation facture annulée") + return False, " Impossible de créer la facture" + + order_id = "" + status_tmp, last_invoice_id = Get_Last_Invoice_ID() + if( status_tmp is False): + mycommon.myprint(str(inspect.stack()[0][ + 3]) + " Impossible de recuperer Get_Last_Invoice_ID ") + return False, " Impossible de créer la facture" + + print(" ######## last_invoice_id = "+str(last_invoice_id)) + last_invoice_id = last_invoice_id + 1 + Order_Invoice = "MySy_0000"+str(last_invoice_id) + diction['invoice_id']= str(Order_Invoice) + now = datetime.now() + diction['due_date'] = str(now.strftime("%d/%m/%Y")) + diction['invoice_date'] = str(now.strftime("%d/%m/%Y")) + diction['printed'] = "0" + + print(" collection de facture = "+str(diction)) + coll_facture = MYSY_GV.dbname['factures'] + ret_val = coll_facture.insert_one(diction) + + if ret_val and ret_val.inserted_id: + print("str(new_data['invoice_email']) = " + str(diction['invoice_email'])) + print("str(diction['invoice_id']) = " + str(diction['invoice_id'])) + + # Envoie de l'email de la facture + PrintAndSendInvoices(str(diction['invoice_id'])) + #email.SalesOrderConfirmationEmail(str(new_data['invoice_email']), new_data) + + + return True, + + 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 facturer la commande N° "+str(order_id)+" " + + +""" +Cette fonction recupere toutes le factures non imprimé (c'est a dire que le pdf n'est pas créé) +1 - Crée le fichier PDF +2 - Envoie l'email avec la facture +""" +def PrintAndSendInvoices(invoice_id=None): + try: + i = 0 + query = {'printed':'0'} + if ( invoice_id and len(str(invoice_id)) > 0): + query = {'printed':'0','factures':str(invoice_id) } + + coll_invoice = MYSY_GV.dbname['factures'] + + for val in coll_invoice.find({'printed':'0'}): + i = i +1 + if( convertHtmlToPdf( val ) is False ): + mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible d'imprimer la facture N° "+ + str(val['invoice_id'])) + else: + mycommon.myprint(" Impression facture N° " +str(val['invoice_id'])+" OK") + + ret_val = coll_invoice.find_one_and_update( + {'invoice_id': str(val['invoice_id'])}, {"$set": {'printed':'1'}}, + upsert=False, + return_document=ReturnDocument.AFTER + ) + + if (ret_val['_id'] is False): + mycommon.myprint(" Impression facture N° " +str(val['invoice_id'])+" ==> Impossible de mettre à jour la facture") + + + return True, str(i)+" Factures ont été traitées" + + except Exception as e: + exc_type, exc_obj, exc_tb = sys.exc_info() + mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) + return False, " Impossible d'imprimer les factures " + + +def convertHtmlToPdf(diction): + try: + field_list_obligatoire =['invoice_nom', 'invoice_adr_street', 'invoice_adr_zip', 'invoice_adr_city', + 'invoice_adr_country', 'invoice_id', 'invoice_date', 'due_date', 'order_id', 'item_0', 'total_ht', 'total_tva', 'total_ttc',] + + 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 d'imprimer les factures" + + + templateLoader = jinja2.FileSystemLoader(searchpath="./") + templateEnv = jinja2.Environment(loader=templateLoader) + TEMPLATE_FILE = "Template/invoice.html" + template = templateEnv.get_template(TEMPLATE_FILE) + # This data can come from database query + body = { + "data": { + "client_name": str(diction['invoice_nom']), + "client_address": str(diction['invoice_adr_street']), + "client_zip_ville": str(diction['invoice_adr_zip'])+" "+str(diction['invoice_adr_city']), + "client_pays": str(diction['invoice_adr_country']), + "invoice_id": str(diction['invoice_id']), + "invoice_date": str(diction['invoice_date']), + "due_date": str(diction['due_date']), + "orign_order": str(diction['order_id']), + "packs": str(diction['item_0']['code']), + "qty": str(diction['item_0']['qty']), + "unit_price": str(diction['item_0']['prix']), + "montant": str(diction['item_0']['amount']), + "total_ht": str(diction['total_ht']), + "tva": str(diction['total_tva']), + "total_ttc": str(diction['total_ttc']), + } + } + + sourceHtml = template.render(json_data=body["data"]) + outputFilename = "invoice_"+str(diction['invoice_id'])+"_.pdf" + + # 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() + + # On deplace la facture vers le serveur ftp + os.rename(outputFilename, MYSY_GV.INVOICE_DIRECTORY+outputFilename) + + print(" debut envoie de la factureeee "+diction['invoice_id']) + + email.SendInvoiceEmail(str(diction['invoice_email']), diction ) + # return True on success and False on errors + print(pisaStatus.err, type(pisaStatus.err)) + return True + + except Exception as e: + print("Exception when calling SMTPApi->send_transac_email: %s\n" % e) + return False + diff --git a/email_mgt.py b/email_mgt.py index 6f5068e..d2cff29 100644 --- a/email_mgt.py +++ b/email_mgt.py @@ -495,6 +495,153 @@ def SalesOrderConfirmationEmail(account_mail, diction): + 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 + + +""" +Cette fonction envoi les factures +""" +def SendInvoiceEmail(account_mail, diction): + try: + ''' + Verification des données obligatoires + ''' + ''' + Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente, + On controle que les champs obligatoires sont presents dans la liste + ''' + field_list_obligatoire = ['invoice_nom', 'invoice_adr_street', 'invoice_adr_zip', 'invoice_adr_city', + 'invoice_adr_country', 'invoice_id', 'invoice_date', 'due_date', 'order_id', 'item_0', + 'total_ht', 'total_tva', 'total_ttc', ] + + 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 d'envoyer la facture par email" + + + order_id = diction['order_id'] + date_order = diction['order_date'] + client_name = str(diction['invoice_nom']) + client_address= str(diction['invoice_adr_street']) + client_zip_ville = str(diction['invoice_adr_zip']) + " " + str(diction['invoice_adr_city']) + client_pays = str(diction['invoice_adr_country']) + invoice_id = str(diction['invoice_id']) + invoice_date = str(diction['invoice_date']) + due_date = str(diction['due_date']) + orign_order = str(diction['order_id']) + packs = str(diction['item_0']['code']) + qty = str(diction['item_0']['qty']) + unit_price = str(diction['item_0']['prix']) + montant = str(diction['item_0']['amount']) + total_ht = str(diction['total_ht']) + tva = str(diction['total_tva']) + total_ttc = str(diction['total_ttc']) + + my_end_date = "" + + if ("end_date" in diction.keys()): + if diction.keys(): + my_end_date = "*Offre valable jusqu'au "+str(diction['end_date']) + + nb_line = mycommon.tryInt(diction['nb_product']) + + if( nb_line == 0 ): + mycommon.myprint(str(inspect.stack()[0][3]) + " - nb_line = '" + nb_line + "' : Aucun produit à facturer") + return False, " Impossible d'envoyer l'email de confirmation" + + print("Facture client_name = "+str(client_name)) + print("Facture client_address = " + str(client_address)) + print("Facture client_zip_ville = " + str(client_zip_ville)) + print("Facture client_pays = " + str(client_pays)) + print("Facture order_id = " + str(order_id)) + print("Facture date_order = " + str(date_order)) + print("Facture nb_line = " + str(nb_line)) + print("Facture End Date = " + str(my_end_date)) + + # Recuperation des produits (max 3 produits) + # produit 1 + if ("item_0" in diction.keys()): + if( diction["item_0"] ): + packs = diction["item_0"]['code'] + qty = diction["item_0"]['qty'] + unit_price = diction["item_0"]['prix'] + montant = diction["item_0"]['amount'] + detail_packs = diction["item_0"]['pack_products'] + print("diction['item_0']['pack_products'] = "+str(diction["item_0"]['pack_products'])) + + # produit 2 + if ("item_1" in diction.keys()): + if (diction["item_1"]): + packs1 = diction["item_1"]['code'] + qty1 = diction["item_0"]['qty'] + unit_price1 = diction["item_1"]['prix'] + montant1 = diction["item_1"]['amount'] + detail_packs1 = diction["item_1"]['pack_products'] + + # produit 3 + if ("item_2" in diction.keys()): + if (diction["item_2"]): + packs2 = diction["item_2"]['code'] + qty2 = diction["item_0"]['qty'] + unit_price2 = diction["item_2"]['prix'] + montant2 = diction["item_2"]['amount'] + detail_packs2 = diction["item_1"]['pack_products'] + + + i = 0 + while (i < nb_line): + row = "item_" + str(i) + print(" product = "+ str(diction[str(row)])) + i = i + 1 + + receiver = [str(account_mail)] + toaddrs = ", ".join(receiver) + + print("Facture mail enoye à toaddrs : " + toaddrs) + print("Facture debut envoi mail de test ") + # on rentre les renseignements pris sur le site du fournisseur + + msg = MIMEMultipart("alternative") + + msg['Subject'] = '[MySy Training]: votre compte PRO est pret' + msg['From'] = 'contact@mysy-training.com' + msg['To'] = str(toaddrs) + msg['Cc'] = 'contact@mysy-training.com' + + to = [{"email": str(account_mail)}] + + print(" Facture ############# to = "+str(to)) + bcc = [{"email": "contact@mysy-training.com"}] + + + send_smtp_email = sib_api_v3_sdk.SendSmtpEmail(template_id=23, params={"order_id": order_id, + "date_order": date_order, + + "total_ht": total_ht, + "tva": tva, + "total_ttc": total_ttc, + "client_name": client_name, + "client_address": client_address, + "client_zip_ville": client_zip_ville, + "client_pays": client_pays, + "packs": packs, + "detail_packs": detail_packs, + "qty": qty, + "unit_price": unit_price, + "montant":montant, + "invoice_id":invoice_id, + "invoice_date":invoice_date, + "due_date":due_date, + "orign_order":orign_order, + }, to=to, bcc=bcc) + api_response = api_instance.send_transac_email(send_smtp_email) + print("Facture "+str(api_response)) + return True + 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)) diff --git a/main.py b/main.py index b561ff3..e2a37bb 100644 --- a/main.py +++ b/main.py @@ -26,6 +26,7 @@ import youtubes_analyse as YTA import test_perso as TP import ela_factures_mgt as invoice import product_service as PS +import ela_factures_mgt as factures app = Flask(__name__) cors = CORS(app, resources={r"/foo": {"origins": "*"}}) @@ -1315,6 +1316,22 @@ def Get_Suggested_Word(): status, message = mycommon.Get_Suggested_Word() return jsonify(status=status, message=message) + +""" +Cette API imprime et envoie les factures aux clients +""" +@app.route('/myclass/api/PrintAndSendInvoices/', methods=['GET','POST']) +@crossdomain(origin='*') +def PrintAndSendInvoices(): + # On recupere le corps (payload) de la requete + payload = request.form.to_dict() + print(" ### payload = ", str(payload)) + status, message = factures.PrintAndSendInvoices() + return jsonify(status=status, message=message) + + + + if __name__ == '__main__': print(" debut api") context = SSL.Context(SSL.SSLv23_METHOD) diff --git a/prj_common.py b/prj_common.py index ca546cb..210adbc 100644 --- a/prj_common.py +++ b/prj_common.py @@ -26,11 +26,11 @@ from pymongo import ReturnDocument from unidecode import unidecode import GlobalVariable as MYSY_GV from serpapi import GoogleSearch -import prj_common as mycommon import re import email_mgt as email_mgt import random import json +import Ela_Spacy as ElaSpacy class JSONEncoder(json.JSONEncoder): def default(self, o): @@ -1081,7 +1081,6 @@ def GetMotFromElaIndex(diction): ''' correction erreur titre mymooc.com ''' - def Migration_mooc_title(): try: coll_name = MYSY_GV.dbname['myclass'] @@ -1627,4 +1626,44 @@ def Get_partner_nb_active_training(partner_recid): 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 \ No newline at end of file + return False, False + + +"""" +Cette fonction recuperer les mot du titre et de la description +pour remplir la collection des suggestions de mot +""" + +def fillSuggestionCollection(): + try: + coll_name = MYSY_GV.dbname['myclass'] + for retVal in coll_name.find({'valide':'1'}).limit(10): + + mytitle = str(retVal['title']) + mydesc = str(retVal['description']) + + class_contact = str(mytitle)+". "+str(mydesc) + + class_token = ElaSpacy.Ela_Tokenize(class_contact) + status, tab_tokens2 = ElaSpacy.Ela_remove_stop_words(class_token) + if (status is False): + break + + status, tab_tokens3 = ElaSpacy.Ela_remove_pronoun(tab_tokens2) + if (status is False): + break + + status, tab_tokens4 = ElaSpacy.Ela_stemmize_Class(tab_tokens3) + if (status is False): + break + + print(" Pour "+str(retVal['title'])+" : On a "+str(tab_tokens4)) + + + return True + + 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, +