Create package

Signed-off-by: Ettore Dreucci <ettore.dreucci@gmail.com>
This commit is contained in:
2021-01-07 00:42:31 +01:00
parent b41ffa1883
commit 307d979832
7 changed files with 38 additions and 0 deletions

0
fatture_ccsr/__init__.py Normal file
View File

View File

@@ -0,0 +1,99 @@
"""ask for an input file (.xlsx) and an output file (.pdf) and downloads and unite every invoice"""
import sys
import os
import subprocess
import shutil
import tempfile
import openpyxl
import PyPDF2
import wx
def get_invoices_info(input_file_path: str) -> tuple:
"""extract invoices IDs and URLs from xlsx input file"""
xlsx_file = openpyxl.load_workbook(input_file_path)
sheet = xlsx_file.active
invoices = dict()
owner_name = '_'.join(sheet["B1"].value.split()[2:])
for i in range(1, sheet.max_row+1):
invoice_id = sheet["I"+str(i)].value
if invoice_id is not None and "CCSR" in invoice_id:
invoice_id = invoice_id.replace("/", "-")
invoice_url = sheet["BG"+str(i)].hyperlink.target
invoice = {
"id": invoice_id,
"url": invoice_url,
"path": None,
"good": None,
}
invoices[invoice_id] = invoice
invoices_info = (owner_name, invoices)
return invoices_info
def open_file(file_path):
"""open a file with the default software"""
if sys.platform == "win32":
os.startfile(file_path) # pylint: disable=maybe-no-member
else:
opener = "open" if sys.platform == "darwin" else "xdg-open"
subprocess.call([opener, file_path])
def download_invoices(parent):
"""download invoices from CCSR"""
output_file_path = None
invoices_info = get_invoices_info(parent.input_file_path)
invoices = invoices_info[1]
parent.log_dialog.log_text.AppendText("Inizio download fatture dal portale CCSR\n")
wx.Yield()
tmp_dir = tempfile.mkdtemp()
invoices_count = len(invoices)
downloaded_count = 0
for invoice_id, invoice in invoices.items():
resp = parent.session.get(invoice["url"])
if resp.status_code == 200:
with open(tmp_dir+"/"+invoice_id+".pdf", "wb") as output_file:
output_file.write(resp.content)
invoice["path"] = output_file.name
try:
PyPDF2.PdfFileReader(open(invoice["path"], "rb"))
except (PyPDF2.utils.PdfReadError, OSError):
parent.log_dialog.log_text.AppendText("Errore: fattura %s corrotta!\n" % invoice_id)
wx.Yield()
invoice["good"] = False
else:
downloaded_count += 1
parent.log_dialog.log_text.AppendText("%d/%d scaricata fattura %s in %s\n" % (downloaded_count, invoices_count, invoice_id, invoice["path"]))
wx.Yield()
invoice["good"] = True
else:
parent.log_dialog.log_text.AppendText("Errore: impossibile scaricare fattura %s: %d\n" % (invoice_id, resp.status_code))
wx.Yield()
invoice["good"] = False
parent.output_pdf_dialog.SetFilename("fatture_%s.pdf" % invoices_info[0])
if parent.output_pdf_dialog.ShowModal() == wx.ID_OK:
output_file_path = parent.output_pdf_dialog.GetPath()
else:
#TODO: avviso errore file output
return
merger = PyPDF2.PdfFileMerger()
for invoice in invoices.values():
if invoice["good"]:
merger.append(PyPDF2.PdfFileReader(open(invoice["path"], "rb")))
merger.write(output_file_path)
open_file(output_file_path)
shutil.rmtree(tmp_dir, ignore_errors=True)
parent.log_dialog.log_text.AppendText("Download terminato.\nIl pdf contenente le fatture si trova in %s\n" % output_file_path)
wx.Yield()

41
fatture_ccsr/exc.py Normal file
View File

@@ -0,0 +1,41 @@
"""Define Python user-defined exceptions"""
class FattureSanRossoreError(Exception):
"""Base class for other exceptions"""
class FileError(FattureSanRossoreError):
"""Basic exception for errors raised by files"""
def __init__(self, file_path, msg=None):
if msg is None:
msg = "An error occurred with file %s" % file_path
super(FileError, self).__init__(msg)
self.file_path = file_path
class NoFileExtensionError(FileError):
"""Raised when a file has no exception"""
def __init__(self, file_path):
super(NoFileExtensionError, self).__init__(file_path, msg="File %s has no extension!" % file_path)
class WrongFileExtensionError(FileError):
"""Raised when a file extension is not accepted"""
def __init__(self, file_path, file_ext, allowed_ext):
super(WrongFileExtensionError, self).__init__(file_path, msg="Cannot accept file %s extension %s. Allowed extensions are %s" % (file_path, file_ext, allowed_ext))
self.file_ext = file_ext
class NoFileError(FileError):
"""Raised when file_path is None or an empty string"""
def __init__(self):
super(NoFileError, self).__init__(None, msg="Not setted or empty file path!")
class ActionError(FattureSanRossoreError):
"""Basic exception for errors raised by actions"""
def __init__(self, action, msg=None):
if msg is None:
msg = "An error occurred with %s action" % action
super(ActionError, self).__init__(msg)
self.action = action
class InvalidActionError(ActionError):
"""Raised when an invalid action is used"""
def __init__(self, action):
super(InvalidActionError, self).__init__(action, "Invalid action %s" % action)

