Leggere dettaglio linee da fatture elettroniche con xmltodict
In questo articolo avevamo visto come esportare in csv i dati di intestazione di una fattura elettronica per poi poterla leggere con Excel.
Il programma utilizzava la libreria eTree per scorrere i valori per poi scriverli su un file di testo csv.
Il problema si pone sulle righe di dettaglio, che naturalmente possono essere più di una.
Qui il problema principale è come accedervi ma anche come successivamente scriverle nel file in uscita.
Utilizzando una libreria diversa, xmltodict possiamo accedere direttamente agli oggetti dell’xml in vari formati o utilizzando degli xpath.
Nel nostro caso ho scelto di scorrere il dictionary creato e individuare il tipo di valore ottenuto dalle singole interrogazioni.
Siccome gli oggetti del dictionary sono raggruppati in liste o liste di dictionary, parlando per esempio dei valori DettagliLinee, della fatturazione elettronica.
Possiamo avere un dictionary con all’interno i campi di dettaglio di una sola riga oppure una lista di dictionary nel caso di fatture con più righe.
L’idea è quindi di ricreare una struttura Python che contenga ogni fattura in un oggetto lista, dove ogni valore di DettaglioLinee sia contenuto in un dictionary facilmente accessibile.
#!/usr/bin/env python3 import os, glob import xmltodict DatiFatture = [] StrutturaCampi = [] # Creiamo una struttura dei campi che ci interessa esportare seguendo la struttura xml, se i campi sono composti da più righe, # come nel caso degli articoli, prendiamo il primo campo 'padre' necessario (DettaglioLinee) il programma si occuperà di prendere # tutti i sottocampi contenuti. StrutturaCampi = [['FatturaElettronicaHeader', 'DatiTrasmissione', 'ProgressivoInvio'], ['FatturaElettronicaHeader', 'DatiTrasmissione', 'CodiceDestinatario'], ['FatturaElettronicaHeader', 'CedentePrestatore', 'DatiAnagrafici', 'Anagrafica', 'Denominazione'], ['FatturaElettronicaHeader', 'CessionarioCommittente', 'Sede', 'Indirizzo'], ['FatturaElettronicaBody', 'DatiPagamento', 'CondizioniPagamento'], ['FatturaElettronicaBody', 'DatiBeniServizi', 'DettaglioLinee']] # Qui indichiamo la certella con i file XML da elaborare path = "C:\\Users\\user\\Downloads" # Leggiamo tutti i file for filename in glob.glob(os.path.join(path, "*.xml")): Fattura = [] with open(filename) as fd: doc = xmltodict.parse(fd.read()) # Prendiamo la chiave radice principale in automatico (es.: p:FatturaElettronica or ns1:FatturaElettronica) root = list(doc.keys())[0] # Facciamo il parse della struttura campi for fieldpath in StrutturaCampi: fieldname = '' # Prepariamo la stringa da interrogare successivamente con il metodo eval string_2_eval = 'doc["' + root + '"]' row_dict = {} for field in fieldpath: # memorizziamo il nome dell'ultimo campo della lista (Es.ProgressivoInvio): fieldname = fieldpath[-1] # accodiamo il percorso per andare a recuperare il valore nell'xml string_2_eval += '["' + field.replace('\n', '') + '"]' # Verifichiamo se il valore esiste e che non dia errori try: value = eval(string_2_eval) except: value = False # Verifichiamo che tipo di dato abbiamo: # se è un dictionary vuol dire che è una fattura con una sola riga di dettaglio if isinstance(value, dict) and value: print("E' UN DICTIONARY !") for k, v in value.items(): row_dict[k] = v Fattura.append(('Righe fattura', row_dict)) # se è una lista vuol dire che è una fattura con una più righe di dettaglio elif isinstance(value, list) and value: print("E' UNA LISTA !") for l in value: for k, v in l.items(): row_dict[k] = v Fattura.append(('Righe fattura', row_dict)) row_dict = {} # se è un valore vuol dire che è un valore singolo elif not isinstance(value, dict) and value: print("VALORE NORMALE") Fattura.append((fieldname, value)) # se è un valore ma non contiene dati aggiungiamo comunque il campo vuoto per non perdere la formattazione delle colonne nel file in uscita elif not isinstance(value, dict) and not value: Fattura.append((fieldname, '')) # Fine lettura campi fattura # A questo punto in Fattura[] abbiamo la lista di tutti i campi che ci interessano, dove ogni valore di 'Righe Fattura' conterrà # il dictionary con i campi della riga. # Volendo possiamo accodare a un'altra lista che conterrà tutte le fatture in formato lista. DatiFatture.append(Fattura) print('Dati fatture') print('------------') print(DatiFatture)
OUTPUT SPIEGATO:
Prima fattura [ [('ProgressivoInvio', '00002'), ('CodiceDestinatario', 'XXXXXX'), ('Denominazione', 'Roberto Zanardo'), ('Indirizzo', 'Via dei Tigli,23'), ('CondizioniPagamento', 'TP02'), Questa è una tuple che contiene come primo dato il nome del campo(Riga fattura) e come secondo dato il dictionary con tutte le chiavi/valori della riga. ('Riga fattura', {'NumeroLinea': '1', 'Descrizione': 'CONSULENZA/SVILUPPO SOFTWARE ODOO', 'Quantita': '1.00', 'PrezzoUnitario': '1600.00', 'PrezzoTotale': '1600.00', 'AliquotaIVA': '1.00', 'Natura': 'N2'}), ('Riga fattura', {'NumeroLinea': '2', 'Descrizione': 'cassa previdenziale 4', 'Quantita': '1.00', 'PrezzoUnitario': '64.00', 'PrezzoTotale': '64.00', 'AliquotaIVA': '2.00', 'Natura': 'N2'}) ] Fine prima fattura , Seconda fattura [ ('ProgressivoInvio', '00002'), ('CodiceDestinatario', 'SUXXXN'), ('Denominazione', 'Roberto Zanardo'), ('Indirizzo', 'Via Alpi 34'), ('CondizioniPagamento', 'TP02'), Questa è la tuple della prima riga che contiene come primo dato il nome del campo(Riga fattura) e come secondo dato il dictionary con tutte le chiavi/valori della riga. ('Riga fattura', {'NumeroLinea': '1', 'Descrizione': 'ORE CONSULENZA E SVILUPPO SOFTWARE', 'Quantita': '1.00', 'PrezzoUnitario': '1200.00', 'PrezzoTotale': '1200.00', 'AliquotaIVA': '0.00', 'Natura': 'N2'}), Questa è la tuple della prima seconda che contiene come primo dato il nome del campo(Riga fattura) e come secondo dato il dictionary con tutte le chiavi/valori della riga. ('Riga fattura', {'NumeroLinea': '2', 'Descrizione': 'Spese', 'Quantita': '1.00', 'PrezzoUnitario': '48.00', 'PrezzoTotale': '48.00', 'AliquotaIVA': '0.00', 'Natura': 'N2'})], ] Fine seconda fattura
Da questo punto sarà quindi necessario rileggere la struttura creata per disporla nel file di output come preferiamo.
-
Consulenza Giornata Odoo (Offerta valida solo per acquisto via Web)
€490.00 Aggiungi al carrello -
Consulenza Oraria Odoo (Offerta valida solo per acquisto via Web)
€99.00 Aggiungi al carrello -
FExplore FREE per Windows – Visualizza dati Fatture elettroniche con demo esportazione Excel
€0.00 Aggiungi al carrello -
In offerta!
FExplore per Windows – Esporta XML Fatture elettroniche in CSV per Excel
Il prezzo originale era: €69.00.€49.00Il prezzo attuale è: €49.00. Aggiungi al carrello
Un commento su “Leggere dettaglio linee da fatture elettroniche con xmltodict”