Miglioramento pagamento scadenze

This commit is contained in:
Thomas Zilio 2019-07-31 18:22:35 +02:00
parent 59e48f2d80
commit 28d74d2a05
17 changed files with 653 additions and 793 deletions

View File

@ -48,6 +48,7 @@ Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://k
### Rimosso (Removed) ### Rimosso (Removed)
- Funzione *get_costi_intervento* del modulo **Attività**, a causa dell'aggiornamento della maggior parte del sistema di gestione degli **Attività** con le classi Eloquent - Funzione *get_costi_intervento* del modulo **Attività**, a causa dell'aggiornamento della maggior parte del sistema di gestione degli **Attività** con le classi Eloquent
- Funzione *aggiorna_scadenziario* del modulo **Prima Nota**
### Fixed ### Fixed

View File

@ -18,6 +18,8 @@ return [
'modules/interventi' => 'Modules\Interventi', 'modules/interventi' => 'Modules\Interventi',
'modules/pagamenti' => 'Modules\Pagamenti', 'modules/pagamenti' => 'Modules\Pagamenti',
'modules/statistiche' => 'Modules\Statistiche', 'modules/statistiche' => 'Modules\Statistiche',
'modules/scadenzario' => 'Modules\Scadenzario',
'modules/primanota' => 'Modules\PrimaNota',
'modules/utenti' => 'Modules\Utenti', 'modules/utenti' => 'Modules\Utenti',
'modules/stato_servizi' => 'Modules\StatoServizi', 'modules/stato_servizi' => 'Modules\StatoServizi',
'modules/stati_intervento' => 'Modules\StatiIntervento', 'modules/stati_intervento' => 'Modules\StatiIntervento',

View File

@ -59,7 +59,7 @@ if (!empty($record['is_fiscale'])) {
//Aggiunta insoluto //Aggiunta insoluto
if (!empty($record['riba']) && ($record['stato'] == 'Emessa' || $record['stato'] == 'Parzialmente pagato' || $record['stato'] == 'Pagato') && $dir == 'entrata') { if (!empty($record['riba']) && ($record['stato'] == 'Emessa' || $record['stato'] == 'Parzialmente pagato' || $record['stato'] == 'Pagato') && $dir == 'entrata') {
?> ?>
<button type="button" class="btn btn-primary" onclick="launch_modal( '<?php echo tr('Registra insoluto'); ?>', '<?php echo $rootdir; ?>/add.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>&id_documenti=<?php echo $id_record; ?>&single=1&insoluto=1');"><i class="fa fa-euro"></i> <?php echo tr('Registra insoluto'); ?>...</button> <button type="button" class="btn btn-primary" onclick="launch_modal( '<?php echo tr('Registra insoluto'); ?>', '<?php echo $rootdir; ?>/add.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>&id_documenti=<?php echo $id_record; ?>&single=1&is_insoluto=1');"><i class="fa fa-euro"></i> <?php echo tr('Registra insoluto'); ?>...</button>
<?php <?php
} }

View File

@ -21,6 +21,7 @@ if (isset($id_record)) {
co_documenti.split_payment AS split_payment, co_documenti.split_payment AS split_payment,
co_statidocumento.descrizione AS `stato`, co_statidocumento.descrizione AS `stato`,
co_tipidocumento.descrizione AS `descrizione_tipodoc`, co_tipidocumento.descrizione AS `descrizione_tipodoc`,
co_pagamenti.riba AS `riba`,
(SELECT is_fiscale FROM zz_segments WHERE id = id_segment) AS is_fiscale, (SELECT is_fiscale FROM zz_segments WHERE id = id_segment) AS is_fiscale,
(SELECT descrizione FROM co_ritenutaacconto WHERE id=idritenutaacconto) AS ritenutaacconto_desc, (SELECT descrizione FROM co_ritenutaacconto WHERE id=idritenutaacconto) AS ritenutaacconto_desc,
(SELECT descrizione FROM co_rivalse WHERE id=idrivalsainps) AS rivalsainps_desc, (SELECT descrizione FROM co_rivalse WHERE id=idrivalsainps) AS rivalsainps_desc,

View File

@ -111,107 +111,6 @@ function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = false)
$fattura->registraScadenze($pagato); $fattura->registraScadenze($pagato);
} }
/**
* 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, $idscadenza = '')
{
$dbo = database();
if ($totale_pagato > 0) {
// Lettura righe scadenziario
if ($idscadenza != '') {
$add_query = 'AND id='.prepare($idscadenza);
}
$query = "SELECT * FROM co_scadenziario WHERE iddocumento='$iddocumento' AND ABS(pagato) < ABS(da_pagare) ".$add_query.' ORDER BY scadenza ASC';
$rs = $dbo->fetchArray($query);
$rimanente_da_pagare = abs($rs[0]['pagato']) + $totale_pagato;
// 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'];
// Ciclo tra le rate dei pagamenti per inserire su `pagato` l'importo effettivamente pagato.
// Nel caso il pagamento superi la rata, devo distribuirlo sulle rate successive
for ($i = 0; $i < sizeof($rs); ++$i) {
if ($rimanente_da_pagare > 0) {
// ...riempio il pagato della rata con il totale della rata stessa se ho ricevuto un pagamento superiore alla rata stessa
if (abs($rimanente_da_pagare) >= abs($rs[$i]['da_pagare'])) {
$pagato = abs($rs[$i]['da_pagare']);
$rimanente_da_pagare -= abs($rs[$i]['da_pagare']);
} else {
// Se si inserisce una somma maggiore al dovuto, tengo valido il rimanente per saldare il tutto...
if (abs($rimanente_da_pagare) > abs($rs[$i]['da_pagare'])) {
$pagato = abs($rs[$i]['da_pagare']);
$rimanente_da_pagare -= abs($rs[$i]['da_pagare']);
}
// ...altrimenti aggiungo l'importo pagato
else {
$pagato = abs($rimanente_da_pagare);
$rimanente_da_pagare -= abs($rimanente_da_pagare);
}
}
if ($dir == 'uscita') {
$rimanente_da_pagare = -$rimanente_da_pagare;
}
if ($pagato > 0) {
if ($dir == 'uscita') {
$dbo->query('UPDATE co_scadenziario SET pagato='.prepare(-$pagato).', data_pagamento='.prepare($data_pagamento).' WHERE id='.prepare($rs[$i]['id']));
} else {
$dbo->query('UPDATE co_scadenziario SET pagato='.prepare($pagato).', data_pagamento='.prepare($data_pagamento).' WHERE id='.prepare($rs[$i]['id']));
}
}
}
}
} else {
// Lettura righe scadenziario
$query = "SELECT * FROM co_scadenziario WHERE iddocumento='$iddocumento' AND ABS(pagato)>0 ORDER BY scadenza DESC";
$rs = $dbo->fetchArray($query);
$residuo_pagato = abs($totale_pagato);
// 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'];
// Ciclo tra le rate dei pagamenti per inserire su `pagato` l'importo effettivamente pagato.
// Nel caso il pagamento superi la rata, devo distribuirlo sulle rate successive
for ($i = 0; $i < sizeof($rs); ++$i) {
if ($residuo_pagato > 0) {
// Se si inserisce una somma maggiore al dovuto, tengo valido il rimanente per saldare il tutto...
if ($residuo_pagato <= abs($rs[$i]['pagato'])) {
$pagato = 0;
$residuo_pagato -= abs($rs[$i]['pagato']);
}
// ...altrimenti aggiungo l'importo pagato
else {
$pagato = abs($residuo_pagato);
$residuo_pagato -= abs($residuo_pagato);
}
if ($dir == 'uscita') {
$residuo_pagato = -$residuo_pagato;
}
if ($pagato >= 0) {
if ($dir == 'uscita') {
$dbo->query('UPDATE co_scadenziario SET pagato='.prepare(-$pagato).', data_pagamento='.prepare($data_pagamento).' WHERE id='.prepare($rs[$i]['id']));
} else {
$dbo->query('UPDATE co_scadenziario SET pagato='.prepare($pagato).', data_pagamento='.prepare($data_pagamento).' WHERE id='.prepare($rs[$i]['id']));
}
}
}
}
}
}
/** /**
* Elimina i movimenti collegati ad una fattura. * Elimina i movimenti collegati ad una fattura.
*/ */

