Fatturazione elettronica B2B: BTS secondo me

di il
7 risposte

Fatturazione elettronica B2B: BTS secondo me

Ricevo ciclicamente richieste su sorgenti e metodi che adotto.
Ogni tanto qualcosa ho postato, ma sembra che non sia stato raccolto.
Non è nulla di particolarmente intelligente, è lavoro artigianale.
Se c'è un interesse concreto potrei mettere qualche snippet su come elaboro xml ed eml.
Che è poi il modo più banale, cioè come stringhe.
Parliamo ovviamente di delphi, ma il Pascal è banalmente comprensibile.

7 Risposte

  • Re: Fatturazione elettronica B2B: BTS secondo me

    Avendo ricevuto un impressionate feedback, pari a zero, solo qualche commento, poi si vedrà.
    Partirei dalle fatture passive, supponendo che le attive ormai siano storia passata.

    La struttura-base che prediligo è la tstringlist, la quale, per chi non è un delfaro, è una lista di stringhe, con alcune particolarità
    (1) è facile caricare da file, basta fare un loadfromfile()
    (2) è facile scaricare da file, basta un savetofile()
    (3) è facile accedere all'intero testo, con la proprietà text
    (4) è facile operare riga per riga, cioè con le stringhe spezzate
    Bon, a questa struttura dati spartana, ma molto utile, basta aggiungere le funzioni
    pos(), che ritorna la prima sottostriga trovata da una stringa più lunga, e
    stringreplace(), che sostituisce una (o tutte) le occorrenze di una stringa (un trova-e-sostituisci in pratica)
    edit: lowercase(), per fare ricerche case insensitive (sono pigro e ricordare come sono i tag è troppo faticoso)

    Basta, non serve nulla di più sia per generare le fatture, sia per parsarle.

    Nota di servizio: attenzione, il parsing NON è efficiente, in termini computazionali.
    Spesso vedrete degli orrori tipo scansioni multiple del testo, mentre basterebbe una singola passata.

    Qui potrei fare il pippone sull'equivalente automa a stati finiti, ma lo risparmio.

    Più in concreto la velocità di elaborazione di una CPU moderna è così fantasticamente alta, rispetto alla dimensione di una FEL che spazia da pochi KB a qualche MB, che i tempi sono irrilevanti.

    Ecco perchè si vedrà come, per mantenere semplice il sorgente, quindi sotto controllo la porzione logica, si fanno "porcherie".

    Un po' come un calcolo ricorsivo: inefficiente, ma "semplice" (nel sorgente).

    Spero si capisca, sennò pazienza.
  • Re: Fatturazione elettronica B2B: BTS secondo me

    Come sono fatti gli XML?
    Bene, penso sia cosa comune, comunque vediamo dal punto di vista del basso livello, cioè delle stringhe
    (NOTA: in realtà c'è un problema dovuto ai tag fantasma, ma lo vedremo)
    <?xml version="1.0" encoding="iso-8859-1"?>
    <?xml-stylesheet type="text/xsl" href="fatturaordinaria_v1.2.1.xsl"?>
    <p:FatturaElettronica versione="FPR12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:p="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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">
    <FatturaElettronicaHeader>
    	<DatiTrasmissione>
    		<IdTrasmittente>
    			<IdPaese>IT</IdPaese>
    			<IdCodice>CCCFFF12T34</IdCodice>
    		</IdTrasmittente>
    		<ProgressivoInvio>a000i</ProgressivoInvio>
    		<FormatoTrasmissione>FPR12</FormatoTrasmissione>
    		<CodiceDestinatario>0000000</CodiceDestinatario>
    		<ContattiTrasmittente>
    			<Telefono>33933333333</Telefono>
    			<Email>bo@tin.it</Email>
    		</ContattiTrasmittente>
    		<PECDestinatario>bisognalavorare@pec.it</PECDestinatario>
    	</DatiTrasmissione>
    	<CedentePrestatore>
    		<DatiAnagrafici>
    			<IdFiscaleIVA>
    				<IdPaese>IT</IdPaese>
    				<IdCodice>039039039039</IdCodice>
    			</IdFiscaleIVA>
    			<CodiceFiscale>XXXXXXXXXXX</CodiceFiscale>
    			<Anagrafica>
    				<Nome>Pippo</Nome>
    				<Cognome>Baudo</Cognome>
    			</Anagrafica>
    			<RegimeFiscale>RF01</RegimeFiscale>
    		</DatiAnagrafici>
    		<Sede>
    			<Indirizzo>Via Roma 1</Indirizzo>
    			<CAP>12345</CAP>
    			<Comune>Bologna</Comune>
    			<Provincia>BO</Provincia>
    			<Nazione>IT</Nazione>
    		</Sede>
    	</CedentePrestatore>
    
  • Re: Fatturazione elettronica B2B: BTS secondo me

    Cosa vedo? Ovviamente che ho dei tag di apertura, e di chiusura, innestati.
    
    (...)
     <Sede>
             <Indirizzo>Via Roma 1</Indirizzo>
             <CAP>12345</CAP>
             <Comune>Bologna</Comune>
             <Provincia>BO</Provincia>
             <Nazione>IT</Nazione>
          </Sede>
    (...)
    Benissimo, come "smontare" questo frammento di esempio?
    (1) cercherò <sede> nel testo.
    memorizzerò l'indirizzo in cui c'è questo tag (cioè vedrò la stringa come un vettore di caratteri, magari al carattere 783 inizia la '<', al 784 c'è 'e', al 785 ci sarà 'd' e così via).
    tipicamente lo chiamerò inizio (!!!).
    poi cercherò il tag di chiusura (</sede>) e lo chiamerò fine.

    Un paio di osservazioni:
    (1) XML deve essere ben composto. Ma noi sappiamo esserlo (sennò ade lo fanculizza).
    (2) devo porre attenzione a far partire la ricerca del tag di chiusura da inizio. potrebbero essercene (e in generale ci sono) tanti tag diversi, ripetuti.
    (3) devo considerare la possibilità che il tag di apertura sia <sede qualche idiota ci scrive dopo>

    a questo punto farò un ciclo del tipo
    
     s:='';
     for i:=inizio to fine do
        s:=s+ilmiofile[i];
    
    Ora nella variabile stringa s avrò proprio tutto quello che parte da <sede> e arriva a </sede>.
    Che farò poi? Non è difficile intuirlo, rifarò il procedimento per "spacchettare" i singoli tag all'interno del blocco.

    Come?
    A mano (se non sono ripetuti), con un'opportuna automazione (se lo sono).
  • Re: Fatturazione elettronica B2B: BTS secondo me

    Esempio:
    sl è la tstringlist, quindi sl.text è l'intero file XML visto come una stringa.
    datitrasmissione è una stringa, la funzione g_xml_prenditag() è quella sopra descritta [magari la posto]
    
       datitrasmissione:=g_xml_prenditag(sl.text,'DatiTrasmissione');
       datitrasmittente:=g_xml_prenditag(datitrasmissione,'IdTrasmittente');
    
    Bene, ma sono pigro, non ho voglia certo di indicare ogni singolo tag (in realtà inizialmente stavo facendo un parser che creava il codice dal file XLS agenzia entrate. in pratica passava da Excel a codice pascal. poi mi son reso conto che nessuno me lo pagava, ed ho lasciato stare. comunque non è impossibile).

    bene, siccome ci sono blocchi omogenei (sedi,anagrafiche etc), cosa meglio di funzioni del tipo
      
      fillaidfiscale(datianagrafici,'terzo_datianagrafici_idfiscaleiva');
      filladenominazione(datianagrafici,'terzo_datianagrafici_anagrafica');
    
    Cosa sono? Banalmente l'uso di funzioni scritte bottom-UP
    procedure filladenominazione(i_stringa:string;i_sezione:string);
    begin
       fillaQualcosa(i_stringa,'denominazione;nome;cognome;titolo;codeori',i_sezione);
    end;
    
    Questa è una funzione che prende, da una stringa, tanti bei tag (che sono indicati nell'elenco).

    Il funzionamento è abbastanza banale, prima c'è una sorta di "explode" PHP (per trasformare la stringa dei parametri in un vettore di parametri).
    E' molto triste, ma funziona su tutte le versioni di Delphi (senza comandi evoluti)
    
    
    procedure fillaQualcosa(i_stringa:string;i_campi:string;i_sezione:string);
    /// campi con ;
    var
       internos:string;
       internolista:TStringList;
       internoi:integer;
       begin
         {$ifndef debug}
           if i_stringa='' then exit;
           if i_sezione='' then exit;
           if i_campi='' then exit;
         {$endif}
         
           internolista:=tstringlist.Create;
           try
               internolista.Delimiter := ';';
               internolista.QuoteChar := #0;
               g_SplitDelimitedText(i_campi, internolista);/// qui si fa una sorta di Explode PHP
               for internoi:=0 to internolista.count-1 do
               begin
                   internos:=g_xml_prenditag(i_stringa,internolista.strings[internoi]);
                   internos:=g_htmltoplain(internos);
                   aggiornaRecord(i_dataset,i_sezione+'_'+internolista.strings[internoi],internos);
               end;
           finally
           internolista.Free;
           end;
       end;
    Come si vede c'è il mitico prenditag, una funzione per togliere la mondezza html, ed infine una funzione che scrive nel dataset (database) un certo campo, con un certo valore.
  • Re: Fatturazione elettronica B2B: BTS secondo me

    Io adoro le TStringList e le uso per mille cose (seguite dalle TStringGrid).
    Però per il parsing (e anche la creazione) dello XML ho usato TXMLDocument (che si appoggia al componente nativo COM di M$): lo reputi inadeguato, buggato o solo non ti ispira?
    Per la generazione, una volta capito, mi è parso semplice e lineare.
    Per la decodifica e ricerca dei tag è più macchinoso e ho dei dubbi in effetti.
    Grazie
    Nicola

    PS: dal xls mi sono generato almeno delle linee di commento per guidarmi nella scrittura del codice:
    //1.2.5          <0.1>  <Contatti>
        Node3 := Node2.AddChild('Contatti', '');
    //1.2.5.1        <0.1>  <Telefono>  xs:normalizedString 5 … 12
        if Darc.TAziendaTelefono.Value <> '' then begin
          Node4 := Node3.AddChild('Telefono', '');
          Node4.Text := Copy(Darc.TAziendaTelefono.Value, 1, 12);
        end;
    
  • Re: Fatturazione elettronica B2B: BTS secondo me

    nicolap ha scritto:


    Però per il parsing (e anche la creazione) dello XML ho usato TXMLDocument (che si appoggia al componente nativo COM di M$): lo reputi inadeguato, buggato o solo non ti ispira?
    (1) è roba M$, quindi evitata se possibile
    (2) introduce delle dipendenze, evitarle se possibile
    (3) soprattutto non so come funziona. se conosco ogni singolo byte scritto (o in questo caso letto) so esattamente cosa, come e perchè succede qualcosa.
    risparmio ore in debug.

    Le funzioni sono tipo queste (in realtà ho tolto dei pezzi, spero funzionino)

    QUESTA E' LA VERSIONE "DIDATTICA", perchè non controlla fine > inizio.
    In realtà prima "distrugge" tutta la parte iniziale (fino a inizio), poi fa il secondo pos().
    Non adotto la tecnica di prendere da inizio fino alla fine del file, perchè tipicamente poi c'è l'allegato
    (che è enormemente più grande della porzione XML).
    Vabbè facciamo finta di non volerci complicare la vita coi dettagli da informatico
    function g_pigliatestoi(i_stringa:string;i_inizio:string;i_fine:string):string;
    var
       inizio:integer;
       fine:integer;
       i:integer;
       lowercasei_stringa:string;
       lowercasei_inizio:string;
    begin
       Result:='';
       if i_stringa='' then Exit;
       if i_inizio='' then Exit;
       if i_fine='' then Exit;
    
       lowercasei_stringa:=LowerCase(i_stringa);
       lowercasei_inizio:=lowercase(i_inizio);
    
       inizio:=Pos(lowercasei_inizio,LowerCasei_stringa);
       if inizio>0 then
       begin
           fine:=Pos(LowerCase(i_fine),LowerCasei_stringa);
           if fine>0 then
               for i:=inizio+length(lowercasei_inizio) to fine-1 do
                   result:=result+i_stringa[i];
       end;
    end;
    
    function g_xml_prenditag(i_stringa:string;i_nometag:string):string;
    begin
       Result:='';
    
       if i_stringa='' then Exit;
       if i_nometag='' then Exit;
    
       Result:=g_pigliatestoi(i_stringa,'<'+i_nometag+'>','</'+i_nometag+'>');
    /// in realtà è un doppione, ma mi piace per il debug. notare che c'è uno spazio aggiunto
       if result='' then
           Result:=g_pigliatestoi(i_stringa,'<'+i_nometag+' ','</'+i_nometag+'>');
    
    end;
    
  • Re: Fatturazione elettronica B2B: BTS secondo me

    Concordo con m2+,

    anche io ho preferito lavorare direttamente sulle stringhe, per aver un controllo assoluto del file. Anche perchè con COBOL ci sta poco o niente circa la gestione degli Xml.
Devi accedere o registrarti per scrivere nel forum
7 risposte