Supporto per FE semplificate
This commit is contained in:
parent
10c3c74a46
commit
7e99578ae0
|
@ -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)
|
||||
|
||||
|
|
|
@ -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_', [
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue