https://github.com/taocomp/php-e-invoice-it
A PHP package for managing italian e-invoice and notice XML formats. (Pacchetto PHP per gestire il formato XML di fatture e notifiche come richiesto dal SdI).
https://github.com/taocomp/php-e-invoice-it
e-invoice einvoice fattura fattura-elettronica fattura-pa fatturazione-elettronica invoice italy open-source opensource php xml
Last synced: 4 months ago
JSON representation
A PHP package for managing italian e-invoice and notice XML formats. (Pacchetto PHP per gestire il formato XML di fatture e notifiche come richiesto dal SdI).
- Host: GitHub
- URL: https://github.com/taocomp/php-e-invoice-it
- Owner: taocomp
- License: gpl-3.0
- Created: 2018-12-16T08:56:41.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2022-06-06T20:28:03.000Z (almost 4 years ago)
- Last Synced: 2025-09-23T22:39:45.756Z (7 months ago)
- Topics: e-invoice, einvoice, fattura, fattura-elettronica, fattura-pa, fatturazione-elettronica, invoice, italy, open-source, opensource, php, xml
- Language: PHP
- Homepage:
- Size: 1.35 MB
- Stars: 75
- Watchers: 13
- Forks: 22
- Open Issues: 9
-
Metadata Files:
- Readme: README.it.org
- License: LICENSE
Awesome Lists containing this project
README
* Installazione
** Composer
~composer require taocomp/php-e-invoice-it~
** Manualmente
- Clonare o scaricare il repository
- ~require_once('/path/to/php-e-invoice-it/vendor/autoload.php');~
* Setup
Se utilizzate ~composer~, avrete già incluso il file ~vendor/autoload.php~ nel vostro codice.
Se avete clonato/scaricato il repository:
#+BEGIN_SRC
require_once('/path/to/php-e-invoice-it/vendor/autoload.php');
#+END_SRC
In entrambi i casi, per utilizzare la classe ~FatturaElettronica~:
#+BEGIN_SRC
use Taocomp\Einvoicing\FatturaElettronica;
#+END_SRC
Per utilizzare la classe ~EsitoCommittente~:
#+BEGIN_SRC
use Taocomp\Einvoicing\EsitoCommittente;
#+END_SRC
* Nuova fattura/notifica
Fattura FPA:
#+BEGIN_SRC
$invoice = new FatturaElettronica('FPA12');
#+END_SRC
Fattura FPR:
#+BEGIN_SRC
$invoice = new FatturaElettronica('FPR12');
#+END_SRC
Notifica EsitoCommittente:
#+BEGIN_SRC
$notice = new EsitoCommittente();
#+END_SRC
* Caricamento di una fattura/notifica esistente
#+BEGIN_SRC
$invoice = new FatturaElettronica('/path/to/invoice.xml');
#+END_SRC
Oppure:
#+BEGIN_SRC
$invoice = new FatturaElettronica('FPR12');
$invoice->load('/path/to/invoice.xml');
#+END_SRC
* Individuare gli elementi
In generale, per individuare gli elementi che si vogliono leggere o modificare all'interno dell'XML sono necessari:
- il nome o path dell'elemento che si vuole leggere o modificare
- (opzionale) un nodo /context/ a cui appartiene l'elemento (stringa o ~\DOMNode~)
La sintassi da utilizzare è quella XPath, con le seguenti facilitazioni.
** Path assoluto
Se il path è assoluto (comincia con ~/~), esso è in realtà relativo al nodo root del documento. Nel caso di una fattura elettronica:
#+BEGIN_SRC
$this->getValue('/FatturaElettronicaHeader/DatiTrasmissione/CodiceDestinatario');
#+END_SRC
è equivalente a una query effettuata con ~\DOMXPath~ per
#+BEGIN_SRC
/p:FatturaElettronica/FatturaElettronicaHeader/DatiTrasmissione/CodiceDestinatario
#+END_SRC
Un path assoluto non può avere /context/.
** Path relativo
A un path relativo viene sempre anteposto ~//~:
#+BEGIN_CENTER
"Selects nodes in the document from the current node that match the selection no matter where they are". ([[https://www.w3schools.com/xml/xpath_syntax.asp][XPath Syntax]])
#+END_CENTER
Se è presente un /context/, viene anteposto ~.//~. Il punto specifica che si intende partire dal nodo /context/.
È possibile anche specificare predicati XPath, ad esempio
#+BEGIN_SRC
$invoice->getValue('DettaglioLinee[2]/NumeroLinea');
#+END_SRC
leggerà il valore di ~NumeroLinea~ del secondo blocco ~DettaglioLinee~. La numerazione parte da 1 e non da 0, come da sintassi XPath.
** Tag
Se viene fornito solo il nome dell'elemento (non sono presenti ~/~), vengono seguite le stesse regole dei path relativi. Ad esempio per selezionare ~ModalitaPagamento~:
#+BEGIN_SRC
$invoice->getValue('ModalitaPagamento');
#+END_SRC
Con un /context/:
#+BEGIN_SRC
$invoice->getValue('NumItem', 'DatiContratto');
#+END_SRC
* Leggere/modificare i valori
** ~getValue( string $expr, $context = null )~
Restituisce il valore dell'elemento individuato da ~$expr/$context~, se ~$expr/$context~ restituisce un elemento univoco, altrimenti genera un'eccezione.
Esempi validi:
#+BEGIN_SRC
$invoice->getValue('ProgressivoInvio');
$invoice->getValue('Sede/Indirizzo', 'CedentePrestatore');
#+END_SRC
Esempi non validi:
#+BEGIN_SRC
$invoice->getValue('IdPaese');
$invoice->getValue('Sede/Indirizzo', 'FatturaElettronicaHeader');
#+END_SRC
Come detto, ~$context~ può essere un oggetto ~\DOMNode~.
** ~setValue( string $expr, $value, $context = null )~
Setta il valore ~$value~ per l'elemento individuato da ~$expr/$context~, se ~$expr/$context~ restituisce un elemento univoco, altrimenti genera un'eccezione.
** ~setValueToAll( string $expr, $value, $context = null )~
Setta il valore ~$value~ per tutti gli elementi individuati da ~$expr/$context~.
** ~setValues( $context, array $array )~
Per ogni coppia chiave/valore ~$k/$v~ dell'array, setta il valore ~$v~ per l'elemento individuato da ~$k/$context~, se ~$k/$context~ restituisce un elemento univoco, altrimenti genera un'eccezione.
Esempio:
#+BEGIN_SRC
$invoice->setValues('CessionarioCommittente', array(
'CodiceFiscale' => '02313821007',
'Anagrafica/Denominazione' => 'AMMINISTRAZIONE',
));
#+END_SRC
** ~setValuesToAll( $context, array $array )~
Per ogni coppia chiave/valore ~$k/$v~ dell'array, setta il valore ~$v~ per tutti gli elementi individuati da ~$k/$context~.
** ~setValuesFromArray( $context, array $array )~
Dato un array che rispecchia fedelmente una porzione di struttura XML di un certo nodo ~$context~, setta ricorsivamente i rispettivi valori.
Esempio:
#+BEGIN_SRC
$array = array(
'DatiAnagraficiVettore' => array(
'IdFiscaleIVA' => array(
'IdPaese' => 'IT',
'IdCodice' => '09876543210'
),
'Anagrafica' => array(
'Denominazione' => 'TRASPORTO SRLS'
),
'NumeroLicenzaGuida' => 'AA090909'
),
'MezzoTrasporto' => 'Mezzo',
'CausaleTrasporto' => 'La causale del traporto',
'NumeroColli' => '1',
'Descrizione' => 'La descrizione'
);
$invoice->setValuesFromArray('DatiTrasporto', $array);
#+END_SRC
* Lotto di fatture
** ~addBody( int $n = 1 )~
Aggiunge n ~FatturaElettronicaBody~ alla fattura.
Poiché clona il primo body, verranno clonati anche tutti gli eventuali valori al suo interno.
** ~getBody( int $bodyIndex = 1 )~
Restituisce l'oggetto ~\DOMNode~ relativo all'i-esimo body.
Come da sintassi XPath, l'indice parte da 1.
** ~setBodyCount( int $n )~
Setta il numero complessivo di ~FatturaElettronicaBody~.
Può essere usato alternativamente a ~addBody~.
Ad esempio per creare un lotto di 5 fatture:
#+BEGIN_SRC
$invoice->setBodyCount(5);
// oppure
$invoice->addBody(4);
#+END_SRC
* Più linee di dettaglio
** ~addLineItem( int $n, int $bodyIndex = 1 )~
Aggiunge ~$n~ linee di dettaglio al body ~$bodyIndex~.
Ad esempio per aggiungere 3 linee di dettaglio al secondo body:
#+BEGIN_SRC
$invoice->addLineItem(3, 2);
#+END_SRC
** ~getLineItem( int $i, int $bodyIndex = 1 )~
Restituisce l'oggetto ~\DOMNode~ relativo alla i-esima linea di dettaglio del body ~$bodyIndex~.
** ~setLineItemCount( int $n, int $bodyIndex = 1 )~
Setta il numero complessivo di ~DettaglioLinee~ del body ~$bodyIndex~.
Può essere usato alternativamente a ~addLineItem~.
* Gestione degli elementi XML
Normalmente non c'è bisogno di utilizzare i seguenti metodi per prendere/aggiungere/rimuovere elementi XML come nodi ~\DOMNode~ perché:
- per leggere/settare i valori degli elementi si possono usare i loro nomi o i path, come stringhe
- per aggiungere elementi ~FatturaElettronicaBody~ (lotto di fatture) si possono usare i metodi ~addBody~, ~getBody~ e ~setBodyCount~
- per aggiungere linee di dettaglio si possono usare i metodi ~addLineItem~, ~getLineItem~ e ~setLineItemCount~
In ogni caso a volte può servire aggiungere, rimuovere o prendere un determinato elemento della struttura XML. È possibile farlo con i seguenti metodi.
** ~addElement( $element, $parent, $beforeRef = null )~
Aggiunge un elemento ~$element~ all'interno del nodo genitore ~$parent~. Viene posizionato prima del nodo fratello ~$beforeRef~, se ~$beforeRef~ non è nullo.
** ~addElementsFromArray( $parent, array $array )~
Dato un array che rispecchia fedelmente una porzione di struttura XML di un certo nodo ~parent~, aggiunge ricorsivamente i vari elementi dell'array. Il metodo viene usato nel ~constructor~ per creare l'intera struttura della fattura (e della notifica).
** ~getElement( $expr, $context = null )~
Prende un determinato elemento individuato da ~$expr/$context~, se ~$expr/$context~ restituisce un elemento univoco, altrimenti genera un'eccezione.
** ~removeElement( $element )~
Rimuove l'elemento ~$element~, se univoco. Altrimenti genera un'eccezione.
** ~setElementCount( $expr, int $n, $context = null )~
Imposta la cardinalità di un certo elemento. Ad esempio per avere 3 ~DatiRiepilogo~:
#+BEGIN_SRC
$invoice->setElementCount('DatiRiepilogo', 3);
#+END_SRC
O nel caso di più bodies:
#+BEGIN_SRC
$body2 = $invoice->getBody(2);
$invoice->setElementCount('DatiRiepilogo', 2, $body2);
#+END_SRC
Settaggio valori:
#+BEGIN_SRC
$invoice->setValue('DatiRiepilogo[1]/AliquotaIVA', '22.00', $body2);
$invoice->setValue('DatiRiepilogo[2]/AliquotaIVA', '10.00', $body2);
#+END_SRC
* Altri metodi comuni a fatture e notifiche
** ~getDOM()~
Restituisce l'oggetto ~\DOMDocument~ relativo alla fattura.
** ~normalize()~
Rimuove gli elementi XML vuoti.
Utilizzato in ~asXML()~ e ~save()~, se non esplicitamente disabilitato.
In ~FatturaElettronica~ divide l'elemento ~DatiGeneraliDocumento/Causale~ in più elementi se il valore supera i 200 caratteri (chunks da 200 caratteri ciascuno).
** ~query( string $expr, $context = null, bool $registerNodeNS = true )~
Restituisce una lista di elementi ~\DOMNodeList~ derivante dalla query ~$expr/$context~.
* Visualizzazione dell'XML
Per recuperare la fattura come stringa XML:
#+BEGIN_SRC
$invoice->asXML();
#+END_SRC
Di default gli elementi vuoti vengono eliminati prima di stampare la stringa XML (normalizzazione). Per visualizzarli:
#+BEGIN_SRC
$invoice->asXML(false);
#+END_SRC
* Validazione della fattura
~php-e-invoice-it~ utilizza la libreria [[https://github.com/Slamdunk/php-validatore-fattura-elettronica][Slamdunk/php-validatore-fattura-elettronica]] per la validazione. Se avete installato ~php-e-invoice-it~ con composer ve la ritrovate già, altrimenti dovete scaricarla e includerla manualmente se volete validare le fatture.
Validazione:
#+BEGIN_SRC
$invoice->validate();
#+END_SRC
* Salvataggio su file
** Fattura
Quando si salva una fattura, di default il nome del file è dato da:
#+BEGIN_SRC
IdPaese . IdCodice . _ . ProgressivoInvio . .xml
#+END_SRC
È possibile in ogni caso assegnare un nome arbitrario alla fattura:
#+BEGIN_SRC
$invoice->setFilename('filename');
#+END_SRC
Per settare una directory di destinazione dove salvare la fattura:
#+BEGIN_SRC
$invoice->setPrefixPath('path/to/dir');
#+END_SRC
Per settare una directory di destinazione per tutti gli oggetti ~FatturaElettronica~ che verranno creati:
#+BEGIN_SRC
FatturaElettronica::setDefaultPrefixPath('path/to/dir');
#+END_SRC
Per salvare la fattura:
#+BEGIN_SRC
$invoice->save();
#+END_SRC
Se è già presente un file con lo stesso nome viene generata un'eccezione. Per sovrascrivere il file:
#+BEGIN_SRC
$overwrite = true;
$invoice->save($overwrite);
#+END_SRC
Prima di salvare il file, l'XML viene normalizzato (vengono rimossi gli elementi vuoti). Per disabilitare la normalizzazione:
#+BEGIN_SRC
$overwrite = false;
$normalize = false;
$invoice->save($overwrite, $normalize);
#+END_SRC
Getters:
#+BEGIN_SRC
FatturaElettronica::getDefaultPrefixPath();
$invoice->getFilename();
$invoice->getPrefixPath();
#+END_SRC
** Notifica
I metodi visti per le fatture valgono anche per le notifiche.
Inoltre, per costruire il nome del file notifica a partire da quello di una certa ~$invoice~:
#+BEGIN_SRC
$notice->setFilenameFromInvoice($invoice, '_EC_001');
#+END_SRC
Per pre-popolare i valori della notifica a partire da quelli di una fattura:
#+BEGIN_SRC
$notice->setValuesFromInvoice($invoice, $bodyIndex);
#+END_SRC
* Invio al Sistema di Interscambio (SdI)
** Fatture
#+BEGIN_SRC
use Taocomp\Einvoicing\SdicoopClient\Client;
use Taocomp\Einvoicing\SdicoopClient\FileSdIBase;
use Taocomp\Einvoicing\SdicoopClient\RispostaSdIRiceviFile;
$invoice = new FatturaElettronica('FPR12');
// ...
// settaggio valori
// ...
Client::setPrivateKey('/path/to/client.key');
Client::setClientCert('/path/to/client.pem');
Client::setCaCert('/path/to/ca.pem');
$client = new Client(array(
'endpoint' => 'https://testservizi.fatturapa.it/ricevi_file',
'wsdl' => '/path/to/wsdl/SdIRiceviFile_v1.0.wsdl'
));
$fileSdI = new FileSdIBase();
$fileSdI->load($invoice);
$response = new RispostaSdIRiceviFile($client->RiceviFile($fileSdI));
#+END_SRC
** Notifiche
#+BEGIN_SRC
use Taocomp\Einvoicing\SdicoopClient\Client;
use Taocomp\Einvoicing\SdicoopClient\FileSdI;
use Taocomp\Einvoicing\SdicoopClient\RispostaSdINotificaEsito;
$notice = new EsitoCommittente();
// ...
// settaggio valori
// ...
Client::setPrivateKey('/path/to/client.key');
Client::setClientCert('/path/to/client.pem');
Client::setCaCert('/path/to/ca.pem');
$client = new Client(array(
'endpoint' => 'https://testservizi.fatturapa.it/ricevi_notifica',
'wsdl' => __DIR__ . '/../wsdl/SdIRiceviNotifica_v1.0.wsdl'
));
$fileSdI = new FileSdI();
$fileSdI->load($notice);
$response = new RispostaSdINotificaEsito($client->NotificaEsito($fileSdI));
#+END_SRC