Come usare tutti i progressivi nel nome file della fattura elettronica con una codifica base 36 in VBA

La data del 1 gennaio 2019 si avvicina e nell’affrontare la conversione dei programmi gestionali alla funzionalità di emissione della fattura elettronica in formato XML tra privati e verso la PA, un problema è costituito dalla esigua dimensione del codice progressivo per numerare il file XML prodotto per ogni fattura emessa e stabilito dalle specifiche fornite sull’apposito sito curato dall’Agenzia delle Entrate, in modo che il nome del file XML (non ancora firmato digitalmente) sia del tipo IT01234567890_FPR02.xml e cioè:

Codice PaeseIdentificativo fiscale univoco del Trasmittente _ Progressivo univoco del file.xml

Vediamo allora in dettaglio le specifiche (ed ho aggiunto i commenti in coda ad ogni punto), dove si indica che:

  1. il Codice Paese va espresso secondo lo standard ISO 3166-1 alpha-2 code (per l’Italia è “IT”)
  2. l’Identificativo univoco del Trasmittente, sia esso persona fisica o soggetto giuridico, è rappresentato dal suo identificativo fiscale (codice fiscale nel caso di soggetto trasmittente residente in Italia, identificativo proprio del Paese di appartenenza nel caso di soggetto trasmittente residente all’estero). La lunghezza di questo identificativo è di:
    • 11 caratteri (minimo) e 16 caratteri (massimo) nel caso di codice paese IT,
    • 2 caratteri (minimo) e 28 caratteri (massimo) altrimenti (per i trasmittenti di paesi esteri),
  3. il progressivo univoco del file è rappresentato da una stringa alfanumerica di lunghezza massima di 5 caratteri e con valori ammessi da “A” a “Z” e da “0” a “9”. (Cosa sarebbe costato, di fronte alla prospettiva di ricevere milioni di fatture ogni mese, permettere un progressivo, che ne so, a 9 cifre? Niente!)
  4. l’estensione del file, pari a .XML (aggiunto per chiarezza)
  5. Ogni file inviato al Sistema di Interscambio deve avere un nome diverso da qualsiasi altro file inviato in precedenza (chiaro e tondo; se ad es. il file della fattura n. 5 venisse poi scartato dallo SdI, il nuovo file della fattura n. 5 corretta dovrà avere, comunque, un progressivo successivo!).

L’evidenza posta sul punto 3, ciò sul progressivo univoco del file sta proprio ad indicare che, essendo un progressivo di massimo 5 caratteri, una applicazione riduttiva della numerazione basata solo sulle cifre da 0 a 9 permetterà di denominare i file delle fatture da 00000 fino a 99999, consentendo cioè di generare un progressivo che arriverà solo a 100.000 (centomila) fatture. Qualche azienda dirà :”Magari! E chi ci arriverà a fare così tante fatture?” Ma in generale, col passare degli anni, specialmente con attività nel settore B2C rivolte a tantissimi privati (e nell’e-Commerce, nel dettaglio, nei carburanti, ecc. i clienti sono sempre molti e quasi sempre diversi) 100.000 progressivi potrebbero essere pochi!

Inoltre, per ogni fattura “scartata” dallo SdI (il Sistema di Interscambio a cui vanno inviate tutte le fatture elettroniche) qualunque sia il motivo di errore, come specificato dalle specifiche tecniche alla pagina di documentazione sullo SdI, il progressivo del nome del file non si deve ripetere mai ed andrà quindi inviata una fattura corretta, con lo stesso numero progressivo del registro fatture interno ma con un nuovo progressivo sul nome del file, pena un ulteriore scarto!

E nel caso delle grandi aziende di telefonia, televisive, delle cosiddette “utilities” di acqua, luce e gas, o di commercio elettronico potrebbero essere pochi anche alcuni milioni di progressivi! Andando ad esempio a guardare la pagina del profilo aziendale della TIM si indicano, per la telefonia fissa e mobile:

  • 32 milioni di linee mobili (qui però molti di più saranno i prepagati, rispetto agli abbonamenti)
  • 19,2 milioni di accessi fissi (e qui la fatturazione mensile produrrà un gran volume di fatture)

Come fare quindi per utilizzare anche le altre 26 lettere disponibili dalla A alla Z nell’alfabeto “informatico”, che sono tutte le 26 lettere dell’alfabeto inglese, per cui la lista è: “0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ” ? Il modo c’è e si potrà agevolmente arrivare un poco oltre i 60.000.000 di fatture!

