Aggiornamento Pianificazione fatturazione di Contratti

This commit is contained in:
Thomas Zilio 2020-02-17 18:43:49 +01:00
parent d1d0625c0e
commit 9fb0d120c3
20 changed files with 527 additions and 533 deletions

View File

@ -36,5 +36,6 @@ return [
'plugins/receiptFE' => 'Plugins\ReceiptFE',
'plugins/dichiarazioni_intento' => 'Plugins\DichiarazioniIntento',
'plugins/pianificazione_interventi' => 'Plugins\PianificazioneInterventi',
'plugins/pianificazione_fatturazione' => 'Plugins\PianificazioneFatturazione',
'plugins/statistiche_articoli' => 'Plugins\StatisticheArticoli',
];

View File

@ -113,6 +113,22 @@ abstract class Description extends Model
return $result;
}
public function toArray()
{
$array = parent::toArray();
$result = array_merge($array, [
'spesa' => $this->spesa,
'imponibile' => $this->imponibile,
'sconto' => $this->sconto,
'totale_imponibile' => $this->totale_imponibile,
'iva' => $this->iva,
'totale' => $this->totale,
]);
return $result;
}
/**
* Imposta il proprietario dell'oggetto e l'ordine relativo all'interno delle righe.
*/

View File

@ -105,7 +105,7 @@ abstract class Row extends Description
public function getIvaAttribute()
{
return ($this->totale_imponibile) * $this->aliquota->percentuale / 100;
return $this->iva_unitaria * $this->qta;
}
public function getIvaDetraibileAttribute()

View File

@ -114,8 +114,8 @@ echo '
</div>
</div>';
echo
'<div class="row">
echo '
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary"><i class="fa fa-plus"></i> '.tr('Aggiungi').'</button>
</div>

View File

@ -8,29 +8,3 @@ if (get('op') == 'get_costo_orario') {
$rs = $dbo->fetchArray('SELECT costo_orario FROM in_tipiintervento WHERE idtipointervento='.prepare($idtipointervento));
echo $rs[0]['costo_orario'];
}
// Copia ordine di servizio da un impianto ad un altro
elseif (get('op') == 'get_pianificazione_os') {
$idcontratto = get('idcontratto');
$matricola_src = get('matricola_src');
$ordiniservizio = [];
if (!empty($matricola_src)) {
// Leggo tutti gli ordini di servizio creati per matricola_src
$rs = $dbo->fetchArray('SELECT * FROM co_ordiniservizio WHERE idcontratto='.prepare($idcontratto).' AND idimpianto='.prepare($matricola_src));
for ($i = 0; $i < sizeof($rs); ++$i) {
// Leggo tutte le voci di servizio
$rs2 = $dbo->fetchArray('SELECT (SELECT id FROM in_vociservizio WHERE descrizione=voce) AS idvoce FROM co_ordiniservizio_vociservizio WHERE idordineservizio='.prepare($rs[$i]['id']));
for ($v = 0; $v < sizeof($rs2); ++$v) {
$ordiniservizio[] = date('Ym', strtotime($rs[$i]['data_scadenza'])).':'.$rs2[$v]['idvoce'];
}
}
// Ritorno l'array con le combinazioni di voce e mese pianificato
echo implode(',', $ordiniservizio);
exit();
}
}

View File

@ -8,8 +8,7 @@ unset($_SESSION['superselect']['idsede_destinazione']);
unset($_SESSION['superselect']['idanagrafica']);
$_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
?><script src="<?php echo $rootdir; ?>/modules/contratti/js/contratti_helper.js"></script>
?>
<form action="" method="post" id="edit-form">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update">

View File

@ -1,44 +0,0 @@
/*
Legge la matricola data e ricrea le spunte e selezioni della matricola data nella nuova pianificazione,
in modo da poter creare un'altra pianificazione simile (o modificando quella appena copiata)
*/
function copia_pianificazione_os(idcontratto, matricola_src) {
$.get(globals.rootdir + '/modules/contratti/ajax.php?op=get_pianificazione_os&idcontratto=' + idcontratto + '&matricola_src=' + matricola_src, function (data, response) {
if (response == 'success') {
//Nascondo tutte le voci pianificate
$('div[id*=voce_]').addClass('hide');
//Tolgo tutte le spunte
$('div[id*=voce_] input[id*=m_]').removeAttr('checked');
//Deseleziono tutte le voci della lista <select> multipla
$('select[name*=voce] option').removeAttr('selected');
/*
La risposta sarà strutturata così:
201301:1,201301:2,201301:3,201302:1,201302:3
e cioè:
Ym `data_scadenza` : idvoce
*/
os = data.split(',');
for (i = 0; i < os.length; i++) {
v = os[i].split(':');
mese = v[0];
idvoce = v[1];
//Seleziono la voce del select multiplo
$('select[name*=voce] option[value=' + idvoce + ']').attr('selected', 'true');
//Mostro il riquadro della voce con i mesi
$('#voce_' + idvoce).removeClass('hide');
//Spunto la coppia mese-anno
$('#m_' + mese + '_' + idvoce).removeAttr('checked').click();
}
}
});
}

View File

