""" Ce fichier permet de gerer la facturation des commandes des partenaires vers leur client. Il se base sur les commandes faite à l'aide du fichier "partner_order.py" """ 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 import partner_order as partner_order def Invoice_Partner_Order(diction): try: diction = mycommon.strip_dictionary(diction) """ Verification des input acceptés """ field_list = ['token', 'order_id', 'order_ref_interne'] incom_keys = diction.keys() for val in incom_keys: if val not in field_list: mycommon.myprint(str( inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé") return False, " Les informations fournies sont incorrectes", False """ Verification des champs obligatoires """ field_list_obligatoire = ['token', 'order_id', 'order_ref_interne'] for val in field_list_obligatoire: if val not in diction: mycommon.myprint( str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans liste ") return False, " Les informations fournies sont incorrectes",False """ Verification de l'identité et autorisation de l'entité qui appelle cette API """ token = "" if ("token" in diction.keys()): if diction['token']: token = diction['token'] local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction) if (local_status is not True): return local_status, my_partner, False # Verification de la validité de la commande à facturer order_to_invoice_data_count = MYSY_GV.dbname['partner_order_header'].count_documents( {'_id': ObjectId(str(diction['order_id'])), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner['recid'], 'order_header_type':'commande', 'valide': '1', 'locked': '0'}) if( order_to_invoice_data_count < 0 ): mycommon.myprint( str(inspect.stack()[0][3]) + " - Les references de la commande sont invalides ") return False, " Les references de la commande sont invalides", False if (order_to_invoice_data_count > 1): mycommon.myprint( str(inspect.stack()[0][3]) + " - Les references correspondent à plusieurs commandes. Facturation annulée. ") return False, " Les references correspondent à plusieurs commandes. Facturation annulée.",False order_to_invoice_data = MYSY_GV.dbname['partner_order_header'].find_one({'_id':ObjectId(str(diction['order_id'])), 'order_header_ref_interne':str(diction['order_ref_interne']), 'partner_owner_recid':my_partner['recid'], 'valide':'1', 'locked':'0', 'order_header_type':'commande'}) print(" #### order_to_invoice_data = ", order_to_invoice_data); if( order_to_invoice_data is None or str(order_to_invoice_data['order_header_status']) != "2" ): mycommon.myprint( str(inspect.stack()[0][ 3]) + " - La commande n'est pas au statut 'Traité'. Facturation annulée. ") return False, " La commande n'est pas au statut 'Traité'. Facturation annulée.",False # Verifier que toutes lignes sont au statut 'traité' nb_line_a_facturer = 0 for order_lines_to_invoice_data in MYSY_GV.dbname['partner_order_line'].find( {'order_header_id': str(diction['order_id']), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner['recid']}): nb_line_a_facturer = nb_line_a_facturer +1 if( str(order_lines_to_invoice_data['order_line_type']) != "commande" or str(order_lines_to_invoice_data['order_line_status']) != "2" or str(order_lines_to_invoice_data['valide']) != "1" or str(order_lines_to_invoice_data['locked']) != "0"): mycommon.myprint( str(inspect.stack()[0][ 3]) + " - La ligne de commande "+str(order_lines_to_invoice_data['order_line_formation'])+" avec la Quantite "+ str(order_lines_to_invoice_data['order_line_qty'])+" n'est pas cohérente. Facturation annulée. ") return False, " La ligne de commande "+str(order_lines_to_invoice_data['order_line_formation'])+" avec la Quantite "+ str(order_lines_to_invoice_data['order_line_qty'])+" n'est pas cohérente. Facturation annulée.",False if( nb_line_a_facturer == 0): # Alors il n'y a aucune ligne à facturer mycommon.myprint( str(inspect.stack()[0][ 3]) + " - Il n'y a aucune ligne à facturer. Facturation annulée. ") return False, "Il n'y a aucune ligne à facturer. Facturation annulée.",False # Verification de la validité du client is_client_valide = MYSY_GV.dbname['partner_client'].count_documents({'_id':ObjectId(str(order_to_invoice_data['order_header_client_id'])), 'valide':'1', 'locked':'0', 'partner_recid':str(my_partner['recid'])}) if( is_client_valide != 1): mycommon.myprint( str(inspect.stack()[0][ 3]) + " - Le client à facturer est invalide. Facturation annulée. ") return False, "Le client à facturer est invalide. Facturation annulée.",False """ A présent la commande est valide, on va 0 - Mettre à jour la commande en mettant le statut "facturé' ==> comme ca on bloque d'evenuelles modification de la commande 1 - Relancer un compute de la commande 2 - copier les données dans la collection 'facture' 3 - on met à jour les lignes de la commande, pr la mettre à facturé """ # 0 - Mettre à jour la commande en mettant le statut "facturé' ==> comme ca on bloque d'evenuelles modification de la commande order_updated = MYSY_GV.dbname['partner_order_header'].update_one({'_id':ObjectId(str(diction['order_id'])), 'order_header_ref_interne':str(diction['order_ref_interne']), 'partner_owner_recid':my_partner['recid'], 'valide':'1', 'locked':'0', 'order_header_type':'commande'}, {'$set':{'order_header_status':'3'} } ) if(order_updated.modified_count != 1 ): mycommon.myprint( str(inspect.stack()[0][ 3]) + " - Impossible de verrouiller la commande à facturer. Facturation annulée. ") return False, "Impossible de verrouiller la commande à facturer. Facturation annulée.",False # 1 - Relancer un compute de la commande comput_diction = {} comput_diction['token'] = diction['token'] comput_diction['_id'] = diction['order_id'] local_retval, local_message = partner_order.Compute_Order_Header(comput_diction) if (local_retval is False): order_updated = MYSY_GV.dbname['partner_order_header'].update_one({{'_id': ObjectId( str(diction['order_id'])), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner[ 'recid'], 'valide': '1', 'locked': '0', 'order_header_type': 'commande'}, {'$set': {'order_header_status': '2'}} }) mycommon.myprint( str(inspect.stack()[0][ 3]) + " - Impossible de mettre à jour les prix de la commande à facturer. Facturation annulée. ") return False, "Impossible de mettre à jour les prix de la commande à facturer. Facturation annulée.",False #2 - copier les données dans la collection 'facture' """ /!\ On va recopier les header et line, telqel. On fera les changements plus tard si besoin """ # Rcuperation de la sequence de l'objet "partner_invoice_header" dans la collection : "mysy_sequence" retval_sequence_invoice = MYSY_GV.dbname['mysy_sequence'].find_one({'partner_invoice_header': 'partner_order_header', 'valide': '1', 'partner_owner_recid': str( my_partner['recid'])}) if (retval_sequence_invoice is None): # Il n'y pas de sequence pour le partenaire, on va aller chercher la sequence par defaut retval_sequence_invoice = MYSY_GV.dbname['mysy_sequence'].find_one( {'related_mysy_object': 'partner_invoice_header', 'valide': '1', 'partner_owner_recid': 'default'}) if (retval_sequence_invoice is None or "current_val" not in retval_sequence_invoice.keys()): # Il n'y aucune sequence meme par defaut. order_updated = MYSY_GV.dbname['partner_order_header'].update_one({{'_id': ObjectId( str(diction['order_id'])), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner[ 'recid'], 'valide': '1', 'locked': '0', 'order_header_type': 'commande'}, {'$set': {'order_header_status': '2'}} }) mycommon.myprint(" Impossible de récupérer la sequence 'retval_sequence_invoice' ") return False, "Impossible de récupérer la sequence 'retval_sequence_invoice'", False current_seq_value = str(retval_sequence_invoice['current_val']) new_sequence_value = int(mycommon.tryInt(current_seq_value)) + 1 new_sequance_data_to_update = {'current_val': new_sequence_value} ret_val2 = MYSY_GV.dbname['mysy_sequence'].find_one_and_update( {'_id': ObjectId(str(retval_sequence_invoice['_id'])), 'valide': '1'}, {"$set": new_sequance_data_to_update}, return_document=ReturnDocument.AFTER, upsert=False, ) invoice_date_time = str(datetime.now()) new_invoice_data_header = MYSY_GV.dbname['partner_order_header'].find_one({'_id':ObjectId(str(diction['order_id'])), 'order_header_ref_interne':str(diction['order_ref_interne']), 'partner_owner_recid':my_partner['recid'], 'valide':'1', 'locked':'0', 'order_header_type':'commande'}, {'_id':0, 'order_header_type':0, 'order_header_status':0}) new_invoice_data_header['invoice_header_ref_interne'] = retval_sequence_invoice['prefixe']+str(current_seq_value) new_invoice_data_header['invoice_header_type'] = "facture" new_invoice_data_header['invoice_date'] = invoice_date_time inserted_invoice_id = MYSY_GV.dbname['partner_invoice_header'].insert_one(new_invoice_data_header).inserted_id if (not inserted_invoice_id): order_updated = MYSY_GV.dbname['partner_order_header'].update_one({{'_id': ObjectId( str(diction['order_id'])), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner[ 'recid'], 'valide': '1', 'locked': '0', 'order_header_type': 'commande'}, {'$set': {'order_header_status': '2'}} }) mycommon.myprint( " Impossible de créer l'entete de la facture ") return False, "Impossible de créer l'entete de la facture ", False for new_invoice_data_line in MYSY_GV.dbname['partner_order_line'].find( {'order_header_id': str(diction['order_id']), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner['recid']}, {'_id':0, 'order_line_type':0, 'order_line_status':0, }): new_invoice_data_line['invoice_header_ref_interne'] = retval_sequence_invoice['prefixe']+str(current_seq_value) new_invoice_data_line['invoice_line_type'] = "facture" new_invoice_data_line['invoice_date'] = invoice_date_time new_invoice_data_line['invoice_header_id'] = str(inserted_invoice_id) inserted_line_id = MYSY_GV.dbname['partner_invoice_line'].insert_one(new_invoice_data_line).inserted_id if (not inserted_line_id): # Vu quil y a un soucis avec l'une des ligne, on fait un roll back complet de la facturation order_updated = MYSY_GV.dbname['partner_order_header'].update_one({{'_id': ObjectId( str(diction['order_id'])), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner[ 'recid'], 'valide': '1', 'locked': '0', 'order_header_type': 'commande'}, {'$set': {'order_header_status': '2'}} }) MYSY_GV.dbname['partner_invoice_header'].delete_one({'_id':ObjectId(str(str(inserted_invoice_id)))}) MYSY_GV.dbname['partner_invoice_line'].delete_many({'invoice_header_id': ObjectId(str(str(inserted_invoice_id)))}) mycommon.myprint( " Impossible de finaliser la facturation des lignes de la ligne la commande ") return False, " Impossible de finaliser la facturation des lignes de la ligne la commande. ", False # 3 - on met à jour les lignes de la commande, pr la mettre à facturé qry = {'order_header_id': str(diction['order_id']), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner['recid'], 'valide': '1', 'locked': '0', 'order_header_type': 'commande'} print(" #### qry = ", qry) order_updated = MYSY_GV.dbname['partner_order_line'].update_many( {'order_header_id': str(diction['order_id']), 'order_header_ref_interne': str(diction['order_ref_interne']), 'partner_owner_recid': my_partner['recid'], 'valide': '1', 'locked': '0', 'order_line_type': 'commande'}, {'$set': {'order_line_status': '3'}} ) if (order_updated.modified_count <= 0): mycommon.myprint( str(inspect.stack()[0][ 3]) + " WARNING - Impossible de mettre les lignes à facturer pour order_header_id = "+str(str(diction['order_id']))) return True, " La commande a été correctement facturée", str(new_invoice_data_header['invoice_header_ref_interne']) except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno)) return False, " Impossible de facturer la commande ", False