diff --git a/config/namespaces.php b/config/namespaces.php index 049f8aa88..07cc75097 100644 --- a/config/namespaces.php +++ b/config/namespaces.php @@ -14,6 +14,7 @@ return [ 'modules/preventivi' => 'Modules\Preventivi', 'modules/contratti' => 'Modules\Contratti', 'modules/interventi' => 'Modules\Interventi', + 'modules/pagamenti' => 'Modules\Pagamenti', 'plugins/exportFE' => 'Plugins\ExportFE', 'plugins/importFE' => 'Plugins\ImportFE', 'plugins/receiptFE' => 'Plugins\ReceiptFE', diff --git a/modules/fatture/actions.php b/modules/fatture/actions.php index 1be71609a..1dc2a47f9 100644 --- a/modules/fatture/actions.php +++ b/modules/fatture/actions.php @@ -144,6 +144,12 @@ switch (post('op')) { break; + // Ricalcolo scadenze + case 'ricalcola_scadenze': + $fattura->registraScadenze(false, true); + + break; + // eliminazione documento case 'delete': $rs = $dbo->fetchArray('SELECT id FROM co_righe_documenti WHERE iddocumento='.prepare($id_record)); diff --git a/modules/fatture/edit.php b/modules/fatture/edit.php index f7341585c..276e8d9de 100644 --- a/modules/fatture/edit.php +++ b/modules/fatture/edit.php @@ -152,14 +152,41 @@ if (empty($record['is_fiscale'])) { fetchArray('SELECT * FROM co_scadenziario WHERE iddocumento = '.prepare($id_record)); echo '

'.tr('Scadenze').'

'; foreach ($scadenze as $scadenza) { echo ' -

'.Translator::dateToLocale($scadenza['scadenza']).': '.Translator::numberToLocale($scadenza['da_pagare']).'€

'; +

'.Translator::dateToLocale($scadenza['scadenza']).': '; + + if ($scadenza['pagato'] == $scadenza['da_pagare']) { + echo ' + '; + } + + echo Translator::numberToLocale($scadenza['da_pagare']).'€'; + + if ($scadenza['pagato'] == $scadenza['da_pagare']) { + echo ' + '; + } + + echo ' +

'; + + $ricalcola = empty(floatval($scadenza['pagato'])) && $ricalcola; } + + if ($fattura->isFE() && $ricalcola && $module['name'] == 'Fatture di acquisto') { + echo ' + '; + } + echo '
'; } @@ -171,7 +198,7 @@ if (empty($record['is_fiscale'])) {
- + {[ "type": "select", "label": "", "name": "idtipodocumento", "required": 1, "values": "query=SELECT id, descrizione FROM co_tipidocumento WHERE dir='' AND (reversed = 0 OR id = )", "value": "$idtipodocumento$", "readonly": , "help": "fetchOne('SELECT tipo FROM an_anagrafiche WHERE idanagrafica = '.prepare($record['idanagrafica']))['tipo'] == 'Ente pubblico') ? 'FPA12 - fattura verso PA' : 'FPR12 - fattura verso privati'; ?>" ]}
@@ -198,18 +225,18 @@ if ($dir == 'uscita') { - +
- +
{[ "type": "number", "label": "", "name": "sconto_generico", "value": "$sconto_globale$", "help": "", "icon-after": "choice|untprc|$tipo_sconto_globale$" ]}
- +
{[ "type": "checkbox", "label": "", "name": "split_payment", "value": "$split_payment$", "help": "", "placeholder": "" ]}
- + {[ "type": "checkbox", "label": "", "name": "is_fattura_conto_terzi", "value": "$is_fattura_conto_terzi$", "help": "fetchOne('SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica = '.prepare(setting('Azienda predefinita')))['ragione_sociale']).') come cessionario e il cliente come cedente/prestatore.'); ?>", "placeholder": "" ]}
- + @@ -225,7 +252,7 @@ if ($dir == 'uscita') {
{[ "type": "select", "label": "", "name": "id_ritenuta_contributi", "value": "$id_ritenuta_contributi$", "values": "query=SELECT * FROM co_ritenuta_contributi" ]}
- +
@@ -499,21 +526,35 @@ include $docroot.'/modules/fatture/row-list.php'; {( "name": "filelist_and_upload", "id_module": "$id_module$", "id_record": "$id_record$" )} '.tr('Per allegare un documento alla fattura elettronica caricare il file PDF specificando come categoria "Fattura Elettronica"').'.
'; - } -?> +} +echo ' -'; if (!empty($note_accredito)) { echo ' @@ -546,10 +587,6 @@ if (!empty($note_accredito)) { $(".btn-sm[data-toggle=\"tooltip\"]").each(function() { $(this).on("click", function() { - /*if(!content_was_modified) { - return; - }*/ - form = $("#edit-form"); btn = $(this); diff --git a/modules/fatture/modutil.php b/modules/fatture/modutil.php index e668c9ace..bae9cbda7 100755 --- a/modules/fatture/modutil.php +++ b/modules/fatture/modutil.php @@ -93,10 +93,9 @@ function get_ivaindetraibile_fattura($iddocumento) */ function elimina_scadenza($iddocumento) { - $dbo = database(); + $fattura = Fattura::find($iddocumento); - $query2 = 'DELETE FROM co_scadenziario WHERE iddocumento='.prepare($iddocumento); - $dbo->query($query2); + $fattura->rimuoviScadenze(); } /** @@ -105,126 +104,19 @@ function elimina_scadenza($iddocumento) * $pagamento string Nome del tipo di pagamento. Se è vuoto lo leggo da co_pagamenti_documenti, perché significa che devo solo aggiornare gli importi. * $pagato boolean Indica se devo segnare l'importo come pagato. */ -function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = 0) +function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = false) { - $dbo = database(); - $fattura = Fattura::find($iddocumento); - if ($fattura->isFE()) { - $scadenze_fe = $fattura->registraScadenzeFE($pagato); - } - - // Lettura data di emissione fattura - $query3 = 'SELECT ritenutaacconto, data FROM co_documenti WHERE id='.prepare($iddocumento); - $rs = $dbo->fetchArray($query3); - $data = $rs[0]['data']; - $ritenutaacconto = $rs[0]['ritenutaacconto']; - - if (empty($scadenze_fe)) { - $totale_da_pagare = 0.00; - - $totale_fattura = get_totale_fattura($iddocumento); - $netto_fattura = get_netto_fattura($iddocumento); - $imponibile_fattura = get_imponibile_fattura($iddocumento); - $totale_iva = sum(abs($totale_fattura), -abs($imponibile_fattura)); - - // Verifico se la fattura è di acquisto o di vendita per scegliere che segno mettere nel totale - $query2 = 'SELECT dir FROM co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id='.prepare($iddocumento); - $rs2 = $dbo->fetchArray($query2); - $dir = $rs2[0]['dir']; - - /* - Inserisco la nuova scadenza (anche più di una riga per pagamenti multipli - */ - // Se il pagamento non è specificato lo leggo dal documento - if ($pagamento == '') { - $query = 'SELECT descrizione FROM co_pagamenti WHERE id=(SELECT idpagamento FROM co_documenti WHERE id='.prepare($iddocumento).')'; - $rs = $dbo->fetchArray($query); - $pagamento = $rs[0]['descrizione']; - } - - $query4 = 'SELECT * FROM co_pagamenti WHERE descrizione='.prepare($pagamento); - $rs = $dbo->fetchArray($query4); - for ($i = 0; $i < sizeof($rs); ++$i) { - // X giorni esatti - if ($rs[$i]['giorno'] == 0) { - $scadenza = date('Y-m-d', strtotime($data.' +'.$rs[$i]['num_giorni'].' day')); - } - - // Ultimo del mese - elseif ($rs[$i]['giorno'] < 0) { - $date = new DateTime($data); - - $add = floor($rs[$i]['num_giorni'] / 30); - for ($c = 0; $c < $add; ++$c) { - $date->modify('last day of next month'); - } - - // Ultimo del mese più X giorni - $giorni = -$rs[$i]['giorno'] - 1; - if ($giorni > 0) { - $date->modify('+'.($giorni).' day'); - } else { - $date->modify('last day of this month'); - } - - $scadenza = $date->format('Y-m-d'); - } - - // Giorno preciso del mese - else { - $scadenza = date('Y-m-'.$rs[$i]['giorno'], strtotime($data.' +'.$rs[$i]['num_giorni'].' day')); - } - - // All'ultimo ciclo imposto come cifra da pagare il totale della fattura meno gli importi già inseriti in scadenziario per evitare di inserire cifre arrotondate "male" - if ($i == (sizeof($rs) - 1)) { - $da_pagare = sum($netto_fattura, -$totale_da_pagare, 2); - } - - // Totale da pagare (totale x percentuale di pagamento nei casi pagamenti multipli) - else { - $da_pagare = sum($netto_fattura / 100 * $rs[$i]['prc'], 0, 2); - } - $totale_da_pagare = sum($da_pagare, $totale_da_pagare, 2); - - if ($dir == 'uscita') { - $da_pagare = -$da_pagare; - } - - $dbo->query('INSERT INTO co_scadenziario(iddocumento, data_emissione, scadenza, da_pagare, pagato, tipo) VALUES('.prepare($iddocumento).', '.prepare($data).', '.prepare($scadenza).', '.prepare($da_pagare).", 0, 'fattura')"); - - if ($pagato) { - $id_scadenza = $dbo->lastInsertedID(); - $dbo->update('co_scadenziario', [ - 'pagato' => $da_pagare, - 'data_pagamento' => $data, - ], ['id' => $id_scadenza]); - } - } - } - - // Se c'è una ritenuta d'acconto, la aggiungo allo scadenzario - if ($dir == 'uscita' && $ritenutaacconto > 0) { - $dbo->query('INSERT INTO co_scadenziario(iddocumento, data_emissione, scadenza, da_pagare, pagato, tipo) VALUES('.prepare($iddocumento).', '.prepare($data).', '.prepare(date('Y-m', strtotime($data.' +1 month')).'-15').', '.prepare(-$ritenutaacconto).", 0, 'ritenutaacconto')"); - - if ($pagato) { - $id_scadenza = $dbo->lastInsertedID(); - $dbo->update('co_scadenziario', [ - 'pagato' => -$ritenutaacconto, - 'data_pagamento' => $data, - ], ['id' => $id_scadenza]); - } - } - - return true; + $fattura->registraScadenze($pagato); } /** - * Funzione per aggiornare lo stato dei pagamenti nello scadenziario - * $iddocumento int ID della fattura - * $totale_pagato float Totale importo pagato - * $data_pagamento datetime Data in cui avviene il pagamento (yyyy-mm-dd). + * Funzione per aggiornare lo stato dei pagamenti nello scadenziario. + * + * @param $iddocumento int ID della fattura + * @param $totale_pagato float Totale importo pagato + * @param $data_pagamento datetime Data in cui avviene il pagamento (yyyy-mm-dd) */ function aggiorna_scadenziario($iddocumento, $totale_pagato, $data_pagamento) { diff --git a/modules/fatture/src/Fattura.php b/modules/fatture/src/Fattura.php index 658ec65d7..4f28b91a5 100644 --- a/modules/fatture/src/Fattura.php +++ b/modules/fatture/src/Fattura.php @@ -4,6 +4,7 @@ namespace Modules\Fatture; use Common\Document; use Modules\Anagrafiche\Anagrafica; +use Modules\Pagamenti\Pagamento; use Modules\RitenuteContributi\RitenutaContributi; use Plugins\ExportFE\FatturaElettronica; use Traits\RecordTrait; @@ -15,11 +16,6 @@ class Fattura extends Document protected $table = 'co_documenti'; - /** - * The attributes that should be casted to native types. - * - * @var array - */ protected $casts = [ 'bollo' => 'float', ]; @@ -208,6 +204,11 @@ class Fattura extends Document return $this->belongsTo(Tipo::class, 'idtipodocumento'); } + public function pagamento() + { + return $this->belongsTo(Pagamento::class, 'idpagamento'); + } + public function stato() { return $this->belongsTo(Stato::class, 'idstatodocumento'); @@ -263,35 +264,110 @@ class Fattura extends Document return !empty($this->progressivo_invio) && $this->module == 'Fatture di acquisto'; } + /** + * Registra le scadenze della fattura elettronica collegata al documento. + * + * @param bool $is_pagato + * + * @return bool + */ public function registraScadenzeFE($is_pagato = false) { - $database = $dbo = database(); - $xml = \Util\XML::read($this->getXML()); $pagamenti = $xml['FatturaElettronicaBody']['DatiPagamento']['DettaglioPagamento']; if (!empty($pagamenti)) { - $scadenze = isset($pagamenti[0]) ? $pagamenti : [$pagamenti]; + $rate = isset($pagamenti[0]) ? $pagamenti : [$pagamenti]; - foreach ($scadenze as $scadenza) { - $data = $scadenza['DataScadenzaPagamento'] ?: $this->data; - $importo = $scadenza['ImportoPagamento']; + foreach ($rate as $rata) { + $scadenza = $rata['DataScadenzaPagamento'] ?: $this->data; + $importo = -$rata['ImportoPagamento']; - $dbo->insert('co_scadenziario', [ - 'iddocumento' => $this->id, - 'data_emissione' => $this->data, - 'scadenza' => $data, - 'da_pagare' => -$importo, - 'tipo' => 'fattura', - 'pagato' => $is_pagato ? $importo : 0, - 'data_pagamento' => $is_pagato ? $data : '', - ], ['id' => $id_scadenza]); + 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) { + $importo = $direzione == 'uscita' ? -$rata['importo'] : $rata['importo']; + $scadenza = $rata['scadenza']; + + self::registraScadenza($this, $importo, $scadenza, $is_pagato); + } + } + + /** + * Registra una specifica scadenza nel database. + * + * @param Fattura $fattura + * @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') + { + 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, + ]); + } + + /** + * 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->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) { + $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]); + } + /** * Restituisce l'elenco delle note di credito collegate. * diff --git a/modules/pagamenti/src/Pagamento.php b/modules/pagamenti/src/Pagamento.php new file mode 100644 index 000000000..194cb49d0 --- /dev/null +++ b/modules/pagamenti/src/Pagamento.php @@ -0,0 +1,82 @@ +hasMany(Fattura::class, 'idpagamento'); + } + + public function rate() + { + return $this->hasMany(Pagamento::class, 'descrizione', 'descrizione'); + } + + public function calcola($importo, $data) + { + $rate = $this->rate->sortBy('num_giorni'); + $number = count($rate); + + //dd($rate, $this); + $totale = 0.0; + + $results = []; + foreach ($rate as $key => $rata) { + // X giorni esatti + if ($rata['giorno'] == 0) { + $scadenza = date('Y-m-d', strtotime($data.' +'.$rata['num_giorni'].' day')); + } + + // Ultimo del mese + elseif ($rata['giorno'] < 0) { + $date = new DateTime($data); + + $add = floor($rata['num_giorni'] / 30); + for ($c = 0; $c < $add; ++$c) { + $date->modify('last day of next month'); + } + + // Ultimo del mese più X giorni + $giorni = -$rata['giorno'] - 1; + if ($giorni > 0) { + $date->modify('+'.($giorni).' day'); + } else { + $date->modify('last day of this month'); + } + + $scadenza = $date->format('Y-m-d'); + } + + // Giorno preciso del mese + else { + $scadenza = date('Y-m-'.$rata['giorno'], strtotime($data.' +'.$rata['num_giorni'].' day')); + } + + // All'ultimo ciclo imposto come cifra da pagare il totale della fattura meno gli importi già inseriti in scadenziario per evitare di inserire cifre arrotondate "male" + if ($key + 1 == $number) { + $da_pagare = sum($importo, -$totale, 2); + } + + // Totale da pagare (totale x percentuale di pagamento nei casi pagamenti multipli) + else { + $da_pagare = sum($importo / 100 * $rata['prc'], 0, 2); + } + + $totale = sum($da_pagare, $totale, 2); + + $results[] = [ + 'scadenza' => $scadenza, + 'importo' => $da_pagare, + ]; + } + + return $results; + } +}