View File

@ -7,7 +7,9 @@ use Common\Document;
use Modules\Anagrafiche\Anagrafica; use Modules\Anagrafiche\Anagrafica;
use Modules\Fatture\Components\Riga; use Modules\Fatture\Components\Riga;
use Modules\Pagamenti\Pagamento; use Modules\Pagamenti\Pagamento;
use Modules\PrimaNota\Movimento;
use Modules\RitenuteContributi\RitenutaContributi; use Modules\RitenuteContributi\RitenutaContributi;
use Modules\Scadenzario\Scadenza;
use Plugins\ExportFE\FatturaElettronica; use Plugins\ExportFE\FatturaElettronica;
use Traits\RecordTrait; use Traits\RecordTrait;
use Util\Generator; use Util\Generator;
@ -290,6 +292,16 @@ class Fattura extends Document
return $this->hasOne(Components\Riga::class, 'iddocumento')->where('id', $this->id_riga_bollo); return $this->hasOne(Components\Riga::class, 'iddocumento')->where('id', $this->id_riga_bollo);
} }
public function scadenze()
{
return $this->hasMany(Scadenza::class, 'iddocumento');
}
public function movimentiContabili()
{
return $this->hasMany(Movimento::class, 'iddocumento')->where('primanota', 1);
}
// Metodi generali // Metodi generali
public function getXML() public function getXML()
@ -361,25 +373,21 @@ class Fattura extends Document
* *
* @param Fattura $fattura * @param Fattura $fattura
* @param float $importo * @param float $importo
* @param string $scadenza * @param string $data_scadenza
* @param bool $is_pagato * @param bool $is_pagato
* @param string $type * @param string $type
*/ */
public static function registraScadenza(Fattura $fattura, $importo, $scadenza, $is_pagato, $type = 'fattura') public static function registraScadenza(Fattura $fattura, $importo, $data_scadenza, $is_pagato, $type = 'fattura')
{ {
// Individuazione della descrizione $numero = $fattura->numero_esterno ?: $fattura->numero;
$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']; $descrizione = $fattura->tipo->descrizione.' numero '.$numero;
database()->insert('co_scadenziario', [ $scadenza = Scadenza::build($descrizione, $importo, $data_scadenza, $type, $is_pagato);
'iddocumento' => $fattura->id,
'data_emissione' => $fattura->data, $scadenza->documento()->associate($fattura);
'scadenza' => $scadenza, $scadenza->data_emissione = $fattura->data;
'da_pagare' => $importo,
'tipo' => $type, $scadenza->save();
'pagato' => $is_pagato ? $importo : 0,
'data_pagamento' => $is_pagato ? $scadenza : null,
'descrizione' => $descrizione,
]);
} }
/** /**
@ -481,62 +489,6 @@ class Fattura extends Document
return $this->tipo->reversed == 1; 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. * Restituisce i dati bancari in base al pagamento.
* *
@ -615,4 +567,60 @@ class Fattura extends Document
$riga->save(); $riga->save();
} }
// 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;
}
} }

View File

@ -2,69 +2,35 @@
include_once __DIR__.'/../../core.php'; include_once __DIR__.'/../../core.php';
use Modules\PrimaNota\Movimento;
use Modules\PrimaNota\PrimaNota;
use Modules\Scadenzario\Scadenza;
switch (post('op')) { switch (post('op')) {
case 'add': case 'add':
$all_ok = true;
$data = post('data'); $data = post('data');
$idmastrino = get_new_idmastrino();
$descrizione = post('descrizione'); $descrizione = post('descrizione');
$is_insoluto = post('is_insoluto');
$prima_nota = PrimaNota::build($descrizione, $data, $is_insoluto, true);
$conti = post('idconto'); $conti = post('idconto');
foreach ($conti as $i => $id_conto) { foreach ($conti as $i => $id_conto) {
$id_scadenza = post('id_scadenza')[$i]; $id_scadenza = post('id_scadenza')[$i];
$insoluto = post('insoluto')[$i];
$dare = post('dare')[$i]; $dare = post('dare')[$i];
$avere = post('avere')[$i]; $avere = post('avere')[$i];
if (!empty($dare) || !empty($avere)) { $scadenza = Scadenza::find($id_scadenza);
if (!empty($avere)) {
$totale = -$avere; $movimento = Movimento::build($prima_nota, $id_conto, $scadenza);
} else { $movimento->setTotale($avere, $dare);
$totale = $dare; $movimento->save();
} }
$scadenza = $database->fetchOne('SELECT iddocumento, data_emissione FROM co_scadenziario WHERE id = '.prepare($id_scadenza)); $prima_nota->aggiornaScadenzario();
$id_documento = $scadenza['iddocumento'];
$database->insert('co_movimenti', [ $id_record = $prima_nota->id;
'idmastrino' => $idmastrino,
'data' => $data,
'data_documento' => $scadenza['data_emissione'],
'iddocumento' => $id_documento ?: 0,
'descrizione' => $descrizione,
'idconto' => $id_conto,
'totale' => $totale,
'primanota' => 1,
]);
// Inserisco nello scadenziario il totale pagato
if (empty($insoluto)) {
aggiorna_scadenziario($id_documento, abs($totale), $data, $id_scadenza);
}
// Rimuovo dallo scadenzario l'insoluto
else {
aggiorna_scadenziario($id_documento, -abs($totale), $data, $id_scadenza);
}
if (!empty($id_documento)) {
// Verifico se la fattura è stata pagata tutta, così imposto lo stato a "Pagato"
$rs = $dbo->fetchArray('SELECT SUM(pagato) AS tot_pagato, SUM(da_pagare) AS tot_da_pagare FROM co_scadenziario WHERE iddocumento='.prepare($id_documento));
// Aggiorno lo stato della fattura
if (abs($rs[0]['tot_pagato']) == abs($rs[0]['tot_da_pagare'])) {
$stato = 'Pagato';
} elseif (abs($rs[0]['tot_pagato']) != abs($rs[0]['tot_da_pagare']) && abs($rs[0]['tot_pagato']) != '0') {
$stato = 'Parzialmente pagato';
} else {
$stato = 'Emessa';
}
$dbo->query('UPDATE co_documenti SET idstatodocumento=(SELECT id FROM co_statidocumento WHERE descrizione='.prepare($stato).') WHERE id='.prepare($id_documento));
}
}
}
$id_record = $idmastrino;
flash()->info(tr('Movimento aggiunto in prima nota!')); flash()->info(tr('Movimento aggiunto in prima nota!'));
// Creo il modello di prima nota // Creo il modello di prima nota
@ -85,204 +51,35 @@ switch (post('op')) {
break; break;
case 'editriga': case 'update':
$all_ok = true;
$iddocumento = post('iddocumento');
$data = post('data'); $data = post('data');
$idmastrino = post('idmastrino');
$descrizione = post('descrizione'); $descrizione = post('descrizione');
// Leggo il totale di questo mastrino $prima_nota->descrizione = $descrizione;
$query = 'SELECT totale FROM co_movimenti WHERE idmastrino='.prepare($idmastrino).' AND primanota=1 AND totale>0'; $prima_nota->data = $data;
$rs = $dbo->fetchArray($query);
$tot_mastrino = 0.00;
for ($i = 0; $i < sizeof($rs); ++$i) { $prima_nota->cleanup();
$tot_mastrino += abs($rs[0]['totale']);
}
// Eliminazione prima nota $conti = post('idconto');
$dbo->query('DELETE FROM co_movimenti WHERE idmastrino='.prepare($idmastrino).' AND primanota=1'); foreach ($conti as $i => $id_conto) {
$id_scadenza = post('id_scadenza')[$i];
for ($i = 0; $i < sizeof(post('idconto')); ++$i) {
$iddocumento = post('iddocumento')[$i];
// Lettura info fattura
$query = 'SELECT *, co_documenti.note, co_documenti.idpagamento, co_documenti.id AS iddocumento, co_statidocumento.descrizione AS `stato`, co_tipidocumento.descrizione AS `descrizione_tipodoc` FROM ((co_documenti LEFT OUTER JOIN co_statidocumento ON co_documenti.idstatodocumento=co_statidocumento.id) INNER JOIN an_anagrafiche ON co_documenti.idanagrafica=an_anagrafiche.idanagrafica) INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id='.prepare($iddocumento);
$rs = $dbo->fetchArray($query);
$ragione_sociale = $rs[0]['ragione_sociale'];
$dir = $rs[0]['dir'];
$idconto = post('idconto')[$i];
$dare = post('dare')[$i]; $dare = post('dare')[$i];
$avere = post('avere')[$i]; $avere = post('avere')[$i];
if ($dare != '' && $dare != 0) { $scadenza = Scadenza::find($id_scadenza);
$totale = $dare;
} elseif ($avere != '' && $avere != 0) { $movimento = Movimento::build($prima_nota, $id_conto, $scadenza);
$totale = -$avere; $movimento->setTotale($avere, $dare);
} else { $movimento->save();
$totale = 0;
} }
if ($totale != 0) { $prima_nota->aggiornaScadenzario();
$query = 'INSERT INTO co_movimenti(idmastrino, data, iddocumento, descrizione, idconto, totale, primanota) VALUES('.prepare($idmastrino).', '.prepare($data).', '.prepare($iddocumento).', '.prepare($descrizione).', '.prepare($idconto).', '.prepare($totale).", '1')";
if (!$dbo->query($query)) {
$all_ok = false;
} else {
$id_record = $idmastrino;
/*
Devo azzerare il totale pagato nello scadenziario perché verrà ricalcolato.
Se c'erano delle rate già pagate ne devo tener conto per rigenerare il totale pagato
*/
// Tengo conto dei valori negativi per gli acquisti e dei valori positivi per le vendite
if (($dir == 'uscita' && $totale < 0) || ($dir == 'entrata' && $totale > 0)) {
// Azzero lo scadenziario e lo ricalcolo
$dbo->query('UPDATE co_scadenziario SET pagato=0, data_pagamento = NULL WHERE iddocumento='.prepare($iddocumento));
// Ricalcolo lo scadenziario per il solo nuovo importo
aggiorna_scadenziario($iddocumento, $totale, $data);
// Se il totale pagato non è il totale da pagare rimetto la fattura in stato "Emessa"
$query2 = 'SELECT SUM(pagato) AS tot_pagato, SUM(da_pagare) AS tot_da_pagare FROM co_scadenziario WHERE iddocumento='.prepare($iddocumento);
$rs2 = $dbo->fetchArray($query2);
// Aggiorno lo stato della fattura a "Emessa"
if (abs($rs2[0]['tot_pagato']) < abs($rs2[0]['tot_da_pagare'])) {
$dbo->query("UPDATE co_documenti SET idstatodocumento=(SELECT id FROM co_statidocumento WHERE descrizione='Emessa') WHERE id=".prepare($iddocumento));
// Aggiorno lo stato dei preventivi collegati alla fattura se ce ne sono
$query3 = 'SELECT idpreventivo FROM co_righe_documenti WHERE iddocumento='.prepare($iddocumento).' AND NOT idpreventivo=0 AND idpreventivo IS NOT NULL';
$rs3 = $dbo->fetchArray($query3);
for ($j = 0; $j < sizeof($rs3); ++$j) {
$dbo->query("UPDATE co_preventivi SET idstato=(SELECT id FROM co_statipreventivi WHERE descrizione='In attesa di pagamento') WHERE id=".prepare($rs3[$j]['idpreventivo']));
// Aggiorno anche lo stato degli interventi collegati ai preventivi
$dbo->query("UPDATE in_interventi SET idstatointervento=(SELECT idstatointervento FROM in_statiintervento WHERE descrizione='Completato') WHERE id_preventivo=".prepare($rs3[$j]['idpreventivo']));
}
// Aggiorno lo stato degli interventi collegati alla fattura se ce ne sono
$query3 = 'SELECT idintervento FROM co_righe_documenti WHERE iddocumento='.prepare($iddocumento).' AND idintervento IS NOT NULL';
$rs3 = $dbo->fetchArray($query3);
for ($j = 0; $j < sizeof($rs3); ++$j) {
$dbo->query("UPDATE in_interventi SET idstatointervento=(SELECT idstatointervento FROM in_statiintervento WHERE descrizione='Fatturato') WHERE id=".prepare($rs3[$j]['idintervento']));
}
}
}
}
}
}
// Se non va a buon fine qualcosa elimino il mastrino per non lasciare incongruenze nel db
if (!$all_ok) {
flash()->error(tr("Errore durante l'aggiunta del movimento!"));
$dbo->query('DELETE FROM co_movimenti WHERE idmastrino='.prepare($idmastrino));
} else {
flash()->info(tr('Movimento modificato in prima nota!')); flash()->info(tr('Movimento modificato in prima nota!'));
foreach (post('iddocumento') as $iddocumento) {
// Verifico se la fattura è stata pagata, così imposto lo stato a "Pagato"
$query = 'SELECT SUM(pagato) AS tot_pagato, SUM(da_pagare) AS tot_da_pagare FROM co_scadenziario GROUP BY iddocumento HAVING iddocumento='.prepare($iddocumento);
$rs = $dbo->fetchArray($query);
// Aggiorno lo stato della fattura
if ($rs[0]['tot_pagato'] == $rs[0]['tot_da_pagare']) {
$stato = 'Pagato';
} else {
$stato = 'Parzialmente pagato';
}
$dbo->query('UPDATE co_documenti SET idstatodocumento=(SELECT id FROM co_statidocumento WHERE descrizione='.prepare($stato).') WHERE id='.prepare($iddocumento));
}
}
break; break;
// eliminazione movimento prima nota // eliminazione movimento prima nota
case 'delete': case 'delete':
$idmastrino = post('idmastrino'); $prima_nota->delete();
if ($idmastrino != '') {
// Leggo l'id della fattura per azzerare i valori di preventivi e interventi collegati
$query = 'SELECT iddocumento FROM co_movimenti WHERE idmastrino='.prepare($idmastrino).' AND primanota=1';
$rs = $dbo->fetchArray($query);
$iddocumento = $rs[0]['iddocumento'];
// Leggo il totale dal mastrino e lo rimuovo dal totale pagato dello scadenziario, ciclando tra le rate
$query = 'SELECT totale FROM co_movimenti WHERE idmastrino='.prepare($idmastrino).' AND primanota=1 AND totale>0';
$rs = $dbo->fetchArray($query);
$totale_mastrino = 0.00;
for ($i = 0; $i < sizeof($rs); ++$i) {
$totale_mastrino += $rs[0]['totale'];
}
$rimanente = $totale_mastrino;
$query = 'SELECT * FROM co_scadenziario WHERE iddocumento='.prepare($iddocumento).' ORDER BY scadenza DESC';
$rs = $dbo->fetchArray($query);
for ($i = 0; $i < sizeof($rs); ++$i) {
if (abs($rimanente) > 0) {
if (abs($rs[$i]['pagato']) >= abs($rimanente)) {
$query2 = 'SELECT pagato FROM co_scadenziario WHERE id='.prepare($rs[$i]['id']);
$rs2 = $dbo->fetchArray($query2);
$pagato = $rs2[0]['pagato'];
($pagato < 0) ? $sign = -1 : $sign = 1;
$new_value = ((abs($pagato) - abs($rimanente)) * $sign);
// Se resta ancora un po' di pagato cambio solo l'importo...
if ($new_value > 0) {
$dbo->query('UPDATE co_scadenziario SET pagato='.prepare($new_value).' WHERE id='.prepare($rs[$i]['id']));
}
// ...se l'importo è a zero, azzero anche la data di pagamento
else {
$dbo->query('UPDATE co_scadenziario SET pagato='.prepare($new_value).', data_pagamento = NULL WHERE id='.prepare($rs[$i]['id']));
}
$rimanente = 0;
} else {
$dbo->query("UPDATE co_scadenziario SET pagato='0', data_pagamento = NULL WHERE id=".prepare($rs[$i]['id']));
$rimanente -= abs($rs[$i]['pagato']);
}
}
}
// Eliminazione prima nota
$dbo->query('DELETE FROM co_movimenti WHERE idmastrino='.prepare($idmastrino).' AND primanota=1');
// Aggiorno lo stato della fattura a "Emessa" o "Parzialmente pagato"
$rs_pagamenti = $dbo->fetchArray("SELECT SUM(pagato) AS pagato FROM co_scadenziario WHERE iddocumento='".$iddocumento."'");
if ($rs_pagamenti[0]['pagato'] > 0) {
$dbo->query("UPDATE co_documenti SET idstatodocumento=(SELECT id FROM co_statidocumento WHERE descrizione='Parzialmente pagato') WHERE id=".prepare($iddocumento));
} else {
$dbo->query("UPDATE co_documenti SET idstatodocumento=(SELECT id FROM co_statidocumento WHERE descrizione='Emessa') WHERE id=".prepare($iddocumento));
}
// Aggiorno lo stato dei preventivi collegati alla fattura se ce ne sono
$query = 'SELECT idpreventivo FROM co_righe_documenti WHERE iddocumento='.prepare($iddocumento).' AND NOT idpreventivo=0 AND idpreventivo IS NOT NULL';
$rs = $dbo->fetchArray($query);
for ($i = 0; $i < sizeof($rs); ++$i) {
$dbo->query("UPDATE co_preventivi SET idstato=(SELECT id FROM co_statipreventivi WHERE descrizione='In attesa di pagamento') WHERE id=".prepare($rs[$i]['idpreventivo']));
// Aggiorno anche lo stato degli interventi collegati ai preventivi
$dbo->query("UPDATE in_interventi SET idstatointervento=(SELECT idstatointervento FROM in_statiintervento WHERE descrizione='Completato') WHERE id_preventivo=".prepare($rs[$i]['idpreventivo']));
}
// Aggiorno lo stato degli interventi collegati alla fattura se ce ne sono
$query = 'SELECT idintervento FROM co_righe_documenti WHERE iddocumento='.prepare($iddocumento).' AND NOT idintervento IS NOT NULL';
$rs = $dbo->fetchArray($query);
for ($i = 0; $i < sizeof($rs); ++$i) {
$dbo->query("UPDATE in_interventi SET idstatointervento=(SELECT idstatointervento FROM in_statiintervento WHERE descrizione='Fatturato') WHERE id=".prepare($rs[$i]['idintervento']));
}
flash()->info(tr('Movimento eliminato!'));
}
break; break;
} }

