diff --git a/modules/fatture/src/Fattura.php b/modules/fatture/src/Fattura.php index 332df547a..90c26030b 100755 --- a/modules/fatture/src/Fattura.php +++ b/modules/fatture/src/Fattura.php @@ -69,7 +69,7 @@ class Fattura extends Document /** @var GestoreMovimenti */ protected $gestoreMovimenti; /** @var GestoreBollo */ - private $gestoreBollo; + protected $gestoreBollo; public function __construct(array $attributes = []) { diff --git a/update/2_4_23.php b/update/2_4_23.php new file mode 100644 index 000000000..cbafec978 --- /dev/null +++ b/update/2_4_23.php @@ -0,0 +1,16 @@ +', '2020-08-01') + ->whereHas('stato', function ($query) { + return $query->whereNotIn('descrizione', ['Bozza', 'Annullata']); + }) + ->get(); + +foreach ($fatture as $fattura) { + $gestore = new GestoreMovimenti($fattura); + $gestore->registra(); +} diff --git a/update/v2_4_10/Anagrafica.php b/update/v2_4_10/Anagrafica.php deleted file mode 100755 index 1b835f462..000000000 --- a/update/v2_4_10/Anagrafica.php +++ /dev/null @@ -1,294 +0,0 @@ -ragione_sociale = $ragione_sociale; - - $model->nome = $nome; - $model->cognome = $cognome; - - $model->codice = static::getNextCodice(); - $model->id_ritenuta_acconto_vendite = setting("Percentuale ritenuta d'acconto"); - $model->save(); - - $model->tipologie = $tipologie; - $model->save(); - - return $model; - } - - public static function fromTipo($type) - { - $tipologia = TipoAnagrafica::where('descrizione', 'Tecnico')->first(); - - $anagrafiche = self::whereHas('tipi', function ($query) use ($tipologia) { - $query->where('an_tipianagrafiche.idtipoanagrafica', '=', $tipologia->id); - }); - - return $anagrafiche; - } - - public static function fixAzienda(Anagrafica $anagrafica) - { - Settings::setValue('Azienda predefinita', $anagrafica->id); - } - - public static function fixCliente(Anagrafica $anagrafica) - { - $database = database(); - - // Creo il relativo conto nel partitario se non esiste - if (empty($anagrafica->idconto_cliente)) { - // Calcolo prossimo numero cliente - $rs = $database->fetchArray("SELECT MAX(CAST(co_pianodeiconti3.numero AS UNSIGNED)) AS max_numero FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti2.descrizione='Crediti clienti e crediti diversi'"); - $new_numero = $rs[0]['max_numero'] + 1; - $new_numero = str_pad($new_numero, 6, '0', STR_PAD_LEFT); - - $database->query('INSERT INTO co_pianodeiconti3(numero, descrizione, idpianodeiconti2, can_delete, can_edit) VALUES('.prepare($new_numero).', '.prepare($anagrafica->ragione_sociale).", (SELECT id FROM co_pianodeiconti2 WHERE descrizione='Crediti clienti e crediti diversi'), 1, 1)"); - $idconto = $database->lastInsertedID(); - - // Collegamento conto - $anagrafica->idconto_cliente = $idconto; - $anagrafica->save(); - } - } - - public static function fixFornitore(Anagrafica $anagrafica) - { - $database = database(); - - // Creo il relativo conto nel partitario se non esiste - if (empty($anagrafica->idconto_fornitore)) { - // Calcolo prossimo numero cliente - $rs = $database->fetchArray("SELECT MAX(CAST(co_pianodeiconti3.numero AS UNSIGNED)) AS max_numero FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti2.descrizione='Debiti fornitori e debiti diversi'"); - $new_numero = $rs[0]['max_numero'] + 1; - $new_numero = str_pad($new_numero, 6, '0', STR_PAD_LEFT); - - $database->query('INSERT INTO co_pianodeiconti3(numero, descrizione, idpianodeiconti2, can_delete, can_edit) VALUES('.prepare($new_numero).', '.prepare($anagrafica->ragione_sociale).", (SELECT id FROM co_pianodeiconti2 WHERE descrizione='Debiti fornitori e debiti diversi'), 1, 1)"); - $idconto = $database->lastInsertedID(); - - // Collegamento conto - $anagrafica->idconto_fornitore = $idconto; - $anagrafica->save(); - } - } - - public static function fixTecnico(Anagrafica $anagrafica) - { - $database = database(); - - $presenti = $database->fetchArray('SELECT idtipointervento AS id FROM in_tariffe WHERE idtecnico = '.prepare($anagrafica->id)); - - // Aggiunta associazioni costi unitari al contratto - $tipi = TipoSessione::whereNotIn('idtipointervento', array_column($presenti, 'id'))->get(); - - foreach ($tipi as $tipo) { - $database->insert('in_tariffe', [ - 'idtecnico' => $anagrafica->id, - 'idtipointervento' => $tipo->id, - 'costo_ore' => $tipo->costo_orario, - 'costo_km' => $tipo->costo_km, - 'costo_dirittochiamata' => $tipo->costo_diritto_chiamata, - 'costo_ore_tecnico' => $tipo->costo_orario_tecnico, - 'costo_km_tecnico' => $tipo->costo_km_tecnico, - 'costo_dirittochiamata_tecnico' => $tipo->costo_diritto_chiamata_tecnico, - ]); - } - } - - /** - * Aggiorna la tipologia dell'anagrafica. - */ - public function setTipologieAttribute(array $tipologie) - { - if ($this->isAzienda()) { - $tipologie[] = TipoAnagrafica::where('descrizione', 'Azienda')->first()->id; - } - - $tipologie = array_clean($tipologie); - - $previous = $this->tipi()->get(); - $this->tipi()->sync($tipologie); - $actual = $this->tipi()->get(); - - $diff = $actual->diff($previous); - - foreach ($diff as $tipo) { - $method = 'fix'.$tipo->descrizione; - if (method_exists($this, $method)) { - self::$method($this); - } - } - } - - /** - * Controlla se l'anagrafica è di tipo 'Azienda'. - * - * @return bool - */ - public function isAzienda() - { - return $this->isTipo('Azienda'); - } - - /** - * Controlla se l'anagrafica è di tipo 'Azienda'. - * - * @return bool - */ - public function isTipo($type) - { - return $this->tipi()->get()->search(function ($item, $key) use ($type) { - return $item->descrizione == $type; - }) !== false; - } - - /** - * Restituisce l'identificativo. - * - * @return int - */ - public function getIdAttribute() - { - return $this->idanagrafica; - } - - public function getPartitaIvaAttribute() - { - return $this->piva; - } - - public function setPartitaIvaAttribute($value) - { - $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)); - } - - public function setCodiceDestinatarioAttribute($value) - { - if ($this->tipo == 'Privato' || in_array($value, ['999999', '0000000']) || $this->sedeLegale->nazione->iso2 != 'IT') { - $codice_destinatario = ''; - } else { - $codice_destinatario = $value; - } - - $this->attributes['codice_destinatario'] = trim(strtoupper($codice_destinatario)); - } - - public function tipi() - { - return $this->belongsToMany(TipoAnagrafica::class, 'an_tipianagrafiche_anagrafiche', 'idanagrafica', 'idtipoanagrafica'); - } - - public function fatture() - { - return $this->hasMany(Fattura::class, 'idanagrafica'); - } - - public function nazione() - { - return $this->belongsTo(Nazione::class, 'id_nazione'); - } - - /** - * Restituisce la sede legale collegata. - * - * @return self - */ - public function getSedeLegaleAttribute() - { - return $this; - } - - // Metodi statici - - /** - * Calcola il nuovo codice di anagrafica. - * - * @return string - */ - public static function getNextCodice() - { - // Recupero maschera per le anagrafiche - $maschera = setting('Formato codice anagrafica'); - - $ultimo = Generator::getPreviousFrom($maschera, 'an_anagrafiche', 'codice', [ - "codice != ''", - 'deleted_at IS NULL', - ]); - $codice = Generator::generate($maschera, $ultimo); - - return $codice; - } - - // Attributi Eloquent - - public function getModuleAttribute() - { - return 'Anagrafiche'; - } - - protected function fixRagioneSociale() - { - if (!empty($this->cognome) || !empty($this->nome)) { - $this->ragione_sociale = $this->cognome.' '.$this->nome; - } - } -} diff --git a/update/v2_4_10/Article.php b/update/v2_4_10/Article.php deleted file mode 100755 index d5389ab51..000000000 --- a/update/v2_4_10/Article.php +++ /dev/null @@ -1,213 +0,0 @@ -articolo()->associate($articolo); - - $model->descrizione = $articolo->descrizione; - $model->abilita_serial = $articolo->abilita_serial; - $model->um = $articolo->um; - - return $model; - } - - abstract public function movimenta($qta); - - abstract public function getDirection(); - - /** - * Imposta i seriali collegati all'articolo. - * - * @param array $serials - */ - public function setSerialsAttribute($serials) - { - $serials = array_clean($serials); - - database()->sync('mg_prodotti', [ - 'id_riga_'.$this->serialRowID => $this->id, - 'dir' => $this->getDirection(), - 'id_articolo' => $this->idarticolo, - ], [ - 'serial' => $serials, - ]); - - $this->serialsList = $serials; - } - - /** - * Rimuove i seriali collegati all'articolo. - * - * @param array $serials - */ - public function removeSerials($serials) - { - database()->detach('mg_prodotti', [ - 'id_riga_'.$this->serialRowID => $this->id, - 'dir' => $this->getDirection(), - 'id_articolo' => $this->idarticolo, - ], [ - 'serial' => array_clean($serials), - ]); - - $this->serialsList = null; - } - - /** - * Restituisce l'elenco dei seriali collegati all'articolo del documento. - * - * @return array - */ - public function getSerialsAttribute() - { - if (empty($this->abilita_serial)) { - return []; - } - - if (!isset($this->serialsList)) { - // Individuazione dei seriali - $results = database()->fetchArray('SELECT serial FROM mg_prodotti WHERE serial IS NOT NULL AND id_riga_'.$this->serialRowID.' = '.prepare($this->id)); - - $this->serialsList = array_column($results, 'serial'); - } - - return $this->serialsList; - } - - /** - * Restituisce il numero di seriali mancanti per il completamento dell'articolo. - * - * @return float - */ - public function getMissingSerialsAttribute() - { - return $this->qta - count($this->serials); - } - - /** - * Modifica la quantità dell'articolo e movimenta automaticamente il magazzino. - * - * @param float $value - */ - public function setQtaAttribute($value) - { - if (!$this->cleanupSerials($value)) { - throw new UnexpectedValueException(); - } - - $diff = parent::setQtaAttribute($value); - - if ($this->abilita_movimentazione) { - $this->qta_movimentazione += $diff; - } - } - - public function articolo() - { - return $this->belongsTo(Original::class, 'idarticolo'); - } - - public function movimentazione($value = true) - { - $this->abilita_movimentazione = $value; - } - - /** - * Salva l'articolo, eventualmente movimentandone il magazzino. - * - * @return bool - */ - public function save(array $options = []) - { - if (!empty($this->qta_movimentazione)) { - $this->movimenta($this->qta_movimentazione); - } - - return parent::save($options); - } - - protected static function boot() - { - parent::boot(true); - - static::addGlobalScope('articles', function (Builder $builder) { - $builder->whereNotNull('idarticolo')->where('idarticolo', '<>', 0); - }); - } - - protected function usedSerials() - { - if ($this->getDirection() == 'uscita') { - $results = database()->fetchArray("SELECT serial FROM mg_prodotti WHERE serial IN (SELECT DISTINCT serial FROM mg_prodotti WHERE dir = 'entrata') AND serial IS NOT NULL AND id_riga_".$this->serialRowID.' = '.prepare($this->id)); - - return array_column($results, 'serial'); - } - - return []; - } - - protected function cleanupSerials($new_qta) - { - // Se la nuova quantità è minore della precedente - if ($this->qta > $new_qta) { - $seriali_usati = $this->usedSerials(); - $count_seriali_usati = count($seriali_usati); - - // Controllo sulla possibilità di rimuovere i seriali (se non utilizzati da documenti di vendita) - if ($this->getDirection() == 'uscita' && $new_qta < $count_seriali_usati) { - return false; - } else { - // Controllo sul numero di seriali effettivi da rimuovere - $seriali = $this->serials; - - if ($new_qta < count($seriali)) { - $rimovibili = array_diff($seriali, $seriali_usati); - - // Rimozione dei seriali aggiuntivi - $serials = array_slice($rimovibili, 0, $new_qta - $count_seriali_usati); - - $this->serials = array_merge($seriali_usati, $serials); - } - } - } - - return true; - } - - protected function customInitCopiaIn($original) - { - $this->articolo()->associate($original->articolo); - } - - protected function customBeforeDataCopiaIn($original) - { - $this->movimentazione(false); - - parent::customBeforeDataCopiaIn($original); - } - - protected function customAfterDataCopiaIn($original) - { - $this->movimentazione(true); - - parent::customAfterDataCopiaIn($original); - } -} diff --git a/update/v2_4_10/Components/Articolo.php b/update/v2_4_10/Components/Articolo.php deleted file mode 100755 index baf0a1e9a..000000000 --- a/update/v2_4_10/Components/Articolo.php +++ /dev/null @@ -1,61 +0,0 @@ -idddt) || !empty($this->idintervento)) { - return; - } - - $fattura = $this->fattura; - $tipo = $fattura->tipo; - - $numero = $fattura->numero_esterno ?: $fattura->numero; - $data = $fattura->data; - - $carico = ($tipo->dir == 'entrata') ? tr('Ripristino articolo da _TYPE_ _NUM_') : tr('Carico magazzino da _TYPE_ numero _NUM_'); - $scarico = ($tipo->dir == 'entrata') ? tr('Scarico magazzino per _TYPE_ numero _NUM_') : tr('Rimozione articolo da _TYPE_ _NUM_'); - - $qta = ($tipo->dir == 'uscita') ? -$qta : $qta; - $movimento = ($qta < 0) ? $carico : $scarico; - - $movimento = replace($movimento, [ - '_TYPE_' => $tipo->descrizione, - '_NUM_' => $numero, - ]); - - $this->articolo->movimenta(-$qta, $movimento, $data, false, [ - 'iddocumento' => $fattura->id, - ]); - } - - public function getDirection() - { - return $this->fattura->tipo->dir; - } -} diff --git a/update/v2_4_10/Components/Descrizione.php b/update/v2_4_10/Components/Descrizione.php deleted file mode 100755 index 0b847227c..000000000 --- a/update/v2_4_10/Components/Descrizione.php +++ /dev/null @@ -1,25 +0,0 @@ -belongsTo(Fattura::class, $this->getParentID()); - } - - public function fattura() - { - return $this->parent(); - } - - public function getNettoAttribute() - { - $result = $this->totale - $this->ritenuta_acconto - $this->ritenuta_contributi; - - if ($this->parent->split_payment) { - $result = $result - $this->iva; - } - - return $result; - } - - /** - * Restituisce il totale (imponibile + iva + rivalsa_inps + iva_rivalsainps) dell'elemento. - * - * @return float - */ - public function getTotaleAttribute() - { - return $this->imponibile_scontato + $this->iva + $this->rivalsa_inps + $this->iva_rivalsa_inps; - } - - public function getRivalsaINPSAttribute() - { - return $this->imponibile_scontato / 100 * $this->rivalsa->percentuale; - } - - public function getIvaRivalsaINPSAttribute() - { - return $this->rivalsa_inps / 100 * $this->aliquota->percentuale; - } - - public function getRitenutaAccontoAttribute() - { - $result = $this->imponibile_scontato; - - if ($this->calcolo_ritenuta_acconto == 'IMP+RIV') { - $result += $this->rivalsainps; - } - - $ritenuta = $this->ritenuta; - $result = $result * $ritenuta->percentuale_imponibile / 100; - - return $result / 100 * $ritenuta->percentuale; - } - - public function getRitenutaContributiAttribute() - { - if ($this->attributes['ritenuta_contributi']) { - $result = $this->imponibile_scontato; - $ritenuta = $this->parent->ritenutaContributi; - - $result = $result * $ritenuta->percentuale_imponibile / 100; - - return $result / 100 * $ritenuta->percentuale; - } - - return 0; - } - - /** - * Imposta l'identificatore della Rivalsa INPS. - * - * @param int $value - */ - public function setIdRivalsaINPSAttribute($value) - { - $this->attributes['idrivalsainps'] = $value; - $this->load('rivalsa'); - } - - /** - * Imposta l'identificatore della Ritenuta d'Acconto. - * - * @param int $value - */ - public function setIdRitenutaAccontoAttribute($value) - { - $this->attributes['idritenutaacconto'] = $value; - $this->load('ritenuta'); - } - - public function getIdContoAttribute() - { - return $this->idconto; - } - - public function setIdContoAttribute($value) - { - $this->attributes['idconto'] = $value; - } - - public function rivalsa() - { - return $this->belongsTo(RivalsaINPS::class, 'idrivalsainps'); - } - - public function ritenuta() - { - return $this->belongsTo(RitenutaAcconto::class, 'idritenutaacconto'); - } - - /** - * Salva la riga, impostando i campi dipendenti dai parametri singoli. - * - * @return bool - */ - public function save(array $options = []) - { - $this->fixRitenutaAcconto(); - $this->fixRivalsaINPS(); - - return parent::save($options); - } - - /** - * Effettua i conti per la Rivalsa INPS. - */ - protected function fixRivalsaINPS() - { - $this->attributes['rivalsainps'] = $this->rivalsa_inps; - } - - /** - * Effettua i conti per la Ritenuta d'Acconto, basandosi sul valore del campo calcolo_ritenuta_acconto. - */ - protected function fixRitenutaAcconto() - { - $this->attributes['ritenutaacconto'] = $this->ritenuta_acconto; - } - - protected function evasione($diff) - { - parent::evasione($diff); - - $database = database(); - - // Se c'è un collegamento ad un ddt, aggiorno la quantità evasa - if (!empty($this->idddt)) { - $database->query('UPDATE dt_righe_ddt SET qta_evasa = qta_evasa + '.$diff.' WHERE descrizione = '.prepare($this->descrizione).' AND idarticolo = '.prepare($this->idarticolo).' AND idddt = '.prepare($this->idddt).' AND idiva = '.prepare($this->idiva).' AND qta_evasa < qta LIMIT 1'); - } - - // Se c'è un collegamento ad un ordine, aggiorno la quantità evasa - elseif (!empty($this->idordine)) { - $database->query('UPDATE or_righe_ordini SET qta_evasa = qta_evasa + '.$diff.' WHERE descrizione = '.prepare($this->descrizione).' AND idarticolo = '.prepare($this->idarticolo).' AND idordine = '.prepare($this->idordine).' AND idiva = '.prepare($this->idiva).' AND qta_evasa < qta LIMIT 1'); - } - - // Se c'è un collegamento ad un preventivo, aggiorno la quantità evasa - elseif (!empty($this->idpreventivo)) { - $database->query('UPDATE co_righe_preventivi SET qta_evasa = qta_evasa + '.$diff.' WHERE descrizione = '.prepare($this->descrizione).' AND idarticolo = '.prepare($this->idarticolo).' AND idpreventivo = '.prepare($this->idpreventivo).' AND idiva = '.prepare($this->idiva).' AND qta_evasa < qta LIMIT 1'); - } - - // Se c'è un collegamento ad un contratto, aggiorno la quantità evasa - elseif (!empty($this->idcontratto)) { - $database->query('UPDATE co_righe_contratti SET qta_evasa = qta_evasa + '.$diff.' WHERE descrizione = '.prepare($this->descrizione).' AND idarticolo = '.prepare($this->idarticolo).' AND idcontratto = '.prepare($this->idcontratto).' AND idiva = '.prepare($this->idiva).' AND qta_evasa < qta LIMIT 1'); - } - } -} diff --git a/update/v2_4_10/Components/Riga.php b/update/v2_4_10/Components/Riga.php deleted file mode 100755 index a6272d271..000000000 --- a/update/v2_4_10/Components/Riga.php +++ /dev/null @@ -1,25 +0,0 @@ - 'float', - ]; - - /** - * Crea una nuova fattura. - * - * @param string $data - * @param int $id_segment - * - * @return self - */ - public static function build(Anagrafica $anagrafica, TipoFattura $tipo_documento, $data, $id_segment) - { - $model = parent::build(); - - $user = Auth::user(); - - $stato_documento = Stato::where('descrizione', 'Bozza')->first(); - - $id_anagrafica = $anagrafica->id; - $direzione = $tipo_documento->dir; - - $database = database(); - - if ($direzione == 'entrata') { - $id_conto = setting('Conto predefinito fatture di vendita'); - $conto = 'vendite'; - } else { - $id_conto = setting('Conto predefinito fatture di acquisto'); - $conto = 'acquisti'; - } - - // Tipo di pagamento e banca predefinite dall'anagrafica - $id_pagamento = $database->fetchOne('SELECT id FROM co_pagamenti WHERE id = :id_pagamento', [ - ':id_pagamento' => $anagrafica['idpagamento_'.$conto], - ])['id']; - $id_banca = $anagrafica['idbanca_'.$conto]; - - $split_payment = $anagrafica->split_payment; - - // Se la fattura è di vendita e non è stato associato un pagamento predefinito al cliente leggo il pagamento dalle impostazioni - if ($direzione == 'entrata' && empty($id_pagamento)) { - $id_pagamento = setting('Tipo di pagamento predefinito'); - } - - // Se non è impostata la banca dell'anagrafica, uso quella del pagamento. - if (empty($id_banca)) { - $id_banca = $database->fetchOne('SELECT id FROM co_banche WHERE id_pianodeiconti3 = (SELECT idconto_'.$conto.' FROM co_pagamenti WHERE id = :id_pagamento)', [ - ':id_pagamento' => $id_pagamento, - ])['id']; - } - - $id_sede = $anagrafica->idsede_fatturazione; - - $model->anagrafica()->associate($anagrafica); - $model->tipo()->associate($tipo_documento); - $model->stato()->associate($stato_documento); - - $model->save(); - - // Salvataggio delle informazioni - $model->data = $data; - $model->data_registrazione = $data; - $model->data_competenza = $data; - $model->id_segment = $id_segment; - - $model->idconto = $id_conto; - - // Imposto, come sede aziendale, la prima sede disponibile come utente - if ($direzione == 'entrata') { - $model->idsede_destinazione = $user->sedi[0]; - } else { - $model->idsede_partenza = $user->sedi[0]; - } - $model->addebita_bollo = setting('Addebita marca da bollo al cliente'); - - $id_ritenuta_contributi = ($tipo_documento->dir == 'entrata') ? setting('Ritenuta contributi') : null; - $model->id_ritenuta_contributi = $id_ritenuta_contributi ?: null; - - if (!empty($id_pagamento)) { - $model->idpagamento = $id_pagamento; - } - if (!empty($id_banca)) { - $model->idbanca = $id_banca; - } - - if (!empty($split_payment)) { - $model->split_payment = $split_payment; - } - - $model->save(); - - return $model; - } - - /** - * Imposta il sezionale relativo alla fattura e calcola il relativo numero. - * **Attenzione**: la data deve inserita prima! - * - * @param int $value - */ - public function setIdSegmentAttribute($value) - { - $previous = $this->id_segment; - - $this->attributes['id_segment'] = $value; - - // Calcolo dei numeri fattura - if ($value != $previous) { - $direzione = $this->tipo->dir; - $data = $this->data; - - $this->numero = static::getNextNumero($data, $direzione, $value); - $this->numero_esterno = static::getNextNumeroSecondario($data, $direzione, $value); - } - } - - /** - * Restituisce il nome del modulo a cui l'oggetto è collegato. - * - * @return string - */ - public function getModuleAttribute() - { - return $this->direzione == 'entrata' ? 'Fatture di vendita' : 'Fatture di acquisto'; - } - - public function getDirezioneAttribute() - { - return $this->tipo->dir; - } - - // Calcoli - - /** - * Calcola il netto a pagare della fattura. - * - * @return float - */ - public function getNettoAttribute() - { - return $this->calcola('netto'); - } - - /** - * Calcola la rivalsa INPS totale della fattura. - * - * @return float - */ - public function getRivalsaINPSAttribute() - { - return $this->calcola('rivalsa_inps'); - } - - /** - * Calcola l'IVA totale della fattura. - * - * @return float - */ - public function getIvaAttribute() - { - return $this->calcola('iva', 'iva_rivalsa_inps'); - } - - /** - * Calcola l'iva della rivalsa INPS totale della fattura. - * - * @return float - */ - public function getIvaRivalsaINPSAttribute() - { - return $this->calcola('iva_rivalsa_inps'); - } - - /** - * Calcola la ritenuta d'acconto totale della fattura. - * - * @return float - */ - public function getRitenutaAccontoAttribute() - { - return $this->calcola('ritenuta_acconto'); - } - - public function getTotaleRitenutaContributiAttribute() - { - return $this->calcola('ritenuta_contributi'); - } - - // Relazioni Eloquent - - public function anagrafica() - { - return $this->belongsTo(Anagrafica::class, 'idanagrafica'); - } - - public function tipo() - { - return $this->belongsTo(TipoFattura::class, 'idtipodocumento'); - } - - public function pagamento() - { - return $this->belongsTo(Pagamento::class, 'idpagamento'); - } - - public function stato() - { - return $this->belongsTo(Stato::class, 'idstatodocumento'); - } - - public function statoFE() - { - return $this->belongsTo(StatoFE::class, 'codice_stato_fe'); - } - - public function articoli() - { - return $this->hasMany(Components\Articolo::class, 'iddocumento'); - } - - public function righe() - { - return $this->hasMany(Components\Riga::class, 'iddocumento'); - } - - public function sconti() - { - return $this->hasMany(Components\Sconto::class, 'iddocumento'); - } - - public function descrizioni() - { - return $this->hasMany(Components\Descrizione::class, 'iddocumento'); - } - - public function ritenutaContributi() - { - return $this->belongsTo(RitenutaContributi::class, 'id_ritenuta_contributi'); - } - - public function rigaBollo() - { - return $this->hasOne(Components\Riga::class, 'iddocumento')->where('id', $this->id_riga_bollo); - } - - // Metodi generali - - public function getXML() - { - if (empty($this->progressivo_invio) && $this->module == 'Fatture di acquisto') { - $fe = new FatturaElettronica($this->id); - - return $fe->toXML(); - } - - $file = $this->uploads()->where('name', 'Fattura Elettronica')->first(); - - return file_get_contents($file->filepath); - } - - public function isFE() - { - $file = $this->uploads()->where('name', 'Fattura Elettronica')->first(); - - return !empty($this->progressivo_invio) and file_exists($file->filepath); - } - - /** - * Registra le scadenze della fattura elettronica collegata al documento. - * - * @param bool $is_pagato - * - * @return bool - */ - public function registraScadenzeFE($is_pagato = false) - { - $xml = \Util\XML::read($this->getXML()); - - $pagamenti = $xml['FatturaElettronicaBody']['DatiPagamento']['DettaglioPagamento']; - if (!empty($pagamenti)) { - $rate = isset($pagamenti[0]) ? $pagamenti : [$pagamenti]; - - foreach ($rate as $rata) { - $scadenza = $rata['DataScadenzaPagamento'] ?: $this->data; - $importo = -$rata['ImportoPagamento']; - - self::registraScadenza($this, $importo, $scadenza, $is_pagato); - } - } - - return !empty($pagamenti); - } - - /** - * Registra le scadenze tradizionali del gestionale. - * - * @param bool $is_pagato - */ - public function registraScadenzeTradizionali($is_pagato = false) - { - $rate = $this->pagamento->calcola($this->netto, $this->data); - $direzione = $this->tipo->dir; - - foreach ($rate as $rata) { - $scadenza = $rata['scadenza']; - $importo = $direzione == 'uscita' ? -$rata['importo'] : $rata['importo']; - - self::registraScadenza($this, $importo, $scadenza, $is_pagato); - } - } - - /** - * Registra una specifica scadenza nel database. - * - * @param float $importo - * @param string $scadenza - * @param bool $is_pagato - * @param string $type - */ - public static function registraScadenza(Fattura $fattura, $importo, $scadenza, $is_pagato, $type = 'fattura') - { - //Calcolo la descrizione - $descrizione = database()->fetchOne("SELECT CONCAT(co_tipidocumento.descrizione, CONCAT(' numero ', IF(numero_esterno!='', numero_esterno, numero))) AS descrizione FROM co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id='".$fattura->id."'")['descrizione']; - - database()->insert('co_scadenziario', [ - 'iddocumento' => $fattura->id, - 'data_emissione' => $fattura->data, - 'scadenza' => $scadenza, - 'da_pagare' => $importo, - 'tipo' => $type, - 'pagato' => $is_pagato ? $importo : 0, - 'data_pagamento' => $is_pagato ? $scadenza : null, - 'descrizione' => $descrizione, - ]); - } - - /** - * Registra le scadenze della fattura. - * - * @param bool $is_pagato - * @param bool $ignora_fe - */ - public function registraScadenze($is_pagato = false, $ignora_fe = false) - { - $this->rimuoviScadenze(); - - if (!$ignora_fe && $this->module == 'Fatture di acquisto' && $this->isFE()) { - $scadenze_fe = $this->registraScadenzeFE($is_pagato); - } - - if (empty($scadenze_fe)) { - $this->registraScadenzeTradizionali($is_pagato); - } - - $direzione = $this->tipo->dir; - $ritenuta_acconto = $this->ritenuta_acconto; - - // Se c'è una ritenuta d'acconto, la aggiungo allo scadenzario - if ($direzione == 'uscita' && $ritenuta_acconto > 0) { - $data = $this->data; - $scadenza = date('Y-m', strtotime($data.' +1 month')).'-15'; - $importo = -$ritenuta_acconto; - - self::registraScadenza($this, $importo, $scadenza, $is_pagato, 'ritenutaacconto'); - } - } - - /** - * Elimina le scadenze della fattura. - */ - public function rimuoviScadenze() - { - database()->delete('co_scadenziario', ['iddocumento' => $this->id]); - } - - /** - * Salva la fattura, impostando i campi dipendenti dai singoli parametri. - * - * @return bool - */ - public function save(array $options = []) - { - // Fix dei campi statici - $this->manageRigaMarcaDaBollo(); - - $this->attributes['ritenutaacconto'] = $this->ritenuta_acconto; - $this->attributes['iva_rivalsainps'] = $this->iva_rivalsa_inps; - $this->attributes['rivalsainps'] = $this->rivalsa_inps; - $this->attributes['ritenutaacconto'] = $this->ritenuta_acconto; - - return parent::save($options); - } - - /** - * Restituisce l'elenco delle note di credito collegate. - * - * @return iterable - */ - public function getNoteDiAccredito() - { - return self::where('ref_documento', $this->id)->get(); - } - - /** - * Restituisce l'elenco delle note di credito collegate. - * - * @return self - */ - public function getFatturaOriginale() - { - return self::find($this->ref_documento); - } - - /** - * Controlla se la fattura è una nota di credito. - * - * @return bool - */ - public function isNota() - { - return $this->tipo->reversed == 1; - } - - // Metodi statici - - /** - * Calcola il nuovo numero di fattura. - * - * @param string $data - * @param string $direzione - * @param int $id_segment - * - * @return string - */ - public static function getNextNumero($data, $direzione, $id_segment) - { - if ($direzione == 'entrata') { - return ''; - } - - // Recupero maschera per questo segmento - $maschera = Generator::getMaschera($id_segment); - - $ultimo = Generator::getPreviousFrom($maschera, 'co_documenti', 'numero', [ - 'YEAR(data) = '.prepare(date('Y', strtotime($data))), - 'id_segment = '.prepare($id_segment), - ]); - $numero = Generator::generate($maschera, $ultimo, 1, Generator::dateToPattern($data)); - - return $numero; - } - - /** - * Calcola il nuovo numero secondario di fattura. - * - * @param string $data - * @param string $direzione - * @param int $id_segment - * - * @return string - */ - public static function getNextNumeroSecondario($data, $direzione, $id_segment) - { - if ($direzione == 'uscita') { - return ''; - } - - // Recupero maschera per questo segmento - $maschera = Generator::getMaschera($id_segment); - - $ultimo = Generator::getPreviousFrom($maschera, 'co_documenti', 'numero_esterno', [ - 'YEAR(data) = '.prepare(date('Y', strtotime($data))), - 'id_segment = '.prepare($id_segment), - ]); - $numero = Generator::generate($maschera, $ultimo, 1, Generator::dateToPattern($data)); - - return $numero; - } - - /** - * Restituisce i dati bancari in base al pagamento. - * - * @return array - */ - public function getBanca() - { - $result = []; - $riba = database()->fetchOne('SELECT riba FROM co_pagamenti WHERE id ='.prepare($this->idpagamento)); - - if ($riba['riba'] == 1) { - $result = database()->fetchOne('SELECT codiceiban, appoggiobancario, bic FROM an_anagrafiche WHERE idanagrafica ='.prepare($this->idanagrafica)); - } else { - $result = database()->fetchOne('SELECT iban AS codiceiban, nome AS appoggiobancario, bic FROM co_banche WHERE id='.prepare($this->idbanca)); - } - - return $result; - } - - public function getBollo() - { - if (isset($this->bollo)) { - return $this->bollo; - } - - $righe_bollo = $this->getRighe()->filter(function ($item, $key) { - return $item->aliquota != null && in_array($item->aliquota->codice_natura_fe, ['N1', 'N2', 'N3', 'N4']); - }); - $importo_righe_bollo = $righe_bollo->sum('netto'); - - // Leggo la marca da bollo se c'è e se il netto a pagare supera la soglia - $bollo = ($this->direzione == 'uscita') ? $this->bollo : setting('Importo marca da bollo'); - - $marca_da_bollo = 0; - if (abs($bollo) > 0 && abs($importo_righe_bollo) > setting("Soglia minima per l'applicazione della marca da bollo")) { - $marca_da_bollo = $bollo; - } - - // Se l'importo è negativo può essere una nota di credito, quindi cambio segno alla marca da bollo - $marca_da_bollo = abs($marca_da_bollo); - - return $marca_da_bollo; - } - - public function manageRigaMarcaDaBollo() - { - $riga = $this->rigaBollo; - - $addebita_bollo = $this->addebita_bollo; - $marca_da_bollo = $this->getBollo(); - - // Rimozione riga bollo se nullo - if (empty($addebita_bollo) || empty($marca_da_bollo)) { - if (!empty($riga)) { - $this->id_riga_bollo = null; - - $riga->delete(); - } - - return; - } - - // Creazione riga bollo se non presente - if (empty($riga)) { - $riga = Components\Riga::build($this); - $riga->save(); - - $this->id_riga_bollo = $riga->id; - } - - $riga->prezzo_unitario_vendita = $marca_da_bollo; - $riga->qta = 1; - $riga->descrizione = setting('Descrizione addebito bollo'); - $riga->id_iva = setting('Iva da applicare su marca da bollo'); - $riga->idconto = setting('Conto predefinito per la marca da bollo'); - - $riga->save(); - } - - // Opzioni di riferimento - - public function getReferenceName() - { - } - - public function getReferenceNumber() - { - } - - public function getReferenceDate() - { - } - - public function getReferenceRagioneSociale() - { - } - - public function getReference() - { - } -} diff --git a/update/v2_4_10/TipoAnagrafica.php b/update/v2_4_10/TipoAnagrafica.php deleted file mode 100755 index 453415043..000000000 --- a/update/v2_4_10/TipoAnagrafica.php +++ /dev/null @@ -1,34 +0,0 @@ -idtipoanagrafica; - } - - public function anagrafiche() - { - return $this->hasMany(Anagrafica::class, 'an_tipianagrafiche_anagrafiche', 'idtipoanagrafica', 'idanagrafica'); - } -} diff --git a/update/v2_4_10/TipoFattura.php b/update/v2_4_10/TipoFattura.php deleted file mode 100755 index 00c656a06..000000000 --- a/update/v2_4_10/TipoFattura.php +++ /dev/null @@ -1,15 +0,0 @@ -hasMany(Fattura::class, 'idtipodocumento'); - } -}