An open API service indexing awesome lists of open source software.

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).

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