Supporto per FE semplificate

This commit is contained in:
Thomas Zilio 2019-04-18 18:18:05 -07:00
parent 10c3c74a46
commit 7e99578ae0
8 changed files with 470 additions and 255 deletions

View File

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

View File

@ -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_', [

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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 '
<form action="'.$rootdir.'/actions.php" method="post">
@ -15,16 +15,16 @@ echo '
<input type="hidden" name="op" value="generate">';
// 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'];

View File

@ -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 allinterno 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 allinterno 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;
}
}

View File

@ -0,0 +1,172 @@
<?php
namespace Plugins\ImportFE;
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Fatture\Components\Articolo;
use Modules\Fatture\Components\Riga;
use Modules\Fatture\Fattura;
use UnexpectedValueException;
use Util\XML;
/**
* Classe per la gestione della fatturazione elettronica in XML.
*
* @since 2.4.2
*/
class FatturaOrdinaria extends FatturaElettronica
{
public function __construct($name)
{
parent::__construct($name);
if ($this->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();
}
}
}

View File

@ -0,0 +1,121 @@
<?php
namespace Plugins\ImportFE;
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Fatture\Components\Articolo;
use Modules\Fatture\Components\Riga;
use UnexpectedValueException;
use Util\XML;
/**
* Classe per la gestione della fatturazione elettronica in XML.
*
* @since 2.4.2
*/
class FatturaSemplificata extends FatturaElettronica
{
public function __construct($name)
{
parent::__construct($name);
if ($this->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();
}
}
}