I want an app that is capable of converting Italian fatture pdfs to xml. Consider the most recent Italian documentation about xml and fatture, as this is a complex task.
To upload files, please first save the app
import streamlit as st
import PyPDF2
import xml.etree.ElementTree as ET
from datetime import datetime
import re
import io
from xml.dom import minidom
# Italian Fattura Elettronica XML converter
st.set_page_config(page_title="Convertitore PDF Fattura โ XML", page_icon="๐")
st.title("๐ฎ๐น Convertitore Fatture PDF โ XML")
st.write("Converte fatture italiane in formato PDF al formato XML standard FatturaPA")
# Upload PDF file
uploaded_file = st.file_uploader("Carica la fattura in PDF", type="pdf")
if uploaded_file is not None:
try:
# Read PDF
pdf_reader = PyPDF2.PdfReader(uploaded_file)
text = ""
for page in pdf_reader.pages:
text += page.extract_text()
st.subheader("Testo estratto dal PDF:")
st.text_area("Contenuto", text, height=200)
# Extract information using regex patterns
def extract_info(text):
info = {}
# Common patterns for Italian invoices
patterns = {
'partita_iva': r'P\.?\s*IVA[:\s]*(\d{11})',
'codice_fiscale': r'C\.?\s*F\.?[:\s]*([A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z])',
'numero_fattura': r'(?:Fattura|N\.|Numero)[:\s]*(\d+)',
'data_fattura': r'(?:Data|del)[:\s]*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4})',
'ragione_sociale': r'(?:FATTURA|INVOICE).*?\n([A-Z\s&]+)',
'importo_totale': r'(?:Totale|TOTALE|Euro)[:\s]*โฌ?\s*(\d+[,\.]\d{2})',
'iva': r'(?:IVA|I\.V\.A\.)[:\s]*โฌ?\s*(\d+[,\.]\d{2})',
'imponibile': r'(?:Imponibile|IMPONIBILE)[:\s]*โฌ?\s*(\d+[,\.]\d{2})'
}
for key, pattern in patterns.items():
match = re.search(pattern, text, re.IGNORECASE | re.MULTILINE)
if match:
info[key] = match.group(1).strip()
else:
info[key] = ""
return info
# Extract information
extracted_info = extract_info(text)
st.subheader("Informazioni estratte:")
col1, col2 = st.columns(2)
with col1:
st.write("**Dati del fornitore:**")
st.write(f"Ragione sociale: {extracted_info.get('ragione_sociale', 'Non trovata')}")
st.write(f"Partita IVA: {extracted_info.get('partita_iva', 'Non trovata')}")
st.write(f"Codice fiscale: {extracted_info.get('codice_fiscale', 'Non trovato')}")
with col2:
st.write("**Dati della fattura:**")
st.write(f"Numero: {extracted_info.get('numero_fattura', 'Non trovato')}")
st.write(f"Data: {extracted_info.get('data_fattura', 'Non trovata')}")
st.write(f"Imponibile: โฌ{extracted_info.get('imponibile', '0,00')}")
st.write(f"IVA: โฌ{extracted_info.get('iva', '0,00')}")
st.write(f"Totale: โฌ{extracted_info.get('importo_totale', '0,00')}")
# Allow manual editing
st.subheader("Modifica dati estratti:")
with st.form("fattura_form"):
col1, col2 = st.columns(2)
with col1:
st.write("**Dati Cedente/Prestatore:**")
denominazione = st.text_input("Denominazione", value=extracted_info.get('ragione_sociale', ''))
partita_iva = st.text_input("Partita IVA", value=extracted_info.get('partita_iva', ''))
codice_fiscale = st.text_input("Codice Fiscale", value=extracted_info.get('codice_fiscale', ''))
indirizzo = st.text_input("Indirizzo", value="")
cap = st.text_input("CAP", value="")
comune = st.text_input("Comune", value="")
provincia = st.text_input("Provincia", value="")
nazione = st.selectbox("Nazione", ["IT", "FR", "DE", "ES"], index=0)
with col2:
st.write("**Dati Fattura:**")
tipo_documento = st.selectbox("Tipo Documento", ["TD01", "TD02", "TD03", "TD04", "TD05", "TD06"], index=0)
numero = st.text_input("Numero", value=extracted_info.get('numero_fattura', ''))
data = st.date_input("Data", value=datetime.now().date())
descrizione = st.text_input("Descrizione", value="Prestazione di servizi")
quantita = st.number_input("Quantitร ", value=1.0, min_value=0.0)
prezzo_unitario = st.number_input("Prezzo Unitario", value=float(extracted_info.get('imponibile', '0').replace(',', '.')), min_value=0.0)
aliquota_iva = st.selectbox("Aliquota IVA", ["22.00", "10.00", "4.00", "0.00"], index=0)
submit = st.form_submit_button("Genera XML")
if submit:
# Generate XML according to FatturaPA standard
def create_xml():
# Root element
root = ET.Element("p:FatturaElettronica")
root.set("versione", "FPR12")
root.set("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#")
root.set("xmlns:p", "http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2")
root.set("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
root.set("xsi:schemaLocation", "http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2 http://www.fatturapa.gov.it/export/fatturazione/sdi/fatturapa/v1.2/Schema_del_file_xml_FatturaPA_versione_1.2.xsd")
# Header
header = ET.SubElement(root, "FatturaElettronicaHeader")
# Transmission data
dati_trasmissione = ET.SubElement(header, "DatiTrasmissione")
ET.SubElement(dati_trasmissione, "IdTrasmittente").text = "IT" + partita_iva
ET.SubElement(dati_trasmissione, "ProgressivoInvio").text = "1"
ET.SubElement(dati_trasmissione, "FormatoTrasmissione").text = "FPR12"
ET.SubElement(dati_trasmissione, "CodiceDestinatario").text = "0000000"
# Supplier data
cedente = ET.SubElement(header, "CedentePrestatore")
dati_anagrafici = ET.SubElement(cedente, "DatiAnagrafici")
ET.SubElement(dati_anagrafici, "IdFiscaleIVA")
ET.SubElement(ET.SubElement(dati_anagrafici, "IdFiscaleIVA"), "IdPaese").text = "IT"
ET.SubElement(ET.SubElement(dati_anagrafici, "IdFiscaleIVA"), "IdCodice").text = partita_iva
if codice_fiscale:
ET.SubElement(dati_anagrafici, "CodiceFiscale").text = codice_fiscale
anagrafica = ET.SubElement(dati_anagrafici, "Anagrafica")
ET.SubElement(anagrafica, "Denominazione").text = denominazione
ET.SubElement(dati_anagrafici, "RegimeFiscale").text = "RF01"
# Supplier address
sede = ET.SubElement(cedente, "Sede")
ET.SubElement(sede, "Indirizzo").text = indirizzo or "Via Roma 1"
ET.SubElement(sede, "CAP").text = cap or "00100"
ET.SubElement(sede, "Comune").text = comune or "Roma"
ET.SubElement(sede, "Provincia").text = provincia or "RM"
ET.SubElement(sede, "Nazione").text = nazione
# Customer data (simplified)
cessionario = ET.SubElement(header, "CessionarioCommittente")
dati_anagrafici_cess = ET.SubElement(cessionario, "DatiAnagrafici")
anagrafica_cess = ET.SubElement(dati_anagrafici_cess, "Anagrafica")
ET.SubElement(anagrafica_cess, "Denominazione").text = "Cliente"
sede_cess = ET.SubElement(cessionario, "Sede")
ET.SubElement(sede_cess, "Indirizzo").text = "Via Cliente 1"
ET.SubElement(sede_cess, "CAP").text = "00100"
ET.SubElement(sede_cess, "Comune").text = "Roma"
ET.SubElement(sede_cess, "Provincia").text = "RM"
ET.SubElement(sede_cess, "Nazione").text = "IT"
# Body
body = ET.SubElement(root, "FatturaElettronicaBody")
# General invoice data
dati_generali = ET.SubElement(body, "DatiGenerali")
dati_generali_doc = ET.SubElement(dati_generali, "DatiGeneraliDocumento")
ET.SubElement(dati_generali_doc, "TipoDocumento").text = tipo_documento
ET.SubElement(dati_generali_doc, "Divisa").text = "EUR"
ET.SubElement(dati_generali_doc, "Data").text = data.strftime("%Y-%m-%d")
ET.SubElement(dati_generali_doc, "Numero").text = numero
# Line items
dati_beni_servizi = ET.SubElement(body, "DatiBeniServizi")
dettaglio_linee = ET.SubElement(dati_beni_servizi, "DettaglioLinee")
ET.SubElement(dettaglio_linee, "NumeroLinea").text = "1"
ET.SubElement(dettaglio_linee, "Descrizione").text = descrizione
ET.SubElement(dettaglio_linee, "Quantita").text = f"{quantita:.2f}"
ET.SubElement(dettaglio_linee, "PrezzoUnitario").text = f"{prezzo_unitario:.2f}"
ET.SubElement(dettaglio_linee, "PrezzoTotale").text = f"{quantita * prezzo_unitario:.2f}"
ET.SubElement(dettaglio_linee, "AliquotaIVA").text = aliquota_iva
# VAT summary
dati_riepilogo = ET.SubElement(dati_beni_servizi, "DatiRiepilogo")
ET.SubElement(dati_riepilogo, "AliquotaIVA").text = aliquota_iva
imponibile_importo = quantita * prezzo_unitario
iva_importo = imponibile_importo * float(aliquota_iva) / 100
ET.SubElement(dati_riepilogo, "ImponibileImporto").text = f"{imponibile_importo:.2f}"
ET.SubElement(dati_riepilogo, "Imposta").text = f"{iva_importo:.2f}"
return root
# Generate XML
xml_root = create_xml()
# Pretty print XML
rough_string = ET.tostring(xml_root, 'unicode')
reparsed = minidom.parseString(rough_string)
pretty_xml = reparsed.toprettyxml(indent=" ")
# Remove empty lines
pretty_xml = '\n'.join([line for line in pretty_xml.split('\n') if line.strip()])
st.subheader("XML Generato:")
st.code(pretty_xml, language="xml")
# Download button
st.download_button(
label="Scarica XML",
data=pretty_xml,
file_name=f"fattura_{numero}_{data.strftime('%Y%m%d')}.xml",
mime="application/xml"
)
st.success("โ
XML generato con successo secondo lo standard FatturaPA!")
# Validation info
st.info("""
**Note importanti:**
- Il file XML generato segue lo standard FatturaPA versione 1.2
- Verificare sempre i dati estratti prima della generazione
- Per l'invio al Sistema di Interscambio (SdI) รจ necessaria la firma digitale
- Completare i dati del cessionario/committente prima dell'invio ufficiale
""")
except Exception as e:
st.error(f"Errore durante l'elaborazione: {str(e)}")
st.write("Assicurati che il file PDF sia leggibile e contenga testo.")
else:
st.info("๐ Carica un file PDF per iniziare la conversione")
# Instructions
st.markdown("""
### ๐ Istruzioni:
1. **Carica** il file PDF della fattura italiana
2. **Verifica** le informazioni estratte automaticamente
3. **Compila** i campi mancanti o correggi eventuali errori
4. **Genera** il file XML conforme allo standard FatturaPA
5. **Scarica** il file XML risultante
### โ ๏ธ Limitazioni:
- L'estrazione automatica potrebbe non essere perfetta per tutti i formati PDF
- ร necessario verificare manualmente i dati estratti
- Il file XML generato richiede ulteriori personalizzazioni per casi specifici
- Per l'invio ufficiale serve la firma digitale
### ๐ Standard supportato:
- **FatturaPA versione 1.2** (formato standard italiano)
- Compatible con il **Sistema di Interscambio (SdI)**
- Include tutti i campi obbligatori richiesti
""")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?