openstamanager/plugins/fatturazione/src/FatturaElettronica.php

1182 lines
34 KiB
PHP
Raw Normal View History

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;
2018-09-06 17:10:23 +02:00
use DateTime;
2018-09-14 11:39:02 +02:00
use Uploads, Modules, Plugins, Prints;
2018-07-05 17:56:38 +02:00
/**
* 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)
{
2018-07-10 16:19:38 +02:00
$database = database();
2018-07-05 17:56:38 +02:00
// 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-10 16:19:38 +02:00
if (empty(static::$azienda)) {
$database = database();
2018-07-06 18:06:23 +02:00
2018-07-10 16:19:38 +02:00
static::$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
}
2018-07-10 16:19:38 +02:00
return static::$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)) {
2018-07-10 16:19:38 +02:00
$database = database();
2018-07-06 18:06:23 +02:00
$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-10 12:14:10 +02:00
$default_code = ($cliente['tipo'] == 'Ente pubblico') ? '999999' : '0000000';
2018-07-09 15:52:40 +02:00
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) {
2018-09-07 16:19:16 +02:00
// TODO: AlboProfessionale, ProvinciaAlbo, NumeroIscrizioneAlbo, DataIscrizioneAlbo
2018-07-06 18:06:23 +02:00
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-10 16:19:38 +02:00
'DatiAnagrafici' => static::getDatiAnagrafici($azienda, true),
'Sede' => static::getSede($azienda),
2018-07-06 18:06:23 +02:00
// TODO: StabileOrganizzazione,
2018-07-05 17:56:38 +02:00
];
2018-07-06 18:06:23 +02:00
// IscrizioneREA
if (!empty($azienda['codicerea'])) {
2018-09-06 15:03:50 +02:00
$codice = explode('-', $azienda['codicerea']);
2018-07-06 18:06:23 +02:00
$result['IscrizioneREA'] = [
2018-09-06 15:03:50 +02:00
'Ufficio' => strtoupper($codice[0]),
'NumeroREA' => $codice[1],
2018-07-06 18:06:23 +02:00
];
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
2018-09-06 15:03:50 +02:00
if (!empty($azienda['fax'])) {
2018-07-06 18:06:23 +02:00
$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 = [
2018-07-10 16:19:38 +02:00
'DatiAnagrafici' => static::getDatiAnagrafici($cliente),
'Sede' => static::getSede($cliente),
2018-07-06 18:06:23 +02:00
// 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 = [
2018-07-10 16:19:38 +02:00
'DatiGeneraliDocumento' => static::getDatiGeneraliDocumento($documento),
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 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
{
2018-07-10 16:19:38 +02:00
$database = database();
2018-07-05 17:56:38 +02:00
$result = [];
// Righe del documento
2018-07-10 16:19:38 +02:00
$righe_documento = $database->fetchArray('SELECT * FROM `co_righe_documenti` WHERE `iddocumento` = '.prepare($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-10 16:19:38 +02:00
$database = database();
2018-07-06 18:06:23 +02:00
$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-09-14 11:39:02 +02:00
protected static function getAllegati($documento) {
$id_module = Modules::get('Fatture di vendita')['id'];
$dir = Uploads::getDirectory($id_module, Plugins::get('Fatturazione Elettronica')['id']);
$rapportino_nome = sanitizeFilename($documento['numero'].'.pdf');
$filename = slashes(DOCROOT.'/'.$dir.'/'.$rapportino_nome);
$print = Prints::getModuleMainPrint($id_module);
Prints::render($print['id'], $documento['id'], $filename);
$pdf = file_get_contents($filename);
$result = [
'NomeAttachment' => 'Fattura',
'FormatoAttachment' => 'PDF',
'Attachment' => base64_encode($pdf),
];
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-10 16:19:38 +02:00
$azienda = static::getAzienda();
2018-07-06 18:06:23 +02:00
$documento = $fattura->getDocumento();
$cliente = $fattura->getCliente();
2018-07-05 17:56:38 +02:00
$result = [
2018-07-10 16:19:38 +02:00
'DatiTrasmissione' => static::getDatiTrasmissione($documento, $azienda, $cliente),
'CedentePrestatore' => static::getCedentePrestatore($azienda),
'CessionarioCommittente' => static::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 = [
2018-07-10 16:19:38 +02:00
'DatiGenerali' => static::getDatiDocumento($documento),
'DatiBeniServizi' => static::getDatiBeniServizi($documento),
'DatiPagamento' => static::getDatiPagamento($documento),
2018-09-14 11:39:02 +02:00
'Allegati' => static::getAllegati($documento),
2018-07-05 17:56:38 +02:00
];
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)) {
2018-07-10 16:19:38 +02:00
$info = static::$validators[$key];
2018-07-05 17:56:38 +02:00
$size = isset($info['size']) ? $info['size'] : null;
$output = $input;
// Operazioni di normalizzazione
2018-09-06 15:03:50 +02:00
// Formattazione decimali
2018-07-05 17:56:38 +02:00
if ($info['type'] == 'decimal') {
$output = number_format($output, 2, '.', '');
2018-09-06 15:03:50 +02:00
}
// Formattazione date
elseif ($info['type'] == 'date') {
2018-09-06 17:10:23 +02:00
$object = DateTime::createFromFormat('Y-m-d H:i:s', $output);
2018-09-06 15:03:50 +02:00
if (is_object($object)) {
$output = $object->format('Y-m-d');
}
}
// Formattazione testo
elseif ($info['type'] == 'string') {
}
// Riduzione delle dimensioni
if ($info['type'] != 'integer' && isset($size[1])) {
2018-07-06 18:06:23 +02:00
$output = trim($output);
2018-09-06 17:10:23 +02:00
$output = S::create($output)->substr(0, $size[1])->__toString();
2018-07-05 17:56:38 +02:00
}
// 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;
2018-09-06 15:03:50 +02:00
// Per debug
//flash()->warning($key.': '.intval($validation));
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
2018-07-10 16:19:38 +02:00
$file = rtrim($directory, '/').'/'.$filename;
$result = directory($directory) && file_put_contents($file, $this->__toString());
2018-07-09 12:57:55 +02:00
// Registrazione come allegato
2018-07-10 16:19:38 +02:00
$this->register($filename);
return ($result === false) ? null : $filename;
}
/**
* Registra il file XML come allegato.
*
* @param string $filename
*/
public function register($filename)
{
$data = [
'original' => $filename,
'category' => tr('Fattura elettronica'),
2018-09-14 11:39:02 +02:00
'id_module' => Modules::get('Fatture di vendita')['id'],
'id_plugin' => Plugins::get('Fatturazione Elettronica')['id'],
'id_record' => $this->getDocumento()['id'],
];
2018-09-14 11:39:02 +02:00
$uploads = Uploads::get($data);
$registered = in_array($filename, array_column($uploads, 'original'));
if (!$registered) {
2018-09-14 11:39:02 +02:00
Uploads::register($data);
}
2018-07-09 12:57:55 +02:00
}
/**
* Restituisce il nome del file XML per la fattura elettronica.
*
* @return string
*/
public function getFilename()
{
2018-07-10 16:19:38 +02:00
$azienda = static::getAzienda();
2018-07-09 15:37:23 +02:00
$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-10 16:19:38 +02:00
$database = database();
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-10 17:07:27 +02:00
//, ['stylesheet' => 'http://www.fatturapa.gov.it/export/fatturazione/sdi/fatturapa/v1.2.1/fatturaPA_v1.2.1.xsl']
$fattura = new FluidXml(null);
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
2018-07-10 16:19:38 +02:00
$xml = static::prepareForXML([
'FatturaElettronicaHeader' => static::getHeader($this),
'FatturaElettronicaBody' => static::getBody($this),
2018-07-06 18:06:23 +02:00
]);
$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',
],
];
}