La soluzione è quella di avere un codice progressivo in base a tutti e 36 i caratteri alfanumerici: 10 cifre e 26 lettere ma, per una pratica gestione dei progressivi interni ad un database, sarebbe agevole memorizzare un progressivo solo numerico di tipo Long da convertire, al momento di salvare il file della fattura elettronica a clienti da inviare in XML, nel corrispondente formato alfanumerico in base 36.

Per questo ho unito i risultati di una ricerca sul web e di un mio lavoro di programmazione per ottenere la coppia funzioni necessarie; il risultato è stato che per la codifica c’è molto buon codice disponibile (quindi il sottostante è pressoché identico ai molti esempi disponibili sul web), mentre per la decodifica ho sviluppato la funzione personalmente.

Quindi, nel leggere il progressivo interno al database dell’ultima fattura emessa, dobbiamo incrementarlo di 1 e poi chiamare la funzione per codificarlo nel formato a base 36 caratteri alfanumerici, quindi la funzione di codifica da numerico a base 36 è:


Function fBase36Encode(ByRef lngNumToConvert As Long) As String
'Converte numeri positivi interi in stringhe Base36 0..9A..Z
'Funzione applicabile fino ad ottenere stringhe da 5 caratteri alfanumerci (es. "AA3ER")
Dim strAlphabet As String
strAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
If lngNumToConvert = 0 Then
   fBase36Encode = "0"
   Exit Function
End If
fBase36Encode = vbNullString
Do While lngNumToConvert <> 0
   fBase36Encode = Mid(strAlphabet, lngNumToConvert Mod 36 + 1, 1) & fBase36Encode
   lngNumToConvert = lngNumToConvert \ 36
Loop
End Function

La corrispondente funzione di decodifica da base 36 a numerico è:

Function fBase36Decode(ByRef StringToConvert As String) As Long
' Converte stringhe base-36 0..9A..Z in numeri positivi interi
' Prende i caratteri nelle 5 posizioni della stringa fornita
' e per ognuno ne fa la ricerca nella stringa base-36: strAlphabet
' moltiplicando per il multiplo alla N-esima potenza di 36 e sommando di volta in volta il tutto
Dim strAlphabet As String
strAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Const Moltiplicatore1 As Long = 36 '=36^1
Const Moltiplicatore2 As Long = 1296 '=36^2
Const Moltiplicatore3 As Long = 46656 '=36^3
Const Moltiplicatore4 As Long = 1679616 '=36^4
Const Moltiplicatore5 As Long = 60466176 '=36^5
If IsNull(StringToConvert) OR  StringToConvert = "" Then
   fBase36Decode = 0
   Exit Function
End If
Select Case Len(StringToConvert)
Case 1
   fBase36Decode = InStr(1, strAlphabet, StringToConvert) - 1
Case 2
   fBase36Decode = (InStr(1, strAlphabet, Left(StringToConvert, 1)) - 1) * Moltiplicatore1 + InStr(1, strAlphabet, Mid(StringToConvert, 2, 1)) - 1
Case 3
   fBase36Decode = (InStr(1, strAlphabet, Left(StringToConvert, 1)) - 1) * Moltiplicatore2 + (InStr(1, strAlphabet, Mid(StringToConvert, 2, 1)) - 1) * Moltiplicatore1 + InStr(1, strAlphabet, Mid(StringToConvert, 3, 1)) - 1
Case 4
   fBase36Decode = (InStr(1, strAlphabet, Left(StringToConvert, 1)) - 1) * Moltiplicatore3 + (InStr(1, strAlphabet, Mid(StringToConvert, 2, 1)) - 1) * Moltiplicatore2 + (InStr(1, strAlphabet, Mid(StringToConvert, 3, 1)) - 1) * Moltiplicatore1 + InStr(1, strAlphabet, Mid(StringToConvert, 4, 1)) - 1
Case 5
   fBase36Decode = (InStr(1, strAlphabet, Left(StringToConvert, 1)) - 1) * Moltiplicatore4 + (InStr(1, strAlphabet, Mid(StringToConvert, 2, 1)) - 1) * Moltiplicatore3 + (InStr(1, strAlphabet, Mid(StringToConvert, 3, 1)) - 1) * Moltiplicatore2 + (InStr(1, strAlphabet, Mid(StringToConvert, 4, 1)) - 1) * Moltiplicatore1 + InStr(1, strAlphabet, Mid(StringToConvert, 5, 1)) - 1
Case Else
   fBase36Decode = 0
End Select
End Function

Tale funzione di decodifica può essere necessaria durante la lettura di un file XML di fattura elettronica, dal quale si voglia conoscere il progressivo raggiunto ma che, per via della codifica alfanumerica, non è evidente “ad occhio nudo” ed occorrerà avvalersi proprio di questa funzione, che spero sia interessante.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *