mirror of
https://github.com/Noettore/fattureCCSR.git
synced 2025-10-15 03:36:39 +02:00
Added ragione sociale check. Added verbose mode. Now saving all, ft and nc in different files
Signed-off-by: Ettore Dreucci <ettore.dreucci@gmail.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
"""ask for an input file (.xlsx) and an output file (.pdf) and downloads and unite every invoice"""
|
"""ask for an input file (.xlsx) and an output file (.pdf) and downloads and unite every invoice"""
|
||||||
|
|
||||||
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import openpyxl
|
import openpyxl
|
||||||
@@ -33,12 +34,15 @@ def get_invoices_info(input_file_path: str) -> tuple:
|
|||||||
owner_name = '_'.join(sheet["B1"].value.split()[2:])
|
owner_name = '_'.join(sheet["B1"].value.split()[2:])
|
||||||
|
|
||||||
for i in range(1, sheet.max_row+1):
|
for i in range(1, sheet.max_row+1):
|
||||||
invoice_id = sheet["I"+str(i)].value
|
row = str(i)
|
||||||
|
invoice_id = sheet["I"+row].value
|
||||||
if invoice_id is not None and "CCSR" in invoice_id:
|
if invoice_id is not None and "CCSR" in invoice_id:
|
||||||
invoice_id = invoice_id.replace("/", "-")
|
invoice_id = invoice_id.replace("/", "-")
|
||||||
invoice_url = sheet["BG"+str(i)].hyperlink.target
|
invoice_type = sheet["AP"+row].value
|
||||||
|
invoice_url = sheet["BG"+row].hyperlink.target
|
||||||
invoice = {
|
invoice = {
|
||||||
"id": invoice_id,
|
"id": invoice_id,
|
||||||
|
"type": invoice_type,
|
||||||
"url": invoice_url,
|
"url": invoice_url,
|
||||||
"path": None,
|
"path": None,
|
||||||
"good": None,
|
"good": None,
|
||||||
@@ -49,7 +53,9 @@ def get_invoices_info(input_file_path: str) -> tuple:
|
|||||||
|
|
||||||
def download_invoices(parent):
|
def download_invoices(parent):
|
||||||
"""download invoices from CCSR"""
|
"""download invoices from CCSR"""
|
||||||
output_file_path = None
|
output_all_file_path = None
|
||||||
|
output_ft_file_path = None
|
||||||
|
output_nc_file_path = None
|
||||||
|
|
||||||
parent.log_dialog.log_text.AppendText("Download file input\n")
|
parent.log_dialog.log_text.AppendText("Download file input\n")
|
||||||
wx.Yield()
|
wx.Yield()
|
||||||
@@ -82,8 +88,9 @@ def download_invoices(parent):
|
|||||||
invoice["good"] = False
|
invoice["good"] = False
|
||||||
else:
|
else:
|
||||||
downloaded_count += 1
|
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"]))
|
if parent.verbose:
|
||||||
wx.Yield()
|
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
|
invoice["good"] = True
|
||||||
else:
|
else:
|
||||||
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.RED, font=wx.Font(wx.FontInfo(8).Bold())))
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.RED, font=wx.Font(wx.FontInfo(8).Bold())))
|
||||||
@@ -100,17 +107,34 @@ def download_invoices(parent):
|
|||||||
parent.output_pdf_dialog.SetFilename("fatture_%s.pdf" % invoices_info[0])
|
parent.output_pdf_dialog.SetFilename("fatture_%s.pdf" % invoices_info[0])
|
||||||
|
|
||||||
if parent.output_pdf_dialog.ShowModal() == wx.ID_OK:
|
if parent.output_pdf_dialog.ShowModal() == wx.ID_OK:
|
||||||
output_file_path = parent.output_pdf_dialog.GetPath()
|
output_all_file_path = parent.output_pdf_dialog.GetPath()
|
||||||
merger = PyPDF2.PdfFileMerger()
|
path, ext = os.path.splitext(output_all_file_path)
|
||||||
for invoice in invoices.values():
|
output_ft_file_path = path+"_ft"+ext
|
||||||
if invoice["good"]:
|
output_nc_file_path = path+"_nc"+ext
|
||||||
merger.append(PyPDF2.PdfFileReader(open(invoice["path"], "rb")))
|
|
||||||
merger.write(output_file_path)
|
|
||||||
|
|
||||||
|
merger_ft = PyPDF2.PdfFileMerger()
|
||||||
|
merger_nc = PyPDF2.PdfFileMerger()
|
||||||
|
merger_all = PyPDF2.PdfFileMerger()
|
||||||
|
for invoice_id, invoice in invoices.items():
|
||||||
|
if invoice["good"]:
|
||||||
|
merger_all.append(PyPDF2.PdfFileReader(open(invoice["path"], "rb")))
|
||||||
|
if invoice["type"] == "Fattura":
|
||||||
|
merger_ft.append(PyPDF2.PdfFileReader(open(invoice["path"], "rb")))
|
||||||
|
elif invoice["type"] == "Nota di credito":
|
||||||
|
merger_nc.append(PyPDF2.PdfFileReader(open(invoice["path"], "rb")))
|
||||||
|
else:
|
||||||
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.RED, font=wx.Font(wx.FontInfo(8).Bold())))
|
||||||
|
parent.log_dialog.log_text.AppendText("Errore: la fattura %s ha tipo sconosciuto %s\n" % (invoice_id, invoice["type"]))
|
||||||
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr())
|
||||||
|
merger_all.write(output_all_file_path)
|
||||||
|
merger_ft.write(output_ft_file_path)
|
||||||
|
merger_nc.write(output_nc_file_path)
|
||||||
shutil.rmtree(tmp_dir, ignore_errors=True)
|
shutil.rmtree(tmp_dir, ignore_errors=True)
|
||||||
|
|
||||||
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.BLACK, font=wx.Font(wx.FontInfo(8).Bold())))
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.BLACK, font=wx.Font(wx.FontInfo(8).Bold())))
|
||||||
parent.log_dialog.log_text.AppendText("Il pdf contenente le fatture si trova in %s\n" % output_file_path)
|
parent.log_dialog.log_text.AppendText("Il pdf contenente tutti i documenti si trova in %s\n" % output_all_file_path)
|
||||||
|
parent.log_dialog.log_text.AppendText("Il pdf contenente tutti le fatture si trova in %s\n" % output_ft_file_path)
|
||||||
|
parent.log_dialog.log_text.AppendText("Il pdf contenente tutti le note di credito si trova in %s\n" % output_nc_file_path)
|
||||||
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr())
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr())
|
||||||
wx.Yield()
|
wx.Yield()
|
||||||
parent.log_dialog.open_file_btn.Enable()
|
parent.log_dialog.open_file_btn.Enable()
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import getopt
|
||||||
import subprocess
|
import subprocess
|
||||||
import atexit
|
import atexit
|
||||||
import wx
|
import wx
|
||||||
@@ -20,6 +21,18 @@ CONVERT_ACTION = 20
|
|||||||
class FattureCCSRFrame(wx.Frame):
|
class FattureCCSRFrame(wx.Frame):
|
||||||
"""main application frame"""
|
"""main application frame"""
|
||||||
def __init__(self, *args, **kwds):
|
def __init__(self, *args, **kwds):
|
||||||
|
self.verbose = False
|
||||||
|
try:
|
||||||
|
opts, _ = getopt.getopt(sys.argv[1:], "v", ["verbose="])
|
||||||
|
for opt, _ in opts:
|
||||||
|
if opt == '-h':
|
||||||
|
print("fatture_ccsr -v|--verbose")
|
||||||
|
elif opt in ('-v', '--verbose'):
|
||||||
|
self.verbose = True
|
||||||
|
except getopt.GetoptError:
|
||||||
|
print("fatture_ccsr -v|--verbose")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
atexit.register(self.exit_handler)
|
atexit.register(self.exit_handler)
|
||||||
|
|
||||||
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE | wx.FULL_REPAINT_ON_RESIZE | wx.TAB_TRAVERSAL
|
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE | wx.FULL_REPAINT_ON_RESIZE | wx.TAB_TRAVERSAL
|
||||||
|
@@ -35,8 +35,8 @@ def validate_xml(xml_tree) -> bool:
|
|||||||
xsd_path = os.path.join(sys._MEIPASS, 'schema.xsd') # pylint: disable=no-member, protected-access
|
xsd_path = os.path.join(sys._MEIPASS, 'schema.xsd') # pylint: disable=no-member, protected-access
|
||||||
else:
|
else:
|
||||||
xsd_path = os.path.join(__location__, 'schema.xsd')
|
xsd_path = os.path.join(__location__, 'schema.xsd')
|
||||||
xmlschema_doc = lxml.etree.parse(xsd_path)
|
xmlschema_doc = lxml.etree.parse(xsd_path) # pylint: disable=c-extension-no-member
|
||||||
xmlschema = lxml.etree.XMLSchema(xmlschema_doc)
|
xmlschema = lxml.etree.XMLSchema(xmlschema_doc) # pylint: disable=c-extension-no-member
|
||||||
|
|
||||||
return xmlschema.validate(xml_tree)
|
return xmlschema.validate(xml_tree)
|
||||||
|
|
||||||
@@ -46,20 +46,20 @@ def import_xml(parent, input_file_path) -> dict:
|
|||||||
if not input_file_path:
|
if not input_file_path:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
xml_tree = lxml.etree.parse(input_file_path)
|
xml_tree = lxml.etree.parse(input_file_path) # pylint: disable=c-extension-no-member
|
||||||
if not validate_xml(xml_tree):
|
if not validate_xml(xml_tree):
|
||||||
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.RED, font=wx.Font(wx.FontInfo(8).Bold())))
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.RED, font=wx.Font(wx.FontInfo(8).Bold())))
|
||||||
parent.log_dialog.log_text.AppendText("ERRORE: xml non valido secondo lo schema xsd")
|
parent.log_dialog.log_text.AppendText("ERRORE: xml non valido secondo lo schema xsd\n")
|
||||||
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr())
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr())
|
||||||
wx.Yield()
|
wx.Yield()
|
||||||
return None
|
|
||||||
root = xml_tree.getroot()
|
root = xml_tree.getroot()
|
||||||
|
|
||||||
for invoice in root.iter('{STAT_FATTURATO_CTERZI}Dettagli'):
|
for invoice in root.iter('{STAT_FATTURATO_CTERZI}Dettagli'):
|
||||||
lines = dict()
|
lines = dict()
|
||||||
invoice_num = invoice.get('protocollo_fatturatestata')
|
invoice_num = invoice.get('protocollo_fatturatestata')
|
||||||
invoice_type = invoice.get('fat_ndc')
|
invoice_type = invoice.get('fat_ndc')
|
||||||
total_amount = int(format(round(float(invoice.get('denorm_importototale_fatturatestata')), 2), '.2f').replace('.', '').replace('-', '')) * -1 if '-' in invoice.get('denorm_importototale_fatturatestata') else 1
|
# total_amount = int(format(round(float(invoice.get('denorm_importototale_fatturatestata')), 2), '.2f').replace('.', '').replace('-', '')) * -1 if '-' in invoice.get('denorm_importototale_fatturatestata') else 1
|
||||||
total_calculated_amount = 0
|
total_calculated_amount = 0
|
||||||
ritenuta_acconto = 0
|
ritenuta_acconto = 0
|
||||||
|
|
||||||
@@ -74,13 +74,21 @@ def import_xml(parent, input_file_path) -> dict:
|
|||||||
else:
|
else:
|
||||||
lines[desc] = amount
|
lines[desc] = amount
|
||||||
total_calculated_amount += amount
|
total_calculated_amount += amount
|
||||||
|
try:
|
||||||
|
ragione_sociale = unidecode.unidecode(invoice.get('cognome_cliente') + ' ' + ' '.join(invoice.get('nome_cliente').split()[0:2]))
|
||||||
|
except TypeError:
|
||||||
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.RED, font=wx.Font(wx.FontInfo(8).Bold())))
|
||||||
|
parent.log_dialog.log_text.AppendText("ERRORE: il documento %s ha ragione sociale non valida!\n" % invoice_num)
|
||||||
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr())
|
||||||
|
wx.Yield()
|
||||||
|
continue
|
||||||
|
|
||||||
invoice_elem = {
|
invoice_elem = {
|
||||||
"numFattura": invoice_num,
|
"numFattura": invoice_num,
|
||||||
"tipoFattura": invoice_type,
|
"tipoFattura": invoice_type,
|
||||||
"rifFattura": invoice.get('protocollo_fatturatestata1'),
|
"rifFattura": invoice.get('protocollo_fatturatestata1'),
|
||||||
"dataFattura": datetime.datetime.fromisoformat(invoice.get('data_fatturatestata')).strftime("%d%m%Y"),
|
"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])),
|
"ragioneSociale": ragione_sociale,
|
||||||
"posDivide": str(len(invoice.get('cognome_cliente')) + 1),
|
"posDivide": str(len(invoice.get('cognome_cliente')) + 1),
|
||||||
"cf": invoice.get('cf_piva_cliente'),
|
"cf": invoice.get('cf_piva_cliente'),
|
||||||
"importoTotale": total_calculated_amount,
|
"importoTotale": total_calculated_amount,
|
||||||
@@ -88,8 +96,9 @@ def import_xml(parent, input_file_path) -> dict:
|
|||||||
"righe": lines,
|
"righe": lines,
|
||||||
}
|
}
|
||||||
invoices[invoice_num] = invoice_elem
|
invoices[invoice_num] = invoice_elem
|
||||||
parent.log_dialog.log_text.AppendText("Importata fattura n. %s\n" % invoice_num)
|
if parent.verbose:
|
||||||
wx.Yield()
|
parent.log_dialog.log_text.AppendText("Importata fattura n. %s\n" % invoice_num)
|
||||||
|
wx.Yield()
|
||||||
return invoices
|
return invoices
|
||||||
|
|
||||||
|
|
||||||
@@ -254,8 +263,9 @@ def convert(parent):
|
|||||||
line.append('S') # TRF-RIF-FATTURA
|
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('S' + ' '*2 + 'S' + ' '*2) # TRF-RISERVATO-B + TRF-MASTRO-CF + TRF-MOV-PRIVATO + TRF-SPESE-MEDICHE + TRF-FILLER
|
||||||
line.append('\n')
|
line.append('\n')
|
||||||
parent.log_dialog.log_text.AppendText("Creato record #0 per fattura n. %s\n" % invoice["numFattura"])
|
if parent.verbose:
|
||||||
wx.Yield()
|
parent.log_dialog.log_text.AppendText("Creato record #0 per fattura n. %s\n" % invoice["numFattura"])
|
||||||
|
wx.Yield()
|
||||||
|
|
||||||
#RECORD 5 per Tessera Sanitaria
|
#RECORD 5 per Tessera Sanitaria
|
||||||
line.append('04103' + '3' + '5') # TRF5-DITTA + TRF5-VERSIONE + TRF5-TARC
|
line.append('04103' + '3' + '5') # TRF5-DITTA + TRF5-VERSIONE + TRF5-TARC
|
||||||
@@ -275,8 +285,9 @@ def convert(parent):
|
|||||||
line.append((' ' + ' ' + ' ')*49) # 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(' ' + 'S' + ' '*76) # TRF-SPESE-FUNEBRI + TRF-A21CO-PAGAM + FILLER + FILLER
|
||||||
line.append('\n')
|
line.append('\n')
|
||||||
parent.log_dialog.log_text.AppendText("Creato record #5 per fattura n. %s\n" % invoice["numFattura"])
|
if parent.verbose:
|
||||||
wx.Yield()
|
parent.log_dialog.log_text.AppendText("Creato record #5 per fattura n. %s\n" % invoice["numFattura"])
|
||||||
|
wx.Yield()
|
||||||
|
|
||||||
#RECORD 1 per num. doc. originale
|
#RECORD 1 per num. doc. originale
|
||||||
line.append('04103' + '3' + '1') # TRF1-DITTA + TRF1-VERSIONE + TRF1-TARC
|
line.append('04103' + '3' + '1') # TRF1-DITTA + TRF1-VERSIONE + TRF1-TARC
|
||||||
@@ -295,14 +306,16 @@ def convert(parent):
|
|||||||
line.append(' '*8) # TRF-CK-RCHARGE
|
line.append(' '*8) # TRF-CK-RCHARGE
|
||||||
line.append('0'*(15-len(invoice["numFattura"])) + invoice["numFattura"]) # TRF-XNUM-DOC-ORI
|
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
|
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"])
|
if parent.verbose:
|
||||||
wx.Yield()
|
parent.log_dialog.log_text.AppendText("Creato record #1 per fattura n. %s\n" % invoice["numFattura"])
|
||||||
|
wx.Yield()
|
||||||
|
|
||||||
line = ''.join(line) + '\n'
|
line = ''.join(line) + '\n'
|
||||||
|
|
||||||
traf2000_file.write(line)
|
traf2000_file.write(line)
|
||||||
parent.log_dialog.log_text.AppendText("Convertita fattura n. %s\n" % invoice["numFattura"])
|
if parent.verbose:
|
||||||
wx.Yield()
|
parent.log_dialog.log_text.AppendText("Convertita fattura n. %s\n" % invoice["numFattura"])
|
||||||
|
wx.Yield()
|
||||||
|
|
||||||
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.BLACK, font=wx.Font(wx.FontInfo(8).Bold())))
|
parent.log_dialog.log_text.SetDefaultStyle(wx.TextAttr(wx.BLACK, font=wx.Font(wx.FontInfo(8).Bold())))
|
||||||
parent.log_dialog.log_text.AppendText("Conversione terminata.\nTracciato TRAF2000 salvato in %s\n" % output_file_path)
|
parent.log_dialog.log_text.AppendText("Conversione terminata.\nTracciato TRAF2000 salvato in %s\n" % output_file_path)
|
||||||
|
Reference in New Issue
Block a user