@ -1,60 +0,0 @@
<?php
include_once __DIR__.'/../../../core.php';
$idcontratto = get('idcontratto');
$idpianificazione = get('idpianificazione');
$importo = get('importo');
$n_rata = get('n_rata');
// Lettura numero contratto e nome zona
$rs = $dbo->fetchArray('SELECT numero, (SELECT descrizione FROM an_zone WHERE id=(SELECT idzona FROM co_ordiniservizio_pianificazionefatture WHERE id='.prepare($idpianificazione).')) AS zona FROM co_contratti WHERE id='.prepare($idcontratto));
$numero = $rs[0]['numero'];
$zona = $rs[0]['zona'];
echo '
<form id="add_form" action="'.$rootdir.'/editor.php?id_module='.Modules::get('Contratti')['id'].'&id_record='.$idcontratto.'&op=addfattura&idpianificazione='.$idpianificazione.'&importo='.$importo.'" method="post">
<input type="hidden" name="backto" value="record-edit">';
// Data
echo '
<div class="row">
<div class="col-md-4">
{[ "type": "date", "label": "'.tr('Data').'", "name": "data", "required": 1, "class": "text-center", "value": "-now-" ]}
</div>';
// Tipo di documento
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Tipo di fattura').'", "name": "idtipodocumento", "required": 1, "values": "query=SELECT * FROM co_tipidocumento WHERE dir=\'entrata\'" ]}
</div>';
// Sezionale
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.Modules::get('Fatture di vendita')['id'].' ORDER BY name", "value":"'.$_SESSION['module_'.Modules::get('Fatture di vendita')['id']]['id_segment'].'" ]}
</div>
</div>';
// Note
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "'.tr('Descrizione').'", "name": "note", "value": "Rata '.$n_rata.' del contratto numero '.$numero.', zona '.$zona.'" ]}
</div>
</div>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary pull-right">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>
</div>
</div>
</form>';
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';

View File

