From 7e99578ae09e8a2ee30370c203e5e430402063a8 Mon Sep 17 00:00:00 2001 From: Thomas Zilio Date: Thu, 18 Apr 2019 18:18:05 -0700 Subject: [PATCH] Supporto per FE semplificate --- CHANGELOG.md | 2 + modules/anagrafiche/actions.php | 21 +- modules/anagrafiche/src/Anagrafica.php | 26 +- plugins/importFE/actions.php | 18 +- plugins/importFE/rows.php | 18 +- plugins/importFE/src/FatturaElettronica.php | 347 +++++++------------ plugins/importFE/src/FatturaOrdinaria.php | 172 +++++++++ plugins/importFE/src/FatturaSemplificata.php | 121 +++++++ 8 files changed, 470 insertions(+), 255 deletions(-) create mode 100644 plugins/importFE/src/FatturaOrdinaria.php create mode 100644 plugins/importFE/src/FatturaSemplificata.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a6f12c55..281426ee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://k - Aggiunto campo data ricezione per le **Fatture di acquisto** - Aggiunta stampa **Preventivo** senza costi totali - Aggiunto export massivo XML fatture + - Aggiunte le impostazioni "Riferimento dei documenti nelle stampe" e "Riferimento dei documenti in Fattura Elettronica" per permettere l'inclusione o meno delle relative diciture in stampe e Fattura Elettronica + - Aggiunto supporto all'importazione delle Fatture Elettroniche Semplificate ### Modificato (Changed) diff --git a/modules/anagrafiche/actions.php b/modules/anagrafiche/actions.php index 0637ff746..b9b28a941 100644 --- a/modules/anagrafiche/actions.php +++ b/modules/anagrafiche/actions.php @@ -26,17 +26,11 @@ switch (post('op')) { $sede->save(); - if (empty(post('ragione_sociale'))) { - $ragione_sociale = post('cognome').' '.post('nome'); - } else { - $ragione_sociale = post('ragione_sociale'); - } - // Informazioni sull'anagrafica $anagrafica->codice = post('codice'); $anagrafica->tipo = post('tipo'); $anagrafica->codice_destinatario = post('codice_destinatario'); - $anagrafica->ragione_sociale = $ragione_sociale; + $anagrafica->ragione_sociale = post('ragione_sociale'); $anagrafica->nome = post('nome'); $anagrafica->cognome = post('cognome'); @@ -127,14 +121,9 @@ switch (post('op')) { case 'add': $idtipoanagrafica = post('idtipoanagrafica'); + $ragione_sociale = post('ragione_sociale'); - if (empty(post('ragione_sociale'))) { - $ragione_sociale = post('cognome').' '.post('nome'); - } else { - $ragione_sociale = post('ragione_sociale'); - } - - $anagrafica = Anagrafica::build($ragione_sociale, $idtipoanagrafica); + $anagrafica = Anagrafica::build($ragione_sociale, post('nome'), post('cognome'), $idtipoanagrafica); $id_record = $anagrafica->id; // Se ad aggiungere un cliente è un agente, lo imposto come agente di quel cliente @@ -152,8 +141,6 @@ switch (post('op')) { $idagente = ($agente_is_logged && in_array($id_cliente, $idtipoanagrafica)) ? $user['idanagrafica'] : 0; - $anagrafica->nome = post('nome'); - $anagrafica->cognome = post('cognome'); $anagrafica->partita_iva = post('piva'); $anagrafica->codice_fiscale = post('codice_fiscale'); $anagrafica->indirizzo = post('indirizzo'); @@ -178,7 +165,7 @@ switch (post('op')) { // Lettura tipologia della nuova anagrafica $descrizioni_tipi = $anagrafica->tipi()->get()->pluck('descrizione')->toArray(); if (isAjaxRequest() && in_array(post('tipoanagrafica'), $descrizioni_tipi)) { - echo json_encode(['id' => $id_record, 'text' => $ragione_sociale]); + echo json_encode(['id' => $id_record, 'text' => $anagrafica->ragione_sociale]); } flash()->info(tr('Aggiunta nuova anagrafica di tipo _TYPE_', [ diff --git a/modules/anagrafiche/src/Anagrafica.php b/modules/anagrafiche/src/Anagrafica.php index 8c45d93fe..b80ec939c 100644 --- a/modules/anagrafiche/src/Anagrafica.php +++ b/modules/anagrafiche/src/Anagrafica.php @@ -36,12 +36,15 @@ class Anagrafica extends Model * * @return self */ - public static function build($ragione_sociale, array $tipologie = []) + public static function build($ragione_sociale, $nome = '', $cognome = '', array $tipologie = []) { $model = parent::build(); $model->ragione_sociale = $ragione_sociale; + $model->nome = $nome; + $model->cognome = $cognome; + $ultimo = database()->fetchOne('SELECT codice FROM an_anagrafiche ORDER BY CAST(codice AS SIGNED) DESC LIMIT 1'); $codice = Generator::generate(setting('Formato codice anagrafica'), $ultimo['codice']); @@ -179,6 +182,20 @@ class Anagrafica extends Model $this->attributes['piva'] = trim(strtoupper($value)); } + public function setNomeAttribute($value) + { + $this->attributes['nome'] = trim($value); + + $this->fixRagioneSociale(); + } + + public function setCognomeAttribute($value) + { + $this->attributes['cognome'] = trim($value); + + $this->fixRagioneSociale(); + } + public function setCodiceFiscaleAttribute($value) { $this->attributes['codice_fiscale'] = trim(strtoupper($value)); @@ -219,4 +236,11 @@ class Anagrafica extends Model { return $this; } + + protected function fixRagioneSociale() + { + if (!empty($this->cognome) || !empty($this->nome)) { + $this->ragione_sociale = $this->cognome.' '.$this->nome; + } + } } diff --git a/plugins/importFE/actions.php b/plugins/importFE/actions.php index a30de556d..99049cc22 100644 --- a/plugins/importFE/actions.php +++ b/plugins/importFE/actions.php @@ -39,7 +39,7 @@ switch (filter('op')) { break; case 'delete': - $directory = Plugins\ImportFE\FatturaElettronica::getImportDirectory(); + $directory = FatturaElettronica::getImportDirectory(); delete($directory.'/'.get('name')); @@ -48,12 +48,18 @@ switch (filter('op')) { case 'generate': $filename = post('filename'); - $fattura_pa = new FatturaElettronica($filename); + $info = [ + 'id_pagamento' => post('pagamento'), + 'id_segment' => post('id_segment'), + 'id_tipo' => post('id_tipo'), + 'articoli' => post('articoli'), + 'iva' => post('iva'), + 'conto' => post('conto'), + 'movimentazione' => post('movimentazione'), + ]; - $id_record = $fattura_pa->saveFattura(post('pagamento'), post('id_segment'), post('id_tipo')); - $fattura_pa->saveRighe(post('articoli'), post('iva'), post('conto'), post('movimentazione')); - - $fattura_pa->saveAllegati(); + $fattura_pa = FatturaElettronica::manage($filename); + $id_record = $fattura_pa->save($info); $idrivalsainps = 0; $idritenutaacconto = 0; diff --git a/plugins/importFE/rows.php b/plugins/importFE/rows.php index b44dce62b..db379f9a5 100644 --- a/plugins/importFE/rows.php +++ b/plugins/importFE/rows.php @@ -2,7 +2,7 @@ include_once __DIR__.'/../../core.php'; -$fattura_pa = new Plugins\ImportFE\FatturaElettronica(get('filename')); +$fattura_pa = \Plugins\ImportFE\FatturaElettronica::manage(get('filename')); echo '
@@ -15,16 +15,16 @@ echo ' '; // Fornitore -$fornitore = $fattura_pa->getHeader()['CedentePrestatore']['DatiAnagrafici']; -$ragione_sociale = $fornitore['Anagrafica']['Denominazione'] ?: $fornitore['Anagrafica']['Nome'].' '.$fornitore['Anagrafica']['Cognome']; -$codice_fiscale = $fornitore['CodiceFiscale']; -$partita_iva = $fornitore['IdFiscaleIVA']['IdCodice']; +$fornitore = $fattura_pa->getAnagrafe(); +$ragione_sociale = $fornitore['ragione_sociale'] ?: $fornitore['cognome'].' '.$fornitore['nome']; +$codice_fiscale = $fornitore['codice_fiscale']; +$partita_iva = $fornitore['partita_iva']; -$sede = $fattura_pa->getHeader()['CedentePrestatore']['Sede']; +$sede = $fornitore['sede']; -$cap = $sede['CAP']; -$citta = $sede['Comune']; -$provincia = $sede['Provincia']; +$cap = $sede['cap']; +$citta = $sede['comune']; +$provincia = $sede['provincia']; // Dati generali $dati_generali = $fattura_pa->getBody()['DatiGenerali']['DatiGeneraliDocumento']; diff --git a/plugins/importFE/src/FatturaElettronica.php b/plugins/importFE/src/FatturaElettronica.php index 46c189d29..c86828cc8 100644 --- a/plugins/importFE/src/FatturaElettronica.php +++ b/plugins/importFE/src/FatturaElettronica.php @@ -6,9 +6,6 @@ use Modules; use Modules\Anagrafiche\Anagrafica; use Modules\Anagrafiche\Nazione; use Modules\Anagrafiche\Tipo as TipoAnagrafica; -use Modules\Articoli\Articolo as ArticoloOriginale; -use Modules\Fatture\Components\Articolo; -use Modules\Fatture\Components\Riga; use Modules\Fatture\Fattura; use Modules\Fatture\Stato as StatoFattura; use Modules\Fatture\Tipo as TipoFattura; @@ -19,7 +16,7 @@ use Util\XML; /** * Classe per la gestione della fatturazione elettronica in XML. * - * @since 2.4.2 + * @since 2.4.9 */ class FatturaElettronica { @@ -31,7 +28,7 @@ class FatturaElettronica /** @var array XML della fattura */ protected $xml = null; - /** @var Fattura Fattura collegata */ + /** @var FatturaElettronica Fattura collegata */ protected $fattura = null; public function __construct($name) @@ -52,8 +49,6 @@ class FatturaElettronica ])->first(); if (!empty($fattura)) { - $this->delete(); - throw new UnexpectedValueException(); } } @@ -91,10 +86,26 @@ class FatturaElettronica return true; } catch (UnexpectedValueException $e) { + $file = static::getImportDirectory().'/'.$name; + delete($file); + return false; } } + public static function manage($name) + { + try { + $fattura = new FatturaOrdinaria($name); + + return $fattura; + } catch (UnexpectedValueException $e) { + $fattura = new FatturaSemplificata($name); + + return $fattura; + } + } + public function getHeader() { return $this->xml['FatturaElettronicaHeader']; @@ -105,204 +116,16 @@ class FatturaElettronica return $this->xml['FatturaElettronicaBody']; } - public static function createAnagrafica($xml, $type = 'Fornitore') + public function delete() { - $database = database(); - - $where = []; - - $partita_iva = $xml['DatiAnagrafici']['IdFiscaleIVA']['IdCodice']; - if (!empty($partita_iva)) { - $where[] = '`piva` = '.prepare($partita_iva); - } - - $codice_fiscale = $xml['DatiAnagrafici']['CodiceFiscale']; - if (!empty($codice_fiscale)) { - $where[] = '`codice_fiscale` = '.prepare($codice_fiscale); - } - - $id_anagrafica = $database->fetchOne('SELECT `an_anagrafiche`.`idanagrafica` FROM `an_anagrafiche` - INNER JOIN `an_tipianagrafiche_anagrafiche` ON `an_anagrafiche`.`idanagrafica` = `an_tipianagrafiche_anagrafiche`.`idanagrafica` - INNER JOIN `an_tipianagrafiche` ON `an_tipianagrafiche`.`idtipoanagrafica` = `an_tipianagrafiche_anagrafiche`.`idtipoanagrafica` - WHERE `an_tipianagrafiche`.`descrizione` = '.prepare($type).' AND ('.implode(' OR ', $where).')')['idanagrafica']; - if (!empty($id_anagrafica)) { - return Anagrafica::find($id_anagrafica); - } - - $ragione_sociale = $xml['DatiAnagrafici']['Anagrafica']['Denominazione'] ?: $xml['DatiAnagrafici']['Anagrafica']['Nome'].' '.$xml['DatiAnagrafici']['Anagrafica']['Cognome']; - $anagrafica = Anagrafica::build($ragione_sociale, [ - TipoAnagrafica::where('descrizione', 'Fornitore')->first()->id, - ]); - - // Informazioni sull'anagrafica - $REA = $xml['IscrizioneREA']; - if (!empty($REA)) { - if (!empty($REA['Ufficio']) and !empty($REA['NumeroREA'])) { - $anagrafica->codicerea = $REA['Ufficio'].'-'.$REA['NumeroREA']; - } - - if (!empty($REA['CapitaleSociale'])) { - $anagrafica->capitale_sociale = $REA['CapitaleSociale']; - } - } - - $anagrafica->save(); - - // Informazioni sulla sede - $info = $xml['Sede']; - $sede = $anagrafica->sedeLegale; - - if (!empty($partita_iva)) { - $sede->partita_iva = $partita_iva; - } - - if (!empty($codice_fiscale)) { - $sede->codice_fiscale = $codice_fiscale; - } - - $sede->indirizzo = $info['Indirizzo']; - $sede->cap = $info['CAP']; - $sede->citta = $info['Comune']; - if (!empty($info['Provincia'])) { - $sede->provincia = $info['Provincia']; - } - $sede->nazione()->associate(Nazione::where('iso2', $info['Nazione'])->first()); - - $contatti = $xml['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; - } - - public function getRighe() - { - $result = $this->getBody()['DatiBeniServizi']['DettaglioLinee']; - - $result = isset($result[0]) ? $result : [$result]; - - return $result; - } - - public function saveRighe($articoli, $iva, $conto, $movimentazione = true) - { - $righe = $this->getRighe(); - $fattura = $this->getFattura(); - - foreach ($righe as $key => $riga) { - $articolo = ArticoloOriginale::find($articoli[$key]); - - $riga['PrezzoUnitario'] = floatval($riga['PrezzoUnitario']); - $riga['Quantita'] = floatval($riga['Quantita']); - - if (!empty($articolo)) { - $obj = Articolo::build($fattura, $articolo); - - $obj->movimentazione($movimentazione); - } else { - $obj = Riga::build($fattura); - } - - $obj->descrizione = $riga['Descrizione']; - $obj->id_iva = $iva[$key]; - $obj->idconto = $conto[$key]; - - // Nel caso il prezzo sia negativo viene gestito attraverso l'inversione della quantità (come per le note di credito) - // TODO: per migliorare la visualizzazione, sarebbe da lasciare negativo il prezzo e invertire gli sconti. - $prezzo = $riga['PrezzoUnitario']; - $prezzo = $riga['PrezzoUnitario'] < 0 ? -$prezzo : $prezzo; - $qta = $riga['Quantita'] ?: 1; - $qta = $riga['PrezzoUnitario'] < 0 ? -$qta : $qta; - - // Prezzo e quantità - $obj->prezzo_unitario_vendita = $prezzo; - $obj->qta = $qta; - - if (!empty($riga['UnitaMisura'])) { - $obj->um = $riga['UnitaMisura']; - } - - // Sconti e maggiorazioni - $sconti = $riga['ScontoMaggiorazione']; - if (!empty($sconti)) { - $sconti = $sconti[0] ? $sconti : [$sconti]; - $tipo = !empty($sconti[0]['Percentuale']) ? 'PRC' : 'UNT'; - - $lista = []; - foreach ($sconti as $sconto) { - $unitario = $sconto['Percentuale'] ?: $sconto['Importo']; - - // Sconto o Maggiorazione - $lista[] = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario; - } - - if ($tipo == 'PRC') { - $elenco = implode('+', $lista); - $sconto = calcola_sconto([ - 'sconto' => $elenco, - 'prezzo' => $obj->prezzo_unitario_vendita, - 'tipo' => 'PRC', - 'qta' => $obj->qta, - ]); - - /* - * Trasformazione di sconti multipli in sconto percentuale combinato. - * Esempio: 40% + 30% è uno sconto del 42%. - */ - $sconto_unitario = $sconto * 100 / $obj->imponibile; - } else { - $sconto_unitario = sum($lista); - } - - $obj->sconto_unitario = $sconto_unitario; - $obj->tipo_sconto = $tipo; - } - - $obj->save(); - } - - // Arrotondamenti differenti nella fattura XML - $totali_righe = array_column($righe, 'PrezzoTotale'); - $totale_righe = sum($totali_righe); - - $dati_generali = $this->getBody()['DatiGenerali']['DatiGeneraliDocumento']; - $totale_documento = $dati_generali['ImportoTotaleDocumento']; - - $diff = $totale_documento ? $totale_documento - $fattura->totale : $totale_righe - $fattura->imponibile_scontato; - if (!empty($diff)) { - // Rimozione dell?IVA calcolata automaticamente dal gestionale - $iva_arrotondamento = database()->fetchOne('SELECT * FROM co_iva WHERE id='.prepare($iva[0])); - $diff = $diff * 100 / (100 + $iva_arrotondamento['percentuale']); - - $obj = Riga::build($fattura); - - $obj->descrizione = tr('Arrotondamento calcolato in automatico'); - $obj->id_iva = $iva[0]; - $obj->idconto = $conto[0]; - $obj->prezzo_unitario_vendita = round($diff, 4); - $obj->qta = 1; - - $obj->save(); - } + delete($this->file); } public function getAllegati() { $result = $this->getBody()['Allegati']; - $result = isset($result[0]) ? $result : [$result]; + $result = $this->forceArray($result); return array_clean($result); } @@ -347,19 +170,94 @@ class FatturaElettronica ])); } - public function getFattura() + public function saveAnagrafica($type = 'Fornitore') { - return $this->fattura; + $info = $this->getAnagrafe(); + + $tipologia = TipoAnagrafica::where('descrizione', $type)->first(); + + $anagrafica = Anagrafica::whereHas('tipi', function ($query) use ($tipologia) { + $query->where('an_tipianagrafiche.idtipoanagrafica', '=', $tipologia->id); + }); + + if (!empty($info['partita_iva'])) { + $anagrafica->where('piva', $info['partita_iva']); + } + + if (!empty($info['codice_fiscale'])) { + $anagrafica->where('codice_fiscale', $info['codice_fiscale']); + } + + $anagrafica = $anagrafica->first(); + + if (!empty($anagrafica)) { + return $anagrafica; + } + + $anagrafica = Anagrafica::build($info['ragione_sociale'], $info['nome'], $info['cognome'], [ + TipoAnagrafica::where('descrizione', $type)->first()->id, + ]); + + 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']; + $sede->citta = $info['sede']['comune']; + 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; } /** * Registra la fattura elettronica come fattura del gestionale. * - * @return int + * @return Fattura */ public function saveFattura($id_pagamento, $id_sezionale, $id_tipo) { - $anagrafica = static::createAnagrafica($this->getHeader()['CedentePrestatore']); + $anagrafica = $this->saveAnagrafica(); $dati_generali = $this->getBody()['DatiGenerali']['DatiGeneraliDocumento']; $data = $dati_generali['Data']; @@ -376,27 +274,13 @@ class FatturaElettronica $fattura->numero_esterno = $numero_esterno; $fattura->idpagamento = $id_pagamento; - //Per il destinatario, la data di ricezione della fattura assume grande rilievo ai fini IVA, poiché determina la decorrenza dei termini per poter esercitare il diritto alla detrazione. - //La data di ricezione della fattura è contenuta all’interno della “ricevuta di consegna” visibile al trasmittente della stessa. + // Per il destinatario, la data di ricezione della fattura assume grande rilievo ai fini IVA, poiché determina la decorrenza dei termini per poter esercitare il diritto alla detrazione. + // La data di ricezione della fattura è contenuta all’interno della “ricevuta di consegna” visibile al trasmittente della stessa. $fattura->data_ricezione = $dati_generali['Data']; $stato_documento = StatoFattura::where('descrizione', 'Emessa')->first(); $fattura->stato()->associate($stato_documento); - // Nodo ScontoMaggiorazione generale per il documento ignorato (issue #542) - /* - // Sconto globale - $sconto = $dati_generali['ScontoMaggiorazione']; - if (!empty($sconto)) { - $tipo = !empty($sconto['Percentuale']) ? 'PRC' : 'UNT'; - $unitario = $sconto['Percentuale'] ?: $sconto['Importo']; - - $unitario = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario; - - $fattura->sconto_globale = $unitario; - $fattura->tipo_sconto_globale = $tipo; - }*/ - // Ritenuta d'Acconto $ritenuta = $dati_generali['DatiRitenuta']; if (!empty($ritenuta)) { @@ -407,7 +291,8 @@ class FatturaElettronica } $causali = $dati_generali['Causale']; - if (count($causali) > 0) { + if (!empty($causali)) { + $note = ''; foreach ($causali as $causale) { $note .= $causale; } @@ -422,11 +307,29 @@ class FatturaElettronica $fattura->save(); - return $fattura->id; + return $fattura; } - public function delete() + public function getFattura() { - delete($this->file); + return $this->fattura; + } + + public function save($info = []) + { + $this->saveFattura($info['id_pagamento'], $info['id_segment'], $info['id_tipo']); + + $this->saveRighe($info['articoli'], $info['iva'], $info['conto'], $info['movimentazione']); + + $this->saveAllegati(); + + return $this->getFattura()->id; + } + + protected function forceArray($result) + { + $result = isset($result[0]) ? $result : [$result]; + + return $result; } } diff --git a/plugins/importFE/src/FatturaOrdinaria.php b/plugins/importFE/src/FatturaOrdinaria.php new file mode 100644 index 000000000..96843abc6 --- /dev/null +++ b/plugins/importFE/src/FatturaOrdinaria.php @@ -0,0 +1,172 @@ +getHeader()['DatiTrasmissione']['FormatoTrasmissione'] == 'FSM10') { + throw new UnexpectedValueException(); + } + } + + public function getAnagrafe() + { + $dati = $this->getHeader()['CedentePrestatore']; + + $anagrafe = $dati['DatiAnagrafici']; + $rea = $dati['IscrizioneREA']; + $sede = $dati['Sede']; + $contatti = $dati['Contatti']; + + $info = [ + 'partita_iva' => $anagrafe['IdFiscaleIVA']['IdCodice'], + 'codice_fiscale' => $anagrafe['CodiceFiscale'], + 'ragione_sociale' => $anagrafe['Anagrafica']['Denominazione'], + 'nome' => $anagrafe['Anagrafica']['Nome'], + 'cognome' => $anagrafe['Anagrafica']['Cognome'], + 'rea' => [ + 'codice' => $rea['Ufficio'].'-'.$rea['NumeroREA'], + 'capitale_sociale' => $rea['CapitaleSociale'], + ], + 'sede' => [ + 'indirizzo' => $sede['Indirizzo'], + 'cap' => $sede['CAP'], + 'citta' => $sede['Comune'], + 'provincia' => $sede['Provincia'], + 'nazione' => $sede['Nazione'], + ], + 'contatti' => [ + 'telefono' => $contatti['Telefono'], + 'fax' => $contatti['Fax'], + 'email' => $contatti['email'], + ], + ]; + + return $info; + } + + public function getRighe() + { + $result = $this->getBody()['DatiBeniServizi']['DettaglioLinee']; + + return $this->forceArray($result); + } + + public function saveRighe($articoli, $iva, $conto, $movimentazione = true) + { + $righe = $this->getRighe(); + $fattura = $this->getFattura(); + + foreach ($righe as $key => $riga) { + $articolo = ArticoloOriginale::find($articoli[$key]); + + $riga['PrezzoUnitario'] = floatval($riga['PrezzoUnitario']); + $riga['Quantita'] = floatval($riga['Quantita']); + + if (!empty($articolo)) { + $obj = Articolo::build($fattura, $articolo); + + $obj->movimentazione($movimentazione); + } else { + $obj = Riga::build($fattura); + } + + $obj->descrizione = $riga['Descrizione']; + $obj->id_iva = $iva[$key]; + $obj->idconto = $conto[$key]; + + // Nel caso il prezzo sia negativo viene gestito attraverso l'inversione della quantità (come per le note di credito) + // TODO: per migliorare la visualizzazione, sarebbe da lasciare negativo il prezzo e invertire gli sconti. + $prezzo = $riga['PrezzoUnitario']; + $prezzo = $riga['PrezzoUnitario'] < 0 ? -$prezzo : $prezzo; + $qta = $riga['Quantita'] ?: 1; + $qta = $riga['PrezzoUnitario'] < 0 ? -$qta : $qta; + + // Prezzo e quantità + $obj->prezzo_unitario_vendita = $prezzo; + $obj->qta = $qta; + + if (!empty($riga['UnitaMisura'])) { + $obj->um = $riga['UnitaMisura']; + } + + // Sconti e maggiorazioni + $sconti = $riga['ScontoMaggiorazione']; + if (!empty($sconti)) { + $sconti = $sconti[0] ? $sconti : [$sconti]; + $tipo = !empty($sconti[0]['Percentuale']) ? 'PRC' : 'UNT'; + + $lista = []; + foreach ($sconti as $sconto) { + $unitario = $sconto['Percentuale'] ?: $sconto['Importo']; + + // Sconto o Maggiorazione + $lista[] = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario; + } + + if ($tipo == 'PRC') { + $elenco = implode('+', $lista); + $sconto = calcola_sconto([ + 'sconto' => $elenco, + 'prezzo' => $obj->prezzo_unitario_vendita, + 'tipo' => 'PRC', + 'qta' => $obj->qta, + ]); + + /* + * Trasformazione di sconti multipli in sconto percentuale combinato. + * Esempio: 40% + 30% è uno sconto del 42%. + */ + $sconto_unitario = $sconto * 100 / $obj->imponibile; + } else { + $sconto_unitario = sum($lista); + } + + $obj->sconto_unitario = $sconto_unitario; + $obj->tipo_sconto = $tipo; + } + + $obj->save(); + } + + // Arrotondamenti differenti nella fattura XML + $totali_righe = array_column($righe, 'PrezzoTotale'); + $totale_righe = sum($totali_righe); + + $dati_generali = $this->getBody()['DatiGenerali']['DatiGeneraliDocumento']; + $totale_documento = $dati_generali['ImportoTotaleDocumento']; + + $diff = $totale_documento ? $totale_documento - $fattura->totale : $totale_righe - $fattura->imponibile_scontato; + if (!empty($diff)) { + // Rimozione dell?IVA calcolata automaticamente dal gestionale + $iva_arrotondamento = database()->fetchOne('SELECT * FROM co_iva WHERE id='.prepare($iva[0])); + $diff = $diff * 100 / (100 + $iva_arrotondamento['percentuale']); + + $obj = Riga::build($fattura); + + $obj->descrizione = tr('Arrotondamento calcolato in automatico'); + $obj->id_iva = $iva[0]; + $obj->idconto = $conto[0]; + $obj->prezzo_unitario_vendita = round($diff, 4); + $obj->qta = 1; + + $obj->save(); + } + } +} diff --git a/plugins/importFE/src/FatturaSemplificata.php b/plugins/importFE/src/FatturaSemplificata.php new file mode 100644 index 000000000..ebf1fd51c --- /dev/null +++ b/plugins/importFE/src/FatturaSemplificata.php @@ -0,0 +1,121 @@ +getHeader()['DatiTrasmissione']['FormatoTrasmissione'] != 'FSM10') { + throw new UnexpectedValueException(); + } + } + + public function getAnagrafe() + { + $anagrafe = $this->getHeader()['CedentePrestatore']; + + $rea = $anagrafe['IscrizioneREA']; + $sede = $anagrafe['Sede']; + $contatti = $anagrafe['Contatti']; + + $info = [ + 'partita_iva' => $anagrafe['IdFiscaleIVA']['IdCodice'], + 'codice_fiscale' => $anagrafe['CodiceFiscale'], + 'ragione_sociale' => $anagrafe['Denominazione'], + 'nome' => $anagrafe['Nome'], + 'cognome' => $anagrafe['Cognome'], + 'rea' => [ + 'codice' => $rea['Ufficio'].'-'.$rea['NumeroREA'], + 'capitale_sociale' => $rea['CapitaleSociale'], + ], + 'sede' => [ + 'indirizzo' => $sede['Indirizzo'], + 'cap' => $sede['CAP'], + 'citta' => $sede['Comune'], + 'provincia' => $sede['Provincia'], + 'nazione' => $sede['Nazione'], + ], + ]; + + return $info; + } + + public function getRighe() + { + $result = $this->getBody()['DatiBeniServizi']; + $result = $this->forceArray($result); + + foreach ($result as $index => $item) { + $result[$index]['Quantita'] = 1; + + if (!empty($item['DatiIVA']['Aliquota'])) { + $result[$index]['AliquotaIVA'] = $item['DatiIVA']['Aliquota']; + } else { + $imposta = floatval($item['DatiIVA']['Imposta']); + $importo = floatval($item['Importo']); + + $prezzo = $importo - $imposta; + + $aliquota = !empty($prezzo) ? $imposta / $prezzo * 100 : 0; + $result[$index]['AliquotaIVA'] = $aliquota; + } + } + + return $result; + } + + public function saveRighe($articoli, $iva, $conto, $movimentazione = true) + { + $righe = $this->getRighe(); + $fattura = $this->getFattura(); + + foreach ($righe as $key => $riga) { + $articolo = ArticoloOriginale::find($articoli[$key]); + + $imposta = floatval($riga['DatiIVA']['Imposta']); + $importo = floatval($riga['Importo']); + + $prezzo_non_ivato = $importo - $imposta; + $riga['Importo'] = !empty($prezzo_non_ivato) ? $prezzo_non_ivato : $importo; + + if (!empty($articolo)) { + $obj = Articolo::build($fattura, $articolo); + + $obj->movimentazione($movimentazione); + } else { + $obj = Riga::build($fattura); + } + + $obj->descrizione = $riga['Descrizione']; + $obj->id_iva = $iva[$key]; + $obj->idconto = $conto[$key]; + + // Nel caso il prezzo sia negativo viene gestito attraverso l'inversione della quantità (come per le note di credito) + // TODO: per migliorare la visualizzazione, sarebbe da lasciare negativo il prezzo e invertire gli sconti. + $prezzo = $riga['Importo']; + $prezzo = $prezzo < 0 ? -$prezzo : $prezzo; + $qta = 1; + $qta = $riga['Importo'] < 0 ? -$qta : $qta; + + // Prezzo e quantità + $obj->prezzo_unitario_vendita = $prezzo; + $obj->qta = $qta; + + $obj->save(); + } + } +}