Warning: include_once(/home/favoledo/robertozanardo.com/wp-content/sunrise.php): Failed to open stream: No such file or directory in /home/favoledo/robertozanardo.com/wp-includes/ms-settings.php on line 52

Warning: include_once(): Failed opening '/home/favoledo/robertozanardo.com/wp-content/sunrise.php' for inclusion (include_path='.:/opt/alt/php83/usr/share/pear:/opt/alt/php83/usr/share/php:/usr/share/pear:/usr/share/php') in /home/favoledo/robertozanardo.com/wp-includes/ms-settings.php on line 52
Leggere dettaglio linee da fatture elettroniche con xmltodict - Odoo e Soluzioni Open Source

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.

 

1 commento su “Leggere dettaglio linee da fatture elettroniche con xmltodict”

Lascia un commento

kolaybet giriş
betgaranti
bettilt
hellocasino
betgaranti
Kolaybet
bettilt
Kolaybet Giriş
Kolaybet
Kolaybet Giriş
Kolaybet
Kolaybet Giriş
Kolaybet
matbet güncel giriş
matbet güncel giriş
matbet güncel giriş
matbet güncel giriş
Hititbet Giriş
betgaranti
Hellocasino
Hello Casino
Hititbet
hititbet
vdcasino
hititbet
bettilt
hititbet giriş
hititbet giriş
vdcasino
kolaybet
kolaybet
betpark
Kolaybet Giriş
betpark
betgaranti
kuponbet giriş
betpark
betgaranti
sahabet
onwin
sahabet
sahabet
sahabet
sahabet
onwin
onwin
onwin
onwin
holiganbet
grandpashabet
onwin
onwin
betpark
betpark
bettilt
mariobet giriş
onwin
onwin
mariobet
betorder
betpark
betorder
safirbet
mariobet
betgaranti
grandpashabet
betgaranti
betpark
betpark
betgaranti
betpark