@ -1,378 +0,0 @@
<?php
include_once __DIR__.'/../../../core.php';
/* GESTIONE ORDINI DI SERVIZI */
// TODO: aggiornare con la funzione months()
$mesi = [
tr('Gennaio'),
tr('Febbraio'),
tr('Marzo'),
tr('Aprile'),
tr('Maggio'),
tr('Giugno'),
tr('Luglio'),
tr('Agosto'),
tr('Settembre'),
tr('Ottobre'),
tr('Novembre'),
tr('Dicembre'),
];
// Pianificazione fatture
if (get('op') == 'add_fatturazione') {
$prev_data = '';
// Azzero la pianificazione zone se era già stata fatta, per poter sostituire la pianificazione,
// mantenendo però le pianificazioni già fatturate
foreach (post('zona') as $data_scadenza => $zone) {
foreach ($zone as $n => $idzona) {
$dbo->query('DELETE FROM co_ordiniservizio_pianificazionefatture WHERE idzona='.prepare($idzona).' AND iddocumento=0 AND idcontratto='.prepare($id_record));
}
}
// Ciclo fra le voci in arrivo dal form
foreach (post('zona') as $data_scadenza => $zone) {
// Ogni data può avere più zone da pianificare
foreach ($zone as $n => $idzona) {
// Aggiunta pianificazione solo se la zona è spuntata
if (in_array($idzona, post('idzona'))) {
// Creazione pianificazione
$dbo->query('INSERT INTO co_ordiniservizio_pianificazionefatture(idcontratto, data_scadenza, idzona, iddocumento) VALUES('.prepare($id_record).', '.prepare($data_scadenza).', '.prepare($idzona).', 0)');
}
$prev_data = $data_scadenza;
}
}
flash()->info(tr('Pianificazione generata correttamente!'));
}
// Eliminazione pianificazione specifica
elseif (get('op') == 'del_pianificazione') {
$idpianificazione = get('idpianificazione');
$n = $dbo->fetchNum('SELECT id FROM co_ordiniservizio_pianificazionefatture WHERE id='.prepare($idpianificazione));
if ($n == 1) {
// Eliminazione ordine di servizio
if ($dbo->query('DELETE FROM co_ordiniservizio_pianificazionefatture WHERE id='.prepare($idpianificazione))) {
flash()->info(tr('Pianificazione eliminata correttamente!'));
}
}
}
// Creazione fattura pianificata
elseif (get('op') == 'addfattura') {
$idpianificazione = get('idpianificazione');
$descrizione = post('note');
$data = post('data');
$idtipodocumento = post('idtipodocumento');
$note = post('note');
// Lettura idanagrafica
$rs = $dbo->fetchArray('SELECT idanagrafica FROM co_contratti WHERE id='.prepare($id_record));
$idanagrafica = $rs[0]['idanagrafica'];
$dir = 'entrata';
$idconto = setting('Conto predefinito fatture di vendita');
$numero = get_new_numerofattura($data);
$id_segment = post('id_segment');
$numero_esterno = get_new_numerosecondariofattura($data);
// Tipo di pagamento + banca predefinite dall'anagrafica
$query = 'SELECT id, (SELECT idbanca_vendite FROM an_anagrafiche WHERE idanagrafica = '.prepare($idanagrafica).') AS idbanca FROM co_pagamenti WHERE id = (SELECT idpagamento_vendite AS pagamento FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica).')';
$rs = $dbo->fetchArray($query);
$idpagamento = $rs[0]['id'];
$idbanca = $rs[0]['idbanca'];
// Se la fattura è di vendita e non è stato associato un pagamento predefinito al cliente leggo il pagamento dalle impostazioni
if ($dir == 'entrata' && $idpagamento == '') {
$idpagamento = setting('Tipo di pagamento predefinito');
}
// Se non è impostata la banca dell'anagrafica, uso quella del pagamento.
if (empty($idbanca)) {
// Banca predefinita del pagamento
$query = 'SELECT id FROM co_banche WHERE id_pianodeiconti3 = (SELECT idconto_vendite FROM co_pagamenti WHERE id = '.prepare($idpagamento).')';
$rs = $dbo->fetchArray($query);
$idbanca = $rs[0]['id'];
}
$query = 'INSERT INTO co_documenti(numero, numero_esterno, idanagrafica, idtipodocumento, idpagamento, data, idstatodocumento, note, idsede_destinazione, id_segment, idconto, idbanca) VALUES ('.prepare($numero).', '.prepare($numero_esterno).', '.prepare($idanagrafica).', '.prepare($idtipodocumento).', '.prepare($idpagamento).', '.prepare($data).", (SELECT `id` FROM `co_statidocumento` WHERE `descrizione`='Bozza'), ".prepare($note).', (SELECT idsede_fatturazione FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica).'), '.prepare($id_segment).', '.prepare($idconto).', '.prepare($idbanca).' )';
$dbo->query($query);
$iddocumento = $dbo->lastInsertedID();
// Imposto l'iddocumento anche sulla pianificazione, giusto per tener traccia della fattura generata
$dbo->query('UPDATE co_ordiniservizio_pianificazionefatture SET iddocumento='.prepare($iddocumento).' WHERE id='.prepare($idpianificazione));
// Leggo quante rate si vogliono pagare per dividerle per mese
$rs = $dbo->fetchArray('SELECT id FROM co_ordiniservizio_pianificazionefatture WHERE idcontratto='.prepare($id_record));
// L'importo deve essere diviso per il numero di mesi
$rs2 = $dbo->fetchArray('SELECT SUM(subtotale) AS totale FROM co_righe_contratti WHERE idcontratto='.prepare($id_record));
$importo = $rs2[0]['totale'] / sizeof($rs);
// Lettura iva del cliente o predefinita
$rs2 = $dbo->fetchArray('SELECT idiva_vendite AS idiva FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica));
$idiva = $rs2[0]['idiva'];
if ($idiva != 0) {
$rs2 = $dbo->fetchArray('SELECT * FROM co_iva WHERE id='.prepare($idiva));
} else {
$rs2 = $dbo->fetchArray('SELECT * FROM co_iva WHERE id='.prepare(setting('Iva predefinita')));
}
$desc_iva = $rs2[0]['descrizione'];
$iva = $importo / 100 * $rs2[0]['percentuale'];
$iva_indetraibile = $importo / 100 * $rs2[0]['indetraibile'];
// Inserimento riga in fattura
$dbo->query('INSERT INTO co_righe_documenti(iddocumento, idcontratto, descrizione, desc_iva, iva, iva_indetraibile, subtotale, um, qta, `order`) VALUES('.prepare($iddocumento).', '.prepare($id_record).', '.prepare($descrizione).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($importo).", '-', 1, (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento=".prepare($iddocumento).'))');
redirect($rootdir.'/editor.php?id_module='.Modules::get('Fatture di vendita')['id'].'&id_record='.$iddocumento.'&dir=entrata');
exit();
}
echo '
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Pianificazione fatturazione').'</h3>
</div>
<div class="box-body">';
echo '
<p>'.tr('Qui puoi programmare la fatturazione del contratto').'.</p>';
/*
Fatture pianificate
*/
$rs = $dbo->fetchArray('SELECT *, (SELECT SUM(subtotale) FROM co_righe_contratti WHERE idcontratto='.prepare($id_record).') AS budget_contratto, (SELECT descrizione FROM an_zone WHERE id=idzona) AS zona FROM co_ordiniservizio_pianificazionefatture WHERE idcontratto='.prepare($id_record).' ORDER BY data_scadenza ASC');
if (empty($rs)) {
echo '
<p>'.tr('Non sono ancora state pianificate fatture').'...</p>';
} else {
$rs2 = $dbo->fetchArray('SELECT * FROM co_ordiniservizio_pianificazionefatture WHERE idcontratto='.prepare($id_record).' ORDER BY idzona');
for ($i = 0; $i < sizeof($rs2); ++$i) {
// Leggo quante rate sono pianificate per dividere l'importo delle sedi in modo corretto
++$n_rate[$rs2[$i]['idzona']];
// Leggo il totale già fatturato per questa zona per toglierlo dalla divisione (totale/n_rate)
$rs3 = $dbo->fetchArray('SELECT SUM(subtotale-sconto) AS totale FROM co_righe_documenti WHERE iddocumento IN (SELECT iddocumento FROM co_ordiniservizio_pianificazionefatture WHERE iddocumento='.prepare($rs2[$i]['iddocumento']).')');
$gia_fatturato[$rs2[$i]['idzona']] += $rs3[0]['totale'];
}
echo '
<table class="table table-bordered table-striped table-hover table-condensed">
<tr>
<th width="10%">'.tr('Scadenza').'</th>
<th width="15%">'.tr('Zona').'</th>
<th width="15%">'.tr('Importo').'</th>
<th>'.tr('Documento').'</th>
<th width="20%">'.tr('Stato').'</th>
<th width="12%"></th>
</tr>';
$prev_mese = '';
$n_rata = 0;
for ($i = 0; $i < sizeof($rs); ++$i) {
// Lettura numero di sedi in cui si sono pianificati ordini di servizio per la zona corrente
if (!empty($rs[$i]['idzona'])) {
$n_sedi_pianificate = $dbo->fetchNum('SELECT DISTINCT(idsede) FROM my_impianti WHERE id IN (SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto='.prepare($id_record).') AND idsede IN(SELECT id FROM an_sedi WHERE idzona='.prepare($rs[$i]['idzona']).')');
// Verifico se ci sono impianti in questa zona legati alla sede legale
$n_sedi_pianificate += $dbo->fetchNum('SELECT DISTINCT(idsede) FROM my_impianti WHERE id IN (SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto='.prepare($id_record).') AND idsede=(SELECT idsede FROM an_anagrafiche WHERE idanagrafica=(SELECT idanagrafica FROM co_contratti WHERE id='.prepare($id_record).') AND idzona='.prepare($rs[$i]['idzona']).') AND idsede=0');
}
// Fix nel caso non siano previste sedi pianificate (l'eventuale 0 portava a problemi nel calcolo dell'importo)
$n_sedi_pianificate = ($n_sedi_pianificate < 1) ? 1 : $n_sedi_pianificate;
// else{
// $n_sedi_pianificate = $dbo->fetchNum("SELECT (idsede) FROM my_impianti WHERE id IN (SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto=\"".$id_record."\") AND idsede=0");
// }
echo '
<tr>
<td>';
// Data scadenza
if ($prev_mese != $rs[$i]['data_scadenza']) {
++$n_rata;
echo '
<b>'.$mesi[intval(date('m', strtotime($rs[$i]['data_scadenza']))) - 1].' '.date('Y', strtotime($rs[$i]['data_scadenza'])).'</b></td>';
}
echo '
</td>';
// Sede
if ($rs[$i]['zona'] == '') {
$zona = 'Altro';
} else {
$zona = $rs[$i]['zona'];
}
if ($n_sedi_pianificate == 1) {
$n_sedi = tr('1 sede');
} else {
$n_sedi = tr('_NUM_ sedi', [
'_NUM_' => $n_sedi_pianificate,
]);
}
echo '
<td>'.$zona.' ('.$n_sedi.')</td>';
/*
Importo
*/
// Se è stata emessa una fattura, bisogna utilizzare il totale della fattura da scalare al totale pianificato
if ($rs[$i]['iddocumento'] != 0) {
$rs2 = $dbo->fetchArray('SELECT SUM(subtotale-sconto) AS totale FROM co_righe_documenti WHERE iddocumento='.prepare($rs[$i]['iddocumento']));
$importo = $rs2[0]['totale'];
} else {
// $importo = ($rs[$i]['budget_contratto'] * $n_sedi_pianificate / $n_rate[ $rs[$i]['idzona'] ]) - ($gia_fatturato[ $rs[$i]['idzona'] ] * $n_sedi_pianificate / sizeof($gia_fatturato[ $rs[$i]['idzona'] ]) );
$importo = ($rs[$i]['budget_contratto'] * $n_sedi_pianificate / $n_rate[$rs[$i]['idzona']]);
}
echo '
<td class="center">
'.moneyFormat($importo).'<br>
<small>'.moneyFormat($rs[$i]['budget_contratto']).' x '.$n_sedi_pianificate.' sedi / '.$n_rate[$rs[$i]['idzona']].' rate'.$extra.'</small>
</td>';
// Documento collegato (fattura)
if ($rs[$i]['iddocumento'] != 0) {
$rsf = $dbo->fetchArray('SELECT numero, numero_esterno, data, (SELECT SUM(subtotale) FROM co_righe_documenti WHERE iddocumento=co_documenti.id) AS imponibile, (SELECT icona FROM co_statidocumento WHERE id=co_documenti.idstatodocumento) AS icona, (SELECT descrizione FROM co_statidocumento WHERE id=co_documenti.idstatodocumento) AS stato FROM co_documenti WHERE id='.prepare($rs[$i]['iddocumento']));
if ($rsf[0]['numero_esterno'] != '') {
$numero_doc = $rsf[0]['numero_esterno'];
} else {
$numero_doc = $rsf[0]['numero'];
}
$documento = Modules::link('Fatture di vendita', $rs[$i]['iddocumento'], tr('Fattura num. _NUM_ del _DATE_', [
'_NUM_' => $numero_doc,
'_DATE_' => Translator::dateToLocale($rsf[0]['data']),
]));
$stato = '<i class="'.$rsf[0]['icona'].'"></i> '.$rsf[0]['stato'];
} else {
$documento = '';
$stato = '<i class="fa fa-clock-o"></i> '.tr('Non ancora fatturato');
}
// Link a fattura
echo '
<td>'.$documento.'</td>';
// Stato
echo '
<td>'.$stato.'</td>';
// Funzioni
echo '
<td>';
if ($rs[$i]['iddocumento'] == 0) {
// Creazione fattura
echo "
<button type='button' class='btn btn-primary btn-sm' onclick=\"launch_modal( 'Crea fattura', '".$rootdir.'/modules/contratti/plugins/addfattura.php?idcontratto='.$id_record.'&idpianificazione='.$rs[$i]['id'].'&importo='.$importo.'&n_rata='.$n_rata."', 1 );\">
<i class='fa fa-euro'></i> ".tr('Crea fattura').'
</button>';
// Eliminazione pianificazione
echo '
<a class="btn btn-danger ask" data-backto="record-edit" data-method="get" data-op="del_pianificazione" data-idpianificazione="'.$rs[$i]['id'].'" data-msg="'.tr('Vuoi eliminare questa pianificazione?').'">
<i class="fa fa-trash"></i>
</a>';
}
echo '
</td>
</tr>';
$prev_mese = $rs[$i]['data_scadenza'];
}
echo '
</table>';
}
echo '
<br><br>';
/*
Schema per pianificare la fatturazione per zona
*/
$rs = $dbo->fetchArray('SELECT id, descrizione FROM an_zone WHERE ( id IN (SELECT idzona FROM an_sedi WHERE id IN (SELECT idsede FROM my_impianti WHERE id IN (SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto='.prepare($id_record).'))) ) OR ( id=(SELECT idzona FROM an_anagrafiche WHERE idanagrafica=(SELECT idanagrafica FROM co_contratti WHERE id='.prepare($id_record).") AND idzona=an_zone.id) ) UNION SELECT 0, 'Altro'");
if (sizeof($rs) == 0) {
echo '
<p>'.tr('Non sono ancora stati pianificati ordini di servizio').'...</p>';
}
// Elenco voci di servizio con mesi in cui eseguirle
else {
// Calcolo mese iniziale e finale del contratto
$rs2 = $dbo->fetchArray('SELECT data_accettazione, data_conclusione, TIMESTAMPDIFF( MONTH, data_accettazione, data_conclusione ) AS mesi FROM co_contratti WHERE id='.prepare($id_record));
$n_mesi = $rs2[0]['mesi'] + 1;
$mese_start = date('m', strtotime($rs2[0]['data_accettazione']));
echo "
<button type='button' class='btn btn-primary' onclick=\"$(this).next().next().removeClass('hide'); $(this).remove();\">
<i class='fa fa-calendar'></i> ".tr('Pianifica la fatturazione').'
</button>
<br>';
echo "
<form action='".$rootdir.'/editor.php?id_module='.Modules::get('Contratti')['id'].'&id_record='.$id_record."&op=add_fatturazione' id='pianifica_form' method='post' class='hide'>
<input type='hidden' name='backto' value='record-edit'>";
// Indice zone fatturabili
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Zone per le quali pianificare la fatturazione').'", "name": "idzona[]", "class": "unblockable", "values": "query=SELECT id, descrizione FROM an_zone WHERE (id IN (SELECT idzona FROM an_sedi WHERE id IN (SELECT idsede FROM my_impianti WHERE id IN (SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto='.prepare($id_record).')))) OR ( id=(SELECT idzona FROM an_anagrafiche WHERE idanagrafica=(SELECT idanagrafica FROM co_contratti WHERE id='.prepare($id_record).') AND idzona=an_zone.id) ) UNION SELECT 0, \'Altro\'", "multiple": 1, "extra": "onchange=\"$(this).find(\'option\').each( function(){ if( $(this).is(\':selected\') ){ $(\'#zona_\'+$(this).val()).removeClass(\'hide\'); }else{ $(\'#zona_\'+$(this).val()).addClass(\'hide\'); } });\"" ]}
</div>
</div>';
// Zone
for ($i = 0; $i < sizeof($rs); ++$i) {
echo '
<div class="hide" id="zona_'.$rs[$i]['id'].'">
<big><b>'.$rs[$i]['descrizione'].'</b></big>
<hr>
<div class="row">';
for ($j = 0; $j < $n_mesi; ++$j) {
echo '
<div class="col-md-3">
<small><label for="m_'.date('Ym', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month')).'_'.$rs[$i]['id'].'">
<input type="checkbox" class="unblockable" id="m_'.date('Ym', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month')).'_'.$rs[$i]['id'].'" name="zona['.date('Y-m-t', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month')).'][]" value="'.$rs[$i]['id'].'" />'.$mesi[intval(date('m', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month'))) - 1].' '.date('Y', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month')).'
</label></small>
</div>';
}
echo '
</div>
</div>';
}
echo "
<div class='clearfix'></div>
<br>";
$disabled_pianificazione = $record['is_fatturabile'] && !empty($rs_documento) && !empty($record['data_conclusione']) && !empty($record['data_accettazione']);
// Pianificazione
echo "
<button type='button ".($disabled_pianificazione ? '' : 'disabled')."' title='".($disabled_pianificazione ? '' : tr('Per pianificare la fatturazione del contratto deve inserita almeno una riga, data accettazione e conclusione devono essere definite e lo stato del contratto deve essere tra: ').$stati_fatturabili)."' class='btn btn-primary ".($disabled_pianificazione ? '' : 'disabled tip')."' data-href=\"if( $('input[type=checkbox]:checked').length>0 ){ if( confirm('Pianificare la fatturazione?') ){ $('#pianifica_form').submit(); } }\">
<i class='fa fa-plus'></i> ".tr('Pianifica ora').'
</button>';
echo '
</form>';
}
echo '
</div>
</div>';

View File

@ -8,6 +8,7 @@ use Common\Document;
use Modules\Anagrafiche\Anagrafica;
use Modules\Interventi\Intervento;
use Modules\TipiIntervento\Tipo as TipoSessione;
use Plugins\PianificazioneFatturazione\Pianificazione;
use Plugins\PianificazioneInterventi\Promemoria;
use Traits\RecordTrait;
use Util\Generator;
@ -149,6 +150,11 @@ class Contratto extends Document
return $this->hasMany(Promemoria::class, 'idcontratto');
}
public function pianificazioni()
{
return $this->hasMany(Pianificazione::class, 'idcontratto');
}
public function fixBudget()
{
$this->budget = $this->totale_imponibile ?: 0;

View File

@ -21,18 +21,18 @@ $mesi = [
// Righe inserite
//idcontratto IN( SELECT id FROM co_contratti WHERE idstato IN(SELECT id FROM co_staticontratti WHERE is_pianificabile = 1) ) AND
$qp = "SELECT *,
(SELECT SUM(subtotale) FROM co_righe_contratti WHERE idcontratto=co_ordiniservizio_pianificazionefatture.idcontratto) AS budget_contratto,
(SELECT SUM(subtotale) FROM co_righe_contratti WHERE idcontratto=co_fatturazione_contratti.idcontratto) AS budget_contratto,
DATE_FORMAT(data_scadenza, '%m-%Y') AS mese,
(SELECT idanagrafica FROM co_contratti WHERE id=idcontratto) AS idcliente,
(SELECT nome FROM co_contratti WHERE id=idcontratto) AS nome,
(SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica=(SELECT idanagrafica FROM co_contratti WHERE id=idcontratto)) AS ragione_sociale,
(SELECT descrizione FROM an_zone WHERE id=co_ordiniservizio_pianificazionefatture.idzona) AS zona
FROM co_ordiniservizio_pianificazionefatture WHERE co_ordiniservizio_pianificazionefatture.iddocumento=0 ORDER BY data_scadenza ASC, idcliente ASC";
(SELECT descrizione FROM an_zone WHERE id=co_fatturazione_contratti.idzona) AS zona
FROM co_fatturazione_contratti WHERE co_fatturazione_contratti.iddocumento=0 ORDER BY data_scadenza ASC, idcliente ASC";
$rsp = $dbo->fetchArray($qp);
if (!empty($rsp)) {
// Lettura numero di rate e totale già fatturato
$rs2 = $dbo->fetchArray('SELECT * FROM co_ordiniservizio_pianificazionefatture');
$rs2 = $dbo->fetchArray('SELECT * FROM co_fatturazione_contratti');
for ($j = 0; $j < sizeof($rs2); ++$j) {
// Leggo quante rate sono pianificate per dividere l'importo delle sedi in modo corretto

View File

@ -194,7 +194,7 @@ switch (post('op')) {
$dbo->query('DELETE FROM co_movimenti WHERE iddocumento='.prepare($id_record));
// Azzeramento collegamento della rata contrattuale alla pianificazione
$dbo->query('UPDATE co_ordiniservizio_pianificazionefatture SET iddocumento=0 WHERE iddocumento='.prepare($id_record));
$dbo->query('UPDATE co_fatturazione_contratti SET iddocumento=0 WHERE iddocumento='.prepare($id_record));
flash()->info(tr('Fattura eliminata!'));
} catch (InvalidArgumentException $e) {

View File

@ -0,0 +1,96 @@
<?php
use Modules\Contratti\Contratto;
use Modules\Contratti\Components\Riga;
use Plugins\PianificazioneFatturazione\Pianificazione;
use Modules\Fatture\Fattura;
use Modules\Fatture\Tipo;
include_once __DIR__.'/../../core.php';
$operazione = filter('op');
// Pianificazione fatturazione
switch ($operazione) {
case 'add':
$contratto = Contratto::find($id_record);
$selezioni = collect(post('selezione_periodo'));
$periodi = post('periodo');
$numero_fatture = 0;
foreach ($selezioni as $key => $selezione) {
$data_scadenza = $periodi[$key];
++$numero_fatture;
// Creazione pianificazione
Pianificazione::build($contratto, $data_scadenza);
}
if ($numero_fatture > 0) {
// Rimozione righe precedenti del contratto
$righe_contratto = $contratto->getRighe();
$iva_righe = collect($righe_contratto->toArray())->groupBy('idiva');
foreach ($righe_contratto as $riga) {
$riga->delete();
}
// Creazione nuove righe
$descrizioni = post('descrizione');
$qta = post('qta');
foreach ($iva_righe as $id_iva => $righe) {
$iva = $righe->first()->aliquota;
$righe = $righe->toArray();
$totale = sum(array_column($righe, setting('Utilizza prezzi di vendita con IVA incorporata') ? 'totale' : 'totale_imponibile'));
$qta_riga = $qta[$id_iva];
$descrizione_riga = $descrizioni[$id_iva];
$prezzo_unitario = $totale / $qta_riga / $numero_fatture;
for($rata = 1; $rata <= $numero_fatture; $rata++) {
$riga = Riga::build($contratto);
$riga->descrizione = $descrizione_riga;
$riga->id_iva = $id_iva;
$riga->prezzo_unitario = $prezzo_unitario;
$riga->qta = $qta_riga;
$riga->save();
}
}
}
break;
case 'add_fattura':
$contratto = Contratto::find($id_record);
$rata = post('rata');
$pianificazione = $contratto->pianificazioni[$rata];
$data = post('data');
$id_segment = post('id_segment');
$tipo = Tipo::find(post('idtipodocumento'));
// Creazione fattura
$fattura = Fattura::build($contratto->anagrafica, $tipo, $data, $id_segment);
// Copia righe
$righe = $pianificazione->getRighe();
foreach ($righe as $riga) {
$copia = $riga->copiaIn($fattura, $riga->qta);
// Aggiornamento movimentazioni
if ($copia->isArticolo()) {
$copia->movimenta($copia->qta);
}
}
// Salvataggio fattura nella pianificazione
$pianificazione->fattura()->associate($fattura);
$pianificazione->save();
break;
}

View File

@ -0,0 +1,94 @@
<?php
use Modules\Contratti\Contratto;
include_once __DIR__.'/../../core.php';
$contratto = Contratto::find($id_record);
echo '
<form action="" method="post">
<input type="hidden" name="op" value="add">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="id_module" value="'.$id_module.'">
<input type="hidden" name="id_plugin" value="'.$id_plugin.'">
<input type="hidden" name="id_record" value="'.$id_record.'">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs nav-justified">
<li class="active"><a href="#periodi" data-toggle="tab">'.tr('Periodi').'</a></li>
<li><a href="#righe" data-toggle="tab">'.tr('Righe').'</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="periodi">
<div class="row">';
$data_corrente = $contratto->data_accettazione->startOfMonth();
$data_conclusione = $contratto->data_conclusione;
$count = 0;
while ($data_corrente->lessThanOrEqualTo($data_conclusione)) {
$data = $data_corrente->endOfMonth()->format('Y-m-d');
echo '
<div class="col-md-3">
<label for="m_'.$count.'">
<input type="checkbox" class="unblockable" id="m_'.$count.'" name="selezione_periodo['.$count.']" />
'.$data_corrente->formatLocalized('%B %Y').'
</label>
<input type="hidden" name="periodo['.$count.']" value="'.$data.'">
</div>';
$data_corrente = $data_corrente->addMonth();
++$count;
}
echo '
</div>
</div>
<div class="tab-pane" id="righe">';
$iva_righe = $contratto->getRighe()->groupBy('idiva');
foreach ($iva_righe as $id_iva => $righe) {
$iva = $righe->first()->aliquota;
$righe = $righe->toArray();
echo '
<h5>'.tr('Informazioni generali sulle righe con IVA: _IVA_', [
'_IVA_' => $iva->descrizione,
]).'</h5>
<div class="row">
<div class="col-md-9">
{[ "type": "textarea", "label": "'.tr('Descrizione').'", "name": "descrizione['.$id_iva.']", "value": "'.tr('Rata dal contratto numero _NUM_: _IVA_', [
'_IVA_' => $iva->descrizione,
'_NUM_' => $contratto->numero,
]).'" ]}
{[ "type": "number", "label": "'.tr('Q.tà').'", "name": "qta['.$id_iva.']", "required": 1, "value": "1", "decimals": "qta", "min-value": "1" ]}
</div>
<div class="col-md-3">
<p><b>'.tr('Imponibile').'</b>: '.moneyFormat(sum(array_column($righe, 'imponibile'))).'</p>
<p><b>'.tr('IVA').'</b>: '.moneyFormat(sum(array_column($righe, 'iva'))).'</p>
<p><b>'.tr('Totale imponibile').'</b>: '.moneyFormat(sum(array_column($righe, 'totale'))).'</p>
</div>
</div>
<hr>';
}
echo '
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary"><i class="fa fa-chevron-right"></i> '.tr('Procedi').'</button>
</div>
</div>
</form>';
echo '
<script>$(document).ready(init)</script>';

View File

@ -0,0 +1,68 @@
<?php
use Modules\Contratti\Contratto;
include_once __DIR__.'/../../core.php';
$contratto = Contratto::find($id_record);
$rata = get('rata');
$pianificazione = $contratto->pianificazioni[$rata];
$module_fattura = Modules::get('Fatture di vendita');
echo '
<form action="" method="post">
<input type="hidden" name="op" value="add_fattura">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="rata" value="'.$rata.'">
<input type="hidden" name="id_module" value="'.$id_module.'">
<input type="hidden" name="id_plugin" value="'.$id_plugin.'">
<input type="hidden" name="id_record" value="'.$id_record.'">';
// Data
echo '
<div class="row">
<div class="col-md-4">
{[ "type": "date", "label": "'.tr('Data').'", "name": "data", "required": 1, "class": "text-center", "value": "-now-" ]}
</div>';
// Tipo di documento
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Tipo di fattura').'", "name": "idtipodocumento", "required": 1, "values": "query=SELECT * FROM co_tipidocumento WHERE dir=\'entrata\'" ]}
</div>';
// Sezionale
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.$module_fattura['id'].' ORDER BY name", "value":"'.$_SESSION['module_'.$module_fattura['id']]['id_segment'].'" ]}
</div>
</div>';
// Descrizione fattura
$descrizione = tr('Rata _N_ del contratto numero _NUM_', [
'_N_' => ($rata + 1),
'_NUM_' => $contratto->numero,
]);
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "'.tr('Note della fattira').'", "name": "note", "value": "'.$descrizione.'" ]}
</div>
</div>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary pull-right">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>
</div>
</div>
</form>';
echo '
<script>$(document).ready(init)</script>';

View File

@ -0,0 +1,110 @@
<?php
include_once __DIR__.'/../../../core.php';
use Modules\Contratti\Contratto;
use Modules\Contratti\Stato;
$contratto = Contratto::find($id_record);
$is_pianificabile = $contratto->stato->is_pianificabile && !empty($contratto['data_accettazione']); // Contratto permette la pianificazione
$stati_pianificabili = Stato::where('is_pianificabile', 1)->get();
$elenco_stati = $stati_pianificabili->implode('descrizione', ', ');
echo '
<p>'.tr('Qui puoi pianificare la suddivisione del budget del contratto in rate uguali fatturabili in modo separato').'. '.tr('Questa procedura può essere effettuata solo una volta, e sovrascriverà in modo irreversibile tutte le righe del contratto').'.</p>
<p>'.tr('Per poter procedere, il contratto deve avere <b>data accettazione</b> e <b>data conclusione</b> definita ed essere in uno dei seguenti stati: _LINK_', [
'_LINK_' => '<b>'.$elenco_stati.'</b>',
]).'.</p>
<div class="alert alert-warning">
<i class="fa fa-warning"></i> '.tr("Tutte le righe del contratto vengono convertite in righe generiche, rendendo impossibile risalire ad eventuali articoli utilizzati all'interno del contratto e pertanto non movimentando il magazzino").'.
</div>';
$pianificazioni = $contratto->pianificazioni;
if (!$pianificazioni->isEmpty()) {
echo '
<hr>
<table class="table table-bordered table-striped table-hover table-condensed">
<thead>
<tr>
<th width="10%">'.tr('Scadenza').'</th>
<th width="15%">'.tr('Importo').'</th>
<th>'.tr('Documento').'</th>
<th width="12%">#</th>
</tr>
</thead>
<tbody>';
$previous = null;
foreach ($pianificazioni as $rata => $pianificazione){
echo '
<tr>
<td>';
// Data scadenza
if (!$pianificazione->data_scadenza->equalTo($previous)) {
$previous = $pianificazione->data_scadenza;
echo '
<b>'.$pianificazione->data_scadenza->formatLocalized('%B %Y').'</b>';
}
echo '
</td>
<td class="center">
'.moneyFormat($pianificazione->totale).'
</td>';
// Documento collegato
echo '
<td>';
$fattura = $pianificazione->fattura;
if (!empty($fattura)) {
echo '
'.Modules::link('Fatture di vendita', $fattura->id, tr('Fattura num. _NUM_ del _DATE_', [
'_NUM_' => $fattura->numero,
'_DATE_' => dateFormat($fattura->data),
])).' (<i class="'.$fattura->stato->icona.'"></i> '.$fattura->stato->descrizione.')';
} else {
echo '
<i class="fa fa-clock-o"></i> '.tr('Non ancora fatturato');
}
echo '
</td>';
// Creazione fattura
echo '
<td>
<button type="button" class="btn btn-primary btn-sm '.(!empty($fattura) ? 'disabled' : '').'" '.(!empty($fattura) ? 'disabled' : '').' onclick="crea_fattura('.$rata.')">
<i class="fa fa-euro"></i> '.tr('Crea fattura').'
</button>
</td>
</tr>';
}
echo '
</tbody>
</table>';
} else {
echo '
<div class="alert alert-info">
<i class="fa fa-warning"></i> '.tr('Pianificazione non ancora effettuata per il contratto corrente').'.
</div>
<button type="button" '.(!empty($is_pianificabile) ? '' : 'disabled').' title="'.tr('Aggiungi una nuova pianificazione').'" data-toggle="tooltip" class="btn btn-primary pull-right tip" id="pianifica">
<i class="fa fa-plus"></i> '.tr('Pianifica').'
</button>
<div class="clearfix"></div>';
}
echo '
<script type="text/javascript">
$("#pianifica").click(function() {
openModal("Nuova pianificazione", "'.$structure->fileurl('add_pianificazione.php').'?id_module='.$id_module.'&id_plugin='.$id_plugin.'&id_record='.$id_record.'");
});
function crea_fattura(rata){
openModal("Crea fattura", "'.$structure->fileurl('crea_fattura.php').'?id_module='.$id_module.'&id_plugin='.$id_plugin.'&id_record='.$id_record.'&rata=" + rata);
}
</script>';

