Aggiunto ricalcolo scadenze FE

This commit is contained in:
Thomas Zilio 2019-03-08 16:59:55 +01:00
parent 01d1d72f91
commit 19d667e1e1
6 changed files with 251 additions and 157 deletions

View File

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

View File

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

View File

@ -152,14 +152,41 @@ if (empty($record['is_fiscale'])) {
<?php
if ($record['stato'] != 'Bozza' && $record['stato'] != 'Annullata') {
$ricalcola = true;
$scadenze = $dbo->fetchArray('SELECT * FROM co_scadenziario WHERE iddocumento = '.prepare($id_record));
echo '
<div class="col-md-3">
<p><strong>'.tr('Scadenze').'</strong></p>';
foreach ($scadenze as $scadenza) {
echo '
<p>'.Translator::dateToLocale($scadenza['scadenza']).': '.Translator::numberToLocale($scadenza['da_pagare']).'&euro;</p>';
<p>'.Translator::dateToLocale($scadenza['scadenza']).': ';
if ($scadenza['pagato'] == $scadenza['da_pagare']) {
echo '
<strike>';
}
echo Translator::numberToLocale($scadenza['da_pagare']).'&euro;';
if ($scadenza['pagato'] == $scadenza['da_pagare']) {
echo '
</strike>';
}
echo '
</p>';
$ricalcola = empty(floatval($scadenza['pagato'])) && $ricalcola;
}
if ($fattura->isFE() && $ricalcola && $module['name'] == 'Fatture di acquisto') {
echo '
<button type="button" class="btn btn-info btn-xs pull-right tip" title="'.tr('Ricalcola le scadenze').'. '.tr('Per ricalcolare correttamente le scadenze, imposta la fattura in stato \'\'Bozza\'\' e correggi il metodo di come desiderato, poi re-imposta lo stato \'\'Emessa\'\' e utilizza questa funzione').'." id="ricalcola_scadenze">
<i class="fa fa-calculator" aria-hidden="true"></i>
</button>';
}
echo '
</div>';
}
@ -171,7 +198,7 @@ if (empty($record['is_fiscale'])) {
<div class="row">
<div class="col-md-3">
<!-- Nella realtà la fattura accompagnatoria non può esistere per la fatturazione elettronica, in quanto la risposta dal SDI potrebbe non essere immediata e le merci in viaggio. Dunque si può emettere una documento di viaggio valido per le merci ed eventualmente una fattura pro-forma per l'incasso della stessa, emettendo infine la fattura elettronica differita. -->
{[ "type": "select", "label": "<?php echo tr('Tipo fattura'); ?>", "name": "idtipodocumento", "required": 1, "values": "query=SELECT id, descrizione FROM co_tipidocumento WHERE dir='<?php echo $dir; ?>' AND (reversed = 0 OR id = <?php echo $record['idtipodocumento']; ?>)", "value": "$idtipodocumento$", "readonly": <?php echo intval($record['stato'] != 'Bozza' && $record['stato'] != 'Annullata'); ?>, "help": "<?php echo ($database->fetchOne('SELECT tipo FROM an_anagrafiche WHERE idanagrafica = '.prepare($record['idanagrafica']))['tipo'] == 'Ente pubblico') ? 'FPA12 - fattura verso PA' : 'FPR12 - fattura verso privati'; ?>" ]}
</div>
@ -198,18 +225,18 @@ if ($dir == 'uscita') {
<?php
}
?>
<div class="row">
<div class="col-md-3">
{[ "type": "number", "label": "<?php echo tr('Sconto incondizionato'); ?>", "name": "sconto_generico", "value": "$sconto_globale$", "help": "<?php echo tr('Sconto complessivo della fattura. Il valore positivo indica uno sconto. Per applicare un rincaro inserire un valore negativo.'); ?>", "icon-after": "choice|untprc|$tipo_sconto_globale$"<?php echo ($record['stato'] == 'Emessa') ? ', "disabled" : 1' : ''; ?> ]}
</div>
<div class="col-md-3">
{[ "type": "checkbox", "label": "<?php echo tr('Split payment'); ?>", "name": "split_payment", "value": "$split_payment$", "help": "<?php echo tr('Abilita lo split payment per questo documento.'); ?>", "placeholder": "<?php echo tr('Split payment'); ?>" ]}
</div>
<?php
//TODO: Fattura per conto del fornitore (es. cooperative agricole che emettono la fattura per conto dei propri soci produttori agricoli conferenti)
if ($dir == 'entrata') {
@ -217,7 +244,7 @@ if ($dir == 'uscita') {
<div class="col-md-3">
{[ "type": "checkbox", "label": "<?php echo tr('Fattura per conto terzi'); ?>", "name": "is_fattura_conto_terzi", "value": "$is_fattura_conto_terzi$", "help": "<?php echo tr('Nell\'xml della FE imposta il fornitore ('.stripslashes($database->fetchOne('SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica = '.prepare(setting('Azienda predefinita')))['ragione_sociale']).') come cessionario e il cliente come cedente/prestatore.'); ?>", "placeholder": "<?php echo tr('Fattura per conto terzi'); ?>" ]}
</div>
<?php
}
?>
@ -225,7 +252,7 @@ if ($dir == 'uscita') {
<div class="col-md-3">
{[ "type": "select", "label": "<?php echo tr('Ritenuta contributi'); ?>", "name": "id_ritenuta_contributi", "value": "$id_ritenuta_contributi$", "values": "query=SELECT * FROM co_ritenuta_contributi" ]}
</div>
</div>
<div class="row">
@ -499,21 +526,35 @@ include $docroot.'/modules/fatture/row-list.php';
{( "name": "filelist_and_upload", "id_module": "$id_module$", "id_record": "$id_record$" )}
<?php
if ($dir == 'entrata') {
echo '
if ($dir == 'entrata') {
echo '
<div class="alert alert-info text-center">'.tr('Per allegare un documento alla fattura elettronica caricare il file PDF specificando come categoria "Fattura Elettronica"').'.</div>';
}
?>
}
echo '
<script type="text/javascript">
$('#idanagrafica').change( function(){
session_set('superselect,idanagrafica', $(this).val(), 0);
$("#idanagrafica").change(function(){
session_set("superselect,idanagrafica", $(this).val(), 0);
$("#idsede").selectReset();
});
</script>
<?php
$("#ricalcola_scadenze").click(function(){
swal({
title: "'.tr('Desideri ricalcolare le scadenze?').'",
type: "warning",
showCancelButton: true,
confirmButtonText: "'.tr('Sì').'"
}).then(function (result) {
redirect(globals.rootdir + "/editor.php", {
id_module: globals.id_module,
id_record: globals.id_record,
op: "ricalcola_scadenze",
backto: "record-edit",
}, "post")
})
});
</script>';
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);

View File

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

View File

@ -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.
*

View File

@ -0,0 +1,82 @@
<?php
namespace Modules\Pagamenti;
use Common\Model;
use DateTime;
class Pagamento extends Model
{
protected $table = 'co_pagamenti';
public function fatture()
{
return $this->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;
}
}