View File

@@ -0,0 +1,271 @@
"""This utility is used for downloading or converting to TRAF2000 invoices from a CCSR .xlsx, .csv or .xml report file"""
import os
import tempfile
import atexit
import wx
import wx.adv
import requests
import requests_ntlm
import downloader
import traf2000_converter
import exc
LOGIN_ACTION = 0
LOGOUT_ACTION = 1
DOWNLOAD_ACTION = 10
CONVERT_ACTION = 20
def file_extension(file_path: str, allowed_ext: set = None) -> str:
"""Return the file extension if that's in the allowed extension set"""
if file_path in (None, ""):
raise exc.NoFileError()
file_ext = os.path.splitext(file_path)[1]
if file_ext in (None, ""):
raise exc.NoFileExtensionError
if allowed_ext is not None and file_ext not in allowed_ext:
raise exc.WrongFileExtensionError
return file_ext
class LogDialog(wx.Dialog):
"""logging panel"""
def __init__(self, parent, title, action):
super(LogDialog, self).__init__(parent, wx.ID_ANY, title, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.log_text = wx.TextCtrl(self, wx.ID_ANY, size=(500, 200), style=wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL|wx.EXPAND)
log_sizer = wx.BoxSizer(wx.HORIZONTAL)
log_sizer.Add(self.log_text, 1, wx.ALL|wx.EXPAND, 2)
self.log_text.Bind(wx.EVT_TEXT, self.on_text_update)
if action == CONVERT_ACTION:
self.nc_text = wx.TextCtrl(self, wx.ID_ANY, size=(300, 200), style=wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
self.nc_text.Bind(wx.EVT_TEXT, self.on_text_update)
log_sizer.Add(self.nc_text, 1, wx.ALL|wx.EXPAND, 2)
main_sizer.Add(log_sizer, 1, wx.ALL|wx.EXPAND, 2)
self.btn = wx.Button(self, wx.ID_OK, "Chiudi")
self.btn.Disable()
main_sizer.Add(self.btn, 0, wx.ALL|wx.CENTER, 2)
self.SetSizerAndFit(main_sizer)
def on_text_update(self, event):
"""autoscroll on text update"""
self.ScrollPages(-1)
event.Skip()
class LoginDialog(wx.Dialog):
"""login dialog for basic auth download"""
def __init__(self, parent, title):
"""constructor"""
super(LoginDialog, self).__init__(parent, wx.ID_ANY, title, style=wx.DEFAULT_DIALOG_STYLE)
self.logged_in = False
user_sizer = wx.BoxSizer(wx.HORIZONTAL)
user_lbl = wx.StaticText(self, wx.ID_ANY, "Username:")
user_sizer.Add(user_lbl, 0, wx.ALL|wx.CENTER|wx.EXPAND, 2)
self.username = wx.TextCtrl(self, size=(265, -1))
user_sizer.Add(self.username, 0, wx.ALL|wx.EXPAND, 2)
pass_sizer = wx.BoxSizer(wx.HORIZONTAL)
pass_lbl = wx.StaticText(self, wx.ID_ANY, "Password:")
pass_sizer.Add(pass_lbl, 0, wx.ALL|wx.CENTER|wx.EXPAND, 2)
self.password = wx.TextCtrl(self, size=(265, -1), style=wx.TE_PASSWORD|wx.TE_PROCESS_ENTER)
pass_sizer.Add(self.password, 0, wx.ALL|wx.EXPAND, 2)
login_btn = wx.Button(self, label="Login")
login_btn.SetDefault()
login_btn.Bind(wx.EVT_BUTTON, self.on_login)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(user_sizer, 1, wx.ALL|wx.EXPAND, 2)
main_sizer.Add(pass_sizer, 1, wx.ALL|wx.EXPAND, 2)
main_sizer.Add(login_btn, 0, wx.ALL|wx.CENTER, 2)
self.SetSizerAndFit(main_sizer)
def disconnect(self):
"""close session and reset input fields"""
self.GetParent().session.close()
self.logged_in = False
def on_login(self, _):
"""check credentials and login"""
if self.username.GetValue() not in ("", None) and self.password.GetValue() not in ("", None):
session = self.GetParent().session
session.auth = requests_ntlm.HttpNtlmAuth("sr\\"+self.username.GetValue(), self.password.GetValue())
if session.get('https://report.casadicurasanrossore.it:8443/Reports/browse/').status_code == 200:
self.logged_in = True
self.username.SetValue('')
self.password.SetValue('')
self.Close()
class FattureCCSRFrame(wx.Frame):
"""main application frame"""
def __init__(self, parent, title):
atexit.register(self.exit_handler)
self._initial_locale = wx.Locale(wx.LANGUAGE_DEFAULT, wx.LOCALE_LOAD_DEFAULT)
self.input_file_path = None
self.input_file_ext = None
self.input_files = list()
self.log_dialog = None
self.session = requests.Session()
super(FattureCCSRFrame, self).__init__(parent, wx.ID_ANY, title, size=(520, 180))
panel = wx.Panel(self)
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
date_sizer = wx.BoxSizer(wx.HORIZONTAL)
btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.login_dlg = LoginDialog(self, "Inserisci le credenziali di login al portale della CCSR")
self.output_traf2000_dialog = wx.FileDialog(panel, "Scegli dove salvare il file TRAF2000", defaultFile="TRAF2000", style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
self.output_pdf_dialog = wx.FileDialog(panel, "Scegli dove salvare il .pdf con le fatture scaricate", defaultFile="fatture.pdf", style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
title_text = wx.StaticText(panel, wx.ID_ANY, "Utility Fatture Casa di Cura San Rossore")
title_text.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
desc_text = wx.StaticText(panel, wx.ID_ANY, "Effettua il login poi seleziona le date di inizio e fine periodo delle fatture da gestire ed esegui un'azione")
start_date_lbl = wx.StaticText(self, wx.ID_ANY, "Dal:")
end_date_lbl = wx.StaticText(self, wx.ID_ANY, "Al:")
self.start_date_picker = wx.adv.DatePickerCtrl(panel, dt=wx.DateTime.Today().SetDay(1))
self.end_date_picker = wx.adv.DatePickerCtrl(panel, dt=wx.DateTime.Today())
date_sizer.Add(start_date_lbl, 0, wx.ALL|wx.CENTER, 2)
date_sizer.Add(self.start_date_picker, 1, wx.ALL|wx.CENTER, 2)
date_sizer.Add(end_date_lbl, 0, wx.ALL|wx.CENTER, 2)
date_sizer.Add(self.end_date_picker, 1, wx.ALL|wx.CENTER, 2)
self.start_date_picker.Disable()
self.end_date_picker.Disable()
self.login_btn = wx.Button(panel, LOGIN_ACTION, "Login")
self.login_btn.SetDefault()
self.login_btn.Bind(wx.EVT_BUTTON, self.btn_onclick)
self.logout_btn = wx.Button(panel, LOGOUT_ACTION, "Logout")
self.logout_btn.Hide()
self.logout_btn.Bind(wx.EVT_BUTTON, self.btn_onclick)
self.download_btn = wx.Button(panel, DOWNLOAD_ACTION, "Scarica Fatture")
btn_sizer.Add(self.download_btn, 0, wx.ALL|wx.CENTER, 2)
self.download_btn.Bind(wx.EVT_BUTTON, self.btn_onclick)
self.download_btn.Disable()
self.traf2000_btn = wx.Button(panel, CONVERT_ACTION, "Genera TRAF2000")
btn_sizer.Add(self.traf2000_btn, 0, wx.ALL|wx.CENTER, 2)
self.traf2000_btn.Bind(wx.EVT_BUTTON, self.btn_onclick)
self.traf2000_btn.Disable()
self.main_sizer.Add(title_text, 0, wx.ALL|wx.CENTER, 2)
self.main_sizer.Add(desc_text, 0, wx.ALL|wx.CENTER, 2)
self.main_sizer.Add(self.login_btn, 0, wx.ALL|wx.CENTER, 4)
self.main_sizer.Add(self.logout_btn, 0, wx.ALL|wx.CENTER, 4)
self.main_sizer.Add(date_sizer, 0, wx.ALL|wx.EXPAND, 2)
self.main_sizer.Add(btn_sizer, 0, wx.ALL|wx.CENTER, 2)
panel.SetSizerAndFit(self.main_sizer)
self.Show()
def enable_on_login(self):
"""enable and show what needed after login"""
self.download_btn.Enable()
self.traf2000_btn.Enable()
self.start_date_picker.Enable()
self.end_date_picker.Enable()
self.login_btn.Hide()
self.logout_btn.Show()
self.main_sizer.Layout()
def disable_on_logout(self):
"""disable and hide what needed after logout"""
self.download_btn.Disable()
self.traf2000_btn.Disable()
self.start_date_picker.Disable()
self.end_date_picker.Disable()
self.login_dlg.disconnect()
self.logout_btn.Hide()
self.login_btn.Show()
self.main_sizer.Layout()
def btn_onclick(self, event):
"""event raised when a button is clicked"""
btn_id = event.GetEventObject().GetId()
if btn_id not in (LOGIN_ACTION, LOGOUT_ACTION, DOWNLOAD_ACTION, CONVERT_ACTION):
#TODO: error
return
elif btn_id == LOGIN_ACTION:
self.login_dlg.ShowModal()
if self.login_dlg.logged_in:
self.enable_on_login()
return
elif btn_id == LOGOUT_ACTION:
self.disable_on_logout()
return
elif not self.login_dlg.logged_in:
#TODO: error
return
start_date = self.start_date_picker.GetValue().Format("%d/%m/%Y")
end_date = self.end_date_picker.GetValue().Format("%d/%m/%Y")
input_file_url = 'https://report.casadicurasanrossore.it:8443/reportserver?/STAT_FATTURATO_CTERZI&dataI='+start_date+'&dataF='+end_date+'&rs:Format='
input_file_url += ('EXCELOPENXML' if btn_id == DOWNLOAD_ACTION else 'XML' if btn_id == CONVERT_ACTION else None)
downloaded_input_file = self.session.get(input_file_url)
if downloaded_input_file.status_code != 200:
#TODO: error
return
input_file_descriptor, self.input_file_path = tempfile.mkstemp(suffix=('.xlsx' if btn_id == DOWNLOAD_ACTION else '.xml' if btn_id == CONVERT_ACTION else None))
self.input_files.append(self.input_file_path)
with open(input_file_descriptor, 'wb') as input_file:
input_file.write(downloaded_input_file.content)
try:
self.input_file_ext = file_extension(self.input_file_path, (".xml", ".csv", ".xlsx"))
except exc.NoFileError as handled_exception:
print(handled_exception.args[0])
return
except exc.NoFileExtensionError as handled_exception:
print(handled_exception.args[0])
return
except exc.WrongFileExtensionError as handled_exception:
print(handled_exception.args[0])
return
if btn_id == DOWNLOAD_ACTION:
self.log_dialog = LogDialog(self, "Download delle fatture dal portale CCSR", DOWNLOAD_ACTION)
self.log_dialog.Show()
downloader.download_invoices(self)
self.log_dialog.btn.Enable()
elif btn_id == CONVERT_ACTION:
self.log_dialog = LogDialog(self, "Conversione delle fatture in TRAF2000", CONVERT_ACTION)
self.log_dialog.Show()
#TODO: error frame
try:
traf2000_converter.convert(self)
except exc.NoFileError as handled_exception:
print(handled_exception.args[0])
except exc.NoFileExtensionError as handled_exception:
print(handled_exception.args[0])
except exc.WrongFileExtensionError as handled_exception:
print(handled_exception.args[0])
self.log_dialog.btn.Enable()
def exit_handler(self):
"""clean the environment befor exiting"""
for input_file in self.input_files:
os.remove(input_file)
if __name__ == "__main__":
app = wx.App()
FattureCCSRFrame(None, "Utility FattureCCSR")
app.MainLoop()

View File

@@ -0,0 +1,299 @@
"""ask for an input file and an output file and generates the TRAF2000 records from a .csv or .xml"""
import datetime
import csv
import xml.etree.ElementTree
import unidecode
import wx
def import_csv(parent) -> dict:
"""Return a dict containing the invoices info"""
invoices = dict()
with open(parent.input_file_path, newline="") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=",")
for _ in range(4):
next(csv_reader)
for line in csv_reader:
if len(line) == 0:
break
invoice_num = line[1]
invoice_type = line[8]
amount = line[15]
sign = 1
if invoice_type == "Nota di credito" and '(' not in amount:
sign = -1
amount = int(line[15].replace("", "").replace(",", "").replace(".", "").replace("(", "").replace(")", "")) * sign
if invoice_num not in invoices:
invoice = {
"numFattura": invoice_num,
"tipoFattura": invoice_type,
"rifFattura": line[4],
"dataFattura": line[2].replace("/", ""),
"ragioneSociale": unidecode.unidecode(line[6] + " " + " ".join(line[5].split()[0:2])),
"posDivide": str(len(line[6]) + 1),
"cf": line[7],
"importoTotale": 0,
"ritenutaAcconto": 0,
"righe": dict()
}
invoices[invoice_num] = invoice
if line[14] == "Ritenuta d'acconto":
invoices[invoice_num]["ritenutaAcconto"] = amount
else:
invoices[invoice_num]["importoTotale"] += amount
invoices[invoice_num]["righe"][line[14]] = amount
parent.log_dialog.log_text.AppendText("Importata fattura n. %s\n" % invoice_num)
wx.Yield()
return invoices
def import_xml(parent) -> dict:
"""Return a dict containing the invoices info"""
invoices = dict()
tree = xml.etree.ElementTree.parse(parent.input_file_path)
root = tree.getroot()
for invoice in root.iter('{STAT_FATTURATO_CTERZI}Dettagli'):
lines = dict()
invoice_num = invoice.get('protocollo_fatturatestata')
invoice_type = invoice.get('fat_ndc')
total_amount = 0
ritenuta_acconto = 0
for line in invoice.iter('{STAT_FATTURATO_CTERZI}Dettagli2'):
desc = line.get('descrizione_fatturariga1')
sign = 1
if invoice_type == 'Nota di credito' and '-' not in line.get('prezzounitario_fatturariga1'):
sign = -1
amount = int(format(round(float(line.get('prezzounitario_fatturariga1')), 2), '.2f').replace('.', '').replace('-', '')) * sign
if desc == "Ritenuta d'acconto":
ritenuta_acconto = amount
else:
lines[desc] = amount
total_amount += amount
invoice_elem = {
"numFattura": invoice_num,
"tipoFattura": invoice_type,
"rifFattura": invoice.get('protocollo_fatturatestata1'),
"dataFattura": datetime.datetime.fromisoformat(invoice.get('data_fatturatestata')).strftime("%d%m%Y"),
"ragioneSociale": unidecode.unidecode(invoice.get('cognome_cliente') + ' ' + ' '.join(invoice.get('nome_cliente').split()[0:2])),
"posDivide": str(len(invoice.get('cognome_cliente')) + 1),
"cf": invoice.get('cf_piva_cliente'),
"importoTotale": total_amount,
"ritenutaAcconto": ritenuta_acconto,
"righe": lines,
}
invoices[invoice_num] = invoice_elem
parent.log_dialog.log_text.AppendText("Importata fattura n. %s\n" % invoice_num)
wx.Yield()
return invoices
def convert(parent):
"""Output to a file the TRAF2000 records"""
output_file_path = None
if parent.input_file_ext == ".csv":
invoices = import_csv(parent)
elif parent.input_file_ext == ".xml":
invoices = import_xml(parent)
if parent.output_traf2000_dialog.ShowModal() == wx.ID_OK:
output_file_path = parent.output_traf2000_dialog.GetPath()
else:
#TODO: avviso errore file output
return
with open(output_file_path, "w") as traf2000_file:
parent.log_dialog.nc_text.AppendText("Note di credito:\n")
wx.Yield()
for invoice in invoices.values():
if invoice["tipoFattura"] != "Fattura" and invoice["tipoFattura"] != "Nota di credito":
parent.log_dialog.log_text.AppendText("Errore: il documento %s può essere FATTURA o NOTA DI CREDITO\n" % invoice["numFattura"])
wx.Yield()
continue
if len(invoice["cf"]) != 16 and len(invoice["cf"]) == 11:
parent.log_dialog.log_text.AppendText("Errore: il documento %s non ha cf/piva\n" % invoice["numFattura"])
wx.Yield()
continue
if invoice["tipoFattura"] == "Nota di credito":
# As for now this script doesn't handle "Note di credito"
parent.log_dialog.nc_text.AppendText(invoice["numFattura"]+"\n")
wx.Yield()
continue
line = ["04103", "3", "0", "00000"] # TRF-DITTA + TRF-VERSIONE + TRF-TARC + TRF-COD-CLIFOR
line.append(invoice["ragioneSociale"][:32]+' '*(32-len(invoice["ragioneSociale"]))) # TRF-RASO
line.append(' '*30) # TRF-IND
line.append('00000') # TRF-CAP
line.append(' '*27) # TRF-CITTA + TRF-PROV
if len(invoice["cf"]) == 16: # se c.f. presente
line.append(invoice["cf"]) # TRF-COFI
line.append('0'*11) # TRF-PIVA
line.append('S') # TRF-PF
else: # se piva presente
line.append(' '*16) # TRF-COFI
line.append(invoice["cf"]) # TRF-PIVA
line.append('N') # TRF-PF
line.append('0'*(2-len(invoice["posDivide"])) + invoice["posDivide"]) # TRF-DIVIDE
line.append('0000') # TRF-PAESE
line.append(' '*33) # TRF-PIVA-ESTERO + TRF-COFI-ESTERO + TRF-SESSO
line.append('0'*8) # TRF-DTNAS
line.append(' '*64) # TRF-COMNA + TRF-PRVNA + TRF-PREF + TRF-NTELE-NUM + TRF-FAX-PREF + TRF-FAX-NUM
line.append('0'*22) # TRF-CFCONTO + TRF-CFCODPAG + TRF-CFBANCA + TRF-CFAGENZIA + TRF-CFINTERM
if invoice["tipoFattura"] == "Fattura":
line.append('001') # TRF-CAUSALE
line.append("FATTURA VENDITA") # TRF-CAU-DES
else:
line.append('002') # TRF-CAUSALE
line.append("N.C. A CLIENTE ") # TRF-CAU-DES
line.append(' '*86) # TRF-CAU-AGG + TRF-CAU-AGG-1 + TRF-CAU-AGG-2
line.append(invoice["dataFattura"]*2) # TRF-DATA-REGISTRAZIONE + TRF-DATA-DOC
line.append('00000000') # TRF-NUM-DOC-FOR
line.append(invoice["numFattura"][4:9]) # TRF-NDOC
line.append('00') # TRF-SERIE
line.append('0'*72) # TRF-EC-PARTITA + TRF-EC-PARTITA-ANNO + TRF-EC-COD-VAL + TRF-EC-CAMBIO + TRF-EC-DATA-CAMBIO + TRF-EC-TOT-DOC-VAL + TRF-EC-TOT-IVA-VAL + TRF-PLAFOND
count = 0
for desc, imponibile in invoice["righe"].items():
count += 1
imponibile = str(imponibile)
if '-' in imponibile:
imponibile.replace('-', '')
imponibile = '0'*(11-len(imponibile)) + imponibile + "-"
else:
imponibile = '0'*(11-len(imponibile)) + imponibile + "+"
line.append(imponibile) # TRF-IMPONIB
if desc != "Bollo":
line.append('308') # TRF-ALIQ
else:
line.append('315') # TRF-ALIQ
line.append('0'*16) # TRF-ALIQ-AGRICOLA + TRF-IVA11 + TRF-IMPOSTA
for _ in range(8-count):
line.append('0'*31)
total = str(invoice["importoTotale"])
if '-' in total:
total.replace('-', '')
total = '0'*(11-len(total)) + total + "-"
else:
total = '0'*(11-len(total)) + total + "+"
line.append(total) # TRF-TOT-FAT
count = 0
for desc, imponibile in invoice["righe"].items():
count += 1
imponibile = str(imponibile)
if '-' in imponibile:
imponibile.replace('-', '')
imponibile = '0'*(11-len(imponibile)) + imponibile + "-"
else:
imponibile = '0'*(11-len(imponibile)) + imponibile + "+"
if desc != "Bollo":
line.append('4004300') # TRF-CONTO-RIC
else:
line.append('4004500') # TRF-CONTO-RIC
line.append(imponibile) # TRF-IMP-RIC
for _ in range(8-count):
line.append('0'*19)
line.append('000') # TRF-CAU-PAG
line.append(' '*83) # TRF-CAU-DES-PAGAM + TRF-CAU-AGG-1-PAGAM + TRF-CAU-AGG-2-PAGAM
line.append(('0000000' + ' ' + '0'*12 + ' '*18 + '0'*26)*80) # TRF-CONTO + TRF-DA + TRF-IMPORTO + TRF-CAU-AGGIUNT + TRF-EC-PARTITA-PAG + TRF-EC-PARTITA-ANNO-PAG + TRF-EC-IMP-VAL
line.append((' ' + '0'*18)*10) # TRF-RIFER-TAB + TRF-IND-RIGA + TRF-DT-INI + TRF-DT-FIN
line.append('000000') # TRF-DOC6
line.append('N' + '0') # TRF-AN-OMONIMI + TRF-AN-TIPO-SOGG
line.append('00'*80) # TRF-EC-PARTITA-SEZ-PAG
line.append('0'*15) # TRF-NUM-DOC-PAG-PROF + TRF-DATA-DOC-PAG-PROF
if invoice["ritenutaAcconto"] != 0:
imponibile = str(invoice["ritenutaAcconto"])
imponibile = '0'*(11-len(imponibile)) + imponibile + "+"
line.append(imponibile) # TRF-RIT-ACC
else:
line.append('0'*12) # TRF-RIT-ACC
line.append('0'*60) # TRF-RIT-PREV + TRF-RIT-1 + TRF-RIT-2 + TRF-RIT-3 + TRF-RIT-4
line.append('00'*8) # TRF-UNITA-RICAVI
line.append('00'*80) # TRF-UNITA-PAGAM
line.append(' '*24) # TRF-FAX-PREF-1 + TRF-FAX-NUM-1
line.append(' ' + ' ') # TRF-SOLO-CLIFOR + TRF-80-SEGUENTE
line.append('0000000') # TRF-CONTO-RIT-ACC
line.append('0'*35) # TRF-CONTO-RIT-PREV + TRF-CONTO-RIT-1 + TRF-CONTO-RIT-2 + TRF-CONTO-RIT-3 + TRF-CONTO-RIT-4
line.append('N' + 'N' + '00000000' + '000') # TRF-DIFFERIMENTO-IVA + TRF-STORICO + TRF-STORICO-DATA + TRF-CAUS-ORI
line.append(' ' + ' ' + '0'*16 + ' ') # TRF-PREV-TIPOMOV + TRF-PREV-RATRIS + TRF-PREV-DTCOMP-INI + TRF-PREV-DTCOMP-FIN + TRF-PREV-FLAG-CONT
line.append(' '*20 + '0'*21 + ' '*44 + '0'*8 + ' ' + '0'*6 + ' ' + '00' + ' ') # TRF-RIFERIMENTO + TRF-CAUS-PREST-ANA + TRF-EC-TIPO-PAGA + TRF-CONTO-IVA-VEN-ACQ + TRF-PIVA-VECCHIA + TRF-PIVA-ESTERO-VECCHIA + # TRF-RISERVATO + TRF-DATA-IVA-AGVIAGGI + TRF-DATI-AGG-ANA-REC4 + TRF-RIF-IVA-NOTE-CRED + TRF-RIF-IVA-ANNO-PREC + TRF-NATURA-GIURIDICA + TRF-STAMPA-ELENCO
line.append('000'*8 + ' '*20 + '0' + ' '*4 + '0'*6 + ' '*20 + 'S' + 'N') # TRF-PERC-FORF + TRF-SOLO-MOV-IVA + TRF-COFI-VECCHIO + TRF-USA-PIVA-VECCHIA + TRF-USA-PIVA-EST-VECCHIA + TRF-USA-COFI-VECCHIO + TRF-ESIGIBILITA-IVA + TRF-TIPO-MOV-RISCONTI + TRF-AGGIORNA-EC + TRF-BLACKLIST-ANAG + TRF-BLACKLIST-IVA-ANNO + TRF-CONTEA-ESTERO + TRF-ART21-ANAG + TRF-ART21-IVA
if invoice["tipoFattura"] == "Fattura":
line.append('N') # TRF-RIF-FATTURA
else:
line.append('S') # TRF-RIF-FATTURA
line.append('S' + ' '*2 + 'S' + ' '*2) # TRF-RISERVATO-B + TRF-MASTRO-CF + TRF-MOV-PRIVATO + TRF-SPESE-MEDICHE + TRF-FILLER
line.append('\n')
parent.log_dialog.log_text.AppendText("Creato record #0 per fattura n. %s\n" % invoice["numFattura"])
wx.Yield()
#RECORD 5 per Tessera Sanitaria
line.append('04103' + '3' + '5') # TRF5-DITTA + TRF5-VERSIONE + TRF5-TARC
line.append(' '*1200) # TRF-ART21-CONTRATTO
line.append('0'*6 + invoice["cf"]) # TRF-A21CO-ANAG + # TRF-A21CO-COFI
total = str(invoice["importoTotale"])
total = '0'*(13-len(total)) + total + "+"
line.append(invoice["dataFattura"] + 'S' + '000' + total + '0'*14 + '0' + invoice["numFattura"][4:9] + '00' + ' '*40) # TRF-A21CO-DATA + TRF-A21CO-FLAG + TRF-A21CO-ALQ + TRF-A21CO-IMPORTO + TRF-A21CO-IMPOSTA + TRF-A21CO-NDOC + TRF-A21CO-CONTRATTO
line.append(('0'*6 + ' '*16 + '0'*8 + ' ' + '000' + '0'*14 + '0'*14 + '0'*8 + ' '*40)*49) # TRF-A21CO-DATA + TRF-A21CO-FLAG + TRF-A21CO-ALQ + TRF-A21CO-IMPORTO + TRF-A21CO-IMPOSTA + TRF-A21CO-NDOC + TRF-A21CO-CONTRATTO
if invoice["tipoFattura"] == "Nota di credito":
line.append('000' + invoice["rifFattura"][4:9]) # TRF-RIF-FATT-NDOC
line.append('0'*8) # TRF-RIF-FATT-DDOC
else:
line.append('0'*16) # TRF-RIF-FATT-NDOC + TRF-RIF-FATT-DDOC
line.append('F' + 'SR' + '2') # TRF-A21CO-TIPO + TRF-A21CO-TIPO-SPESA + TRF-A21CO-FLAG-SPESA
line.append((' ' + ' ' + ' ')*49) # TRF-A21CO-TIPO + TRF-A21CO-TIPO-SPESA + TRF-A21CO-FLAG-SPESA
line.append(' ' + 'S' + ' '*76) # TRF-SPESE-FUNEBRI + TRF-A21CO-PAGAM + FILLER + FILLER
line.append('\n')
parent.log_dialog.log_text.AppendText("Creato record #5 per fattura n. %s\n" % invoice["numFattura"])
wx.Yield()
#RECORD 1 per num. doc. originale
line.append('04103' + '3' + '1') # TRF1-DITTA + TRF1-VERSIONE + TRF1-TARC
line.append('0'*7 + ' '*3 + '0'*14) # TRF-NUM-AUTOFATT + TRF-SERIE-AUTOFATT + TRF-COD-VAL + TRF-TOTVAL
line.append((' '*8 + '0'*24 + ' ' + '0'*36 + ' '*2 + '0'*9 + ' '*5)*20) # TRF-NOMENCLATURA + TRF-IMP-LIRE + TRF-IMP-VAL + TRF-NATURA + TRF-MASSA + TRF-UN-SUPPL + TRF-VAL-STAT + TRF-REGIME + TRF-TRASPORTO + TRF-PAESE-PROV + TRF-PAESE-ORIG + TRF-PAESE-DEST + TRF-PROV-DEST + TRF-PROV-ORIG + TRF-SEGNO-RET
line.append(' ' + '0'*6 + ' '*173) # TRF-INTRA-TIPO + TRF-MESE-ANNO-RIF + SPAZIO
line.append('0'*45 + ' '*4 + '0'*20 + ' '*28 + '0'*25) # TRF-RITA-TIPO + TRF-RITA-IMPON + TRF-RITA-ALIQ + TRF-RITA-IMPRA + TRF-RITA-PRONS + TRF-RITA-MESE + TRF-RITA-CAUSA + TRF-RITA-TRIBU + TRF-RITA-DTVERS + TRF-RITA-IMPAG + TRF-RITA-TPAG + TRF-RITA-SERIE + TRF-RITA-QUIETANZA + TRF-RITA-NUM-BOLL + TRF-RITA-ABI + TRF-RITA-CAB + TRF-RITA-AACOMP + TRF-RITA-CRED
line.append(' ' + '0'*44 + ' '*11 + '0'*64) #TRF-RITA-SOGG + TRF-RITA-BASEIMP + TRF-RITA-FRANCHIGIA + TRF-RITA-CTO-PERC + TRF-RITA-CTO-DITT + FILLER + TRF-RITA-DATA + TRF-RITA-TOTDOC + TRF-RITA-IMPVERS + TRF-RITA-DATA-I + TRF-RITA-DATA-F + TRF-EMENS-ATT + TRF-EMENS-RAP + TRF-EMENS-ASS + TRF-RITA-TOTIVA
line.append('0'*6 + ' '*178) # TRF-CAUS-PREST-ANA-B + TRF-RITA-CAUSA-B + FILLER
line.append('0'*13 + ' '*30 + '0'*14) # TRF-POR-CODPAG + TRF-POR-BANCA + TRF-POR-AGENZIA + TRF-POR-DESAGENZIA + TRF-POR-TOT-RATE + TRF-POR-TOTDOC
line.append(('0'*65 + ' '*2)*12) # TRF-POR-NUM-RATA + TRF-POR-DATASCAD + TRF-POR-TIPOEFF + TRF-POR-IMPORTO-EFF + TRF-POR-IMPORTO-EFFVAL + TRF-POR-IMPORTO-BOLLI + TRF-POR-IMPORTO-BOLLIVAL + TRF-POR-FLAG + TRF-POR-TIPO-RD
line.append('0'*4 + ' '*336) # TRF-POR-CODAGE + TRF-POR-EFFETTO-SOSP + TRF-POR-CIG + TRF-POR-CUP + SPAZIO
line.append((' '*3 + '0'*16)*20) # TRF-COD-VAL-IV + TRF-IMP-VALUTA-IV
line.append((' '*6 + '0'*35 + ' '*2 + '0'*20 + ' '*19 + '0'*16)*20) # TRF-CODICE-SERVIZIO + TRF-STATO-PAGAMENTO + TRF-SERV-IMP-EURO + TRF-SERV-IMP-VAL + TRF-DATA-DOC-ORIG + TRF-MOD-EROGAZIONE + TRF-MOD-INCASSO + TRF-PROT-REG + TRF-PROG-REG + TRF-COD-SEZ-DOG-RET + TRF-ANNO-REG-RET + TRF-NUM-DOC-ORIG + TRF-SERV-SEGNO-RET + TRF-SERV-COD-VAL-IV + TRF-SERV-IMP-VALUTA-IV
line.append(' '*1 + '0'*6) # TRF-INTRA-TIPO-SERVIZIO + TRF-SERV-MESE-ANNO-RIF
line.append(' '*8) # TRF-CK-RCHARGE
line.append('0'*(15-len(invoice["numFattura"])) + invoice["numFattura"]) # TRF-XNUM-DOC-ORI
line.append(' ' + '00' + ' '*1090) # TRF-MEM-ESIGIB-IVA + TRF-COD-IDENTIFICATIVO + TRF-ID-IMPORTAZIONE + TRF-XNUM-DOC-ORI-20 + SPAZIO + FILLER
parent.log_dialog.log_text.AppendText("Creato record #1 per fattura n. %s\n" % invoice["numFattura"])
wx.Yield()
line = ''.join(line) + '\n'
traf2000_file.write(line)
parent.log_dialog.log_text.AppendText("Convertita fattura n. %s\n" % invoice["numFattura"])
wx.Yield()
parent.log_dialog.log_text.AppendText("Conversione terminata.\nTracciato TRAF2000 salvato in %s\n" % output_file_path)
wx.Yield()