View File

@ -0,0 +1,104 @@
<?php
namespace Plugins\PianificazioneFatturazione;
use Common\Document;
use Modules\Contratti\Contratto;
use Modules\Fatture\Fattura;
use Modules\Interventi\Intervento;
use Modules\TipiIntervento\Tipo as TipoSessione;
use Traits\RecordTrait;
class Pianificazione extends Document
{
protected $table = 'co_fatturazione_contratti';
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = [
'data_scadenza',
];
/**
* Crea un nuovo promemoria.
*
* @param string $data_richiesta
*
* @return self
*/
public static function build(Contratto $contratto, $data_scadenza)
{
$model = parent::build();
$model->contratto()->associate($contratto);
$model->data_scadenza = $data_scadenza;
// Salvataggio delle informazioni
$model->save();
return $model;
}
public function getPluginAttribute()
{
return 'Pianificazione fatturazione';
}
public function getDirezioneAttribute()
{
return 'entrata';
}
public function anagrafica()
{
return $this->contratto->anagrafica();
}
public function contratto()
{
return $this->belongsTo(Contratto::class, 'idcontratto');
}
public function fattura()
{
return $this->belongsTo(Fattura::class, 'iddocumento');
}
public function getRighe()
{
$righe = $this->contratto->getRighe();
$pianificazioni = $this->contratto->pianificazioni;
$numero_righe = $righe->count() / $pianificazioni->count();
$p = $this;
$index = $pianificazioni->search(function($item) use($p){
return $item->id == $p->id;
});
return $righe->splice($index*$numero_righe, $numero_righe);
}
public function articoli()
{
return $this->contratto->articoli();
}
public function righe()
{
return $this->contratto->righe();
}
public function sconti()
{
return $this->contratto->sconti();
}
public function descrizioni()
{
return $this->contratto->descrizioni();
}
}

View File

@ -128,7 +128,7 @@ switch ($operazione) {
]);
}
$count_promemoria++;
++$count_promemoria;
} else {
$promemoria_corrente = $promemoria_contratto[$data_promemoria]->first();
$date_con_promemoria[] = dateFormat($data_promemoria);
@ -152,7 +152,7 @@ switch ($operazione) {
// Copia delle informazioni del promemoria
$promemoria_corrente->pianifica($intervento);
$count_interventi++;
++$count_interventi;
} elseif (post('pianifica_intervento')) {
$date_con_intervento[] = dateFormat($data_promemoria);
}

View File

@ -14,10 +14,11 @@ $stati_pianificabili = Stato::where('is_pianificabile', 1)->get();
$elenco_stati = $stati_pianificabili->implode('descrizione', ', ');
echo '
<p>'.tr('Puoi <b>pianificare dei "promemoria" o direttamente gli interventi</b> da effettuare entro determinate scadenze').'. '.tr('Per poter pianificare i promemoria, il contratto deve avere <b>data accettazione</b> e <b>data conclusione</b> definita ed essere in uno dei seguenti stati: _LINK_', [
'_LINK_' => '<b>'.$elenco_stati.'</b>',
]).'
<p>'.tr('Puoi <b>pianificare dei "promemoria" o direttamente gli interventi</b> da effettuare entro determinate scadenze. Per poter pianificare i promemoria, il contratto deve avere <b>data accettazione</b> e <b>data conclusione</b> definita ed essere in uno dei seguenti stati: <b>'.$elenco_stati.'</b>').'.
<span class="tip" title="'.tr("I promemoria verranno visualizzati sulla 'Dashboard' e serviranno per semplificare la pianificazione del giorno dell'intervento, ad esempio nel caso di interventi con cadenza mensile").'">
<span class="tip" title="'.tr("I promemoria verranno visualizzati sulla 'Dashboard' e serviranno per semplificare la pianificazione del giorno dell'intervento, ad esempio nel caso di interventi con cadenza mensile").'">
<i class="fa fa-question-circle-o"></i>
</span></p>';

