Costruzione, validazione e serializzazione fatture elettroniche FatturaPA.
Builder fluent per la costruzione di fatture.
import { FatturaBuilder } from '@fatturazione-elettronica-aruba/xml-builder';
const builder = FatturaBuilder.create();
Crea una nuova istanza del builder.
const builder = FatturaBuilder.create();
Imposta la versione dello schema (default: '1.2.2').
builder.setVersione('1.2.2');
Imposta i dati di trasmissione completi.
builder.setDatiTrasmissione({
idTrasmittente: { idPaese: 'IT', idCodice: '01234567890' },
progressivoInvio: '00001',
formatoTrasmissione: 'FPR12',
codiceDestinatario: 'ABC1234',
pecDestinatario?: string,
contattiTrasmittente?: { telefono?: string, email?: string },
});
Helper per trasmissione B2B (formato FPR12).
builder.setTrasmissioneB2B({
idPaese: string;
idCodice: string;
progressivoInvio: string;
codiceDestinatario?: string; // Default: '0000000'
pecDestinatario?: string;
});
Helper per trasmissione PA (formato FPA12).
builder.setTrasmissionePA({
idPaese: string;
idCodice: string;
progressivoInvio: string;
codiceDestinatario: string; // Codice IPA 6 caratteri
});
Imposta il cedente/prestatore (venditore).
builder.setCedentePrestatore({
datiAnagrafici: {
idFiscaleIVA?: { idPaese: string, idCodice: string },
codiceFiscale?: string,
anagrafica: { denominazione?: string, nome?: string, cognome?: string },
regimeFiscale: RegimeFiscale,
},
sede: Indirizzo,
stabileOrganizzazione?: Indirizzo,
iscrizioneREA?: IscrizioneREA,
contatti?: Contatti,
riferimentoAmministrazione?: string,
});
Imposta il cessionario/committente (acquirente).
builder.setCessionarioCommittente({
datiAnagrafici: {
idFiscaleIVA?: { idPaese: string, idCodice: string },
codiceFiscale?: string,
anagrafica: { denominazione?: string, nome?: string, cognome?: string },
},
sede: Indirizzo,
stabileOrganizzazione?: Indirizzo,
rappresentanteFiscale?: RappresentanteFiscale,
});
Imposta i dati generali del documento.
builder.setDatiGenerali({
datiGeneraliDocumento: {
tipoDocumento: TipoDocumento,
divisa: string, // Es: 'EUR'
data: string, // YYYY-MM-DD
numero: string,
importoTotaleDocumento?: number,
causale?: string[],
datiRitenuta?: DatiRitenuta,
datiBollo?: DatiBollo,
},
datiOrdineAcquisto?: DatiDocumentoCorrelato[],
datiContratto?: DatiDocumentoCorrelato[],
datiDDT?: DatiDDT[],
});
Imposta le linee di dettaglio e riepilogo IVA.
builder.setDatiBeniServizi({
dettaglioLinee: [
{
numeroLinea: number,
descrizione: string,
quantita?: number,
unitaMisura?: string,
prezzoUnitario: number,
prezzoTotale: number,
aliquotaIVA: number,
natura?: Natura,
scontoMaggiorazione?: ScontoMaggiorazione[],
},
],
datiRiepilogo: [
{
aliquotaIVA: number,
imponibileImporto: number,
imposta: number,
natura?: Natura,
esigibilitaIVA?: 'I' | 'D' | 'S',
riferimentoNormativo?: string,
},
],
});
Aggiunge una singola linea di dettaglio. numeroLinea (progressivo) e
prezzoTotale (prezzoUnitario × quantita, con sconti applicati) sono calcolati
se omessi. DatiRiepilogo e ImportoTotaleDocumento vengono calcolati in build().
builder.addLinea({
descrizione: string,
quantita?: number,
unitaMisura?: string,
prezzoUnitario: number,
aliquotaIVA: number,
natura?: Natura,
scontoMaggiorazione?: ScontoMaggiorazione[],
numeroLinea?: number, // opzionale, auto-assegnato
prezzoTotale?: number, // opzionale, auto-calcolato
});
Imposta tutte le linee in un colpo solo (sostituisce quelle già aggiunte). Stesso auto-calcolo di addLinea.
builder.setDettaglioLinee([
{ descrizione: 'Articolo A', quantita: 2, prezzoUnitario: 50, aliquotaIVA: 22 },
{ descrizione: 'Articolo B', quantita: 1, prezzoUnitario: 100, aliquotaIVA: 10 },
]);
Imposta l'EsigibilitaIVA di default ('I' | 'D' | 'S', default 'I') applicata
ai DatiRiepilogo calcolati automaticamente. Non applicata ai gruppi con Natura.
builder.setEsigibilitaIVA('S'); // split payment
Aggiunge dati di pagamento.
builder.addDatiPagamento({
condizioniPagamento: 'TP01' | 'TP02' | 'TP03',
dettaglioPagamento: [
{
modalitaPagamento: ModalitaPagamento,
importoPagamento: number,
dataScadenzaPagamento?: string,
iban?: string,
istitutoFinanziario?: string,
},
],
});
Finalizza il body corrente e inizia uno nuovo (per fatture lotto).
builder
.setDatiGenerali({ ... })
.setDatiBeniServizi({ ... })
.newBody()
.setDatiGenerali({ ... }) // Nuova fattura
.setDatiBeniServizi({ ... });
Costruisce la fattura elettronica. Ripetibile: non muta lo stato del builder.
const fattura: FatturaElettronica = builder.build();
Costruisce e valida in un'unica chiamata, restituendo un ValidationResult.
const result = builder.validate({ strict: true });
Costruisce e serializza in XML FatturaPA in un'unica chiamata.
const xml = builder.toXml({ includeSchemaLocation: true });
Costruisce, valida e serializza in un'unica chiamata, restituendo anche il nome file SDI.
const { fattura, xml, validazione, filename } = builder.toResult({
validation?: ValidationOptions,
serializer?: FatturaSerializerOptions,
});
// filename: '<IdPaese><IdCodice>_<Progressivo>.xml'
Resetta il builder allo stato iniziale.
builder.reset();
Validatore per fatture elettroniche.
import { FatturaValidator, validateFattura } from '@fatturazione-elettronica-aruba/xml-builder';
// Istanza
const validator = new FatturaValidator(options);
const result = validator.validate(fattura);
// Helper
const result = validateFattura(fattura, options);
interface ValidationOptions {
validateTotals?: boolean; // Default: true
validateCodiceFiscale?: boolean; // Default: true
validatePartitaIVA?: boolean; // Default: true
validateDates?: boolean; // Default: true
strict?: boolean; // Default: false
}
interface ValidationResult {
valid: boolean;
errors: ValidationError[];
warnings: ValidationError[];
}
interface ValidationError {
path: string;
message: string;
code: string;
}
Serializza fatture in XML.
import { FatturaSerializer } from '@fatturazione-elettronica-aruba/xml-builder';
const serializer = new FatturaSerializer({
includeSchemaLocation?: boolean, // Default: true
});
const xml = serializer.serialize(fattura);
number passati dove sono attese
stringhe (es. P.IVA dal database) vengono serializzati senza errori. Quantita
mantiene 2–8 decimali (es. 0.001), prezzi/aliquote usano 2 decimali.Helper puri esportati dal package. Utili per mappare i dati di dominio senza re-implementare la logica IVA/totali o gli oggetti anagrafici annidati.
Calcola i DatiRiepilogo (raggruppati per aliquotaIVA + natura) e
l'importoTotaleDocumento dalle linee, con arrotondamenti corretti (regole SDI).
const { datiRiepilogo, importoTotaleDocumento } = calcolaRiepilogo(linee, {
esigibilitaIVA: 'I', // default; non applicata ai gruppi con Natura
});
Calcola il PrezzoTotale di una linea (= prezzoUnitario × quantita, con
sconti/maggiorazioni applicati), arrotondato a 2 decimali.
calcolaPrezzoTotale(75, 40); // 3000
calcolaPrezzoTotale(100, 1, [{ tipo: 'SC', percentuale: 10 }]); // 90
toNumber converte number | string | null | undefined in number (i numerici dei
DB arrivano spesso come stringa). round2 arrotonda a 2 decimali evitando errori di floating point.
toNumber('12.50'); // 12.5
round2(1.005); // 1.01
Costruiscono CedentePrestatore / CessionarioCommittente da campi piatti, con
coercizione a stringa e IdFiscaleIVA/CodiceFiscale/contatti opzionali.
const cedente = cedentePrestatore({
piva: '01234567890', codiceFiscale, denominazione: 'Azienda SRL',
regimeFiscale: 'RF01', // default 'RF01'
indirizzo, cap, comune, provincia, nazione, // nazione default 'IT'
telefono, email,
});
const cliente = cessionario({
piva, codiceFiscale, // entrambi opzionali
denominazione, indirizzo, cap, comune, provincia,
});
sede costruisce un Indirizzo (default nazione: 'IT'); contatti costruisce un
blocco Contatti oppure ritorna undefined se tutti i campi sono vuoti.
Costruisce il nome file SDI <IdPaese><IdCodice>_<Progressivo>.xml (progressivo
completato a 5 caratteri con zeri a sinistra).
nomeFileSdi('IT', '01234567890', '1'); // 'IT01234567890_00001.xml'
type TipoDocumento =
| 'TD01' | 'TD02' | 'TD03' | 'TD04' | 'TD05' | 'TD06'
| 'TD07' | 'TD08' | 'TD09' | 'TD10' | 'TD11' | 'TD12'
| 'TD16' | 'TD17' | 'TD18' | 'TD19' | 'TD20' | 'TD21'
| 'TD22' | 'TD23' | 'TD24' | 'TD25' | 'TD26' | 'TD27' | 'TD28';
type RegimeFiscale =
| 'RF01' | 'RF02' | 'RF04' | 'RF05' | 'RF06' | 'RF07'
| 'RF08' | 'RF09' | 'RF10' | 'RF11' | 'RF12' | 'RF13'
| 'RF14' | 'RF15' | 'RF16' | 'RF17' | 'RF18' | 'RF19';
type Natura =
| 'N1' | 'N2' | 'N2.1' | 'N2.2'
| 'N3' | 'N3.1' | 'N3.2' | 'N3.3' | 'N3.4' | 'N3.5' | 'N3.6'
| 'N4' | 'N5' | 'N6' | 'N6.1' | 'N6.2' | 'N6.3' | 'N6.4'
| 'N6.5' | 'N6.6' | 'N6.7' | 'N6.8' | 'N6.9' | 'N7';
type ModalitaPagamento =
| 'MP01' | 'MP02' | 'MP03' | 'MP04' | 'MP05'
| 'MP06' | 'MP07' | 'MP08' | 'MP09' | 'MP10'
| 'MP11' | 'MP12' | 'MP13' | 'MP14' | 'MP15'
| 'MP16' | 'MP17' | 'MP18' | 'MP19' | 'MP20'
| 'MP21' | 'MP22' | 'MP23';
interface Indirizzo {
indirizzo: string;
numeroCivico?: string;
cap: string;
comune: string;
provincia?: string;
nazione: string;
}