Files
AttribWinbiz/main.py
2023-01-24 15:10:03 +01:00

1031 lines
47 KiB
Python

import csv
import json
import os
import logging
import shutil
import subprocess
import textwrap
import time
import uuid
import tkinter
from datetime import datetime
import tkinter.filedialog
from tkinter import *
from tkinter import font
from tkinter import messagebox
from tkinter.ttk import Progressbar
from tkinter.scrolledtext import ScrolledText
from threading import *
from class_invoices import *
from class_addresses import *
from auto_update import *
from class_debitors import *
from version import *
from custom_popup import *
src_dir = os.getenv('APPDATA') + "\Attrib2Biz\src"
dest_dir = os.getenv('APPDATA') + "\Attrib2Biz\output"
temp_dir = os.getenv('APPDATA') + '\Attrib2Biz\.temp'
file_path ="" #os.path.dirname(__file__)
Elements = []
export_csv = "";
con_csv = "";
if not os.path.exists(src_dir):
os.makedirs(src_dir)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
if not os.path.exists(temp_dir):
os.makedirs(temp_dir)
class TextHandler(logging.Handler):
"""This class allows you to log to a Tkinter Text or ScrolledText widget"""
def __init__(self, text):
# run the regular Handler __init__
logging.Handler.__init__(self)
# Store a reference to the Text it will log to
self.text = text
def emit(self, record):
msg = self.format(record)
print("pass 1 " + msg)
def append():
self.text.configure(state='normal')
self.text.insert(tkinter.END, msg + '\n')
self.text.configure(state='disabled')
# Autoscroll to the bottom
self.text.yview(tkinter.END)
# This is necessary because we can't modify the Text from other threads
self.text.after(0, append)
class ClercAttrib2Biz():
def __init__(self):
self.count_facture = 0
self.a_index = {"invoice": [], "intervention": [], "patient": [], "debtor": [], "articles": [], "global": []}
self.addresses = cls_Addresses()
self.o_debs = cls_debitors(filepath=temp_dir)
self.index_counter = 0
self.bs_counter = 70
self.a_listings = {}
self.export_filename = "export.csv"
self.fenetre = Tk()
self.prompt = None
self.b_prompt_open = False
self.check_addresses = BooleanVar(self.fenetre)
self.delete_after_parse = BooleanVar(self.fenetre)
self.export_format_biz = BooleanVar(self.fenetre)
self.export_one_file = BooleanVar(self.fenetre)
self.run_excel_after_export = BooleanVar(self.fenetre)
self.check_addresses.set(True)
self.export_one_file.set(True)
self.run_excel_after_export.set(False)
self.export_format_biz.set(True)
self.draw_mainWindows()
self.refresh_ui()
self.read_addresses()
self.timer = self.fenetre.after(1000, self.main_timer_fn)
self.fenetre.mainloop()
def main_timer_fn(self):
#print("Pass tick timer main app")
self.timer = self.fenetre.after(5000, self.main_timer_fn)
self.nb_facture_var.set(self.count_facture)
self.count_src()
def draw_mainWindows(self):
#Init de la fenêtre principale
self.fenetre.iconbitmap("./logo_clerc_03X_icon.ico")
self.fenetre.title("Clerc Attrib2Biz v" + str(VERSION))
self.fenetre.resizable(True, True)
self.fenetre.geometry("700x475")
self.fenetre.columnconfigure(0, weight=3)
self.fenetre.columnconfigure(1, weight=1)
self.fenetre.rowconfigure(3,weight=1)
lbf_2 = LabelFrame(self.fenetre, text="Nb de facture")
lbf_2.grid(row=1, column=0, sticky='W',padx=5, pady=5)
lbf_3 = LabelFrame(self.fenetre, text="Options")
lbf_3.grid(row=0, column=8, sticky='WE',padx=5, pady=5)
#GUI Nb Files
lbf_1 = LabelFrame(self.fenetre, text="Nb de fichiers")
lbf_1.grid(row=0, column=0, sticky='WE', padx=5, pady=5)
self.nb_files_var = IntVar()
Label(lbf_1, textvariable=self.nb_files_var, anchor="e", font=('Helvetica', 13, 'bold')).grid(row=0, column=0, sticky="W", pady=5)
Label(lbf_1, text="fichiers .json dans le dossier source", anchor="w" ).grid(row=0,column=1, sticky="W", pady=5)
f1 = Frame(lbf_1)
f1.grid(row=1, column=1)
bt_open_src = Button(f1, text="Ouvrir le dossier source", command=self.open_src)
bt_open_src.grid(row=1, column=0, padx=5, pady=5)
self.bt_clear_src = Button(f1, text="Vider le dossier source", command=self.clear_src, state="disabled")
self.bt_clear_src.grid(row=1, column=2, padx=5, pady=5)
# GUI Nb facture
lbf_2 = LabelFrame(self.fenetre, text="Nb de Facture", width=250)
lbf_2.grid(row=1, column=0, sticky='WE', padx=5, pady=5)
lbf_2.columnconfigure(2, weight=1)
self.nb_facture_var = IntVar()
Label(lbf_2, textvariable=self.nb_facture_var, anchor="e", font=('Helvetica', 13, 'bold')).grid(row=0, column=0, sticky="W", pady=5)
Label(lbf_2, text="factures trouvées sur l'ensemble des fichiers", anchor="w").grid(row=0, column=1, sticky="W", pady=5)
f2 = Frame(lbf_2)
f2.grid(row=1, column=1)
self.bt_parse = Button(f2, text="Lancer la conversion", command=self.start_parsing, state="disabled")
self.bt_parse.grid(row=1, column=0,columnspan=2, padx=5, pady=5, sticky="W")
bt_open_dest = Button(f2, text="Ouvrir le dossier de sortie", command=self.open_dest)
bt_open_dest.grid(row=1, column=2, padx=5, pady=5, sticky="W")
self.txt_progress = LabelFrame(self.fenetre, text="Progress")
self.txt_progress.grid(row=2, column=0, sticky='WE', columnspan=2, padx=5, pady=5)
self.txt_progress.columnconfigure(0,weight=1)
self.progress_bar = Progressbar(self.txt_progress, orient=HORIZONTAL, mode='determinate')
self.progress_bar.grid(sticky='WE')
self.frame_logs = LabelFrame(self.fenetre, text="Log")
self.frame_logs.grid(row=3, column=0, sticky='WENS', columnspan=2, padx=5, pady=5)
self.frame_logs.columnconfigure(0, weight=1)
self.frame_logs.rowconfigure(0, weight=1)
st = ScrolledText( self.frame_logs, state='disabled', height=10)
st.grid(row=0, column=0, sticky="WENS", pady=5)
text_handler = TextHandler(st)
self.logger = logging.getLogger()
self.logger.addHandler(text_handler)
lbf_3 = LabelFrame(self.fenetre, text="Options")
lbf_3.grid(row=0, column=1, rowspan=2, sticky='NSEW', padx=5, pady=5)
Checkbutton(lbf_3, text="Vérifier les Adresses", variable=self.check_addresses, onvalue=True, offvalue=False).grid(row=0, sticky='W')
Checkbutton(lbf_3, text="Supprimer fichiers après conversion", variable= self.delete_after_parse, onvalue=True, offvalue=False).grid(row=1, sticky='W')
Checkbutton(lbf_3, text="Export au format .biz", variable= self.export_format_biz, onvalue=True, offvalue=False, command=self.refresh_ui).grid(row=2, sticky='W')
Checkbutton(lbf_3, text="Export en 1 seul fichier", variable= self.export_one_file, onvalue=True, offvalue=False, command=self.refresh_ui).grid(row=3, sticky='W')
self.cb_run = Checkbutton(lbf_3, text="Lancer la conversion excel", variable=self.run_excel_after_export, onvalue=True, offvalue=False)
self.cb_run.grid(row=4, sticky='W')
menu_bar = Menu(self.fenetre)
menu_param = Menu(menu_bar, tearoff=0)
menu_param.add_command(label="Affichage des débiteurs", command=self.o_debs.print_all_debs)
menu_bar.add_cascade(label="Paramètre", menu=menu_param)
self.fenetre.config(menu=menu_bar)
self.var_file_count = StringVar(self.fenetre)
self.running = False
self.thread = Thread(target=self.start_parsing)
auto_update = auto_updater()
auto_update.temp_dir = temp_dir + '\\'
update_available = auto_update.new_update_available()
if update_available == True:
self.logger.warning(f"Nouvelle version du script disponible. {auto_update.dl_version}")
if messagebox.askyesno(title="Nouvelle version trouvée", message=f"Une nouvelle version a été trouvée, vous pouvez l'installer dès maintenant !", ):
subprocess.call(temp_dir + "\\update.exe")
self.fenetre.destroy()
elif update_available == "ERROR":
messagebox.showerror(title="ERREUR téléchargement", message="Erreur lors du téléchargement de la nouvelle mise à jour")
def disable_prompt(self):
self.prompt.destroy()
self.b_prompt_open = False
def refresh_ui(self):
#print("pass refresh UI")
if self.export_one_file.get() and not self.export_format_biz.get():
self.cb_run['state'] = "active"
else:
self.cb_run['state'] = "disabled"
self.run_excel_after_export.set(False)
if self.export_format_biz.get():
self.cb_run['state'] = "disabled"
self.run_excel_after_export.set(False)
def read_addresses(self):
file_addresses_path = os.path.join(dest_dir, f"adresses.txt")
if os.path.exists(file_addresses_path):
file = open(file_addresses_path)
csvreader = csv.reader(file, delimiter=';')
rows = []
for row in csvreader:
rows.append(row)
o_addresse = cls_addresse()
o_addresse.AVS = row[5]
o_addresse.lastName = row[9]
o_addresse.firstName = row[10]
o_addresse.birth = row[38]
o_addresse.street = row[11]
o_addresse.street_cpl = row[12]
o_addresse.npa = row[13]
o_addresse.city = row[15]
self.addresses.add_addresse(o_addresse)
file.close()
else:
messagebox.showwarning(title="Impossible d'ouvrir le fichier d'adresse existantes", message=f"Le fichier {file_addresses_path} est introuvable. Aucune vérification des adresses possible")
def start_parsing(self):
dir = src_dir
self.count_facture = 0
x = 0
self.export_filename = f"bizexdoc_export_Attrib_v{datetime.now().year}{datetime.now().month}{datetime.now().day}{datetime.now().hour}{datetime.now().minute}.csv"
if self.export_format_biz:
if self.export_one_file.get() and os.path.exists(os.path.join(dest_dir, self.export_filename)):
try:
os.remove(os.path.join(dest_dir, self.export_filename))
except:
messagebox.showerror(title="Erreur fichier déjà ouvert", message=f"Le fichier {self.export_filename} est déjà ouvert. Veuillez le fermer et recommencer")
return
print(f"remove {self.export_filename} => {os.path.join(dest_dir, self.export_filename)}")
else:
if self.export_one_file.get() and os.path.exists(os.path.join(dest_dir, f"src.csv")):
try:
os.remove(os.path.join(dest_dir, f"src.csv"))
except:
messagebox.showerror(title="Erreur fichier déjà ouvert", message=f"Le fichier src.csv est déjà ouvert. Veuillez le fermer et recommencer")
return
print(f"remove src.csv => {os.path.join(dest_dir, 'src.csv')}")
self.progress_bar["value"] = 0
for filename in os.listdir(dir):
x += 1
if ".json" in filename:
print(filename)
with open(dir + "/" + filename, encoding="utf-8") as f:
data = json.load(f)
if self.export_format_biz.get():
bRet = self.parseFile(data, filename)
if bRet:
messagebox.showinfo(title="Fin de conversion",
message="La conversion s'est terminée avec succès")
return False
else:
self.convertFile(data, filename)
if self.delete_after_parse.get():
os.remove(dir + "/" + filename)
self.progress_bar["value"] = x / len(os.listdir(dir)) * 100
self.fenetre.update_idletasks()
self.nb_facture_var.set(self.count_facture)
if self.run_excel_after_export.get():
self.open_export_file()
def ifNotNull(self,value, ret=""):
if value == None:
return ret
return value.strip()
def trim_all_data(self, data):
if data.Patient["lastname"] is not None:
data.Patient["lastname"] = data.Patient["lastname"].strip()
if data.Patient["firstname"] is not None:
data.Patient["firstname"] = data.Patient["firstname"].strip()
if data.Patient["street"] is not None:
data.Patient["street"] = data.Patient["street"].strip()
if data.Debtor["lastname"] is not None:
data.Debtor["lastname"] = data.Debtor["lastname"].strip()
if data.Debtor["firstname"] is not None:
data.Debtor["firstname"] = data.Debtor["firstname"].strip()
if data.Debtor["street"] is not None:
data.Debtor["street"] = data.Debtor["street"].strip()
if data.data["comments"] is not None:
data.data["comments"] = data.data["comments"].strip().replace("\n",'')
if "name" in data.Debtor.keys() and data.Debtor["name"] is not None:
data.Debtor["name"] = data.Debtor["name"].replace("(facturation)","")
data.Debtor["name"] = data.Debtor["name"].strip()
def check_code_validity(self, code,data):
ret = True
check_patients = ["firstname", "lastname", "street"]
check_Debtor = ["firstname", "lastname", "street"]
if code == 1:
for check in check_patients:
if data.Patient[check] is None:
ret = False
for check in check_Debtor:
if data.Debtor[check] is None:
ret = False
if not ret:
messagebox.showerror(title="Erreur Critique", message=f"Les informations de la factures [{data.data['id']}] comportes trop d'erreur arrêt du processus ")
return False
return ret
def compare_old_and_new_adresses(self, new, old):
if new['insurance_policy_number'].replace('.','') != old.AVS:
return False
if new['lastname'].replace('.','') != old.lastName:
return False
if new['firstname'].replace('.','') != old.firstName:
return False
if datetime.strptime(new['birthdate'], "%Y-%m-%d").strftime("%d.%m.%Y") != old.birth:
return False
if f"{new['street']} {new['street_number']}" != old.street:
return False
if f"{new['postal_code']} {new['city']}" != f"{old.npa} {old.city}":
return False
return True
def parseFile(self, data, filename):
self.progress_bar["value"] = 0
self.index_counter += 1
lines = []
self.count_facture += len(data["invoices"])
self.a_listings["to_check"] = []
if self.index_counter == 1:
csv_col = cls_Col(True)
csv_col.data[0] = "V:" + VERSION
csv_col.data[5] = f""
lines.append(csv_col.data)
cur_invoice_index = 0
for ele in data["invoices"]:
cur_invoice_index += 1
self.progress_bar["value"] = cur_invoice_index / self.count_facture * 100
b_address_update = True
data = cls_Invoice()
data.parse_item(ele)
self.trim_all_data(data)
print(f"Code débiteur => {data.data['id']}: {data.Debtor['code']}")
if data.Debtor["code"] is None or '.' in data.Debtor["code"]:
print("ERROR code débiteur #1")
messagebox.showerror(title="Erreur code débiteur", message=f"Le code débiteur de la facture {data.data['id']} est faux: [{data.Debtor['code']}], merci de le corriger ")
inp_popup = Input_popup(self.fenetre, default=data.Debtor["code"], factureID=data.data['id'], fip=data.Patient['fip_number'])
data.Debtor["code"] = str(inp_popup.show())
if data.Debtor["code"] is None or '.' in data.Debtor["code"]:
messagebox.showerror(title="Erreur Critique",
message=f"Les informations de la factures [{data.data['id']}] comportes trop d'erreur arrêt du processus ")
return False
if int(data.Debtor["code"]) == 1:
if not self.check_code_validity(data.Debtor["code"],data):
messagebox.showerror(title="Erreur Critique",
message=f"Les informations de la factures [{data.data['id']}] comportes trop d'erreur arrêt du processus ")
return False
if data.Debtor["code"] != "1" and data.Debtor["code"] != None and int(data.Debtor["code"]) < 100:
if data.Patient["fip_number"] not in self.a_listings["to_check"]:
self.a_listings["to_check"].append(data.Patient["fip_number"])
self.logger.warning(f"Vérifier facture N°: {data.data['id']} / {data.Patient['fip_number']} {data.Debtor['code']} {data.Debtor['lastname']} {data.Debtor['firstname']}")
for elem in data.Debtor:
pass
''' TODO activer ce code quand les débiteur auront un bon numéro
try:
if int(data.Debtor["code"]) > 100:
print("code débiteur > 100 => no update data")
b_update_debitor = False
except:
messagebox.showerror(title="Erreur de code débiteur", message=f"il y a une erreur dans le code débiteur, il faut le vérifier. \n(n'est pas un chiffre) {data.Patient['fip_number']}")
exit()
'''
'''
if data.Debtor["type"] == "Établissement":
self.a_listings["to_check"].append(data.Patient["fip_number"])
print(data.Patient["complement"])
self.logger.warn(f"Débiteur établissement facture N°: {data.data['id']} / {data.Patient['fip_number']} {data.Debtor['name']}")
'''
if int(data.Debtor["code"]) == 1:
b_check_debitor = False
if data.Debtor["lastname"] == None:
b_check_debitor = True
data.Debtor["lastname"] = ""
messagebox.showerror(title="Erreur",
message=f"Le débiteur n'a pas de nom, vérifier la facture ATTRIB et vérifier le code débiteur: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
if data.Debtor["firstname"] == None:
b_check_debitor = True
data.Debtor["firstname"] = ""
messagebox.showerror(title="Erreur",
message=f"Le débiteur n'a pas de prénom, vérifier la facture ATTRIB et vérifier le code débiteur: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
if b_check_debitor:
debitor_popup = Check_debitor_popup(self.fenetre, data.Debtor,
self.o_debs.get_names_by_code(data.Debtor['code']),
data.data['id'],
data.Patient['fip_number'], object=self.o_debs)
data.Debtor["code"] = debitor_popup.show()
if data.Patient["lastname"] + data.Patient["firstname"] != data.Debtor["lastname"] + data.Debtor["firstname"]:
self.a_listings["to_check"].append(data.Patient["fip_number"])
print(data.Patient["complement"])
self.logger.warning(f"Débiteur différents: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
if int(data.Debtor["code"]) >= 100:
if "name" not in data.Debtor.keys():
data.Debtor["name"] = "Invalide"
self.logger.warning(
f"Débiteur > 100 sans nom, vérifier la facture ATTRIB et vérifier le code débiteur: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
messagebox.showerror(title="Erreur",
message=f"Débiteur > 100 sans nom de débiteur ou d'établissement, vérifier la facture ATTRIB et vérifier le code débiteur: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
self.a_listings["to_check"].append(data.Patient["fip_number"])
if not self.o_debs.is_in_debitor_name(code=data.Debtor["code"],search_name=data.Debtor["name"]):
#messagebox.showerror(title="Erreur code débiteur erroné", message=f"Information débiteur incohérente: facture N°: {data.data['id']} / {data.Patient['fip_number']}.\nCode débiteur: {data.Debtor['code']}\nNom du débiteur: {data.Debtor['name']}. \nAurait dû être: {self.o_debs.get_names_by_code(data.Debtor['code'])}")
debitor_popup = Check_debitor_popup(self.fenetre,data.Debtor,self.o_debs.get_names_by_code(data.Debtor['code']),data.data['id'],data.Patient['fip_number'], object=self.o_debs)
data.Debtor["code"] = debitor_popup.show()
if data.Debtor["code"] is None or '.' in data.Debtor["code"]:
messagebox.showerror(title="Erreur Critique",
message=f"Les informations de la factures [{data.data['id']}] comportes trop d'erreur arrêt du processus ")
return False
if data.Patient["complement"] != None:
self.a_listings["to_check"].append(data.Patient["fip_number"])
print(data.Patient["complement"])
self.logger.warning(f"Complément patient: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
if data.Patient['insurance_policy_number'] == None:
data.Patient['insurance_policy_number'] = f"{uuid.uuid4()}"[:15]
if self.check_addresses.get():
addresses_exist = self.addresses.get_item_by_AVS(data.Patient['insurance_policy_number'].replace(".", ""))
if addresses_exist is not None and not self.compare_old_and_new_adresses(new=data.Patient, old=addresses_exist):
popup = Check_addresses_popup(self.fenetre, item_1=data.Patient, item_2=addresses_exist, debitor=data.Debtor, factureID=data.data['id'])
b_address_update = popup.show()
print(f"Result Popup: {b_address_update}")
else:
b_address_update = True
#self.draw_test(item_1=data.Patient, item_2=addresses_exist)
#messagebox.showerror(title="AVS Trouvé", message=f"Le code AVS de l'adresse {data.Patient['insurance_policy_number']} est déjà existant: [{data.Debtor['code']}], merci de le corriger ")
b_HRF = False
sHRF = ""
for article in data.Articles:
if "code" in article.keys():
if article["code"] == "HRF":
b_HRF = True
sHRF = article["line_1"].replace("h", ":")
print(f"pass HRF => {data.Patient['fip_number']} = {b_HRF}")
#self.logger.warning(f"HRF: {data.data['id']}")
break
for article in data.Articles:
self.bs_counter += 1
csv_col = cls_Col(True)
print(article)
if "code" in article.keys() and article["code"] == "HRF":
break
##Donnée globales
csv_col.data[0] = data.data["id"] # N° document
csv_col.data[1] = 20 # Type of document 20 = facture débiteur
csv_col.data[2] = datetime.strptime(data.data["date"], "%Y-%m-%d").strftime("%d.%m.%Y") # Date du document
csv_col.data[4] = data.Patient["fip_number"] # Référence
csv_col.data[10] = "<AUTO>" # Compte collectif du tiers = <AUTO>
csv_col.data[139] = "COND-30" # Conditions de payement à 30, COND-30 selon config dans winbiz
if "without_transportation" in data.Intervention.keys() and data.Intervention["without_transportation"] == True:
csv_col.data[15] = "Sans transport"
print(f"->NO DEST** {data.data['id']}")
elif data.Intervention["destination_name"] == None and data.Intervention["destination_street"] == None and data.Intervention["destination_city"] == None:
csv_col.data[15] = "Sans destination"
print(f"->NO DEST sans destination transmis à autruit** {data.data['id']}")
else:
con = ""
concat_str = ""
if data.Intervention["destination_name"] is not None:
concat_str += con + data.Intervention["destination_name"]
con = ", "
if data.Intervention["destination_street"] is not None:
concat_str += con + data.Intervention["destination_street"] + " " + self.ifNotNull(data.Intervention["destination_street_number"])
con = ", "
concat_str += con + data.Intervention["destination_postal_code"] + " " + data.Intervention["destination_city"]
csv_col.data[15] = concat_str # Adresse DEST
con = ""
concat_str = ""
if data.Intervention["site_name"] is not None:
concat_str += con + data.Intervention["site_name"]
con = ", "
if data.Intervention["site_street"] is not None:
concat_str += con + self.ifNotNull(data.Intervention["site_street"]) + " " + self.ifNotNull(data.Intervention["site_street_number"])
con = ", "
concat_str += con + self.ifNotNull(data.Intervention["site_postal_code"]) + " " + self.ifNotNull(data.Intervention["site_city"])
csv_col.data[18] = concat_str # Adresse PEC
print(f'debug FIP:{data.Patient["fip_number"]} id:{data.data["id"]} code: {data.Debtor["code"]}')
if int(data.Debtor["code"]) < 100:
csv_col.data[19] = data.Patient['insurance_policy_number'].replace(".","")
csv_col.data[22] = data.Patient["lastname"]
csv_col.data[23] = data.Patient["firstname"]
csv_col.data[24] = data.Patient["complement"]
csv_col.data[25] = self.ifNotNull(data.Patient["street"]) + " " + self.ifNotNull(data.Patient["street_number"])
csv_col.data[26] = data.Patient["postal_code"]
csv_col.data[27] = data.Patient["city"]
if data.Patient["country_name"] != "Suisse":
csv_col.data[29] = data.Patient["country_name"]
csv_col.data[41] = "Monsieur" if data.Patient["gender"] == "Masculin" else "Madame"
csv_col.data[44] = csv_col.data[41]
#csv_col.data[46] = 0 # Maj adresse
if b_address_update:
csv_col.data[46] = 0 # Maj adresse ajoute ou met à jour l'adresse
print("mise à jour de l'adresse")
else:
csv_col.data[46] = 1 # Maj adresse, ajoute, mais ne met pas à jour l'adresse si elle existe
print("NON mise à jour de l'adresse")
if int(data.Debtor["code"]) > 1:
con = ""
concat_str = ""
if "name" in data.Debtor.keys():
if data.Debtor["name"] is not None:
concat_str += con + data.Debtor["name"]
con = "#chr(13)##chr(10)#"
else:
messagebox.showerror(title="Erreur nom débiteur", message=f"Le nom débiteur de la facture {data.data['id']} est faux: [{data.Debtor['name']}], merci de le corriger ")
if data.Debtor["gender"] is not None:
concat_str += con + "Monsieur" if data.Debtor["gender"] == "Masculin" else con + "Madame"
con = "#chr(13)##chr(10)#"
if data.Debtor["lastname"] is not None:
concat_str += con + self.ifNotNull(data.Debtor["lastname"]) + " " + self.ifNotNull(data.Debtor["firstname"])
con = "#chr(13)##chr(10)#"
if data.Debtor["complement"] is not None:
concat_str += con + data.Debtor["complement"]
con = "#chr(13)##chr(10)#"
if data.Debtor["street"] is not None:
concat_str += con + self.ifNotNull(data.Debtor["street"]) + " " + self.ifNotNull(data.Debtor["street_number"])
con = "#chr(13)##chr(10)#"
if data.Debtor["city"] is not None:
concat_str += con + self.ifNotNull(data.Debtor["postal_code"]) + " " + self.ifNotNull(data.Debtor["city"])
con = "#chr(13)##chr(10)#"
if data.Debtor["country_name"] != "Suisse":
concat_str += con + data.Debtor["country_name"]
con = "#chr(13)##chr(10)#"
csv_col.data[42] = concat_str #Adresse de livraison
else:
csv_col.data[19] = data.Debtor["code"] # Code adresse à récupérer dans recherche d'adresse automatisée
csv_col.data[22] = data.Debtor["lastname"]
csv_col.data[23] = data.Debtor["firstname"]
csv_col.data[24] = data.Debtor["complement"]
csv_col.data[25] = self.ifNotNull(data.Debtor["street"]) + " " + self.ifNotNull(data.Debtor["street_number"])
csv_col.data[26] = data.Debtor["postal_code"]
csv_col.data[27] = data.Debtor["city"]
if data.Debtor["country_name"] != "Suisse":
csv_col.data[29] = data.Debtor["country_name"]
csv_col.data[46] =1 # Maj adresse, ajoute, mais ne met pas à jour l'adresse si elle existe
if "name" in data.Debtor.keys():
csv_col.data[21] = self.ifNotNull(data.Debtor["name"])
else:
csv_col.data[21] = ''
if data.Patient["birthdate"] is not None:
csv_col.data[40] = datetime.strptime(data.Patient["birthdate"], "%Y-%m-%d").strftime("%d.%m.%Y")
else:
csv_col.data[40] = ""
messagebox.showerror(title="Erreur date de naissance", message=f"La date de naissance de la facture {data.data['id']} ({data.Patient['lastname']}) est faux: [{data.Patient['birthdate']}], merci de le corriger ")
csv_col.data[48] = 0
## Données prestations
if "code" in article.keys():
csv_col.data[49] = article["code"] # Code de prestations
csv_col.data[50] = article["line_1"]
if article["line_2"] != None:
csv_col.data[50] = article["line_1"] + "#chr(13)##chr(10)#" + article["line_2"] # Descriptions prestations
csv_col.data[52] = article["quantity"] # Quantité
csv_col.data[53] = article["unit_price"] # prix unitaire
csv_col.data[54] = self.ifNotNull(article["unit"]) # unité
csv_col.data[56] = article["price"] # prix total
else:
csv_col.data[49] = "0"
csv_col.data[50] = article["line_1"]
if article["line_2"] != None:
csv_col.data[50] = article["line_1"] + " / " + article["line_2"] # Descriptions prestations
csv_col.data[52] = 0
csv_col.data[53] = 0
csv_col.data[56] = 0 # prix total
compte_number = None
if data.Intervention["base_name"] == "Uvrier":
compte_number = 3018
else:
if data.Intervention["type"] == "P1":
compte_number = 3001 if data.Intervention["team_name"] == "Planification" else 3011
if data.Intervention["type"] == "P2":
compte_number = 3002 if data.Intervention["team_name"] == "Planification" else 3012
if data.Intervention["type"] == "P3":
compte_number = 3003 if data.Intervention["team_name"] == "Planification" else 3013
if data.Intervention["type"] == "S1":
compte_number = 3004 if data.Intervention["team_name"] == "Planification" else 3014
if data.Intervention["type"] == "S2":
compte_number = 3005 if data.Intervention["team_name"] == "Planification" else 3015
if data.Intervention["type"] == "S3":
compte_number = 3005 if data.Intervention["team_name"] == "Planification" else 3015
csv_col.data[59] = compte_number
csv_col.data[60] = 0
csv_col.data[61] = 0
csv_col.data[63] = 0
csv_col.data[69] = "Libre"
csv_col.data[70] = "BS - " + str(self.bs_counter)
csv_col.data[72] = "BU - 73 - aff"
csv_col.data[73] = 0
#Objet facture
csv_col.data[108] = self.ifNotNull(data.Patient["lastname"]) + " " + self.ifNotNull(data.Patient["firstname"])
csv_col.data[115] = data.Patient["complement"]
csv_col.data[109] = datetime.strptime(data.Patient["birthdate"], "%Y-%m-%d").strftime("%d.%m.%Y") if data.Patient["birthdate"] is not None else ""
if data.Patient["insurance_policy_number"] is not None and '-' not in data.Patient["insurance_policy_number"]:
csv_col.data[109] += ", " + data.Patient["insurance_policy_number"]
csv_col.data[110] = data.Patient["insurance_name"]
date_PEC = datetime.strptime(data.Intervention["start_time"], "%Y-%m-%dT%H:%M:%S%z").strftime(
"%d.%m.%Y")
csv_col.data[51] = date_PEC # Date de ligne articles
csv_col.data[111] =date_PEC # Date PEC
csv_col.data[111] += " - " + datetime.strptime(data.Intervention["start_time"], "%Y-%m-%dT%H:%M:%S%z").strftime(
"%H:%M") # Heure START PEC
if b_HRF:
csv_col.data[111] += "-" + sHRF
else:
csv_col.data[111] += "-" + datetime.strptime(data.Intervention["end_time"], "%Y-%m-%dT%H:%M:%S%z").strftime(
"%H:%M") # Heure END PEC
csv_col.data[112] = self.ifNotNull(data.Patient["street"]) + " " + self.ifNotNull(data.Patient["street_number"])
csv_col.data[113] = self.ifNotNull(data.Patient["postal_code"]) + " " + self.ifNotNull(data.Patient["city"])
if data.Patient["country_name"] != "Suisse":
csv_col.data[113] += ", " + data.Patient["country_name"]
csv_col.data[107] = data.Patient["fip_number"]
csv_col.data[107] += " - " + data.data["comments"] if data.data["comments"] is not None else ""
csv_col.data[116] = self.ifNotNull(data.Patient["category"]) + " - " + self.ifNotNull(data.Intervention["type"])
csv_col.data[118] = data.Intervention["kilometers"]
csv_col.data[135] = data.Intervention["base_name"]
csv_col.data[136] = 3 if data.Debtor["code"] != "101" else "EBILL" #code présentation de facture
csv_col.data[146] = 3 #Code méthode de payement définit à 3
csv_col.data[168] = 1 if data.Intervention["team_name"] == "Planification" else 2
csv_col.data[169] = data.Patient['insurance_policy_number']
lines.append(csv_col.data)
csv_col = None
if not self.export_one_file.get():
with open(os.path.join(dest_dir, f"bizexdoc_" + filename.replace(".json", "") + ".csv"), "w+", errors='replace', newline='') as csv_file:
wr = csv.writer(csv_file, delimiter=';')
for cdr in lines:
wr.writerow(cdr)
else:
self.save_file(lines,fileName=self.export_filename)
return True
def addToIndexs(self,obj,data,cat, key):
#self.a_index[cat].append({"key":key,"index":len(obj.data)})
if key not in self.a_index[cat]:
self.a_index[cat].append(key)
self.a_index["global"].append(key)
obj.data.append(data)
def convertFile(self, data, filename): #à utiliser pour un export avec fichier excel de Thomas
self.count_facture += len(data["invoices"])
self.a_listings["to_check"] = []
lines = []
for ele in data["invoices"]:
data = cls_Invoice()
data.parse_item(ele)
b_update_debitor = True
print(f"Code débiteur => {data.data['id']}: {data.Debtor['code']}" )
if data.Debtor["code"] == "None" or '.' in data.Debtor["code"]:
print("ERROR code débiteur")
messagebox.showerror(title="Erreur code débiteur", message=f"Le code débiteur de la facture {data.data['id']} est faux: [{data.Debtor['code']}], merci de le corriger ")
inp_popup = Input_popup(self.fenetre,default=data.Debtor["code"],factureID=data.data['id'], fip=data.Patient['fip_number'])
data.Debtor["code"] = str(inp_popup.show())
if data.Debtor["code"] != "1" and data.Debtor["code"] != None and int(data.Debtor["code"]) < 100:
if data.Patient["fip_number"] not in self.a_listings["to_check"] :
self.a_listings["to_check"].append(data.Patient["fip_number"])
self.logger.warning(f"Vérifier facture N°: {data.data['id']} / {data.Patient['fip_number']} {data.Debtor['code']} {data.Debtor['lastname']} {data.Debtor['firstname']}")
for elem in data.Debtor:
pass
''' TODO activer ce code quand les débiteur auront un bon numéro
try:
if int(data.Debtor["code"]) > 100:
print("code débiteur > 100 => no update data")
b_update_debitor = False
except:
messagebox.showerror(title="Erreur de code débiteur", message=f"il y a une erreur dans le code débiteur, il faut le vérifier. \n(n'est pas un chiffre) {data.Patient['fip_number']}")
exit()
'''
'''
if data.Debtor["type"] == "Établissement":
self.a_listings["to_check"].append(data.Patient["fip_number"])
print(data.Patient["complement"])
self.logger.warn(f"Débiteur établissement facture N°: {data.data['id']} / {data.Patient['fip_number']} {data.Debtor['name']}")
'''
if data.Debtor["code"] == 1 and data.Patient["lastname"] + data.Patient["firstname"] != data.Debtor["lastname"] + data.Debtor["firstname"]:
self.a_listings["to_check"].append(data.Patient["fip_number"])
print(data.Patient["complement"])
self.logger.warning(f"Débiteur différents: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
if data.Patient["complement"] != None :
self.a_listings["to_check"].append(data.Patient["fip_number"])
print(data.Patient["complement"])
self.logger.warning(f"Complément 22 patient: facture N°: {data.data['id']} / {data.Patient['fip_number']}")
if data.Patient['insurance_policy_number'] == None:
data.Patient['insurance_policy_number'] = f"{uuid.uuid4()}"[:15]
b_HRF = False
sHRF = ""
for article in data.Articles:
if "code" in article.keys():
if article["code"] == "HRF":
b_HRF = True
sHRF = article["line_1"].replace("h",":")
print(f"pass HRF => {data.Patient['fip_number']}")
break
for article in data.Articles:
csv_col = cls_Col(False)
pass_article = False
##Donnée globales
self.addToIndexs(obj=csv_col,data=data.data["id"],cat="invoice",key="ID")
self.addToIndexs(obj=csv_col,data=data.data["date"],cat="invoice",key="date") # Date du document
self.addToIndexs(obj=csv_col, data=data.data["total_price"], cat="invoice", key="total_price")
self.addToIndexs(obj=csv_col, data=data.data["comments"], cat="invoice", key="comments")
whitout_transport = False
for elem in data.Intervention:
if elem == "without_transportation":
whitout_transport = True
print(f"without_transportation {data.Patient['fip_number']}")
break
self.addToIndexs(obj=csv_col, data=data.Intervention[elem], cat="intervention", key=elem)
if whitout_transport:
for x in range(8):
pass
#csv_col.data.append("")
self.addToIndexs(obj=csv_col, data="", cat="intervention", key=x)
self.addToIndexs(obj=csv_col, data=whitout_transport, cat="intervention", key="whitout_transport")
if b_HRF:
print(f"pass Change end_time on b_HRF")
dt = datetime.fromisoformat(csv_col.data[self.a_index["global"].index("end_time")])
month = "0" + str(dt.month) if dt.month < 10 else dt.month
csv_col.data[self.a_index["global"].index("end_time")] = f"{dt.year}-{month}-{dt.day}T"+sHRF+":00+01:00"
print( csv_col.data[self.a_index["global"].index("end_time")])
for elem in data.Patient:
if elem == "lastname":
if data.Patient[elem] == None:
data.Patient[elem] = "Patient inconnu"
if elem == "street_number":
print(f"ADRESS: data.Patient[elem]")
if data.Patient[elem] != None and "-" in data.Patient[elem] and "\t" not in data.Patient[elem]:
data.Patient[elem] = f"\t{data.Patient[elem]}"
print(f"ERROR DEBUG ADRESS: { data.Patient[elem]}")
self.addToIndexs(obj=csv_col, data=data.Patient[elem], cat="patient", key=elem)
for elem in data.Debtor:
if "name" in data.Debtor.keys():
pass
if elem == "street_number":
if data.Patient[elem] != None and "-" in data.Patient[elem] and "\t" not in data.Patient[elem]:
data.Patient[elem] = f"\t{data.Patient[elem]}"
if elem != "name":
csv_col.data.append(data.Debtor[elem])
if "name" in data.Debtor.keys():
csv_col.data.append(data.Debtor["name"])
else:
csv_col.data.append("")
# csv_col.data[126] = ' '.join(filter(None,temp_data)) # Débiteur nom
## Données prestations
if "code" in article.keys():
if article["code"] == "HRF":
csv_col = None
break
else:
csv_col.data.append(article["code"])
else:
csv_col.data.append("")
csv_col.data.append(article["line_1"])
csv_col.data.append(article["line_2"])
if "quantity" in article.keys():
csv_col.data.append(article["quantity"])
else:
csv_col.data.append("")
if "unit_price" in article.keys():
csv_col.data.append(article["unit_price"])
else:
csv_col.data.append("")
if "unit" in article.keys():
csv_col.data.append(article["unit"])
else:
csv_col.data.append("")
if "price" in article.keys():
csv_col.data.append(article["price"])
else:
csv_col.data.append("")
lines.append(csv_col.data)
csv_col = None
if not self.export_one_file.get():
with open(os.path.join(dest_dir, f"bizexdoc_" + filename.replace(".json", "") + ".csv"), "w+", errors='replace', newline='') as csv_file:
wr = csv.writer(csv_file, delimiter=';')
for cdr in lines:
wr.writerow(cdr)
else:
self.save_file(lines)
def save_file(self,lines, fileName = "src.csv"):
with open(os.path.join(dest_dir, fileName), "a+", errors='replace',newline='') as csv_file:
wr = csv.writer(csv_file, delimiter=';')
for cdr in lines:
wr.writerow(cdr)
def reset_export_file(self):
if os.path.exists(os.path.join(dest_dir, f"src.csv")):
os.remove(os.path.join(dest_dir, f"src.csv"))
def open_export_file(self):
print("RUN EXCEL with open")
os.startfile(os.path.join(dest_dir, f"src.csv"))
shutil.copy(file_path + "convert.xlsm", os.path.join(dest_dir, f"convert.xlsm"))
time.sleep(1)
os.startfile(os.path.join(dest_dir, f"convert.xlsm"))
def open_src(self):
os.startfile(file_path + src_dir)
def open_dest(self):
os.startfile(file_path + dest_dir)
def clear_src(self):
file_in_src = os.listdir(src_dir)
for file in file_in_src:
os.remove(src_dir + "\\" + file)
print(f"Supression du fichier: {file}")
self.count_src()
def clear_dest(self):
file_in = os.listdir(dest_dir)
for file in file_in:
os.remove(dest_dir + "\\" + file)
print(f"Supression du fichier: {file}")
def count_src(self):
file_in_src = os.listdir(src_dir)
count = len(file_in_src)
if count > 0:
self.bt_clear_src["state"] = "normal"
self.bt_parse["state"] = "normal"
else:
self.bt_clear_src["state"] = "disabled"
self.bt_parse["state"] = "disabled"
if not self.running:
self.nb_files_var.set(count)
app = ClercAttrib2Biz()