diff --git a/downloader.py b/downloader.py index a3e0584..01cab55 100644 --- a/downloader.py +++ b/downloader.py @@ -1,5 +1,8 @@ """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 requests @@ -30,6 +33,13 @@ def get_invoices_info(input_file_path: str) -> dict: return invoices +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(input_file_path: str, output_file_path: str, username: str, password: str): """download invoices from CCSR""" @@ -42,11 +52,10 @@ def download_invoices(input_file_path: str, output_file_path: str, username: str tmp_dir = tempfile.mkdtemp() invoices_count = len(invoices) - processed_count = 0 + downloaded_count = 0 for invoice_id, invoice in invoices.items(): resp = session.get(invoice["url"]) - processed_count += 1 if resp.status_code == 200: with open(tmp_dir+"/"+invoice_id+".pdf", "wb") as output_file: output_file.write(resp.content) @@ -55,13 +64,14 @@ def download_invoices(input_file_path: str, output_file_path: str, username: str try: PyPDF2.PdfFileReader(open(invoice["path"], "rb")) except (PyPDF2.utils.PdfReadError, OSError): - logger.downloader_logger.error("%d/%d fattura %s corrotta!", processed_count, invoices_count, invoice_id) + logger.downloader_logger.error("fattura %s corrotta!", invoice_id) invoice["good"] = False else: - logger.downloader_logger.info("%d/%d scaricata fattura %s in %s", processed_count, invoices_count, invoice_id, invoice["path"]) + downloaded_count += 1 + logger.downloader_logger.info("%d/%d scaricata fattura %s in %s", downloaded_count, invoices_count, invoice_id, invoice["path"]) invoice["good"] = True else: - logger.downloader_logger.error("%d/%d impossibile scaricare fattura %s: %d", processed_count, invoices_count, invoice_id, resp.status_code) + logger.downloader_logger.error("impossibile scaricare fattura %s: %d", invoice_id, resp.status_code) invoice["good"] = False merger = PyPDF2.PdfFileMerger() @@ -69,7 +79,9 @@ def download_invoices(input_file_path: str, output_file_path: str, username: str 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) logger.downloader_logger.info("Download terminato. Il pdf contenente le fatture si trova in %s", output_file_path) diff --git a/fattureDownloader/fattureSanRossore.go b/fattureDownloader/fattureSanRossore.go deleted file mode 100644 index a597f30..0000000 --- a/fattureDownloader/fattureSanRossore.go +++ /dev/null @@ -1,313 +0,0 @@ -package main - -import ( - "bufio" - "io" - "io/ioutil" - "log" - "net/http" - "os" - "os/exec" - "path/filepath" - "runtime" - "sort" - "strings" - "sync" - - "github.com/extrame/xls" - "github.com/pdfcpu/pdfcpu/pkg/api" - "github.com/sqweek/dialog" - "mvdan.cc/xurls/v2" -) - -var tmpDir string -var outDir string -var mw io.Writer -var logPath string -var exitWithError bool - -func getInvoiceIDs(fileName string) []string { - xlFile, err := xls.Open(fileName, "utf-8") - if err != nil { - exitWithError = true - log.Panicf("Impossibile aprire il file xls: %v\n", err) - } - - sheet := xlFile.GetSheet(0) - if sheet == nil { - exitWithError = true - log.Panicf("Impossibile aprire il foglio nell'xls: %v\n", err) - } - - var invoiceIDs []string - - for i := 0; i <= int(sheet.MaxRow); i++ { - row := sheet.Row(i) - if strings.Contains(row.Col(8), "CCSR") { - id := strings.ReplaceAll(row.Col(8), "/", "-") - invoiceIDs = append(invoiceIDs, id) - } - } - return invoiceIDs -} - -func convertXLStoFODS(fileName string) string { - var sofficePath = "libreoffice" - if runtime.GOOS == "windows" { - sofficePath = filepath.FromSlash("C:/Program Files/LibreOffice/program/soffice.exe") - } - cmd := exec.Command(sofficePath, "--convert-to", "fods", "--outdir", outDir, fileName) - cmd.Stdout = mw - cmd.Stderr = mw - err := cmd.Run() - if err != nil { - exitWithError = true - log.Panicf("Impossibile convertire l'XLS in FODS: %v\n", err) - } - return (outDir + "/" + strings.TrimSuffix(filepath.Base(fileName), filepath.Ext(fileName)) + ".fods") -} - -func getInvoiceURLs(fileName string) []string { - fods := convertXLStoFODS(fileName) - f, err := os.Open(fods) - if err != nil { - exitWithError = true - log.Panicf("Impossibile aprire il FODS convertito: %v\n", err) - } - defer func() { - err = f.Close() - if err != nil { - log.Printf("Impossibile chiudere il file %v: %v\n", fods, err) - } - }() - var invoiceURLs []string - s := bufio.NewScanner(f) - for s.Scan() { - line := s.Text() - if strings.Contains(line, "http://report.casadicurasanrossore.it:9146/files/get?type=invoice&id=") { - url := xurls.Strict().FindString(line) - url = strings.ReplaceAll(url, "&", "&") - invoiceURLs = append(invoiceURLs, url) - } - } - if err := s.Err(); err != nil { - exitWithError = true - log.Panicf("Impossibile leggere dal file %v: %v\n", fods, err) - } - return invoiceURLs -} - -func checkFile(fileName string) string { - _, err := os.Stat(fileName) - if err != nil { - exitWithError = true - log.Panicf("Errore nell'apertura del file %v: %v\n", fileName, err) - } - absPath, err := filepath.Abs(fileName) - if err != nil { - exitWithError = true - log.Panicf("Impossibile recuperare il percorso assoluto del file %v: %v\n", fileName, err) - } - return absPath -} - -func downloadFile(fileName string, url string) error { - resp, err := http.Get(url) - - if err != nil { - resp.Body.Close() - return err - } - - out, err := os.Create(fileName) - if err != nil { - out.Close() - return err - } - - _, err = io.Copy(out, resp.Body) - out.Close() - resp.Body.Close() - - return err -} - -func createTmpDir() string { - dir := filepath.FromSlash(tmpDir + "/fattureSanRossore") - - if _, err := os.Stat(dir); err == nil { - log.Printf("Pulizia della directory temporanea pre-esistente") - err := os.RemoveAll(dir) - if err != nil { - exitWithError = true - log.Panicf("Impossibile eliminare la directory temporanea pre-esistente %v: %v\n", dir, err) - } - } else if !os.IsNotExist(err) { - exitWithError = true - log.Panicf("Impossibile eseguire lo stat sulla directory temporanea %v: %v\n", dir, err) - } - err := os.Mkdir(dir, os.ModePerm) - if err != nil { - exitWithError = true - log.Panicf("Impossibile creare la directory temporanea di salvataggio %v: %v\n", dir, err) - } - - return dir -} - -func downloadInvoices(ids []string, urls []string) []string { - if len(ids) != len(urls) { - exitWithError = true - log.Printf("Il numero di fatture da scaricare non corrisponde al numero di URL individuati nel file. IDs: %d/URLs: %d", len(ids), len(urls)) - } - - wg := sync.WaitGroup{} - sem := make(chan bool, 30) - mu := sync.Mutex{} - invoiceNum := minOf(len(ids), len(urls)) - downloadCount := 0 - downloadedFiles := make([]string, 0) - - log.Printf("Inizio il download di %d fatture\n", invoiceNum) - for i := 0; i < invoiceNum; i++ { - id := ids[i] - url := urls[i] - out := filepath.FromSlash(outDir + "/" + id + ".pdf") - - wg.Add(1) - go func(i int) { - sem <- true - log.Printf("Scaricamento di %v\n", id) - err := downloadFile(out, url) - if err != nil { - log.Printf("Impossibile scaricare il file %v: %v\n", url, err) - } else if api.ValidateFile(out, nil) != nil { - log.Printf("Errore nella validazione del file %v\n", out) - } else { - mu.Lock() - downloadedFiles = append(downloadedFiles, out) - downloadCount++ - mu.Unlock() - } - <-sem - wg.Done() - }(i) - } - wg.Wait() - log.Printf("Scaricate %d/%d fatture\n", downloadCount, invoiceNum) - sort.Strings(downloadedFiles) - return downloadedFiles -} - -func mergeInvoices(files []string) string { - out, err := dialog.File().Filter("PDF files", "pdf").Title("Scegli dove salvare le fatture unite").Save() - if err != nil { - exitWithError = true - log.Panicf("Impossibile recuperare il file selezionato: %v\n", err) - } - if filepath.Ext(out) == "" { - out += ".pdf" - } - err = api.MergeFile(files, out, nil) - if err != nil { - exitWithError = true - log.Panicf("Impossibile unire i pdf: %v\nFatture singole non rimosse\n", err) - } - return out -} - -func openPDF(fileName string) { - var cmd *exec.Cmd - if runtime.GOOS == "windows" { - cmd = exec.Command("cmd", "/C start "+fileName) - - } else { - cmd = exec.Command("xdg-open", fileName) - } - cmd.Stdout = mw - cmd.Stderr = mw - err := cmd.Start() - if err != nil { - exitWithError = true - log.Panicf("Impossibile aprire il pdf con le fatture unite: %v\n", err) - } -} - -func cleanTmpDir() { - files, err := ioutil.ReadDir(outDir) - if err != nil { - exitWithError = true - log.Panicf("Impossibile recuperare la lista di file creati nella directory temporanea: %v\n", err) - } - for _, file := range files { - err = os.Remove(filepath.FromSlash(outDir + "/" + file.Name())) - if err != nil { - log.Printf("Impossibile eliminare la fattura singola %v: %v\n", file, err) - } - } - err = os.Remove(outDir) - if err != nil { - log.Printf("Impossibile eliminare la directory temporanea %v: %v\n", outDir, err) - } -} - -func minOf(vars ...int) int { - min := vars[0] - - for _, i := range vars { - if min > i { - min = i - } - } - - return min -} - -func main() { - exitWithError = false - args := os.Args - tmpDir = os.TempDir() - - if runtime.GOOS == "linux" { - logPath = tmpDir + "/log_fattureSanRossore.log" - } else { - logPath = filepath.FromSlash(tmpDir + "/log_fattureSanRossore.txt") - } - logFile, err := os.OpenFile(filepath.FromSlash(logPath), os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666) - if err != nil { - exitWithError = true - log.Panicf("Impossibile creare il file di log: %v\n", err) - } - mw = io.MultiWriter(os.Stderr, logFile) - log.SetOutput(mw) - - defer func() { - if !exitWithError { - cleanTmpDir() - } else { - log.Println("I file temporanei non sono stati eliminati per poterli riesaminare") - } - log.Printf("Log file salvato in %v\n", logPath) - }() - - outDir = createTmpDir() - - var fileName string - if len(args) < 2 { - var err error - fileName, err = dialog.File().Filter("XLS files", "xls").Load() - if err != nil { - exitWithError = true - log.Panicf("Impossibile recuperare il file selezionato: %v\n", err) - } - } else { - fileName = args[1] - } - - filePath := checkFile(fileName) - IDs := getInvoiceIDs(filePath) - URLs := getInvoiceURLs(filePath) - dlFiles := downloadInvoices(IDs, URLs) - pdf := mergeInvoices(dlFiles) - openPDF(pdf) -} diff --git a/fattureDownloader/go.mod b/fattureDownloader/go.mod deleted file mode 100644 index ae6f420..0000000 --- a/fattureDownloader/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module github.com/Noettore/fattureSanRossore/fattureDownloader - -go 1.14 - -require ( - github.com/extrame/ole2 v0.0.0-20160812065207-d69429661ad7 // indirect - github.com/extrame/xls v0.0.1 - github.com/gotk3/gotk3 v0.4.0 // indirect - github.com/pdfcpu/pdfcpu v0.3.2 - github.com/sqweek/dialog v0.0.0-20200304031853-0dcd55bfe06a - mvdan.cc/xurls/v2 v2.2.0 -) diff --git a/fattureDownloader/go.sum b/fattureDownloader/go.sum deleted file mode 100644 index 5143524..0000000 --- a/fattureDownloader/go.sum +++ /dev/null @@ -1,45 +0,0 @@ -github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= -github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k= -github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf h1:FPsprx82rdrX2jiKyS17BH6IrTmUBYqZa/CXT4uvb+I= -github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I= -github.com/extrame/ole2 v0.0.0-20160812065207-d69429661ad7 h1:n+nk0bNe2+gVbRI8WRbLFVwwcBQ0rr5p+gzkKb6ol8c= -github.com/extrame/ole2 v0.0.0-20160812065207-d69429661ad7/go.mod h1:GPpMrAfHdb8IdQ1/R2uIRBsNfnPnwsYE9YYI5WyY1zw= -github.com/extrame/xls v0.0.1 h1:jI7L/o3z73TyyENPopsLS/Jlekm3nF1a/kF5hKBvy/k= -github.com/extrame/xls v0.0.1/go.mod h1:iACcgahst7BboCpIMSpnFs4SKyU9ZjsvZBfNbUxZOJI= -github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/gotk3/gotk3 v0.4.0 h1:TIuhyQitGeRTxOQIV3AJlYtEWWJpC74JHwAIsxlH8MU= -github.com/gotk3/gotk3 v0.4.0/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo= -github.com/hhrutter/lzw v0.0.0-20190827003112-58b82c5a41cc/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk= -github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650 h1:1yY/RQWNSBjJe2GDCIYoLmpWVidrooriUr4QS/zaATQ= -github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk= -github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7 h1:o1wMw7uTNyA58IlEdDpxIrtFHTgnvYzA8sCQz8luv94= -github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7/go.mod h1:WkUxfS2JUu3qPo6tRld7ISb8HiC0gVSU91kooBMDVok= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mattn/go-gtk v0.0.0-20180216084204-5a311a1830ab/go.mod h1:PwzwfeB5syFHXORC3MtPylVcjIoTDT/9cvkKpEndGVI= -github.com/mattn/go-pointer v0.0.0-20171114154726-1d30dc4b6f28/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= -github.com/pdfcpu/pdfcpu v0.3.2 h1:oHnvW3KUed/jVLnNcN5FyJsmInXAyyfoZ4yG3mxJdk8= -github.com/pdfcpu/pdfcpu v0.3.2/go.mod h1:/ULj8B76ZnB4445B0yuSASQqlN0kEO+khtEnmPdEoXU= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/skelterjohn/go.wde v0.0.0-20180104102407-a0324cbf3ffe/go.mod h1:zXxNsJHeUYIqpg890APBNEn9GoCbA4Cdnvuv3mx4fBk= -github.com/sqweek/dialog v0.0.0-20200304031853-0dcd55bfe06a h1:BHv3lo0aZg2IPfeBfgYFjq48DoKehP+JC9dtACUEmT4= -github.com/sqweek/dialog v0.0.0-20200304031853-0dcd55bfe06a/go.mod h1:QSrNdZLZB8VoFPGlZ2vDuA2oNaVdhld3g0PZLc7soX8= -github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE= -github.com/tealeg/xlsx/v2 v2.0.1 h1:RP+VEscpPFjH2FnpKh1p9HVLAk1htqb9Urcxi2AU1ns= -github.com/tealeg/xlsx/v2 v2.0.1/go.mod h1:l9GvhCCjdaIGkAyZcFedDALcYcXUOei55f6umRMOz9c= -golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20191214001246-9130b4cfad52 h1:2fktqPPvDiVEEVT/vSTeoUPXfmRxRaGy6GU8jypvEn0= -golang.org/x/image v0.0.0-20191214001246-9130b4cfad52/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -mvdan.cc/xurls v1.1.0 h1:kj0j2lonKseISJCiq1Tfk+iTv65dDGCl0rTbanXJGGc= -mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= -mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= diff --git a/fatture_ccsr.py b/fatture_ccsr.py index 4619110..eae7c33 100644 --- a/fatture_ccsr.py +++ b/fatture_ccsr.py @@ -147,6 +147,7 @@ class FattureCCSRFrame(wx.Frame): def file_picker_changed(self, event): """event raised when the input file path is changed""" self.input_file_path = event.GetEventObject().GetPath() + #TODO: error frame try: self.input_file_ext = utils.file_extension(self.input_file_path, (".xml", ".csv", ".xlsx")) except exc.NoFileError as handled_exception: @@ -185,6 +186,7 @@ class FattureCCSRFrame(wx.Frame): return self.log_dialog = LogDialog(self, "Conversione delle fatture in TRAF2000", CONVERT_ACTION) self.log_dialog.Show() + #TODO: error frame try: traf2000_converter.convert(self.input_file_path, self.output_file_path) except exc.NoFileError as handled_exception: