openstamanager/plugins/importFE/src/FatturaElettronica.php

448 lines
15 KiB
PHP
Raw Normal View History

2018-09-24 18:10:16 +02:00
<?php
2020-09-07 15:04:06 +02:00
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
2021-01-20 15:08:51 +01:00
* Copyright (C) DevCode s.r.l.
2020-09-07 15:04:06 +02:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2018-09-24 18:10:16 +02:00
2018-11-30 15:33:25 +01:00
namespace Plugins\ImportFE;
2018-09-24 18:10:16 +02:00
2024-03-22 15:52:24 +01:00
use Models\Module;
2018-12-29 12:03:22 +01:00
use Modules\Anagrafiche\Anagrafica;
use Modules\Anagrafiche\Nazione;
use Modules\Anagrafiche\Tipo as TipoAnagrafica;
2021-10-18 10:23:39 +02:00
use Modules\Banche\Banca;
2018-12-29 12:03:22 +01:00
use Modules\Fatture\Fattura;
2024-02-14 16:46:45 +01:00
use Modules\Fatture\Stato;
2018-09-24 18:10:16 +02:00
use Modules\Fatture\Tipo as TipoFattura;
2018-12-29 12:03:22 +01:00
use Util\XML;
2018-09-24 18:10:16 +02:00
/**
* Classe per la gestione della fatturazione elettronica in XML.
*
2019-04-19 03:18:05 +02:00
* @since 2.4.9
2018-09-24 18:10:16 +02:00
*/
class FatturaElettronica
{
2024-01-15 15:30:45 +01:00
protected static $directory;
2018-11-30 15:33:25 +01:00
/** @var array Percorso del file XML */
2024-01-15 15:30:45 +01:00
protected $file;
2018-11-30 15:33:25 +01:00
2018-09-24 18:10:16 +02:00
/** @var array XML della fattura */
2024-01-15 15:30:45 +01:00
protected $xml;
2018-09-24 18:10:16 +02:00
2019-05-04 00:37:49 +02:00
/** @var Fattura Fattura collegata */
2024-01-15 15:30:45 +01:00
protected $fattura;
2018-09-24 18:10:16 +02:00
2019-02-20 16:07:42 +01:00
public function __construct($name)
2018-09-24 18:10:16 +02:00
{
2019-02-20 16:07:42 +01:00
$this->file = static::getImportDirectory().'/'.$name;
2019-02-13 11:26:56 +01:00
if (string_ends_with($name, '.p7m')) {
2019-02-13 11:26:56 +01:00
$file = XML::decodeP7M($this->file);
2019-02-13 12:04:36 +01:00
if (!empty($file)) {
2019-02-13 11:26:56 +01:00
delete($this->file);
$this->file = $file;
}
}
2018-12-07 10:56:49 +01:00
$this->xml = XML::readFile($this->file);
2018-09-24 18:10:16 +02:00
2018-09-25 11:55:52 +02:00
// Individuazione fattura pre-esistente
$dati_generali = $this->getBody()['DatiGenerali']['DatiGeneraliDocumento'];
$data = $dati_generali['Data'];
$numero = $dati_generali['Numero'];
2018-11-30 15:33:25 +01:00
$progressivo_invio = $this->getHeader()['DatiTrasmissione']['ProgressivoInvio'];
2018-09-25 11:55:52 +02:00
$fattura = Fattura::where([
2018-11-30 15:33:25 +01:00
'progressivo_invio' => $progressivo_invio,
2018-12-07 10:56:49 +01:00
'numero_esterno' => $numero,
2018-09-25 11:55:52 +02:00
'data' => $data,
])->first();
if (!empty($fattura) && $fattura->tipo->dir == 'uscita') {
2024-01-15 15:30:45 +01:00
throw new \UnexpectedValueException();
2018-11-30 15:33:25 +01:00
}
}
public static function getImportDirectory()
{
if (!isset(self::$directory)) {
2024-03-27 16:43:30 +01:00
$module = Module::find((new Module())->getByField('name', 'Fatture di acquisto', \Models\Locale::getPredefined()->id));
2018-11-30 15:33:25 +01:00
2019-07-05 09:53:53 +02:00
$plugins = $module->plugins;
if (!empty($plugins)) {
2024-04-09 12:18:08 +02:00
$plugin = $plugins->first(fn ($value, $key) => $value->getTranslation('name') == 'Fatturazione Elettronica');
2018-11-30 15:33:25 +01:00
self::$directory = base_dir().'/'.$plugin->upload_directory;
2019-07-05 09:53:53 +02:00
}
2018-11-30 15:33:25 +01:00
}
return self::$directory;
}
public static function store($filename, $content)
{
2018-12-12 17:26:25 +01:00
$directory = static::getImportDirectory();
$file = $directory.'/'.$filename;
2018-11-30 15:33:25 +01:00
2018-12-12 17:26:25 +01:00
directory($directory);
2018-11-30 15:33:25 +01:00
file_put_contents($file, $content);
return $filename;
}
2019-02-20 16:07:42 +01:00
public static function isValid($name)
2018-11-30 15:33:25 +01:00
{
try {
2019-02-20 16:07:42 +01:00
new static($name);
2018-11-30 15:33:25 +01:00
return true;
2024-01-15 15:30:45 +01:00
} catch (\UnexpectedValueException $e) {
2019-04-19 03:18:05 +02:00
$file = static::getImportDirectory().'/'.$name;
delete($file);
2018-11-30 15:33:25 +01:00
return false;
2018-09-25 11:55:52 +02:00
}
2018-09-24 18:10:16 +02:00
}
2019-04-19 03:18:05 +02:00
public static function manage($name)
2018-09-24 18:10:16 +02:00
{
2019-04-19 03:18:05 +02:00
try {
2019-07-22 12:52:48 +02:00
$manager = new FatturaOrdinaria($name);
2018-09-24 18:10:16 +02:00
2019-07-22 12:52:48 +02:00
$tipo = $manager->getBody()['DatiGenerali']['DatiGeneraliDocumento']['TipoDocumento'];
if ($tipo == 'TD06') {
$manager = new Parcella($name);
}
2024-01-15 15:30:45 +01:00
} catch (\UnexpectedValueException $e) {
2019-07-22 12:52:48 +02:00
$manager = new FatturaSemplificata($name);
2018-09-24 18:10:16 +02:00
}
2019-07-22 12:52:48 +02:00
return $manager;
2018-09-24 18:10:16 +02:00
}
2019-04-19 03:18:05 +02:00
public function getHeader()
2018-09-24 18:10:16 +02:00
{
2019-04-19 03:18:05 +02:00
return $this->xml['FatturaElettronicaHeader'];
2018-09-24 18:10:16 +02:00
}
2019-04-19 03:18:05 +02:00
public function getBody()
2018-09-24 18:10:16 +02:00
{
2019-04-19 03:18:05 +02:00
return $this->xml['FatturaElettronicaBody'];
}
2019-02-18 10:34:31 +01:00
2019-04-19 03:18:05 +02:00
public function delete()
{
delete($this->file);
2018-09-24 18:10:16 +02:00
}
2018-09-25 11:55:52 +02:00
public function getAllegati()
2018-09-24 18:10:16 +02:00
{
2018-09-25 11:55:52 +02:00
$result = $this->getBody()['Allegati'];
2019-04-19 03:18:05 +02:00
$result = $this->forceArray($result);
2018-09-25 11:55:52 +02:00
2018-12-07 10:56:49 +01:00
return array_clean($result);
2018-09-24 18:10:16 +02:00
}
2018-11-30 15:33:25 +01:00
public function saveAllegati()
2018-09-24 18:10:16 +02:00
{
2018-09-25 11:55:52 +02:00
$allegati = $this->getAllegati();
2018-09-24 18:10:16 +02:00
2024-03-27 16:43:30 +01:00
$id_module = (new Module())->getByField('name', 'Fatture di acquisto', \Models\Locale::getPredefined()->id);
2018-09-25 16:47:44 +02:00
2018-11-30 15:33:25 +01:00
$info = [
'category' => tr('Fattura Elettronica'),
2024-03-05 16:01:45 +01:00
'id_module' => $id_module,
2018-11-30 15:33:25 +01:00
'id_record' => $this->fattura->id,
];
2018-09-24 18:10:16 +02:00
foreach ($allegati as $allegato) {
$content = base64_decode($allegato['Attachment']);
$extension = '.pdf';
if (!empty($allegato['FormatoAttachment'])) {
$extension = '.'.strtolower($allegato['FormatoAttachment']);
}
2024-03-25 09:23:58 +01:00
if (preg_match('/\./', $allegato['NomeAttachment'])) {
$original = $allegato['NomeAttachment'];
} else {
2024-03-25 12:27:34 +01:00
$original = $allegato['NomeAttachment'].$extension;
2024-03-25 09:23:58 +01:00
}
2022-05-10 15:46:23 +02:00
try {
2024-01-15 15:30:45 +01:00
\Uploads::upload($content, array_merge($info, [
2022-05-10 15:46:23 +02:00
'name' => $allegato['NomeAttachment'],
'original_name' => $original,
]));
2024-01-15 15:30:45 +01:00
} catch (\UnexpectedValueException $e) {
2023-08-04 14:54:28 +02:00
}
2018-09-24 18:10:16 +02:00
}
2018-11-30 15:33:25 +01:00
// Registrazione XML come allegato
2024-01-15 15:30:45 +01:00
\Uploads::upload($this->file, array_merge($info, [
2018-11-30 15:33:25 +01:00
'name' => tr('Fattura Elettronica'),
'original_name' => basename($this->file),
2018-11-30 15:33:25 +01:00
]));
2018-09-24 18:10:16 +02:00
}
public function findAnagrafica($type = 'Fornitore')
2018-09-25 11:55:52 +02:00
{
2019-04-19 03:18:05 +02:00
$info = $this->getAnagrafe();
2024-02-06 12:07:51 +01:00
$anagrafica = Anagrafica::where('tipo', $type);
2019-04-19 03:18:05 +02:00
2019-07-24 15:41:04 +02:00
if (!empty($info['partita_iva']) && !empty($info['codice_fiscale'])) {
$anagrafica->where('piva', $info['partita_iva'])
->orWhere('codice_fiscale', $info['codice_fiscale'])
->orWhere('piva', 'like', '__'.$info['partita_iva'])
->orwhere('codice_fiscale', 'like', '__'.$info['codice_fiscale']);
2019-07-24 15:41:04 +02:00
} elseif (!empty($info['codice_fiscale'])) {
$anagrafica->where('codice_fiscale', $info['codice_fiscale'])
->orWhere('codice_fiscale', 'like', '__'.$info['codice_fiscale']);
2019-07-24 15:41:04 +02:00
} elseif (!empty($info['partita_iva'])) {
$anagrafica->where('piva', $info['partita_iva'])
->orWhere('piva', 'like', '__'.$info['partita_iva']);
}
2024-02-06 12:07:51 +01:00
$anagrafica = $anagrafica->get();
2024-01-15 15:30:45 +01:00
// Se non trovo l'anagrafica tra i fornitori, provo a ricercarla anche tra i clienti
2024-02-06 12:07:51 +01:00
if (empty($anagrafica)) {
$type = 'Cliente';
2024-02-06 17:25:50 +01:00
2024-02-06 12:07:51 +01:00
$anagrafica = Anagrafica::where('tipo', $type);
2023-08-04 14:54:28 +02:00
if (!empty($info['partita_iva']) && !empty($info['codice_fiscale'])) {
$anagrafica->where('piva', $info['partita_iva'])
->orWhere('codice_fiscale', $info['codice_fiscale'])
->orWhere('piva', 'like', '__'.$info['partita_iva'])
->orwhere('codice_fiscale', 'like', '__'.$info['codice_fiscale']);
} elseif (!empty($info['codice_fiscale'])) {
$anagrafica->where('codice_fiscale', $info['codice_fiscale'])
->orWhere('codice_fiscale', 'like', '__'.$info['codice_fiscale']);
} elseif (!empty($info['partita_iva'])) {
$anagrafica->where('piva', $info['partita_iva'])
->orWhere('piva', 'like', '__'.$info['partita_iva']);
}
2019-04-19 03:18:05 +02:00
}
return $anagrafica->first();
}
/**
* Restituisce l'anagrafica collegata alla fattura, eventualmente generandola con i dati forniti.
*
* @param string $type
*
* @return Anagrafica
*/
public function saveAnagrafica($type = 'Fornitore')
{
$anagrafica = $this->findAnagrafica($type);
2019-04-19 03:18:05 +02:00
if (!empty($anagrafica)) {
return $anagrafica;
}
$info = $this->getAnagrafe();
2019-04-19 03:18:05 +02:00
$anagrafica = Anagrafica::build($info['ragione_sociale'], $info['nome'], $info['cognome'], [
2024-03-28 16:38:03 +01:00
(new TipoAnagrafica())->getByField('name', $type, \Models\Locale::getPredefined()->id),
2019-04-19 03:18:05 +02:00
]);
if (!empty($info['partita_iva'])) {
$anagrafica->partita_iva = $info['partita_iva'];
}
if (!empty($info['codice_fiscale'])) {
$anagrafica->codice_fiscale = $info['codice_fiscale'];
}
// Informazioni sull'anagrafica
if (!empty($info['rea'])) {
if (!empty($info['rea']['codice'])) {
$anagrafica->codicerea = $info['rea']['codice'];
}
if (!empty($info['rea']['capitale_sociale'])) {
$anagrafica->capitale_sociale = $info['rea']['capitale_sociale'];
}
}
$anagrafica->save();
// Informazioni sulla sede
$sede = $anagrafica->sedeLegale;
$sede->indirizzo = $info['sede']['indirizzo'];
$sede->cap = $info['sede']['cap'];
2020-06-30 13:33:42 +02:00
$sede->citta = $info['sede']['citta'];
2019-04-19 03:18:05 +02:00
if (!empty($info['sede']['provincia'])) {
$sede->provincia = $info['sede']['provincia'];
}
$sede->nazione()->associate(Nazione::where('iso2', $info['sede']['nazione'])->first());
$contatti = $info['contatti'];
if (!empty($contatti)) {
if (!empty($contatti['telefono'])) {
$sede->telefono = $contatti['telefono'];
}
if (!empty($contatti['fax'])) {
$sede->fax = $contatti['fax'];
}
if (!empty($contatti['email'])) {
$sede->email = $contatti['email'];
}
}
$sede->save();
return $anagrafica;
2018-09-25 11:55:52 +02:00
}
2018-09-24 18:10:16 +02:00
/**
* Registra la fattura elettronica come fattura del gestionale.
*
2019-07-22 12:52:48 +02:00
* @param int $id_pagamento
* @param int $id_sezionale
* @param int $id_tipo
2019-07-22 11:35:44 +02:00
* @param string $data_registrazione
2019-07-22 12:52:48 +02:00
* @param int $ref_fattura
2019-07-22 11:35:44 +02:00
*
2019-04-19 03:18:05 +02:00
* @return Fattura
2018-09-24 18:10:16 +02:00
*/
public function saveFattura($id_pagamento, $id_sezionale, $id_tipo, $data_registrazione, $ref_fattura, $is_ritenuta_pagata = false)
2018-09-24 18:10:16 +02:00
{
$dati_generali = $this->getBody()['DatiGenerali']['DatiGeneraliDocumento'];
2020-10-09 16:43:07 +02:00
$data = self::parseDate($dati_generali['Data']);
2019-01-10 18:41:25 +01:00
$fattura = $this->prepareFattura($id_tipo, $data, $data_registrazione, $id_sezionale, $ref_fattura);
2019-07-22 12:52:48 +02:00
$this->fattura = $fattura;
$numero_esterno = $dati_generali['Numero'];
2018-11-30 15:33:25 +01:00
$progressivo_invio = $this->getHeader()['DatiTrasmissione']['ProgressivoInvio'];
2018-09-24 18:10:16 +02:00
2018-11-30 15:33:25 +01:00
$fattura->progressivo_invio = $progressivo_invio;
$fattura->numero_esterno = $numero_esterno;
2018-09-25 16:47:44 +02:00
$fattura->idpagamento = $id_pagamento;
$fattura->is_ritenuta_pagata = $is_ritenuta_pagata;
2019-04-04 17:30:58 +02:00
2023-06-27 17:16:56 +02:00
// Salvataggio banca fornitore se specificata nel file XML
$info_pagamento = $this->getBody()['DatiPagamento']['DettaglioPagamento'];
if ($info_pagamento['IBAN']) {
$banca_fornitore = Banca::where('iban', $info_pagamento['IBAN'])->first();
if (empty($banca_fornitore)) {
$anagrafica = $fattura->anagrafica;
$nome = $info_pagamento['IstitutoFinanziario'] ?: 'Banca di '.$anagrafica->ragione_sociale;
try {
$banca_fornitore = Banca::build($anagrafica, $nome, $info_pagamento['IBAN'], $info_pagamento['BIC'] ?: '');
} catch (\UnexpectedValueException $e) {
2024-02-08 13:10:46 +01:00
flash()->error(tr('Errore durante la creazione della banca: verificare la correttezza dei dati').'.');
}
2023-06-27 17:16:56 +02:00
}
}
// Banca addebito del cliente o banca collegata al pagamento
if (!empty($fattura->anagrafica->idbanca_acquisti)) {
$banca = $fattura->anagrafica->idbanca_acquisti;
} else {
$banca = Banca::where('id_pianodeiconti3', $fattura->pagamento->idconto_acquisti)->where('id_anagrafica', setting('Azienda predefinita'))->first()->id;
}
$fattura->id_banca_azienda = $banca;
2019-07-22 11:35:44 +02:00
// Riferimento per nota di credito e debito
$fattura->ref_documento = $ref_fattura ?: null;
2019-07-22 15:45:36 +02:00
// Per il destinatario, la data di registrazione della fattura assume grande rilievo ai fini IVA, poiché determina la decorrenza dei termini per poter esercitare il diritto alla detrazione.
2019-04-19 03:18:05 +02:00
// La data di ricezione della fattura è contenuta allinterno della “ricevuta di consegna” visibile al trasmittente della stessa.
2019-07-22 15:45:36 +02:00
$fattura->data_registrazione = $data_registrazione;
$fattura->data_competenza = $fattura->data;
2018-09-24 18:10:16 +02:00
2024-03-27 16:43:30 +01:00
$stato_documento = (new Stato())->getByField('name', 'Emessa', \Models\Locale::getPredefined()->id);
2018-09-24 18:10:16 +02:00
$fattura->stato()->associate($stato_documento);
2019-01-10 18:41:25 +01:00
$causali = $dati_generali['Causale'];
2019-04-19 03:18:05 +02:00
if (!empty($causali)) {
$note = '';
2019-01-10 18:41:25 +01:00
foreach ($causali as $causale) {
$note .= $causale;
}
2019-07-23 18:04:01 +02:00
2019-01-10 18:41:25 +01:00
$fattura->note = $note;
}
// Sconto finale da ScontoMaggiorazione: non importato
2018-09-25 11:55:52 +02:00
$fattura->save();
2018-09-24 18:10:16 +02:00
2020-04-27 10:24:03 +02:00
// Fix generazione idsede
$fattura->refresh();
2019-04-19 03:18:05 +02:00
return $fattura;
2018-09-24 18:10:16 +02:00
}
2018-11-30 15:33:25 +01:00
2019-04-19 03:18:05 +02:00
public function getFattura()
2018-11-30 15:33:25 +01:00
{
2019-04-19 03:18:05 +02:00
return $this->fattura;
}
public function save($info = [])
{
$this->saveFattura($info['id_pagamento'], $info['id_segment'], $info['id_tipo'], $info['data_registrazione'], $info['ref_fattura'], $info['is_ritenuta_pagata']);
2019-04-19 03:18:05 +02:00
$this->saveRighe($info['articoli'], $info['iva'], $info['conto'], $info['movimentazione'], $info['crea_articoli'], $info['tipo_riga_riferimento'], $info['id_riga_riferimento'], $info['tipo_riga_riferimento_vendita'], $info['id_riga_riferimento_vendita'], $info['update_info'], $info['serial']);
2019-04-19 03:18:05 +02:00
$this->saveAllegati();
2021-10-21 09:45:51 +02:00
$this->getFattura()->save(['forza_emissione']);
2019-04-19 03:18:05 +02:00
return $this->getFattura()->id;
}
2020-10-09 16:43:07 +02:00
public static function parseDate($data)
{
return date('Y-m-d', strtotime($data));
}
protected function prepareFattura($id_tipo, $data, $data_registrazione, $id_sezionale, $ref_fattura)
2019-07-22 12:52:48 +02:00
{
$anagrafica = $this->saveAnagrafica();
$tipo = TipoFattura::where('id', $id_tipo)->first();
$fattura = Fattura::build($anagrafica, $tipo, $data, $id_sezionale, null, $data_registrazione);
2019-07-22 12:52:48 +02:00
$this->fattura = $fattura;
// Riferimento per nota di credito e debito
$fattura->ref_documento = $ref_fattura ?: null;
return $fattura;
}
2019-04-19 03:18:05 +02:00
protected function forceArray($result)
{
$result = isset($result[0]) ? $result : [$result];
return $result;
2018-11-30 15:33:25 +01:00
}
2018-09-24 18:10:16 +02:00
}