2018-07-05 17:56:38 +02:00
< ? php
namespace Plugins\Fatturazione ;
use FluidXml\FluidXml ;
use Respect\Validation\Validator as v ;
use Stringy\Stringy as S ;
/**
* Classe per la gestione della fatturazione elettronica in XML .
*
* @ since 2.4 . 2
*/
class FatturaElettronica
{
2018-07-06 18:06:23 +02:00
/** @var array Informazioni sull'anagrafica Azienda */
protected static $azienda = [];
2018-07-05 17:56:38 +02:00
2018-07-06 18:06:23 +02:00
/** @var array Informazioni sull'anagrafica Cliente del documento */
protected $cliente = [];
/** @var array Informazioni sul documento */
protected $documento = [];
/** @var array Stato di validazione interna dell'XML della fattura */
protected $is_valid = null ;
/** @var array XML della fattura */
protected $xml = null ;
2018-07-05 17:56:38 +02:00
public function __construct ( $id_documento )
{
$database = \Database :: getConnection ();
// Documento
2018-07-09 12:57:55 +02:00
$this -> documento = $database -> fetchOne ( 'SELECT *, (SELECT `codice_tipo_documento_fe` FROM `co_tipidocumento` WHERE `co_tipidocumento`.`id` = `co_documenti`.`idtipodocumento`) AS `tipo_documento`, (SELECT `descrizione` FROM `co_statidocumento` WHERE `co_documenti`.`idstatodocumento` = `co_statidocumento`.`id`) AS `stato` FROM `co_documenti` WHERE `id` = ' . prepare ( $id_documento ));
2018-07-05 17:56:38 +02:00
2018-07-06 18:06:23 +02:00
// Controllo sulla possibilità di creare la fattura elettronica
2018-07-09 12:57:55 +02:00
if ( $this -> documento [ 'stato' ] != 'Emessa' || $this -> getCliente ()[ 'tipo' ] == 'Privato' ) {
throw new \UnexpectedValueException ();
2018-07-06 18:06:23 +02:00
}
2018-07-05 17:56:38 +02:00
}
2018-07-06 18:06:23 +02:00
/**
* Restituisce le informazioni sull ' anagrafica azienda .
*
* @ return array
*/
public static function getAzienda ()
2018-07-05 17:56:38 +02:00
{
2018-07-06 18:06:23 +02:00
if ( empty ( self :: $azienda )) {
$database = \Database :: getConnection ();
2018-07-09 10:44:54 +02:00
self :: $azienda = $database -> fetchOne ( 'SELECT *, (SELECT `iso2` FROM `an_nazioni` WHERE `an_nazioni`.`id` = `an_anagrafiche`.`id_nazione`) AS nazione FROM `an_anagrafiche` WHERE `idanagrafica` = ' . prepare ( setting ( 'Azienda predefinita' )));
2018-07-06 18:06:23 +02:00
}
return self :: $azienda ;
2018-07-05 17:56:38 +02:00
}
2018-07-06 18:06:23 +02:00
/**
* Restituisce le informazioni sull ' anagrafica cliente legata al documento .
*
* @ return array
*/
2018-07-05 17:56:38 +02:00
public function getCliente ()
{
2018-07-06 18:06:23 +02:00
if ( empty ( $this -> cliente )) {
$database = \Database :: getConnection ();
$this -> cliente = $database -> fetchOne ( 'SELECT *, (SELECT `iso2` FROM `an_nazioni` WHERE `an_nazioni`.`id` = `an_anagrafiche`.`id_nazione`) AS nazione FROM `an_anagrafiche` WHERE `idanagrafica` = ' . prepare ( $this -> getDocumento ()[ 'idanagrafica' ]));
}
2018-07-05 17:56:38 +02:00
return $this -> cliente ;
}
2018-07-06 18:06:23 +02:00
/**
* Restituisce le informazioni relative al documento .
*
* @ return array
*/
2018-07-05 17:56:38 +02:00
public function getDocumento ()
{
return $this -> documento ;
}
/**
2018-07-06 18:06:23 +02:00
* Restituisce lo stato di validazione interna dell ' XML della fattura .
*
* @ return bool
*/
public function isValid ()
{
if ( empty ( $this -> is_valid )) {
$this -> __toString ();
}
return $this -> is_valid ;
}
/**
* Restituisce l ' array responsabile per la generazione del tag DatiTrasmission .
2018-07-05 17:56:38 +02:00
*
* @ return array
*/
protected static function getDatiTrasmissione ( $documento , $azienda , $cliente )
{
2018-07-09 15:52:40 +02:00
$default_code = ( $cliente [ 'tipo' ] == 'Ente pubblico' ) ? '999999999' : '0000000' ;
2018-07-05 17:56:38 +02:00
// Generazione dell'header
$result = [
'IdTrasmittente' => [
'IdPaese' => $azienda [ 'nazione' ],
'IdCodice' => $azienda [ 'piva' ],
],
'ProgressivoInvio' => $documento [ 'numero_esterno' ],
'FormatoTrasmissione' => ( $cliente [ 'tipo' ] == 'Ente pubblico' ) ? 'FPA12' : 'FPR12' ,
2018-07-09 18:26:22 +02:00
'CodiceDestinatario' => ! empty ( $cliente [ 'codice_destinatario' ]) ? $cliente [ 'codice_destinatario' ] : $default_code ,
2018-07-05 17:56:38 +02:00
];
2018-07-06 18:06:23 +02:00
// Telefono di contatto
if ( ! empty ( $azienda [ 'telefono' ])) {
$result [ 'ContattiTrasmittente' ][ 'Telefono' ] = $azienda [ 'telefono' ];
}
// Email di contatto
if ( ! empty ( $azienda [ 'email' ])) {
$result [ 'ContattiTrasmittente' ][ 'Email' ] = $azienda [ 'email' ];
}
2018-07-05 17:56:38 +02:00
// Inizializzazione PEC solo se necessario
2018-07-09 18:26:22 +02:00
if ( empty ( $cliente [ 'codice_destinatario' ])) {
2018-07-06 18:06:23 +02:00
$result [ 'PECDestinatario' ] = $cliente [ 'pec' ];
2018-07-05 17:56:38 +02:00
}
return $result ;
}
/**
2018-07-06 18:06:23 +02:00
* Restituisce l ' array responsabile per la generazione dei tag DatiAnagrafici per Azienda e Cliente .
2018-07-05 17:56:38 +02:00
*
* @ return array
*/
2018-07-06 18:06:23 +02:00
protected static function getDatiAnagrafici ( $anagrafica , $azienda = false )
{
$result = [];
// Partita IVA (obbligatoria se presente)
if ( ! empty ( $anagrafica [ 'piva' ])) {
$result [ 'IdFiscaleIVA' ] = [
'IdPaese' => $anagrafica [ 'nazione' ],
'IdCodice' => $anagrafica [ 'piva' ],
];
}
// Codice fiscale
if ( ! empty ( $anagrafica [ 'codice_fiscale' ])) {
$result [ 'CodiceFiscale' ] = $anagrafica [ 'codice_fiscale' ];
}
$result [ 'Anagrafica' ] = [
'Denominazione' => $anagrafica [ 'ragione_sociale' ],
// TODO: 'Nome' => $azienda['ragione_sociale'],
// TODO: 'Cognome' => $azienda['ragione_sociale'],
// TODO: 'Titolo' => $azienda['ragione_sociale'],
// TODO: CodEORI
];
// Informazioni specifiche azienda
if ( $azienda ) {
// AlboProfessionale, ProvinciaAlbo, NumeroIscrizioneAlbo, DataIscrizioneAlbo
2018-07-09 10:44:54 +02:00
$result [ 'RegimeFiscale' ] = setting ( 'Regime Fiscale' );
2018-07-06 18:06:23 +02:00
}
return $result ;
}
/**
* Restituisce l ' array responsabile per la generazione dei tag Sede per Azienda e Cliente .
*
* @ return array
*/
protected static function getSede ( $anagrafica )
2018-07-05 17:56:38 +02:00
{
$result = [
2018-07-06 18:06:23 +02:00
'Indirizzo' => $anagrafica [ 'indirizzo' ],
'CAP' => $anagrafica [ 'cap' ],
'Comune' => $anagrafica [ 'citta' ],
2018-07-05 17:56:38 +02:00
];
2018-07-06 18:06:23 +02:00
// Provincia se impostata e SOLO SE nazione ITALIA
if ( ! empty ( $azienda [ 'provincia' ]) && $azienda [ 'nazione' ] == 'IT' ) {
$result [ 'Provincia' ] = $azienda [ 'provincia' ];
}
$result [ 'Nazione' ] = $anagrafica [ 'nazione' ];
2018-07-05 17:56:38 +02:00
return $result ;
}
/**
2018-07-06 18:06:23 +02:00
* Restituisce l ' array responsabile per la generazione del tag CedentePrestatore .
2018-07-05 17:56:38 +02:00
*
* @ return array
*/
2018-07-06 18:06:23 +02:00
protected static function getCedentePrestatore ( $azienda )
2018-07-05 17:56:38 +02:00
{
$result = [
2018-07-06 18:06:23 +02:00
'DatiAnagrafici' => self :: getDatiAnagrafici ( $azienda , true ),
'Sede' => self :: getSede ( $azienda ),
// TODO: StabileOrganizzazione,
2018-07-05 17:56:38 +02:00
];
2018-07-06 18:06:23 +02:00
// IscrizioneREA
if ( ! empty ( $azienda [ 'codicerea' ])) {
$result [ 'IscrizioneREA' ] = [
'Ufficio' => strtoupper ( substr ( $azienda [ 'capitale_sociale' ], 0 , 2 )),
'NumeroREA' => $azienda [ 'codicerea' ],
];
if ( ! empty ( $azienda [ 'capitale_sociale' ])) {
$result [ 'IscrizioneREA' ][ 'CapitaleSociale' ] = $azienda [ 'capitale_sociale' ];
}
$result [ 'IscrizioneREA' ][ 'StatoLiquidazione' ] = 'LN' ; // Non in liquidazione
}
// Contatti
// Telefono
if ( ! empty ( $azienda [ 'telefono' ])) {
$result [ 'Contatti' ][ 'Telefono' ] = $azienda [ 'telefono' ];
}
// Fax
if ( ! empty ( $azienda [ 'email' ])) {
$result [ 'Contatti' ][ 'Fax' ] = $azienda [ 'fax' ];
}
// Email
if ( ! empty ( $azienda [ 'email' ])) {
$result [ 'Contatti' ][ 'Email' ] = $azienda [ 'email' ];
}
// TODO: RiferimentoAmministrazione
2018-07-05 17:56:38 +02:00
return $result ;
}
/**
2018-07-06 18:06:23 +02:00
* Restituisce l ' array responsabile per la generazione del tag CessionarioCommittente .
*
* @ return array
*/
protected static function getCessionarioCommittente ( $cliente )
{
$result = [
'DatiAnagrafici' => self :: getDatiAnagrafici ( $cliente ),
'Sede' => self :: getSede ( $cliente ),
// TODO: StabileOrganizzazione, RappresentanteFiscale
];
return $result ;
}
/**
* Restituisce l ' array responsabile per la generazione del tag DatiGeneraliDocumento .
2018-07-05 17:56:38 +02:00
*
* @ return array
*/
protected static function getDatiGeneraliDocumento ( $documento )
{
$result = [
'TipoDocumento' => $documento [ 'tipo_documento' ],
'Divisa' => 'EUR' ,
'Data' => $documento [ 'data' ],
'Numero' => $documento [ 'numero_esterno' ],
//'Causale' => $documento['causale'],
];
return $result ;
}
/**
2018-07-06 18:06:23 +02:00
* Restituisce l ' array responsabile per la generazione del tag DatiDocumento .
2018-07-05 17:56:38 +02:00
*
* @ return array
*/
protected static function getDatiDocumento ( $documento )
{
$result = [
'DatiGeneraliDocumento' => self :: getDatiGeneraliDocumento ( $documento ),
];
return $result ;
}
/**
2018-07-06 18:06:23 +02:00
* Restituisce l ' array responsabile per la generazione del tag DatiBeniServizi .
2018-07-05 17:56:38 +02:00
*
* @ return array
*/
2018-07-09 14:53:02 +02:00
protected static function getDatiBeniServizi ( $documento )
2018-07-05 17:56:38 +02:00
{
$database = \Database :: getConnection ();
$result = [];
// Righe del documento
2018-07-09 14:53:02 +02:00
$righe_documento = $database -> select ( 'co_righe_documenti' , '*' , [ 'iddocumento' => $documento [ 'id' ]]);
2018-07-05 17:56:38 +02:00
foreach ( $righe_documento as $numero => $riga ) {
$prezzo_unitario = $riga [ 'subtotale' ] / $riga [ 'qta' ];
$prezzo_totale = $riga [ 'subtotale' ] - $riga [ 'sconto' ];
2018-07-06 18:06:23 +02:00
$iva = $database -> fetchArray ( 'SELECT `percentuale` FROM `co_iva` WHERE `id` = ' . prepare ( $riga [ 'idiva' ]));
$percentuale = $iva [ 0 ][ 'percentuale' ];
2018-07-05 17:56:38 +02:00
2018-07-09 15:11:19 +02:00
$dettaglio = [
'NumeroLinea' => $numero + 1 ,
'Descrizione' => $riga [ 'descrizione' ],
'Quantita' => $riga [ 'qta' ],
'PrezzoUnitario' => $prezzo_unitario ,
];
// Sconto
if ( ! empty ( $riga [ 'sconto' ])) {
$sconto = [
'Tipo' => 'SC' ,
];
if ( $riga [ 'tipo_sconto' ] == 'PRC' ) {
$sconto [ 'Percentuale' ] = $riga [ 'sconto' ];
} else {
$sconto [ 'Importo' ] = $riga [ 'sconto' ];
}
$dettaglio [ 'ScontoMaggiorazione' ] = $sconto ;
}
$dettaglio [ 'PrezzoTotale' ] = $prezzo_totale ;
$dettaglio [ 'AliquotaIVA' ] = $percentuale ;
2018-07-05 17:56:38 +02:00
$result [] = [
2018-07-09 15:11:19 +02:00
'DettaglioLinee' => $dettaglio ,
2018-07-05 17:56:38 +02:00
];
}
// Riepiloghi per IVA
2018-07-06 18:06:23 +02:00
$riepiloghi = $database -> fetchArray ( 'SELECT SUM(`subtotale` - `sconto`) as totale, SUM(`iva`) as iva, `idiva` FROM `co_righe_documenti` WHERE `iddocumento` = ' . prepare ( $documento [ 'id' ]) . ' GROUP BY `idiva`' );
foreach ( $riepiloghi as $riepilogo ) {
$iva = $database -> fetchArray ( 'SELECT `percentuale` FROM `co_iva` WHERE `id` = ' . prepare ( $riepilogo [ 'idiva' ]));
$percentuale = $iva [ 0 ][ 'percentuale' ];
2018-07-05 17:56:38 +02:00
$result [] = [
'DatiRiepilogo' => [
2018-07-06 18:06:23 +02:00
'AliquotaIVA' => $percentuale ,
'ImponibileImporto' => $riepilogo [ 'totale' ],
2018-07-05 17:56:38 +02:00
'Imposta' => $riepilogo [ 'iva' ],
'EsigibilitaIVA' => 'I' ,
],
];
}
return $result ;
}
/**
2018-07-06 18:06:23 +02:00
* Restituisce l ' array responsabile per la generazione del tag DatiPagamento .
2018-07-05 17:56:38 +02:00
*
* @ return array
*/
protected static function getDatiPagamento ( $documento )
{
2018-07-06 18:06:23 +02:00
$database = \Database :: getConnection ();
$pagamento = $database -> fetchOne ( 'SELECT * FROM `co_pagamenti` WHERE `id` = ' . prepare ( $documento [ 'idpagamento' ]));
2018-07-05 17:56:38 +02:00
$result = [
2018-07-06 18:06:23 +02:00
'CondizioniPagamento' => ( $pagamento [ 'prc' ] == 100 ) ? 'TP02' : 'TP01' ,
2018-07-05 17:56:38 +02:00
];
2018-07-06 18:06:23 +02:00
$scadenze = $database -> fetchArray ( 'SELECT * FROM `co_scadenziario` WHERE `iddocumento` = ' . prepare ( $documento [ 'id' ]));
foreach ( $scadenze as $scadenza ) {
$result [] = [
'DettaglioPagamento' => [
'ModalitaPagamento' => $pagamento [ 'codice_modalita_pagemento_fe' ],
'DataScadenzaPagamento' => $scadenza [ 'scadenza' ],
'ImportoPagamento' => $scadenza [ 'da_pagare' ],
],
];
}
2018-07-05 17:56:38 +02:00
return $result ;
}
2018-07-06 18:06:23 +02:00
/**
* Restituisce l ' array responsabile per la generazione del tag FatturaElettronicaHeader .
*
* @ return array
*/
protected static function getHeader ( $fattura )
2018-07-05 17:56:38 +02:00
{
2018-07-06 18:06:23 +02:00
$azienda = self :: getAzienda ();
$documento = $fattura -> getDocumento ();
$cliente = $fattura -> getCliente ();
2018-07-05 17:56:38 +02:00
$result = [
'DatiTrasmissione' => self :: getDatiTrasmissione ( $documento , $azienda , $cliente ),
2018-07-06 18:06:23 +02:00
'CedentePrestatore' => self :: getCedentePrestatore ( $azienda ),
'CessionarioCommittente' => self :: getCessionarioCommittente ( $cliente ),
2018-07-05 17:56:38 +02:00
];
return $result ;
}
2018-07-06 18:06:23 +02:00
/**
* Restituisce l ' array responsabile per la generazione del tag FatturaElettronicaBody .
*
* @ return array
*/
protected static function getBody ( $fattura )
2018-07-05 17:56:38 +02:00
{
2018-07-06 18:06:23 +02:00
$documento = $fattura -> getDocumento ();
2018-07-05 17:56:38 +02:00
$result = [
'DatiGenerali' => self :: getDatiDocumento ( $documento ),
2018-07-09 14:53:02 +02:00
'DatiBeniServizi' => self :: getDatiBeniServizi ( $documento ),
2018-07-05 17:56:38 +02:00
'DatiPagamento' => self :: getDatiPagamento ( $documento ),
];
return $result ;
}
2018-07-06 18:06:23 +02:00
/**
* Prepara i contenuti per la generazione dell ' XML della fattura .
* Effettua inoltre dei controlli interni di validità sui campi previsti dallo standard .
*
* @ param mixed $input
* @ param string $key
*
* @ return mixed
*/
protected function prepareForXML ( $input , $key = null )
2018-07-05 17:56:38 +02:00
{
$output = null ;
if ( is_array ( $input )) {
foreach ( $input as $key => $value ) {
2018-07-06 18:06:23 +02:00
$output [ $key ] = $this -> prepareForXML ( $value , $key );
2018-07-05 17:56:38 +02:00
}
} elseif ( ! is_null ( $input )) {
$info = self :: $validators [ $key ];
$size = isset ( $info [ 'size' ]) ? $info [ 'size' ] : null ;
$output = $input ;
// Operazioni di normalizzazione
if ( $info [ 'type' ] == 'decimal' ) {
$output = number_format ( $output , 2 , '.' , '' );
2018-07-06 18:06:23 +02:00
} elseif ( $info [ 'type' ] != 'integer' && isset ( $size [ 1 ])) {
$output = trim ( $output );
2018-07-05 17:56:38 +02:00
S :: create ( $output ) -> substr ( 2 , $size [ 1 ]);
}
// Validazione
if ( $info [ 'type' ] == 'string' || $info [ 'type' ] == 'normalizedString' ) {
2018-07-06 18:06:23 +02:00
$validator = v :: stringType ();
2018-07-05 17:56:38 +02:00
if ( isset ( $size [ 1 ])) {
$validator = $validator -> length ( $size [ 0 ], $size [ 1 ]);
}
} elseif ( $info [ 'type' ] == 'decimal' ) {
$validator = v :: floatVal ();
2018-07-06 18:06:23 +02:00
} elseif ( $info [ 'type' ] == 'integer' ) {
$validator = v :: intVal ();
2018-07-05 17:56:38 +02:00
} elseif ( $info [ 'type' ] == 'date' ) {
$validator = v :: date ();
}
if ( ! empty ( $validator )) {
2018-07-06 18:06:23 +02:00
$validation = $validator -> validate ( $output );
$this -> is_valid &= $validation ;
//echo $key.': '.intval($validation).'<br>';
2018-07-05 17:56:38 +02:00
}
}
return $output ;
}
2018-07-09 18:26:22 +02:00
public static function PA ( $codice_fiscale )
{
$id = setting ( 'Authorization ID Indice PA' );
if ( empty ( $id )) {
return null ;
}
// Localhost: ['curl' => [CURLOPT_SSL_VERIFYPEER => false]]
$client = new \GuzzleHttp\Client ();
$response = $client -> request ( 'POST' , 'https://www.indicepa.gov.it/public-ws/WS01_SFE_CF.php' , [
'form_params' => [
'AUTH_ID' => $id ,
'CF' => $codice_fiscale ,
],
]);
$json = json_decode ( $response -> getBody (), true );
return isset ( $json [ 'data' ][ 0 ][ 'OU' ][ 0 ][ 'cod_uni_ou' ]) ? $json [ 'data' ][ 0 ][ 'OU' ][ 0 ][ 'cod_uni_ou' ] : null ;
}
2018-07-06 18:06:23 +02:00
/**
* Salva il file XML .
*
* @ param string $directory
*
* @ return string Nome del file
*/
2018-07-05 17:56:38 +02:00
public function save ( $directory )
{
2018-07-09 12:57:55 +02:00
// Generazione nome XML
$filename = $this -> getFilename ();
2018-07-05 17:56:38 +02:00
2018-07-09 12:57:55 +02:00
// Salvataggio del file
$result = directory ( $directory ) && file_put_contents ( rtrim ( $directory , '/' ) . '/' . $filename , $this -> __toString ());
return ( $result === false ) ? null : $filename ;
}
/**
* Restituisce il nome del file XML per la fattura elettronica .
*
* @ return string
*/
public function getFilename ()
{
2018-07-09 15:37:23 +02:00
$azienda = self :: getAzienda ();
$codice = 'IT' . ( empty ( $azienda [ 'piva' ]) ? $azienda [ 'codice_fiscale' ] : $azienda [ 'piva' ]);
2018-07-06 18:06:23 +02:00
2018-07-09 15:37:23 +02:00
if ( empty ( $this -> documento [ 'codice_xml' ])) {
2018-07-06 18:06:23 +02:00
$database = \Database :: getConnection ();
2018-07-05 17:56:38 +02:00
2018-07-06 18:06:23 +02:00
do {
2018-07-09 15:37:23 +02:00
$code = date ( 'y' ) . secure_random_string ( 3 );
} while ( $database -> fetchNum ( 'SELECT `id` FROM `co_documenti` WHERE `codice_xml` = ' . prepare ( $code )) != 0 );
2018-07-05 17:56:38 +02:00
// Registrazione
2018-07-09 15:37:23 +02:00
$database -> update ( 'co_documenti' , [ 'codice_xml' => $code ], [ 'id' => $this -> getDocumento ()[ 'id' ]]);
$this -> documento [ 'codice_xml' ] = $code ;
2018-07-05 17:56:38 +02:00
}
2018-07-09 15:37:23 +02:00
return $codice . '_' . $this -> documento [ 'codice_xml' ] . '.xml' ;
2018-07-05 17:56:38 +02:00
}
2018-07-06 18:06:23 +02:00
/**
* Restituisce il codice XML della fattura elettronica .
*
* @ return string
*/
2018-07-05 17:56:38 +02:00
public function __toString ()
{
2018-07-06 18:06:23 +02:00
if ( empty ( $this -> xml )) {
$this -> is_valid = true ;
2018-07-05 17:56:38 +02:00
2018-07-06 18:06:23 +02:00
$cliente = $this -> getCliente ();
// Inizializzazione libreria per la generazione della fattura in XML
2018-07-09 15:52:40 +02:00
$fattura = new FluidXml ( null , [ 'stylesheet' => 'http://www.fatturapa.gov.it/export/fatturazione/sdi/fatturapa/v1.2.1/fatturaPA_v1.2.1.xsl' ]);
2018-07-05 17:56:38 +02:00
2018-07-06 18:06:23 +02:00
// Generazione dell'elemento root
$fattura -> namespace ( 'p' , 'http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2' );
$root = $fattura -> addChild ( 'p:FatturaElettronica' , true );
$rootNode = $root [ 0 ];
// Completamento dei tag
$attributes = [
'versione' => ( $cliente [ 'tipo' ] == 'Ente pubblico' ) ? 'FPA12' : 'FPR12' ,
'xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#' ,
'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' ,
];
foreach ( $attributes as $key => $value ) {
$rootNode -> setAttribute ( $key , $value );
}
// Generazione della fattura elettronica
$xml = self :: prepareForXML ([
'FatturaElettronicaHeader' => self :: getHeader ( $this ),
'FatturaElettronicaBody' => self :: getBody ( $this ),
]);
$fattura -> add ( $xml );
$this -> xml = $fattura -> __toString ();
}
2018-07-05 17:56:38 +02:00
2018-07-06 18:06:23 +02:00
return $this -> xml ;
2018-07-05 17:56:38 +02:00
}
2018-07-06 18:06:23 +02:00
/** @var array Elenco di campi dello standard per la formattazione e la validazione */
2018-07-05 17:56:38 +02:00
protected static $validators = [
'IdPaese' => [
'type' => 'string' ,
'size' => 2 ,
],
'IdCodice' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 28 ],
2018-07-05 17:56:38 +02:00
],
'ProgressivoInvio' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 10 ],
2018-07-05 17:56:38 +02:00
],
'FormatoTrasmissione' => [
'type' => 'string' ,
'size' => 5 ,
],
'CodiceDestinatario' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 6 , 7 ],
2018-07-05 17:56:38 +02:00
],
'Telefono' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 5 , 12 ],
2018-07-05 17:56:38 +02:00
],
'Email' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 7 , 256 ],
2018-07-05 17:56:38 +02:00
],
'PECDestinatario' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 7 , 256 ],
2018-07-05 17:56:38 +02:00
],
'CodiceFiscale' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 11 , 16 ],
2018-07-05 17:56:38 +02:00
],
'Denominazione' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 80 ],
2018-07-05 17:56:38 +02:00
],
'Nome' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'Cognome' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'Titolo' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 2 , 10 ],
2018-07-05 17:56:38 +02:00
],
'CodEORI' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 13 , 17 ],
2018-07-05 17:56:38 +02:00
],
'AlboProfessionale' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'ProvinciaAlbo' => [
'type' => 'string' ,
'size' => 2 ,
],
'NumeroIscrizioneAlbo' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'DataIscrizioneAlbo' => [
'type' => 'date' ,
'size' => 10 ,
],
'RegimeFiscale' => [
'type' => 'string' ,
'size' => 4 ,
],
'Indirizzo' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'NumeroCivico' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 8 ],
2018-07-05 17:56:38 +02:00
],
'CAP' => [
'type' => 'string' ,
'size' => 5 ,
],
'Comune' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'Provincia' => [
'type' => 'string' ,
'size' => 2 ,
],
'Nazione' => [
'type' => 'string' ,
'size' => 2 ,
],
'Ufficio' => [
'type' => 'string' ,
'size' => 2 ,
],
'NumeroREA' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'CapitaleSociale' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'SocioUnico' => [
'type' => 'string' ,
'size' => 2 ,
],
'StatoLiquidazione' => [
'type' => 'string' ,
'size' => 2 ,
],
'Fax' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 5 , 12 ],
2018-07-05 17:56:38 +02:00
],
'RiferimentoAmministrazione' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'SoggettoEmittente' => [
'type' => 'string' ,
'size' => 2 ,
],
'TipoDocumento' => [
'type' => 'string' ,
'size' => 4 ,
],
'Divisa' => [
'type' => 'string' ,
'size' => 3 ,
],
'Data' => [
'type' => 'date' ,
'size' => 10 ,
],
'Numero' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'TipoRitenuta' => [
'type' => 'string' ,
'size' => 4 ,
],
'ImportoRitenuta' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'AliquotaRitenuta' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 6 ],
2018-07-05 17:56:38 +02:00
],
'CausalePagamento' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 2 ],
2018-07-05 17:56:38 +02:00
],
'BolloVirtuale' => [
'type' => 'string' ,
'size' => 2 ,
],
'ImportoBollo' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'TipoCassa' => [
'type' => 'string' ,
'size' => 4 ,
],
'AlCassa' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 6 ],
2018-07-05 17:56:38 +02:00
],
'ImportoContributoCassa' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'ImponibileCassa' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'AliquotaIVA' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 6 ],
2018-07-05 17:56:38 +02:00
],
'Ritenuta' => [
'type' => 'string' ,
'size' => 2 ,
],
'Natura' => [
'type' => 'string' ,
'size' => 2 ,
],
'Tipo' => [
'type' => 'string' ,
'size' => 2 ,
],
'Percentuale' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 6 ],
2018-07-05 17:56:38 +02:00
],
'Importo' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'ImportoTotaleDocumento' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'Arrotondamento' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 21 ],
2018-07-05 17:56:38 +02:00
],
'Causale' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 200 ],
2018-07-05 17:56:38 +02:00
],
'Art73' => [
'type' => 'string' ,
'size' => 2 ,
],
'RiferimentoNumeroLinea' => [
'type' => 'integer' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 4 ],
2018-07-05 17:56:38 +02:00
],
'IdDocumento' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'NumItem' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'CodiceCommessaConvenzione' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 100 ],
2018-07-05 17:56:38 +02:00
],
'CodiceCUP' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 15 ],
2018-07-05 17:56:38 +02:00
],
'CodiceCIG' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 15 ],
2018-07-05 17:56:38 +02:00
],
'RiferimentoFase' => [
'type' => 'integer' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 3 ],
2018-07-05 17:56:38 +02:00
],
'NumeroDDT' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'DataDDT' => [
'type' => 'date' ,
'size' => 10 ,
],
'NumeroLicenzaGuida' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'MezzoTrasporto' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 80 ],
2018-07-05 17:56:38 +02:00
],
'CausaleTrasporto' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 100 ],
2018-07-05 17:56:38 +02:00
],
'NumeroColli' => [
'type' => 'integer' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 4 ],
2018-07-05 17:56:38 +02:00
],
'Descrizione' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 1000 ],
2018-07-05 17:56:38 +02:00
],
'UnitaMisuraPeso' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 10 ],
2018-07-05 17:56:38 +02:00
],
'PesoLordo' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 7 ],
2018-07-05 17:56:38 +02:00
],
'PesoNetto' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 7 ],
2018-07-05 17:56:38 +02:00
],
'DataOraRitiro' => [
'type' => 'date' ,
'size' => 19 ,
],
'DataInizioTrasporto' => [
'type' => 'date' ,
'size' => 10 ,
],
'TipoResa' => [
'type' => 'string' ,
'size' => 3 ,
],
'DataOraConsegna' => [
'type' => 'date' ,
'size' => 19 ,
],
'NumeroFatturaPrincipale' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'DataFatturaPrincipale' => [
'type' => 'date' ,
'size' => 10 ,
],
'NumeroLinea' => [
'type' => 'integer' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 4 ],
2018-07-05 17:56:38 +02:00
],
'TipoCessionePrestazione' => [
'type' => 'string' ,
'size' => 2 ,
],
'CodiceArticolo' => [
'type' => 'normalizedString' ,
],
'CodiceTipo' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 35 ],
2018-07-05 17:56:38 +02:00
],
'CodiceValore' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 35 ],
2018-07-05 17:56:38 +02:00
],
'Quantita' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 21 ],
2018-07-05 17:56:38 +02:00
],
'UnitaMisura' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 10 ],
2018-07-05 17:56:38 +02:00
],
'DataInizioPeriodo' => [
'type' => 'date' ,
'size' => 10 ,
],
'DataFinePeriodo' => [
'type' => 'date' ,
'size' => 10 ,
],
'PrezzoUnitario' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 21 ],
2018-07-05 17:56:38 +02:00
],
'PrezzoTotale' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 21 ],
2018-07-05 17:56:38 +02:00
],
'TipoDato' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 10 ],
2018-07-05 17:56:38 +02:00
],
'RiferimentoTesto' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'RiferimentoNumero' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 21 ],
2018-07-05 17:56:38 +02:00
],
'RiferimentoData' => [
'type' => 'normalizedString' ,
'size' => 10 ,
],
'SpeseAccessorie' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'ImponibileImporto' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'Imposta' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'EsigibilitaIVA' => [
'type' => 'string' ,
'size' => 1 ,
],
'RiferimentoNormativo' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 100 ],
2018-07-05 17:56:38 +02:00
],
'TotalePercorso' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 15 ],
2018-07-05 17:56:38 +02:00
],
'CondizioniPagamento' => [
'type' => 'string' ,
'size' => 4 ,
],
'Beneficiario' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 200 ],
2018-07-05 17:56:38 +02:00
],
'ModalitaPagamento' => [
'type' => 'string' ,
'size' => 4 ,
],
'DataRiferimentoTerminiPagamento' => [
'type' => 'date' ,
'size' => 10 ,
],
'GiorniTerminiPagamento' => [
'type' => 'integer' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 3 ],
2018-07-05 17:56:38 +02:00
],
'DataScadenzaPagamento' => [
'type' => 'date' ,
'size' => 10 ,
],
'ImportoPagamento' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'CodUfficioPostale' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 20 ],
2018-07-05 17:56:38 +02:00
],
'CognomeQuietanzante' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'NomeQuietanzante' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'CFQuietanzante' => [
'type' => 'string' ,
'size' => 16 ,
],
'TitoloQuietanzante' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 2 , 10 ],
2018-07-05 17:56:38 +02:00
],
'IstitutoFinanziario' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 80 ],
2018-07-05 17:56:38 +02:00
],
'IBAN' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 15 , 34 ],
2018-07-05 17:56:38 +02:00
],
'ABI' => [
'type' => 'string' ,
'size' => 5 ,
],
'CAB' => [
'type' => 'string' ,
'size' => 5 ,
],
'BIC' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 8 , 11 ],
2018-07-05 17:56:38 +02:00
],
'ScontoPagamentoAnticipato' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'DataLimitePagamentoAnticipato' => [
'type' => 'date' ,
'size' => 10 ,
],
'PenalitaPagamentiRitardati' => [
'type' => 'decimal' ,
2018-07-06 18:06:23 +02:00
'size' => [ 4 , 15 ],
2018-07-05 17:56:38 +02:00
],
'DataDecorrenzaPenale' => [
'type' => 'date' ,
'size' => 10 ,
],
'CodicePagamento' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'NomeAttachment' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 60 ],
2018-07-05 17:56:38 +02:00
],
'AlgoritmoCompressione' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 10 ],
2018-07-05 17:56:38 +02:00
],
'FormatoAttachment' => [
'type' => 'string' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 10 ],
2018-07-05 17:56:38 +02:00
],
'DescrizioneAttachment' => [
'type' => 'normalizedString' ,
2018-07-06 18:06:23 +02:00
'size' => [ 1 , 100 ],
2018-07-05 17:56:38 +02:00
],
'Attachment' => [
'type' => 'base64Binary' ,
],
];
}