View File

@ -21,8 +21,9 @@ if (!empty($id_records)) {
} }
// ID predefiniti // ID predefiniti
$dir = get('dir'); $dir = 'uscita'; // Le scadenze normali hanno solo direzione in uscita
$singola_scadenza = get('single') != null; $singola_scadenza = get('single') != null;
$is_insoluto = get('is_insoluto') != null;
$id_documenti = $id_documenti ?: get('id_documenti'); $id_documenti = $id_documenti ?: get('id_documenti');
$id_documenti = $id_documenti ? explode(',', $id_documenti) : []; $id_documenti = $id_documenti ? explode(',', $id_documenti) : [];
@ -32,12 +33,14 @@ $id_scadenze = $id_scadenze ? explode(',', $id_scadenze) : [];
// Scadenze // Scadenze
foreach ($id_scadenze as $id_scadenza) { foreach ($id_scadenze as $id_scadenza) {
$scadenza = $dbo->fetchOne('SELECT descrizione, scadenza, iddocumento, SUM(da_pagare - pagato) AS rata FROM co_scadenziario WHERE id='.prepare($id_scadenza)); $scadenza = $dbo->fetchOne('SELECT *, SUM(da_pagare - pagato) AS rata FROM co_scadenziario WHERE id='.prepare($id_scadenza));
if (!empty($scadenza['iddocumento'])) { if (!empty($scadenza['iddocumento'])) {
$id_documenti[] = $scadenza['iddocumento']; $id_documenti[] = $scadenza['iddocumento'];
continue; continue;
} }
$scadenza['rata'] = abs($scadenza['rata']);
$descrizione_conto = ($dir == 'entrata') ? 'Riepilogativo clienti' : 'Riepilogativo fornitori'; $descrizione_conto = ($dir == 'entrata') ? 'Riepilogativo clienti' : 'Riepilogativo fornitori';
$conto = $dbo->fetchOne('SELECT id FROM co_pianodeiconti3 WHERE descrizione = '.prepare($descrizione_conto)); $conto = $dbo->fetchOne('SELECT id FROM co_pianodeiconti3 WHERE descrizione = '.prepare($descrizione_conto));
$id_conto_controparte = $conto['id']; $id_conto_controparte = $conto['id'];
@ -45,18 +48,27 @@ foreach ($id_scadenze as $id_scadenza) {
$righe_documento = []; $righe_documento = [];
$righe_documento[] = [ $righe_documento[] = [
'id_scadenza' => $scadenza['id'], 'id_scadenza' => $scadenza['id'],
'conto' => null, 'id_conto' => null,
'dare' => ($dir == 'entrata') ? 0 : $scadenza['rata'], 'dare' => ($dir == 'entrata') ? 0 : $scadenza['rata'],
'avere' => ($dir == 'entrata') ? $scadenza['rata'] : 0, 'avere' => ($dir == 'entrata') ? $scadenza['rata'] : 0,
]; ];
$righe_documento[] = [ $righe_documento[] = [
'id_scadenza' => $scadenza['id'], 'id_scadenza' => $scadenza['id'],
'conto' => $id_conto_controparte, 'id_conto' => $id_conto_controparte,
'dare' => ($dir == 'entrata') ? $scadenza['rata'] : 0, 'dare' => ($dir == 'entrata') ? $scadenza['rata'] : 0,
'avere' => ($dir == 'entrata') ? 0 : $scadenza['rata'], 'avere' => ($dir == 'entrata') ? 0 : $scadenza['rata'],
]; ];
// Se è un insoluto, inverto i valori
if ($is_insoluto) {
foreach ($righe_documento as $key => $value) {
$tmp = $value['avere'];
$righe_documento[$key]['avere'] = $righe_documento[$key]['dare'];
$righe_documento[$key]['dare'] = $tmp;
}
}
$righe = array_merge($righe, $righe_documento); $righe = array_merge($righe, $righe_documento);
} }
@ -78,7 +90,6 @@ foreach ($id_documenti as $id_documento) {
$numeri[] = !empty($fattura['numero_esterno']) ? $fattura['numero_esterno'] : $fattura['numero']; $numeri[] = !empty($fattura['numero_esterno']) ? $fattura['numero_esterno'] : $fattura['numero'];
$nota_credito = $tipo->descrizione == 'Nota di credito'; $nota_credito = $tipo->descrizione == 'Nota di credito';
$is_insoluto = (!empty($fattura['riba']) && $dir == 'entrata');
// Predisposizione prima riga // Predisposizione prima riga
$conto_field = 'idconto_'.($dir == 'entrata' ? 'vendite' : 'acquisti'); $conto_field = 'idconto_'.($dir == 'entrata' ? 'vendite' : 'acquisti');
@ -103,8 +114,7 @@ foreach ($id_documenti as $id_documento) {
if ($totale != 0) { if ($totale != 0) {
$righe_documento[] = [ $righe_documento[] = [
'id_scadenza' => $scadenze[0]['id'], 'id_scadenza' => $scadenze[0]['id'],
'insoluto' => $is_insoluto, 'id_conto' => $id_conto_aziendale,
'conto' => $id_conto_aziendale,
'dare' => ($dir == 'entrata') ? 0 : $totale, 'dare' => ($dir == 'entrata') ? 0 : $totale,
'avere' => ($dir == 'entrata') ? $totale : 0, 'avere' => ($dir == 'entrata') ? $totale : 0,
]; ];
@ -114,14 +124,13 @@ foreach ($id_documenti as $id_documento) {
foreach ($scadenze as $scadenza) { foreach ($scadenze as $scadenza) {
$righe_documento[] = [ $righe_documento[] = [
'id_scadenza' => $scadenza['id'], 'id_scadenza' => $scadenza['id'],
'insoluto' => $is_insoluto, 'id_conto' => $id_conto_controparte,
'conto' => $id_conto_controparte,
'dare' => ($dir == 'entrata') ? $scadenza['rata'] : 0, 'dare' => ($dir == 'entrata') ? $scadenza['rata'] : 0,
'avere' => ($dir == 'entrata') ? 0 : $scadenza['rata'], 'avere' => ($dir == 'entrata') ? 0 : $scadenza['rata'],
]; ];
} }
// Se è una nota di credito, inverto i valori // Se è una nota di credito o un insoluto, inverto i valori
if ($nota_credito || $is_insoluto) { if ($nota_credito || $is_insoluto) {
foreach ($righe_documento as $key => $value) { foreach ($righe_documento as $key => $value) {
$tmp = $value['avere']; $tmp = $value['avere'];
@ -186,7 +195,8 @@ echo '
<input type="hidden" name="op" value="add"> <input type="hidden" name="op" value="add">
<input type="hidden" name="backto" value="record-edit"> <input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="crea_modello" id="crea_modello" value="0"> <input type="hidden" name="crea_modello" id="crea_modello" value="0">
<input type="hidden" name="idmastrino" id="idmastrino" value="0">'; <input type="hidden" name="idmastrino" id="idmastrino" value="0">
<input type="hidden" name="is_insoluto" value="'.$is_insoluto.'">';
echo ' echo '
<div class="row"> <div class="row">
@ -205,70 +215,7 @@ echo '
</div> </div>
</div>'; </div>';
echo ' include $structure->filepath('movimenti.php');
<table class="table table-striped table-condensed table-hover table-bordered"
<tr>
<th>'.tr('Conto').'</th>
<th width="20%">'.tr('Dare').'</th>
<th width="20%">'.tr('Avere').'</th>
</tr>';
$max = max(count($righe), 10);
for ($i = 0; $i < $max; ++$i) {
$required = ($i <= 1);
$riga = $righe[$i];
// Conto
echo '
<tr>
<input type="hidden" name="id_scadenza[]" value="'.$riga['id_scadenza'].'">
<input type="hidden" name="insoluto[]" value="'.$riga['insoluto'].'">
<td>
{[ "type": "select", "name": "idconto[]", "id": "conto'.$i.'", "value": "'.($riga['conto'] ?: '').'", "ajax-source": "conti", "required": "'.$required.'" ]}
</td>';
// Dare
echo '
<td>
{[ "type": "number", "name": "dare[]", "id": "dare'.$i.'", "value": "'.($riga['dare'] ?: 0).'" ]}
</td>';
// Avere
echo '
<td>
{[ "type": "number", "name": "avere[]", "id": "avere'.$i.'", "value": "'.($riga['avere'] ?: 0).'" ]}
</td>
</tr>';
}
// Totale per controllare sbilancio
echo '
<tr>
<td align="right"><b>'.tr('Totale').':</b></td>';
// Totale dare
echo '
<td align="right">
<span><span id="totale_dare"></span> '.currency().'</span>
</td>';
// Totale avere
echo '
<td align="right">
<span><span id="totale_avere"></span> '.currency().'</span>
</td>
</tr>';
// Verifica sbilancio
echo '
<tr>
<td align="right"></td>
<td colspan="2" align="center">
<span id="testo_aggiuntivo"></span>
</td>
</tr>
</table>';
echo ' echo '
<!-- PULSANTI --> <!-- PULSANTI -->
@ -287,118 +234,20 @@ echo '
<script type="text/javascript"> <script type="text/javascript">
var variables = <?php echo json_encode($variables); ?>; var variables = <?php echo json_encode($variables); ?>;
var formatted_zero = "<?php echo Translator::numberToLocale(0); ?>";
var nuovo_modello = "<?php echo tr('Aggiungi e crea modello'); ?>"; var nuovo_modello = "<?php echo tr('Aggiungi e crea modello'); ?>";
var modifica_modello = "<?php echo tr('Aggiungi e modifica modello'); ?>"; var modifica_modello = "<?php echo tr('Aggiungi e modifica modello'); ?>";
var sbilancio = "<?php echo tr('sbilancio di _NUM_', [
'_NUM_' => '|value| '.currency(),
]); ?>";
$("#bs-popup #add-form").submit(function() {
return calcolaBilancio();
});
// Ad ogni modifica dell'importo verifica che siano stati selezionati: il conto, la causale, la data. Inoltre aggiorna lo sbilancio
function calcolaBilancio() {
bilancio = 0.00;
totale_dare = 0.00;
totale_avere = 0.00;
// Calcolo il totale dare e totale avere
$('#bs-popup input[id*=dare]').each(function() {
valore = $(this).val() ? $(this).val().toEnglish() : 0;
totale_dare += Math.round(valore * 100) / 100;
});
$('#bs-popup input[id*=avere]').each(function() {
valore = $(this).val() ? $(this).val().toEnglish() : 0;
totale_avere += Math.round(valore * 100) / 100;
});
$('#bs-popup #totale_dare').text(totale_dare.toLocale());
$('#bs-popup #totale_avere').text(totale_avere.toLocale());
bilancio = Math.round(totale_dare * 100) / 100 - Math.round(totale_avere * 100) / 100;
if (bilancio == 0) {
$('#bs-popup #testo_aggiuntivo').removeClass('text-danger').html("");
$('#bs-popup #add-submit').removeClass('hide');
$('#bs-popup #btn_crea_modello').removeClass('hide');
} else {
$('#bs-popup #testo_aggiuntivo').addClass('text-danger').html(sbilancio.replace('|value|', bilancio.toLocale()));
$('#bs-popup #add-submit').addClass('hide');
$('#bs-popup #btn_crea_modello').addClass('hide');
}
return bilancio == 0;
}
function bloccaZeri(){
$('#bs-popup input[id*=dare], #bs-popup input[id*=avere]').each(function() {
if ($(this).val() == formatted_zero) {
$(this).prop("disabled", true);
} else {
$(this).prop("disabled", false);
}
});
}
$(document).ready(function() { $(document).ready(function() {
calcolaBilancio();
bloccaZeri();
$("#bs-popup #add-form").submit(function() { $("#bs-popup #add-form").submit(function() {
var result = calcolaBilancio(); var result = calcolaBilancio();
if(!result) bloccaZeri(); if(!result) {
setTimeout(function(){ bloccaZeri(); }, 300);
}
return result; return result;
}); });
$('select').on('change', function() {
if ($(this).parent().parent().find('input[disabled]').length != 1) {
if ($(this).val()) {
$(this).parent().parent().find('input').prop("disabled", false);
} else {
$(this).parent().parent().find('input').prop("disabled", true);
$(this).parent().parent().find('input').val("0.00");
}
}
});
$('#bs-popup input[id*=dare]').on('keyup change', function() {
if (!$(this).prop('disabled')) {
if ($(this).val()) {
$(this).parent().parent().find('input[id*=avere]').prop("disabled", true);
} else {
$(this).parent().parent().find('input[id*=avere]').prop("disabled", false);
}
calcolaBilancio();
}
});
$('#bs-popup input[id*=avere]').on('keyup change', function() {
if (!$(this).prop('disabled')) {
if ($(this).val()) {
$(this).parent().parent().find('input[id*=dare]').prop("disabled", true);
} else {
$(this).parent().parent().find('input[id*=dare]').prop("disabled", false);
}
calcolaBilancio();
}
});
// Trigger dell'evento keyup() per la prima volta, per eseguire i dovuti controlli nel caso siano predisposte delle righe in prima nota
$("#bs-popup input[id*=dare][value!=''], #bs-popup input[id*=avere][value!='']").keyup();
$("#bs-popup select[id*=idconto]").click(function() {
$("#bs-popup input[id*=dare][value!=''], #bs-popup input[id*=avere][value!='']").keyup();
});
$('#bs-popup #modello_primanota').change(function() { $('#bs-popup #modello_primanota').change(function() {
if ($(this).val() != '') { if ($(this).val() != '') {
$('#btn_crea_modello').html('<i class="fa fa-edit"></i> ' + modifica_modello); $('#btn_crea_modello').html('<i class="fa fa-edit"></i> ' + modifica_modello);

View File

@ -3,7 +3,7 @@
include_once __DIR__.'/../../core.php'; include_once __DIR__.'/../../core.php';
?><form action="" method="post" id="edit-form"> ?><form action="" method="post" id="edit-form">
<input type="hidden" name="op" value="editriga"> <input type="hidden" name="op" value="update">
<input type="hidden" name="backto" value="record-edit"> <input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="id_record" value="<?php echo $id_record; ?>"> <input type="hidden" name="id_record" value="<?php echo $id_record; ?>">
<input type="hidden" name="idmastrino" value="<?php echo $record['idmastrino']; ?>"> <input type="hidden" name="idmastrino" value="<?php echo $record['idmastrino']; ?>">
@ -55,216 +55,27 @@ include_once __DIR__.'/../../core.php';
{[ "type": "text", "label": "<?php echo tr('Causale'); ?>", "name": "descrizione", "required": 1, "value": "$descrizione$" ]} {[ "type": "text", "label": "<?php echo tr('Causale'); ?>", "name": "descrizione", "required": 1, "value": "$descrizione$" ]}
</div> </div>
</div> </div>
<?php <?php
$conti3 = []; // contenitore conti di terzo livello
$totale_dare = 0.00;
$totale_avere = 0.00;
$idmastrino = $record['idmastrino'];
// Salvo l'elenco conti in un array (per non fare il ciclo ad ogni riga) $righe = $prima_nota->movimenti->toArray();
$query2 = 'SELECT * FROM co_pianodeiconti2';
$conti2 = $dbo->fetchArray($query2);
for ($x = 0; $x < sizeof($conti2); ++$x) {
$query3 = 'SELECT * FROM co_pianodeiconti3 WHERE idpianodeiconti2='.prepare($conti2[$x]['id']);
$rs3 = $dbo->fetchArray($query3);
for ($y = 0; $y < sizeof($rs3); ++$y) {
// Creo un array con le descrizioni dei conti di livello 3 che ha come indice l'id del livello2 e del livello3
$conti3[$rs3[$y]['idpianodeiconti2']][$y]['id'] = $rs3[$y]['id'];
$conti3[$rs3[$y]['idpianodeiconti2']][$y]['descrizione'] = $conti2[$x]['numero'].'.'.$rs3[$y]['numero'].' '.$rs3[$y]['descrizione'];
}
}
/* include $structure->filepath('movimenti.php');
Form di modifica riga movimento
*/
// Lettura movimenti del mastrino selezionato
$query = 'SELECT * FROM co_movimenti WHERE idmastrino='.prepare($record['idmastrino']).' AND primanota='.prepare($record['primanota']);
$rs = $dbo->fetchArray($query);
$n = sizeof($rs);
$iddocumento = $rs[0]['iddocumento'];
echo '
<table class="table table-striped table-condensed table-hover table-bordered"
<tr>
<th>'.tr('Conto').'</th>
<th width="20%">'.tr('Dare').'</th>
<th width="20%">'.tr('Avere').'</th>
</tr>';
if (sizeof($rs) >= 10) {
$rows = sizeof($rs) + 2;
} else {
$rows = 10;
}
for ($i = 0; $i < $rows; ++$i) {
($i <= 1) ? $required = 1 : $required = 0;
// Conto
echo '
<tr>
<td>
<input type="hidden" name="iddocumento['.$i.']" value="'.$rs[$i]['iddocumento'].'">
{[ "type": "select", "name": "idconto['.$i.']", "value": "'.$rs[$i]['idconto'].'", "ajax-source": "conti", "required": "'.$required.'" ]}
</td>';
// Importo dare e avere
if ($rs[$i]['totale'] > 0) {
$value_dare = $rs[$i]['totale'];
$value_avere = '';
} elseif ($rs[$i]['totale'] < 0) {
$value_dare = '';
$value_avere = -$rs[$i]['totale'];
} else {
$value_dare = '';
$value_avere = '';
}
// Dare
echo '
<td>
{[ "type": "number", "name": "dare['.$i.']", "value": "'.$value_dare.'", "disabled": 1 ]}
</td>';
// Avere
echo '
<td>
{[ "type": "number", "name": "avere['.$i.']", "value": "'.$value_avere.'", "disabled": 1 ]}
</td>
</tr>';
}
// Totale per controllare sbilancio
echo '
<tr>
<td align="right"><b>Totale:</b></td>';
if ($totale_dare != $totale_avere) {
$class = 'text-danger';
$txt = 'sbilancio di '.moneyFormat($totale_dare - $totale_avere);
} else {
$class = '';
$txt = '';
}
// Totale dare
echo '
<td align="right">
<span><span class="'.$class.'" id="totale_dare">'.Translator::numberToLocale($totale_dare).'</span> '.currency().'</span>
</td>';
// Totale avere
echo '
<td align="right">
<span><span class="'.$class.'" id="totale_avere">'.Translator::numberToLocale($totale_avere).'</span> '.currency().'</span>
</td>
</tr>';
// Verifica sbilancio
echo '
<tr>
<td align="right"></td>
<td colspan="2" align="center">
<span id="testo_aggiuntivo">'.$txt.'</span>
</td>
</tr>
</table>';
?> ?>
</form>
<script>
$("#edit-form").submit(function(e) {
var result = calcolaBilancio();
<script type="text/javascript"> if(!result) {
$(document).ready( function(){ setTimeout(function(){ bloccaZeri(); }, 300);
$('input[id*=dare], input[id*=avere]').each(function(){ e.preventDefault();
if($(this).val() != "<?php echo Translator::numberToLocale(0); ?>") $(this).prop("disabled", false);
});
$('select').on('change', function(){
if($(this).parent().parent().find('input[disabled]').length != 1){
if($(this).val()) {
$(this).parent().parent().find('input').prop("disabled", false);
}
else{
$(this).parent().parent().find('input').prop("disabled", true);
$(this).parent().parent().find('input').val("");
}
}
});
$('input[id*=dare]').on('keyup change', function(){
if(!$(this).prop('disabled')){
if($(this).val()) {
$(this).parent().parent().find('input[id*=avere]').prop("disabled", true);
}
else {
$(this).parent().parent().find('input[id*=avere]').prop("disabled", false);
} }
calcolaBilancio(); return result;
}
});
$('input[id*=avere]').on('keyup change', function(){
if(!$(this).prop('disabled')){
if($(this).val()) {
$(this).parent().parent().find('input[id*=dare]').prop("disabled", true);
}
else {
$(this).parent().parent().find('input[id*=dare]').prop("disabled", false);
}
calcolaBilancio();
}
});
// Ad ogni modifica dell'importo verifica che siano stati selezionati: il conto, la causale, la data. Inoltre aggiorna lo sbilancio
function calcolaBilancio(){
bilancio = 0.00;
totale_dare = 0.00;
totale_avere = 0.00;
// Calcolo il totale dare e totale avere
$('input[id*=dare]').each( function(){
if( $(this).val() == '' ) valore = 0;
else valore = $(this).val().toEnglish();
totale_dare += Math.round(valore*100)/100;
});
$('input[id*=avere]').each( function(){
if( $(this).val() == '' ) valore = 0;
else valore = $(this).val().toEnglish();
totale_avere += Math.round(valore*100)/100;
});
$('#totale_dare').text(totale_dare.toLocale());
$('#totale_avere').text(totale_avere.toLocale());
bilancio = Math.round(totale_dare*100)/100 - Math.round(totale_avere*100)/100;
if( bilancio == 0 ){
$("#testo_aggiuntivo").removeClass('text-danger').html("");
//$("button[type=submit]").removeClass('hide');
$("#save").removeClass('hide');
}
else{
$("#testo_aggiuntivo").addClass('text-danger').html("sbilancio di " + bilancio.toLocale() + " " + globals.currency );
//$("button[type=submit]").addClass('hide');
$("#save").addClass('hide');
}
}
// Trigger dell'evento keyup() per la prima volta, per eseguire i dovuti controlli nel caso siano predisposte delle righe in prima nota
$("input[id*=dare][value!=''], input[id*=avere][value!='']").keyup();
$("select[id*=idconto]").click( function(){
$("input[id*=dare][value!=''], input[id*=avere][value!='']").keyup();
});
}); });
</script> </script>
</form>
<a class="btn btn-danger ask" data-backto="record-list" data-idmastrino="<?php echo $record['idmastrino']; ?>"> <a class="btn btn-danger ask" data-backto="record-list" data-idmastrino="<?php echo $record['idmastrino']; ?>">
<i class="fa fa-trash"></i> <?php echo tr('Elimina'); ?> <i class="fa fa-trash"></i> <?php echo tr('Elimina'); ?>

View File

@ -2,6 +2,10 @@
include_once __DIR__.'/../../core.php'; include_once __DIR__.'/../../core.php';
use Modules\PrimaNota\PrimaNota;
if (isset($id_record)) { if (isset($id_record)) {
$prima_nota = PrimaNota::find($id_record);
$record = $dbo->fetchOne('SELECT * FROM co_movimenti WHERE idmastrino='.prepare($id_record)); $record = $dbo->fetchOne('SELECT * FROM co_movimenti WHERE idmastrino='.prepare($id_record));
} }

View File

@ -0,0 +1,169 @@
<?php
include_once __DIR__.'/../../core.php';
echo '
<table class="table table-striped table-condensed table-hover table-bordered"
<tr>
<th>'.tr('Conto').'</th>
<th width="20%">'.tr('Dare').'</th>
<th width="20%">'.tr('Avere').'</th>
</tr>';
$max = max(count($righe), 10);
for ($i = 0; $i < $max; ++$i) {
$required = ($i <= 1);
$riga = $righe[$i];
// Conto
echo '
<tr>
<input type="hidden" name="id_scadenza['.$i.']" value="'.$riga['id_scadenza'].'">
<td>
{[ "type": "select", "name": "idconto['.$i.']", "id": "conto'.$i.'", "value": "'.($riga['id_conto'] ?: '').'", "ajax-source": "conti", "required": "'.$required.'" ]}
</td>';
// Dare
echo '
<td>
{[ "type": "number", "name": "dare['.$i.']", "id": "dare'.$i.'", "value": "'.($riga['dare'] ?: 0).'" ]}
</td>';
// Avere
echo '
<td>
{[ "type": "number", "name": "avere['.$i.']", "id": "avere'.$i.'", "value": "'.($riga['avere'] ?: 0).'" ]}
</td>
</tr>';
}
// Totale per controllare sbilancio
echo '
<tr>
<td align="right"><b>'.tr('Totale').':</b></td>';
// Totale dare
echo '
<td align="right">
<span><span id="totale_dare"></span> '.currency().'</span>
</td>';
// Totale avere
echo '
<td align="right">
<span><span id="totale_avere"></span> '.currency().'</span>
</td>
</tr>';
// Verifica sbilancio
echo '
<tr>
<td align="right"></td>
<td colspan="2" align="center">
<span id="testo_aggiuntivo"></span>
</td>
</tr>
</table>';
echo '
<script>
var formatted_zero = "'.Translator::numberToLocale(0).'";
var sbilancio = "'.tr('sbilancio di _NUM_', [
'_NUM_' => '|value| '.currency(),
]).'";
// Ad ogni modifica dell\'importo verifica che siano stati selezionati: il conto, la causale, la data. Inoltre aggiorna lo sbilancio
function calcolaBilancio() {
bilancio = 0.00;
totale_dare = 0.00;
totale_avere = 0.00;
// Calcolo il totale dare e totale avere
$("input[id*=dare]").each(function() {
valore = $(this).val() ? $(this).val().toEnglish() : 0;
totale_dare += Math.round(valore * 100) / 100;
});
$("input[id*=avere]").each(function() {
valore = $(this).val() ? $(this).val().toEnglish() : 0;
totale_avere += Math.round(valore * 100) / 100;
});
$("#totale_dare").text(totale_dare.toLocale());
$("#totale_avere").text(totale_avere.toLocale());
bilancio = Math.round(totale_dare * 100) / 100 - Math.round(totale_avere * 100) / 100;
if (bilancio == 0) {
$("#testo_aggiuntivo").removeClass("text-danger").html(\'\');
$("#add-submit").removeClass("hide");
$("#btn_crea_modello").removeClass("hide");
} else {
$("#testo_aggiuntivo").addClass("text-danger").html(sbilancio.replace("|value|", bilancio.toLocale()));
$("#add-submit").addClass("hide");
$("#btn_crea_modello").addClass("hide");
}
return bilancio == 0;
}
function bloccaZeri(){
$("input[id*=dare], input[id*=avere]").each(function() {
if ($(this).val() == formatted_zero) {
$(this).prop("disabled", true);
} else {
$(this).prop("disabled", false);
}
});
}
$(document).ready(function() {
calcolaBilancio();
bloccaZeri();
$("select").on("change", function() {
if ($(this).parent().parent().find("input[disabled]").length != 1) {
if ($(this).val()) {
$(this).parent().parent().find("input").prop("disabled", false);
} else {
$(this).parent().parent().find("input").prop("disabled", true);
$(this).parent().parent().find("input").val("0.00");
}
}
});
$("input[id*=dare]").on("keyup change", function() {
if (!$(this).prop("disabled")) {
if ($(this).val()) {
$(this).parent().parent().find("input[id*=avere]").prop("disabled", true);
} else {
$(this).parent().parent().find("input[id*=avere]").prop("disabled", false);
}
calcolaBilancio();
}
});
$("input[id*=avere]").on("keyup change", function() {
if (!$(this).prop("disabled")) {
if ($(this).val()) {
$(this).parent().parent().find("input[id*=dare]").prop("disabled", true);
} else {
$(this).parent().parent().find("input[id*=dare]").prop("disabled", false);
}
calcolaBilancio();
}
});
// Trigger dell"evento keyup() per la prima volta, per eseguire i dovuti controlli nel caso siano predisposte delle righe in prima nota
$("input[id*=dare][value!=\'\'], input[id*=avere][value!=\'\']").keyup();
$("select[id*=idconto]").click(function() {
$("input[id*=dare][value!=\'\'], input[id*=avere][value!=\'\']").keyup();
});
});
</script>';

View File

@ -0,0 +1,84 @@
<?php
namespace Modules\PrimaNota;
use Common\Model;
use Modules\Fatture\Fattura;
use Modules\Scadenzario\Scadenza;
class Movimento extends Model
{
protected $table = 'co_movimenti';
protected $appends = [
'id_conto',
'avere',
'dare',
];
public static function build(PrimaNota $prima_nota, $id_conto, Scadenza $scadenza = null)
{
$model = parent::build();
$model->idmastrino = $prima_nota->idmastrino;
$model->data = $prima_nota->data;
$model->descrizione = $prima_nota->descrizione;
$model->primanota = $prima_nota->primanota;
$model->is_insoluto = $prima_nota->is_insoluto;
$model->id_scadenza = $scadenza ? $scadenza->id : null;
$documento = $scadenza ? $scadenza->documento : null;
if (!empty($documento)) {
$model->data_documento = $documento->data;
$model->iddocumento = $documento->id;
$model->idanagrafica = $documento->idanagrafica;
}
$model->idconto = $id_conto;
$model->save();
return $model;
}
public function setTotale($avere, $dare)
{
if (!empty($avere)) {
$totale = -$avere;
} else {
$totale = $dare;
}
$this->totale = $totale;
}
// Attributi
public function getIdContoAttribute()
{
return $this->attributes['idconto'];
}
public function getAvereAttribute()
{
return $this->totale < 0 ? abs($this->totale) : 0;
}
public function getDareAttribute()
{
return $this->totale > 0 ? abs($this->totale) : 0;
}
// Relazioni Eloquent
public function scadenza()
{
return $this->belongsTo(Scadenza::class, 'id_scadenza');
}
public function documento()
{
return $this->belongsTo(Fattura::class, 'iddocumento');
}
}

View File

@ -0,0 +1,199 @@
<?php
namespace Modules\PrimaNota;
use Common\Model;
use Modules\Fatture\Fattura;
use Modules\Scadenzario\Scadenza;
class PrimaNota extends Model
{
public $incrementing = false;
protected $table = 'co_movimenti';
protected $primaryKey = 'idmastrino';
protected $hidden = [
'idmastrino',
'data_documento',
'iddocumento',
'idanagrafica',
];
public static function build($descrizione, $data, $is_insoluto = false, $contabile = false)
{
$model = parent::build();
$model->idmastrino = self::getNextMastrino();
$model->data = $data;
$model->descrizione = $descrizione;
$model->is_insoluto = $is_insoluto;
$model->primanota = $contabile;
return $model;
}
public function cleanup()
{
$movimenti = $this->movimenti;
foreach ($movimenti as $movimento) {
$movimento->delete();
}
return $movimenti;
}
public function save(array $options = [])
{
}
public function delete()
{
$movimenti = $this->cleanup();
$this->aggiornaScadenzario($movimenti);
return parent::delete(); // TODO: Change the autogenerated stub
}
// Attributi
public function getIdAttribute()
{
return $this->idmastrino;
}
public function getTotaleAttribute()
{
$movimenti = $this->movimenti->where('totale', '>', 0);
$totale = $movimenti->sum('totale');
return $totale;
}
// Metodi generali
public function aggiornaScadenzario($movimenti = null)
{
$movimenti = $movimenti ?: $this->movimenti;
$documenti = [];
$scadenze = [];
foreach ($movimenti as $movimento) {
$scadenza = $movimento->scadenza;
$documento = $movimento->documento;
// Retrocompatibilità per versioni <= 2.4.11
if (!empty($documento)) {
if (!in_array($documento->id, $documenti)) {
$documenti[] = $documento->id;
$this->correggiScadenza($movimento, $scadenza, $documento);
}
} elseif (!empty($scadenza)) {
$id_documento = $scadenza->documento->id;
if (!in_array($id_documento, $documenti) && !in_array($scadenza->id, $scadenze)) {
$documenti[] = $id_documento;
$scadenze[] = $scadenza->id;
$this->correggiScadenza($movimento, $scadenza);
}
}
}
// Fix dello stato della Fattura
$database = database();
foreach ($documenti as $id_documento) {
// Verifico se la fattura è stata pagata tutta, così imposto lo stato a "Pagato"
$totali = $database->fetchOne('SELECT SUM(pagato) AS tot_pagato, SUM(da_pagare) AS tot_da_pagare FROM co_scadenziario WHERE iddocumento='.prepare($id_documento));
$totale_pagato = abs(floatval($totali['tot_pagato']));
$totale_da_pagare = abs(floatval($totali['tot_da_pagare']));
// Aggiorno lo stato della fattura
if ($totale_pagato == $totale_da_pagare) {
$stato = 'Pagato';
} elseif ($totale_pagato != $totale_da_pagare && $totale_pagato != 0) {
$stato = 'Parzialmente pagato';
} else {
$stato = 'Emessa';
}
$database->query('UPDATE co_documenti SET idstatodocumento = (SELECT id FROM co_statidocumento WHERE descrizione = '.prepare($stato).') WHERE id = '.prepare($id_documento));
}
}
public function correggiScadenza(Movimento $movimento, Scadenza $scadenza = null, Fattura $documento = null)
{
$documento = $documento ?: $scadenza->documento;
if ($documento) {
$dir = $documento->direzione;
$scadenze = $documento->scadenze->sortBy('scadenza');
$movimenti = $documento->movimentiContabili;
$totale_movimenti = $movimenti->where('totale', '>', 0)->where('is_insoluto', 0)->sum('totale');
$totale_insoluto = $movimenti->where('totale', '>', 0)->where('is_insoluto', 1)->sum('totale');
$totale_pagato = $totale_movimenti - $totale_insoluto;
} else {
$scadenze = [$scadenza];
$dir = 'uscita';
$totale_pagato = $movimento->totale;
}
$rimanente_da_pagare = abs($totale_pagato);
// Ciclo tra le rate dei pagamenti per inserire su `pagato` l'importo effettivamente pagato.
// Nel caso il pagamento superi la rata, devo distribuirlo sulle rate successive
foreach ($scadenze as $scadenza) {
if ($rimanente_da_pagare <= 0) {
$pagato = 0;
}
// ...riempio il pagato della rata con il totale della rata stessa se ho ricevuto un pagamento superiore alla rata stessa
elseif (abs($rimanente_da_pagare) >= abs($scadenza['da_pagare'])) {
$pagato = abs($scadenza['da_pagare']);
$rimanente_da_pagare -= abs($scadenza['da_pagare']);
}
// Se si inserisce una somma maggiore al dovuto, tengo valido il rimanente per saldare il tutto...
elseif (abs($rimanente_da_pagare) > abs($scadenza['da_pagare'])) {
$pagato = abs($scadenza['da_pagare']);
$rimanente_da_pagare -= abs($scadenza['da_pagare']);
}
// ...altrimenti aggiungo l'importo pagato
else {
$pagato = abs($rimanente_da_pagare);
$rimanente_da_pagare -= abs($rimanente_da_pagare);
}
$pagato = $dir == 'uscita' ? -$pagato : $pagato;
$scadenza->pagato = $pagato;
$scadenza->data_pagamento = $pagato ? $this->data : null;
$scadenza->save();
}
}
// Relazioni Eloquent
public function fattura()
{
return $this->belongsTo(Fattura::class, 'iddocumento');
}
public function movimenti()
{
return $this->hasMany(Movimento::class, 'idmastrino');
}
// Metodi statici
public static function getNextMastrino()
{
$ultimo = database()->fetchOne('SELECT MAX(idmastrino) AS max FROM co_movimenti');
return intval($ultimo['max']) + 1;
}
}

View File

@ -9,7 +9,7 @@ switch (post('op')) {
$da_pagare = post('da_pagare'); $da_pagare = post('da_pagare');
$descrizione = post('descrizione'); $descrizione = post('descrizione');
$dbo->query('INSERT INTO co_scadenziario(descrizione, tipo, data_emissione, scadenza, da_pagare, pagato) VALUES('.prepare($descrizione).', '.prepare($tipo).', CURDATE(), '.prepare($data).', '.prepare($da_pagare).", '0')"); $dbo->query('INSERT INTO co_scadenziario(descrizione, tipo, data_emissione, scadenza, da_pagare, pagato) VALUES('.prepare($descrizione).', '.prepare($tipo).', CURDATE(), '.prepare($data).', '.prepare(-$da_pagare).", '0')");
$id_record = $dbo->lastInsertedID(); $id_record = $dbo->lastInsertedID();
flash()->info(tr('Scadenza inserita!')); flash()->info(tr('Scadenza inserita!'));

View File

@ -154,7 +154,7 @@ echo '
</table> </table>
<div class='pull-right'> <div class='pull-right'>
<a onclick="launch_modal( 'Registra contabile pagamento', '<?php echo $rootdir; ?>/add.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>&dir=<?php echo $dir; ?>&id_scadenze=<?php echo $id_record; ?>');" class="btn btn-sm btn-primary"><i class="fa fa-euro"></i> <?php echo tr('Registra contabile pagamento...'); ?></a> <a onclick="launch_modal( 'Registra contabile pagamento', '<?php echo $rootdir; ?>/add.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>&id_scadenze=<?php echo $id_record; ?>');" class="btn btn-sm btn-primary"><i class="fa fa-euro"></i> <?php echo tr('Registra contabile pagamento...'); ?></a>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>

View File

@ -0,0 +1,33 @@
<?php
namespace Modules\Scadenzario;
use Common\Model;
use Modules\Fatture\Fattura;
class Scadenza extends Model
{
protected $table = 'co_scadenziario';
public static function build($descrizione, $importo, $data_scadenza, $type = 'fattura', $is_pagato = false)
{
$model = parent::build();
$model->descrizione = $descrizione;
$model->scadenza = $data_scadenza;
$model->da_pagare = $importo;
$model->tipo = $type;
$model->pagato = $is_pagato ? $importo : 0;
$model->data_pagamento = $is_pagato ? $data_scadenza : null;
$model->save();
return $model;
}
public function documento()
{
return $this->belongsTo(Fattura::class, 'iddocumento');
}
}

View File

@ -287,3 +287,6 @@ INSERT INTO `zz_widgets` (`id`, `name`, `type`, `id_module`, `location`, `class`
-- Aggiunto collegamento degli allegati al creatore -- Aggiunto collegamento degli allegati al creatore
ALTER TABLE `zz_files` ADD `created_by` INT(11) AFTER `id_record`, ADD FOREIGN KEY (`created_by`) REFERENCES `zz_users`(`id`) ON DELETE SET NULL; ALTER TABLE `zz_files` ADD `created_by` INT(11) AFTER `id_record`, ADD FOREIGN KEY (`created_by`) REFERENCES `zz_users`(`id`) ON DELETE SET NULL;
-- Aggiunto riferimento allo Scadenzario nella Prima Nota
ALTER TABLE `co_movimenti` ADD `id_scadenza` INT(11) AFTER `iddocumento`, ADD FOREIGN KEY (`id_scadenza`) REFERENCES `co_scadenziario`(`id`) ON DELETE CASCADE, ADD `is_insoluto` BOOLEAN NOT NULL DEFAULT FALSE AFTER `id_scadenza`;