View File

@ -158,3 +158,10 @@ ALTER TABLE `in_righe_interventi` ADD `original_id` int(11), ADD `original_type`
-- Aggiunta supporto a prezzi ivati
INSERT INTO `zz_settings` (`id`, `nome`, `valore`, `tipo`, `editable`, `sezione`, `created_at`, `updated_at`, `order`, `help`) VALUES (NULL, 'Utilizza prezzi di vendita con IVA incorporata', '0', 'boolean', '1', 'Fatturazione', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, 'Abilita la gestione degli importi ivati per i documenti di vendita.');
-- Fix plugin "Pianificazione fatturazione"
UPDATE `zz_plugins` SET `options` = 'custom', `script` = '', `directory` = 'pianificazione_fatturazione' WHERE `name` = 'Pianificazione fatturazione';
DROP TABLE `co_ordiniservizio_vociservizio`;
ALTER TABLE `co_ordiniservizio_pianificazionefatture` RENAME TO `co_fatturazione_contratti`;
UPDATE `zz_widgets` SET `query` = 'SELECT COUNT(id) AS dato FROM co_fatturazione_contratti WHERE idcontratto IN( SELECT id FROM co_contratti WHERE idstato IN(SELECT id FROM co_staticontratti WHERE descrizione IN("Bozza", "Accettato", "In lavorazione", "In attesa di pagamento")) ) AND co_fatturazione_contratti.iddocumento=0' WHERE `name` = 'Rate contrattuali';