Merge branch '2.4.11'

This commit is contained in:
Thomas Zilio 2019-07-24 10:19:51 +02:00
commit 42813fe55a
246 changed files with 7534 additions and 8853 deletions

View File

@ -5,7 +5,7 @@ function serverError()
$error = error_get_last();
if ($error['type'] == E_ERROR) {
ob_end_clean();
echo API::error('serverError');
echo Response::error('serverError');
}
}
@ -22,61 +22,21 @@ session_write_close();
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS');
// Attenzione: al momento l'API permette la lettura di tutte le tabelle presenti nel database (non limitate a quelle del progetto)
use API\Response;
try {
// Controlli sulla chiave di accesso
$api = new API();
// Lettura delle informazioni
$request = API::getRequest();
// Gestione della richiesta
$method = $_SERVER['REQUEST_METHOD'];
switch ($method) {
// Richiesta PUT (modifica elementi)
case 'PUT':
$response = $api->update($request);
break;
// Richiesta POST (creazione elementi)
case 'POST':
$response = $api->create($request);
break;
// Richiesta GET (ottenimento elementi)
case 'GET':
// Risorsa specificata
if (count($request) > 1) {
$response = $api->retrieve($request);
}
// Risorsa non specificata (lista delle risorse disponibili)
else {
$response = API::response([
'resources' => array_keys(API::getResources()['retrieve']),
]);
}
break;
// Richiesta DELETE (eliminazione elementi)
case 'DELETE':
$response = $api->delete($request);
break;
}
} catch (InvalidArgumentException $e) {
$response = API::error('unauthorized');
$response = Response::manage();
} catch (Exception $e) {
// Log dell'errore
$logger = logger();
$logger->addRecord(\Monolog\Logger::ERROR, $e);
$response = API::error('serverError');
$response = Response::error('serverError');
}
// Richiesta OPTIONS (controllo da parte del dispositivo)
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
$response = API::error('ok');
$response = Response::error('ok');
}
json_decode($response);

View File

@ -17,6 +17,12 @@ return [
'modules/interventi' => 'Modules\Interventi',
'modules/pagamenti' => 'Modules\Pagamenti',
'modules/statistiche' => 'Modules\Statistiche',
'modules/utenti' => 'Modules\Utenti',
'modules/stato_servizi' => 'Modules\StatoServizi',
'modules/stati_intervento' => 'Modules\StatiIntervento',
'modules/stati_preventivo' => 'Modules\StatiPreventivo',
'modules/stati_contratto' => 'Modules\StatiContratto',
'modules/stato_servizi' => 'Modules\StatoServizi',
'modules/tipi_intervento' => 'Modules\TipiIntervento',
'plugins/exportFE' => 'Plugins\ExportFE',
'plugins/importFE' => 'Plugins\ImportFE',

View File

@ -28,6 +28,9 @@ $namespaces = require_once __DIR__.'/config/namespaces.php';
foreach ($namespaces as $path => $namespace) {
$loader->addPsr4($namespace.'\\', __DIR__.'/'.$path.'/custom/src');
$loader->addPsr4($namespace.'\\', __DIR__.'/'.$path.'/src');
$loader->addPsr4($namespace.'\\API\\', __DIR__.'/'.$path.'/custom/api');
$loader->addPsr4($namespace.'\\API\\', __DIR__.'/'.$path.'/api');
}
// Individuazione dei percorsi di base
@ -60,7 +63,7 @@ use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
$handlers = [];
if (!API::isAPIRequest()) {
if (!API\Response::isAPIRequest()) {
// File di log di base (logs/error.log, logs/setup.log)
$handlers[] = new StreamHandler($docroot.'/logs/error.log', Monolog\Logger::ERROR);
$handlers[] = new StreamHandler($docroot.'/logs/setup.log', Monolog\Logger::EMERGENCY);
@ -124,7 +127,7 @@ Monolog\ErrorHandler::register($logger, [], Monolog\Logger::ERROR, Monolog\Logge
$dbo = $database = database();
/* SESSIONE */
if (!API::isAPIRequest()) {
if (!API\Response::isAPIRequest()) {
// Sicurezza della sessioni
ini_set('session.use_trans_sid', '0');
ini_set('session.use_only_cookies', '1');
@ -162,7 +165,7 @@ $revision = Update::getRevision();
/* ACCESSO E INSTALLAZIONE */
// Controllo sulla presenza dei permessi di accesso basilari
$continue = $dbo->isInstalled() && !Update::isUpdateAvailable() && (Auth::check() || API::isAPIRequest());
$continue = $dbo->isInstalled() && !Update::isUpdateAvailable() && (Auth::check() || API\Response::isAPIRequest());
if (!empty($skip_permissions)) {
Permissions::skip();
@ -179,7 +182,7 @@ if (!$continue && getURLPath() != slashes(ROOTDIR.'/index.php') && !Permissions:
/* INIZIALIZZAZIONE GENERALE */
// Operazione aggiuntive (richieste non API)
if (!API::isAPIRequest()) {
if (!API\Response::isAPIRequest()) {
// Impostazioni di Content-Type e Charset Header
header('Content-Type: text/html; charset=UTF-8');
@ -278,3 +281,18 @@ $list = array_merge($files, $custom_files);
foreach ($list as $file) {
include_once $file;
}
// Inclusione dei file vendor/autoload.php di Composer
$files = glob(__DIR__.'/{modules,plugins}/*/vendor/autoload.php', GLOB_BRACE);
$custom_files = glob(__DIR__.'/{modules,plugins}/*/custom/vendor/autoload.php', GLOB_BRACE);
foreach ($custom_files as $key => $value) {
$index = array_search(str_replace('custom/', '', $value), $files);
if ($index !== false) {
unset($files[$index]);
}
}
$list = array_merge($files, $custom_files);
foreach ($list as $file) {
include_once $file;
}

View File

@ -13,7 +13,7 @@ if (empty($id_record) && !empty($id_module)) {
include_once App::filepath('include|custom|', 'top.php');
Util\Query::setSegments(false);
$query = Util\Query::getQuery($module, [
$query = Util\Query::getQuery($structure, [
'id' => $id_record,
]);
Util\Query::setSegments(true);

View File

@ -198,6 +198,15 @@ gulp.task('colorpicker', function () {
.pipe(gulp.dest(config.production + '/' + config.paths.images + '/bootstrap-colorpicker'));
});
gulp.task('password-strength', function () {
gulp.src([
config.main.bowerDirectory + '/pwstrength-bootstrap/dist/*.js',
])
.pipe(concat('password.min.js'))
.pipe(minifyJS())
.pipe(gulp.dest(config.production + '/password-strength'));
});
gulp.task('chartjs', function () {
gulp.src([
config.main.bowerDirectory + '/chart.js/dist/Chart.min.js',
@ -368,6 +377,7 @@ gulp.task('bower', ['clean'], function () {
gulp.task('other', ['clean'], function () {
gulp.start('ckeditor');
gulp.start('colorpicker');
gulp.start('password-strength');
gulp.start('i18n');
gulp.start('pdfjs');

View File

@ -30,4 +30,4 @@ echo '
</form>';
echo '
<script src="'.ROOTDIR.'/lib/init.js"></script>';
<script src="'.ROOTDIR.'/lib/init.js"></script>';

View File

@ -1,197 +1,270 @@
<?php
$id_record = $result['id_record'];
$id_documento_finale = $result['id_documento'];
$final_module = Modules::get($options['final_module']);
$original_module = Modules::get($options['original_module']);
$dir = $options['dir'];
$op = $options['op'];
$table = $options['sql']['table'];
$rows = $options['sql']['rows'];
$id_rows = $options['sql']['id_rows'];
// Info documento
$documento = $dbo->fetchOne('SELECT * FROM '.$table.' WHERE id = '.prepare($id_record));
$numero = !empty($documento['numero_esterno']) ? $documento['numero_esterno'] : $documento['numero'];
$id_anagrafica = $documento['idanagrafica'];
$id_pagamento = $documento['idpagamento'];
$id_conto = $documento['idconto'];
if (empty($documento)) {
// Inizializzazione
$documento = $options['documento'];
$documento_finale = $options['documento_finale'];
if (empty($documento) || (!empty($documento_finale) && $documento_finale->direzione != $documento->direzione)) {
return;
}
// Informazioi utili
$dir = $documento->direzione;
$original_module = Modules::get($documento->module);
$name = !empty($documento_finale) ? $documento_finale->module : $options['module'];
$final_module = Modules::get($name);
// IVA predefinta
$id_iva = $id_iva ?: setting('Iva predefinita');
if (empty($id_conto)) {
$id_conto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto');
$righe = $documento->getRighe()->where('qta_rimanente', '>', 0);
if (empty($righe)) {
echo '
<p>'.tr('Non ci sono elementi da evadere').'...</p>';
return;
}
// Selezione articoli dell'ordine da portare nel ddt
$righe = $dbo->fetchArray('SELECT *, IFNULL((SELECT codice FROM mg_articoli WHERE id=idarticolo),"") AS codice, (qta - qta_evasa) AS qta_rimanente FROM '.$table.' INNER JOIN '.$rows.' ON '.$table.'.id='.$rows.'.'.$id_rows.' WHERE '.$table.'.id='.prepare($id_record).' HAVING qta_rimanente > 0 OR is_descrizione = 1 ORDER BY `order`');
$link = !empty($documento_finale) ? ROOTDIR.'/editor.php?id_module='.$final_module['id'].'&id_record='.$documento_finale->id : ROOTDIR.'/controller.php?id_module='.$final_module['id'];
if (!empty($righe)) {
echo '
echo '
<form action="'.ROOTDIR.'/controller.php?id_module='.$final_module['id'].(!empty($id_documento_finale) ? '&id_record='.$id_documento_finale : '').'" method="post">
<input type="hidden" name="'.$options['id_importazione'].'" value="'.$id_record.'">
<input type="hidden" name="idanagrafica" value="'.$id_anagrafica.'">
<input type="hidden" name="idconto" value="'.$id_conto.'">
<input type="hidden" name="idpagamento" value="'.$id_pagamento.'">
<input type="hidden" name="iddocumento" value="'.$id_record.'">
<input type="hidden" name="op" value="'.$op.'">
<form action="'.$link.'" method="post">
<input type="hidden" name="op" value="'.$options['op'].'">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="dir" value="'.$dir.'">';
<input type="hidden" name="id_documento" value="'.$documento->id.'">
<input type="hidden" name="type" value="'.$options['type'].'">';
// Creazione fattura dal documento
if (!empty($options['create_document'])) {
echo '
<div class="row">
<input type="hidden" name="create_document" value="on"/>
// Creazione fattura dal documento
if (!empty($options['create_document'])) {
echo '
<div class="box box-warning">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Nuovo documento').'</h3>
</div>
<div class="box-body">
<div class="row">
<input type="hidden" name="create_document" value="on" />
<div class="col-md-6">
{[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]}
</div>';
<div class="col-md-6">
{[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]}
</div>';
if (in_array($final_module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
if ($op == 'nota_accredito' && !empty($segmenti)) {
$segmento = $dbo->fetchOne("SELECT * FROM zz_segments WHERE predefined_accredito='1'");
if ($final_module['name'] == 'Fatture di vendita' || $final_module['name'] == 'Fatture di acquisto') {
if ($op == 'nota_accredito' && !empty($segmenti)) {
$segmento = $dbo->fetchOne("SELECT * FROM zz_segments WHERE predefined_accredito='1'");
$id_segment = $segmento['id'];
} else {
$id_segment = $_SESSION['module_'.$final_module['id']]['id_segment'];
}
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare($final_module['id']).' ORDER BY name", "value": "'.$id_segment.'" ]}
</div>';
$id_segment = $segmento['id'];
} else {
$id_segment = $_SESSION['module_'.$final_module['id']]['id_segment'];
}
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Ritenuta contributi').'", "name": "id_ritenuta_contributi", "value": "$id_ritenuta_contributi$", "values": "query=SELECT * FROM co_ritenuta_contributi" ]}
</div>
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare($final_module['id']).' ORDER BY name", "value": "'.$id_segment.'" ]}
</div>';
}
echo '
</div>
</div>
</div>';
}
// Conto, rivalsa INPS, ritenuta d'acconto e ritenuta contributi
if (in_array($final_module['name'], ['Fatture di vendita', 'Fatture di acquisto']) && !in_array($original_module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
$id_rivalsa_inps = setting('Percentuale rivalsa');
if ($dir == 'uscita') {
$id_ritenuta_acconto = $documento->anagrafica->id_ritenuta_acconto_acquisti;
} else {
$id_ritenuta_acconto = $documento->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto");
}
$calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito");
$show_rivalsa = !empty($id_rivalsa_inps);
$show_ritenuta_acconto = setting("Percentuale ritenuta d'acconto") != '' || !empty($id_ritenuta_acconto);
$show_ritenuta_contributi = !empty($documento_finale['id_ritenuta_contributi']);
$id_conto = $documento_finale['idconto'];
if (empty($id_conto)) {
$id_conto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto');
}
echo '
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Opzioni generali delle righe').'</h3>
</div>
<div class="box-body">';
if ($show_rivalsa || $show_ritenuta_acconto) {
echo '
<div class="row">';
// Rivalsa INPS
if ($show_rivalsa) {
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Rivalsa').'", "name": "id_rivalsa_inps", "value": "'.$id_rivalsa_inps.'", "values": "query=SELECT * FROM co_rivalse", "help": "'.(($options['dir'] == 'entrata') ? setting('Tipo Cassa Previdenziale') : null).'" ]}
</div>';
}
// Ritenuta d'acconto
if ($show_ritenuta_acconto) {
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr("Ritenuta d'acconto").'", "name": "id_ritenuta_acconto", "value": "'.$id_ritenuta_acconto.'", "values": "query=SELECT * FROM co_ritenutaacconto" ]}
</div>';
// Calcola ritenuta d'acconto su
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr("Calcola ritenuta d'acconto su").'", "name": "calcolo_ritenuta_acconto", "value": "'.$calcolo_ritenuta_acconto.'", "values": "list=\"IMP\":\"Imponibile\", \"IMP+RIV\":\"Imponibile + rivalsa\"", "required": "1" ]}
</div>';
}
echo '
</div>';
}
$width = $show_ritenuta_contributi ? 6 : 12;
echo '
<div class="row">';
// Ritenuta contributi
if ($show_ritenuta_contributi) {
echo '
<div class="col-md-'.$width.'">
{[ "type": "checkbox", "label": "'.tr('Ritenuta contributi').'", "name": "ritenuta_contributi", "value": "1" ]}
</div>';
}
// Conto
if (($final_module['name'] == 'Fatture di vendita' || $final_module['name'] == 'Fatture di acquisto') && !($original_module['name'] == 'Fatture di vendita' || $original_module['name'] == 'Fatture di acquisto')) {
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Conto').'", "name": "id_conto", "required": 1, "value": "'.$id_conto.'", "ajax-source": "'.($dir == 'entrata' ? 'conti-vendite' : 'conti-acquisti').'" ]}
echo '
<div class="col-md-'.$width.'">
{[ "type": "select", "label": "'.tr('Conto').'", "name": "id_conto", "required": 1, "value": "'.$id_conto.'", "ajax-source": "'.($dir == 'entrata' ? 'conti-vendite' : 'conti-acquisti').'" ]}
</div>
</div>
</div>
</div>';
}
}
echo '
<div class="clearfix"></div>
<br>
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Righe da importare').'</h3>
</div>
<p>'.tr('Seleziona le righe e le relative quantità da inserire nel documento').'.</p>
<table class="box-body table table-striped table-hover table-condensed">
<tr>
<th>'.tr('Descrizione').'</th>
<th width="10%">'.tr('Q.').'</th>
<th width="15%">'.tr('Q. da evadere').'</th>
<th width="20%">'.tr('Subtot.').'</th>';
<table class="table table-striped table-hover table-condensed">
<tr>
<th>'.tr('Descrizione').'</th>
<th width="10%">'.tr('Q.').'</th>
<th width="15%">'.tr('Q. da evadere').'</th>
<th width="20%">'.tr('Subtot.').'</th>';
if (!empty($options['serials'])) {
echo '
<th width="20%">'.tr('Seriali').'</th>';
}
echo '
</tr>';
foreach ($righe as $i => $r) {
// Descrizione
echo '
<tr>
<td>
<input type="hidden" id="subtot_'.$i.'" name="subtot['.$r['id'].']" value="'.$r['prezzo_unitario_vendita'].'" />
<input type="hidden" id="sconto_'.$i.'" name="sconto['.$r['id'].']" value="'.$r['sconto'] / $r['qta'].'" />
<input type="hidden" id="iva_'.$i.'" name="iva['.$r['id'].']" value="'.$r['iva'] / $r['qta'].'" />
<input type="hidden" id="qtamax_'.$i.'" value="'.($r['qta_rimanente']).'" />';
// Checkbox - da evadere?
echo '
<input type="checkbox" checked="checked" id="checked_'.$i.'" name="evadere['.$r['id'].']" value="on" onclick="ricalcola_subtotale_riga('.$i.');" />';
$descrizione = ($r->isArticolo() ? $r->articolo->codice.' - ' : '').$r['descrizione'];
echo '&nbsp;'.nl2br($descrizione);
echo '
</td>';
// Q.tà rimanente
echo '
<td class="text-center">
'.Translator::numberToLocale($r['qta_rimanente']).'
</td>';
// Q.tà da evadere
echo '
<td>
{[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta_rimanente'].'", "decimals": "qta", "min-value": "0", "extra": "'.(($r['is_descrizione']) ? 'readonly' : '').' onkeyup=\"ricalcola_subtotale_riga('.$i.');\"" ]}
</td>';
echo '
<td>
<big id="subtotale_'.$i.'">'.moneyFormat($r->totale).'</big><br/>
<small style="color:#777;" id="subtotaledettagli_'.$i.'">'.Translator::numberToLocale($r->totale_imponibile).' + '.Translator::numberToLocale($r->iva).'</small>
</td>';
// Seriali
if (!empty($options['serials'])) {
echo '
<th width="20%">'.tr('Seriali').'</th>';
}
<td>';
echo '
</tr>';
if (!empty($r['abilita_serial'])) {
$serials = $r->serials;
foreach ($righe as $i => $r) {
// Descrizione
echo '
<tr>
<td>';
// Checkbox - da evadere?
echo '
<input type="checkbox" checked="checked" id="checked_'.$i.'" name="evadere['.$r['id'].']" value="on" onclick="ricalcola_subtotale_riga('.$i.');" />';
$descrizione = (!empty($r['codice']) ? $r['codice'].' - ' : '').$r['descrizione'];
echo '&nbsp;'.nl2br($descrizione);
echo '
</td>';
// Q.tà rimanente
echo '
<td>
<input type="hidden" id="qtamax_'.$i.'" value="'.($r['qta'] - $r['qta_evasa']).'" />
<p class="text-center">'.Translator::numberToLocale($r['qta_rimanente']).'</p>
</td>';
// Q.tà da evadere
echo '
<td>
{[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta_rimanente'].'", "decimals": "qta", "min-value": "0", "extra": "'.(($r['is_descrizione']) ? 'readonly' : '').' onkeyup=\"ricalcola_subtotale_riga('.$i.');\"" ]}
</td>';
// Subtotale
$subtotale = $r['subtotale'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
$sconto = $r['sconto'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
$iva = $r['iva'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
echo '
<td>
<input type="hidden" id="subtot_'.$i.'" name="subtot['.$r['id'].']" value="'.$r['subtotale'] / $r['qta'].'" />
<input type="hidden" id="sconto_'.$i.'" name="sconto['.$r['id'].']" value="'.$r['sconto'] / $r['qta'].'" />
<input type="hidden" id="iva_'.$i.'" name="iva['.$r['id'].']" value="'.$r['iva'] / $r['qta'].'" />
<big id="subtotale_'.$i.'">'.moneyFormat($subtotale - $sconto + $iva).'</big><br/>
<small style="color:#777;" id="subtotaledettagli_'.$i.'">'.Translator::numberToLocale($subtotale - $sconto).' + '.Translator::numberToLocale($iva).'</small>
</td>';
// Seriali
if (!empty($options['serials'])) {
echo '
<td>';
if (!empty($r['abilita_serial'])) {
$query = 'SELECT DISTINCT serial AS id, serial AS descrizione FROM mg_prodotti WHERE dir='.prepare($dir).' AND '.$options['serials']['id_riga'].' = '.prepare($r['id']).' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti AS t WHERE serial IS NOT NULL AND dir='.prepare($dir).' AND '.$options['serials']['condition'].')';
$values = $dbo->fetchArray($query);
if (!empty($values)) {
echo '
{[ "type": "select", "name": "serial['.$r['id'].'][]", "id": "serial_'.$i.'", "multiple": 1, "values": "query='.$query.'", "value": "'.implode(',', array_column($values, 'id')).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]}';
}
$list = [];
foreach ($serials as $serial) {
$list[] = [
'id' => $serial,
'text' => $serial,
];
}
if (empty($r['abilita_serial']) || empty($values)) {
echo '-';
if (!empty($serials)) {
echo '
{[ "type": "select", "name": "serial['.$r['id'].'][]", "id": "serial_'.$i.'", "multiple": 1, "values": '.json_encode($list).', "value": "'.implode(',', $serials).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]}';
}
}
echo '
</td>';
if (empty($r['abilita_serial']) || empty($serials)) {
echo '-';
}
echo '
</tr>';
</td>';
}
// Totale
echo '
<tr>
<td colspan="'.(!empty($options['serials']) ? 4 : 3).'" align="right" class="text-right">
<b>'.tr('Totale').':</b>
</td>
<td class="text-right" colspan="2">
<big id="totale"></big>
</td>
</tr>
</table>';
</tr>';
}
echo '
// Totale
echo '
<tr>
<td colspan="'.(!empty($options['serials']) ? 4 : 3).'" align="right" class="text-right">
<b>'.tr('Totale').':</b>
</td>
<td class="text-right" colspan="2">
<big id="totale"></big>
</td>
</tr>
</table>
</div>';
echo '
<!-- PULSANTI -->
<div class="row">
@ -202,10 +275,6 @@ if (!empty($righe)) {
</div>
</div>
</form>';
} else {
echo '
<p>'.tr('Non ci sono elementi da evadere').'...</p>';
}
echo '
<script src="'.ROOTDIR.'/lib/init.js"></script>';
@ -255,13 +324,13 @@ echo '
}
function ricalcola_totale() {
tot_qta = 0;
r = 0;
totale = 0.00;
$('input[id*=qta_]').each(function() {
qta = $(this).val().toEnglish();
r = $(this).attr("id").replace("qta_", "");
if (!$('#checked_' + r).is(':checked') || isNaN(qta)) {
if (!$("#checked_" + r).is(":checked") || isNaN(qta)) {
qta = 0;
}
@ -278,17 +347,13 @@ echo '
if(subtot) {
totale += subtot * qta + iva * qta;
}
r++;
tot_qta += qta;
});
$('#totale').html((totale.toLocale()) + " " + globals.currency);
<?php
if (empty($options['sql']['allow-empty'])) {
if (empty($options['allow-empty'])) {
echo '
if (tot_qta > 0)
$("#submit_btn").show();

View File

@ -16,7 +16,7 @@ echo '
// Quantità
echo '
<div class="col-md-4">
{[ "type": "number", "label": "'.tr('Q.tà').'", "name": "qta", "required": 1, "value": "'.$result['qta'].'", "decimals": "qta" ]}
{[ "type": "number", "label": "'.tr('Q.tà').'", "name": "qta", "required": 1, "value": "'.$result['qta'].'", "decimals": "qta"'.(isset($result['max_qta']) ? ', "icon-after": "/ '.numberFormat($result['max_qta'], 'qta').'", "help": "'.tr("Quantità dell'elemento / quantità totale massima").'"' : '').' ]}
</div>';
// Unità di misura
@ -92,70 +92,3 @@ echo '
{[ "type": "number", "label": "'.tr('Sconto unitario').'", "name": "sconto", "value": "'.$result['sconto_unitario'].'", "icon-after": "choice|untprc|'.$result['tipo_sconto'].'", "help": "'.tr('Il valore positivo indica uno sconto. Per applicare un rincaro inserire un valore negativo.').'" ]}
</div>
</div>';
if ($module['name'] == 'Fatture di vendita') {
$collapsed = empty($result['data_inizio_periodo']) && empty($result['data_fine_periodo']) && empty($result['riferimento_amministrazione']);
echo '
<div class="box box-info '.($collapsed ? 'collapsed-box' : '').'">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Dati Fatturazione Elettronica').'</h3>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse">
<i class="fa fa-plus"></i>
</button>
</div>
</div>
<div class="box-body">';
$tipi_cessione_prestazione = [
[
'id' => 'SC',
'text' => 'SC - '.tr('Sconto'),
],
[
'id' => 'PR',
'text' => 'PR - '.tr('Premio'),
],
[
'id' => 'AB',
'text' => 'AB - '.tr('Abbuono'),
],
[
'id' => 'AC',
'text' => 'AC - '.tr('Spesa accessoria'),
],
];
// Data inizio periodo
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Tipo Cessione Prestazione').'", "name": "tipo_cessione_prestazione", "value": "'.$result['tipo_cessione_prestazione'].'", "values": '.json_encode($tipi_cessione_prestazione).' ]}
</div>';
// Riferimento amministrazione
echo '
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Riferimento Amministrazione').'", "name": "riferimento_amministrazione", "value": "'.$result['riferimento_amministrazione'].'", "maxlength": 20 ]}
</div>
</div>';
// Data inizio periodo
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "date", "label": "'.tr('Data Inizio Periodo').'", "name": "data_inizio_periodo", "value": "'.$result['data_inizio_periodo'].'" ]}
</div>';
// Data fine periodo
echo '
<div class="col-md-6">
{[ "type": "date", "label": "'.tr('Data Fine Periodo').'", "name": "data_fine_periodo", "value": "'.$result['data_fine_periodo'].'" ]}
</div>
</div>';
echo '
</div>
</div>';
}

View File

@ -39,7 +39,7 @@ echo '
var sconto_percentuale = form.find("#sconto_percentuale");
var sconto_unitario = form.find("#sconto_unitario");
var totale = '.($options['imponibile_scontato'] ?: 0).';
var totale = '.($options['totale_imponibile'] ?: 0).';
function aggiorna_sconto_percentuale() {
var sconto = sconto_percentuale.val().toEnglish();
@ -48,13 +48,20 @@ echo '
msg = sconto >= 0 ? "'.tr('Sconto percentuale').'" : "'.tr('Maggiorazione percentuale').'";
sconto_unitario.val(unitario.toLocale());
descrizione.val(msg + " " + Math.abs(sconto).toLocale() + "%");
if (!descrizione.val()) {
descrizione.val(msg + " " + Math.abs(sconto).toLocale() + "%");
}
}
function aggiorna_sconto_unitario(){
msg = sconto_unitario.val().toEnglish() >= 0 ? "'.tr('Sconto unitario').'" : "'.tr('Maggiorazione unitaria').'";
descrizione.val(msg);
sconto_percentuale.val(0);
if (!descrizione.val()) {
descrizione.val(msg);
}
}
sconto_percentuale.keyup(aggiorna_sconto_percentuale);

View File

@ -128,11 +128,11 @@ if (!$has_user) {
</div>
<div class="col-md-6">
{[ "type": "password", "label": "'.tr('Password').'", "id": "password", "name": "admin_password", "value": "'.$osm_password.'", "placeholder": "'.tr("Digita la password dell'amministratore").'", "required": 1, "icon-after": "<i onclick=\" if ($(this).parent().find(\'i\').hasClass(\'fa-eye\')) { $(\'#password\').attr(\'type\', \'text\'); $(this).parent().find(\'i\').removeClass(\'fa-eye\').addClass(\'fa-eye-slash\'); $(this).parent().find(\'i\').attr(\'title\', \'Nascondi password\'); } else { $(\'#password\').attr(\'type\', \'password\'); $(this).parent().find(\'i\').removeClass(\'fa-eye-slash\').addClass(\'fa-eye\'); $(this).parent().find(\'i\').attr(\'title\', \'Visualizza password\'); } \" title=\"'.tr('Visualizza password').'\" class=\"fa fa-eye clickable\" ></i>" ]}
{[ "type": "password", "label": "'.tr('Password').'", "id": "password", "name": "admin_password", "value": "'.$osm_password.'", "placeholder": "'.tr("Digita la password dell'amministratore").'", "required": 1, "strength": "#config" ]}
</div>
<div class="col-md-6">
{[ "type": "email", "label": "'.tr('Email').'", "name": "admin_email", "value": "'.$osm_email.'", "placeholder": "'.tr("Digita l'indirizzo email dell'amministratore").'" ]}
{[ "type": "email", "label": "'.tr('Email').'", "name": "admin_email", "value": "'.$osm_email.'", "placeholder": "'.tr("Digita l'indirizzo email dell'amministratore").'", "required": 1 ]}
</div>
</div>
</div>

View File

@ -9,6 +9,7 @@ use UnexpectedValueException;
abstract class Article extends Row
{
public $movimenta_magazzino = true;
protected $serialRowID = null;
protected $abilita_movimentazione = true;
protected $serialsList = null;
@ -28,7 +29,24 @@ abstract class Article extends Row
return $model;
}
abstract public function movimenta($qta);
public function movimenta($qta)
{
if (!$this->movimenta_magazzino) {
return;
}
$movimenta = true;
// Movimenta il magazzino solo se l'articolo non è già stato movimentato da un documento precedente
if ($this->hasOriginal()) {
$original = $this->getOriginal();
$movimenta = !$original->movimenta_magazzino;
}
if ($movimenta) {
$this->movimentaMagazzino($qta);
}
}
abstract public function getDirection();
@ -96,9 +114,15 @@ abstract class Article extends Row
*
* @return float
*/
public function getMissingSerialsAttribute()
public function getMissingSerialsNumberAttribute()
{
return $this->qta - count($this->serials);
if (!$this->abilita_serial) {
return 0;
}
$missing = $this->qta - count($this->serials);
return $missing;
}
/**
@ -145,12 +169,39 @@ abstract class Article extends Row
return parent::save($options);
}
public function canDelete()
{
$serials = $this->usedSerials();
return empty($serials);
}
public function delete()
{
if (!$this->canDelete()) {
throw new \InvalidArgumentException();
}
$this->serials = [];
$this->qta = 0; // Fix movimentazione automatica
if (!empty($this->qta_movimentazione)) {
$this->movimenta($this->qta_movimentazione);
}
return parent::delete();
}
abstract protected function movimentaMagazzino($qta);
protected static function boot()
{
parent::boot(true);
static::addGlobalScope('articles', function (Builder $builder) {
$builder->whereNotNull('idarticolo')->where('idarticolo', '<>', 0);
$table = parent::getTableName();
static::addGlobalScope('articles', function (Builder $builder) use ($table) {
$builder->whereNotNull($table.'.idarticolo')->where($table.'.idarticolo', '<>', 0);
});
}

View File

@ -8,8 +8,14 @@ use Illuminate\Database\Eloquent\Builder;
abstract class Description extends Model
{
use MorphTrait;
protected $guarded = [];
protected $appends = [
'max_qta',
];
public static function build(Document $document, $bypass = false)
{
$model = parent::build();
@ -24,6 +30,17 @@ abstract class Description extends Model
return $model;
}
public function getMaxQtaAttribute()
{
if (!$this->hasOriginal()) {
return null;
}
$original = $this->getOriginal();
return $original->qta_rimanente + $this->qta;
}
/**
* Modifica la quantità dell'elemento.
*
@ -36,9 +53,23 @@ abstract class Description extends Model
$previous = $this->qta;
$diff = $value - $previous;
if ($this->hasOriginal()) {
$original = $this->getOriginal();
if ($original->qta_rimanente < $diff) {
$diff = $original->qta_rimanente;
$value = $previous + $diff;
}
}
$this->attributes['qta'] = $value;
$this->evasione($diff);
if ($this->hasOriginal()) {
$original = $this->getOriginal();
$original->qta_evasa += $diff;
$original->save();
}
return $diff;
}
@ -53,11 +84,23 @@ abstract class Description extends Model
return $this->qta - $this->qta_evasa;
}
public function canDelete()
{
return true;
}
public function delete()
{
$this->evasione(-$this->qta);
if (!$this->canDelete()) {
throw new \InvalidArgumentException();
}
return parent::delete();
$this->qta = 0;
$result = parent::delete();
$this->parent->fixStato($this);
return $result;
}
/**
@ -98,6 +141,9 @@ abstract class Description extends Model
// Attributi dell'oggetto da copiare
$attributes = $this->getAttributes();
unset($attributes['id']);
unset($attributes['original_id']);
unset($attributes['original_type']);
unset($attributes['order']);
if ($qta !== null) {
$attributes['qta'] = $qta;
@ -108,6 +154,15 @@ abstract class Description extends Model
// Creazione del nuovo oggetto
$model = new $object();
// Rimozione attributo in conflitto
unset($attributes[$model->getParentID()]);
$model->original_id = $this->id;
$model->original_type = $current;
// Impostazione del genitore
$model->setParent($document);
// Azioni specifiche di inizalizzazione
$model->customInitCopiaIn($this);
@ -123,18 +178,11 @@ abstract class Description extends Model
$attributes = array_intersect_key($attributes, $accepted);
$model->fill($attributes);
// Impostazione del genitore
$model->setParent($document);
// Azioni specifiche successive
$model->customAfterDataCopiaIn($this);
$model->save();
// Rimozione quantità evasa
$this->qta_evasa = $this->qta_evasa + abs($attributes['qta']);
$this->save();
return $model;
}
@ -162,8 +210,13 @@ abstract class Description extends Model
return $this instanceof Article;
}
protected function evasione($diff)
public function save(array $options = [])
{
$result = parent::save($options);
$this->parent->fixStato($this);
return $result;
}
/**
@ -199,13 +252,15 @@ abstract class Description extends Model
{
parent::boot();
$table = parent::getTableName();
if (!$bypass) {
static::addGlobalScope('descriptions', function (Builder $builder) {
$builder->where('is_descrizione', '=', 1);
static::addGlobalScope('descriptions', function (Builder $builder) use ($table) {
$builder->where($table.'.is_descrizione', '=', 1);
});
} else {
static::addGlobalScope('not_descriptions', function (Builder $builder) {
$builder->where('is_descrizione', '=', 0);
static::addGlobalScope('not_descriptions', function (Builder $builder) use ($table) {
$builder->where($table.'.is_descrizione', '=', 0);
});
}
}

View File

@ -24,6 +24,11 @@ abstract class Discount extends Row
return $this->attributes['iva'];
}
public function isMaggiorazione()
{
return $this->totale_imponibile < 0;
}
/**
* Effettua i conti per l'IVA.
*/
@ -43,8 +48,10 @@ abstract class Discount extends Row
{
parent::boot(true);
static::addGlobalScope('discounts', function (Builder $builder) {
$builder->where('is_sconto', '=', 1);
$table = parent::getTableName();
static::addGlobalScope('discounts', function (Builder $builder) use ($table) {
$builder->where($table.'.is_sconto', '=', 1);
});
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Common\Components;
trait MorphTrait
{
public function hasOriginal()
{
return !empty($this->original_type) && !empty($this->original);
}
public function original()
{
return $this->morphedByMany($this->original_type, 'original', $this->table, 'id');
}
public function getOriginal()
{
return $this->original()->first();
}
}

View File

@ -33,11 +33,11 @@ abstract class Row extends Description
}
/**
* Restituisce l'imponibile scontato dell'elemento.
* Restituisce il totale imponibile dell'elemento.
*
* @return float
*/
public function getImponibileScontatoAttribute()
public function getTotaleImponibileAttribute()
{
$result = $this->prezzo_unitario_vendita >= 0 ? $this->imponibile : -$this->imponibile;
@ -53,7 +53,7 @@ abstract class Row extends Description
*/
public function getTotaleAttribute()
{
return $this->imponibile_scontato + $this->iva;
return $this->totale_imponibile + $this->iva;
}
/**
@ -67,13 +67,13 @@ abstract class Row extends Description
}
/**
* Restituisce il gaudagno totale (imponibile_scontato - spesa) relativo all'elemento.
* Restituisce il gaudagno totale (totale_imponibile - spesa) relativo all'elemento.
*
* @return float
*/
public function getGuadagnoAttribute()
{
return $this->imponibile_scontato - $this->spesa;
return $this->totale_imponibile - $this->spesa;
}
// Attributi della componente
@ -85,7 +85,7 @@ abstract class Row extends Description
public function getIvaAttribute()
{
return ($this->imponibile_scontato) * $this->aliquota->percentuale / 100;
return ($this->totale_imponibile) * $this->aliquota->percentuale / 100;
}
public function getIvaDetraibileAttribute()
@ -125,7 +125,7 @@ abstract class Row extends Description
}
/**
* Imposta il costo unitario della riga.
* Imposta il prezzo unitario della riga.
*
* @param float $value
*/
@ -135,7 +135,7 @@ abstract class Row extends Description
}
/**
* Restituisce il costo unitario della riga.
* Restituisce il prezzo unitario della riga.
*/
public function getPrezzoUnitarioVenditaAttribute()
{
@ -173,13 +173,15 @@ abstract class Row extends Description
{
parent::boot(true);
$table = parent::getTableName();
if (!$bypass) {
static::addGlobalScope('rows', function (Builder $builder) {
$builder->whereNull('idarticolo')->orWhere('idarticolo', '=', 0);
static::addGlobalScope('rows', function (Builder $builder) use ($table) {
$builder->whereNull($table.'.idarticolo')->orWhere($table.'.idarticolo', '=', 0);
});
static::addGlobalScope('not_discounts', function (Builder $builder) {
$builder->where('is_sconto', '=', 0);
static::addGlobalScope('not_discounts', function (Builder $builder) use ($table) {
$builder->where($table.'.is_sconto', '=', 0);
});
}
}

View File

@ -2,6 +2,8 @@
namespace Common;
use Common\Components\Description;
abstract class Document extends Model
{
/**
@ -19,6 +21,29 @@ abstract class Document extends Model
return $descrizioni->merge($righe)->merge($articoli)->merge($sconti)->sortBy('order');
}
/**
* Restituisce la collezione di righe e articoli con valori rilevanti per i conti, raggruppate sulla base dei documenti di provenienza.
* La chiave è la serializzazione del documento di origine, oppure null in caso non esista.
*
* @return iterable
*/
public function getRigheRaggruppate()
{
$righe = $this->getRighe();
$groups = $righe->groupBy(function ($item, $key) {
if (!$item->hasOriginal()) {
return null;
}
$parent = $item->getOriginal()->parent;
return serialize($parent);
});
return $groups;
}
abstract public function righe();
abstract public function articoli();
@ -48,13 +73,13 @@ abstract class Document extends Model
}
/**
* Calcola l'imponibile scontato del documento.
* Calcola il totale imponibile del documento.
*
* @return float
*/
public function getImponibileScontatoAttribute()
public function getTotaleImponibileAttribute()
{
return $this->calcola('imponibile_scontato');
return $this->calcola('totale_imponibile');
}
/**
@ -97,6 +122,40 @@ abstract class Document extends Model
return $this->calcola('guadagno');
}
public function delete()
{
$righe = $this->getRighe();
$can_delete = true;
foreach ($righe as $riga) {
$can_delete &= $riga->canDelete();
}
if (!$can_delete) {
throw new \InvalidArgumentException();
}
foreach ($righe as $riga) {
$riga->delete();
}
return parent::delete();
}
/**
* Effettua un controllo sui campi del documento.
* Viene richiamatp dalle modifiche alle righe del documento.
*
* @param Description $trigger
*/
public function fixStato(Description $trigger)
{
$this->load('righe');
$this->load('articoli');
$this->load('descrizioni');
$this->load('sconti');
}
/**
* Calcola la somma degli attributi indicati come parametri.
* Il metodo **non** deve essere adattato per ulteriori funzionalità: deve esclusivamente calcolare la somma richiesta in modo esplicito dagli argomenti.
@ -122,9 +181,7 @@ abstract class Document extends Model
*/
protected function getRigheContabili()
{
$sconto = $this->scontoGlobale ? [$this->scontoGlobale] : [];
return $this->getRighe()->merge(collect($sconto));
return $this->getRighe();
}
/**

View File

@ -7,7 +7,10 @@ use Illuminate\Database\Eloquent\Model as Original;
abstract class Model extends Original
{
// Retrocompatibilità MySQL
const UPDATED_AT = null;
public function setUpdatedAtAttribute($value)
{
// to Disable updated_at
}
/**
* Crea una nuova istanza del modello.
@ -18,4 +21,9 @@ abstract class Model extends Original
{
return new static();
}
public static function getTableName()
{
return with(new static())->getTable();
}
}

View File

@ -96,6 +96,23 @@ if (Auth::check()) {
'.$key.': "'.addslashes($value).'",';
}
echo '
password: {
"wordMinLength": "'.tr('La tua password è troppo corta').'",
"wordMaxLength": "'.tr('La tua password è troppo lunga').'",
"wordInvalidChar": "'.tr('La tua password contiene un carattere non valido').'",
"wordNotEmail": "'.tr('Non usare la tua e-mail come password').'",
"wordSimilarToUsername": "'.tr('La tua password non può contenere il tuo nome').'",
"wordTwoCharacterClasses": "'.tr('Usa classi di caratteri diversi').'",
"wordRepetitions": "'.tr('Troppe ripetizioni').'",
"wordSequences": "'.tr('La tua password contiene sequenze').'",
"errorList": "'.tr('Errori').':",
"veryWeak": "'.tr('Molto debole').'",
"weak": "'.tr('Debole').'",
"normal": "'.tr('Normale').'",
"medium": "'.tr('Media').'",
"strong": "'.tr('Forte').'",
"veryStrong": "'.tr('Molto forte').'",
},
};
globals = {
rootdir: "'.$rootdir.'",
@ -138,7 +155,25 @@ if (Auth::check()) {
rootdir: "'.$rootdir.'",
search: {},
translations: {},
translations: {
password: {
"wordMinLength": "'.tr('La tua password è troppo corta').'",
"wordMaxLength": "'.tr('La tua password è troppo lunga').'",
"wordInvalidChar": "'.tr('La tua password contiene un carattere non valido').'",
"wordNotEmail": "'.tr('Non usare la tua e-mail come password').'",
"wordSimilarToUsername": "'.tr('La tua password non può contenere il tuo nome').'",
"wordTwoCharacterClasses": "'.tr('Usa classi di caratteri diversi').'",
"wordRepetitions": "'.tr('Troppe ripetizioni').'",
"wordSequences": "'.tr('La tua password contiene sequenze').'",
"errorList": "'.tr('Errori').':",
"veryWeak": "'.tr('Molto debole').'",
"weak": "'.tr('Debole').'",
"normal": "'.tr('Normale').'",
"medium": "'.tr('Media').'",
"strong": "'.tr('Forte').'",
"veryStrong": "'.tr('Molto forte').'",
},
},
locale: "'.$lang.'",
full_locale: "'.$lang.'_'.strtoupper($lang).'",
@ -275,7 +310,7 @@ if (Auth::check()) {
<i class="fa fa-info"></i>
</a></li>
<li><a href="'.$rootdir.'/index.php?op=logout" class="bg-red tip" title="'.tr('Esci').'">
<li><a href="'.$rootdir.'/index.php?op=logout" onclick="sessionStorage.clear()" class="bg-red tip" title="'.tr('Esci').'">
<i class="fa fa-power-off"></i>
</a></li>
</ul>
@ -289,18 +324,27 @@ if (Auth::check()) {
<section class="sidebar">
<!-- Sidebar user panel -->
<div class="user-panel text-center info">
<div class="user-panel text-center info" style="height: 60px">
<div class="info">
<p><a href="'.$rootdir.'/modules/utenti/info.php">
<i class="fa fa-user"></i>
'.$user['username'].'
</a></p>
<p id="datetime"></p>
</div>
<div class="image">
<img src="'.$paths['img'].'/logo.png" class="img-circle img-responsive" alt="'.tr('OpenSTAManager').'" />
</div>
<a class="image" href="'.$rootdir.'/modules/utenti/info.php">';
$user_photo = $user->photo;
if ($user_photo) {
echo '
<img src="'.$user_photo.'" class="img-responsive" alt="'.$user['username'].'" />';
} else {
echo '
<i class="fa fa-user fa-3x pull-left" alt="'.tr('OpenSTAManager').'"></i>';
}
echo '
</a>
</div>
<!-- search form -->

View File

@ -142,18 +142,25 @@ if (isset($username)) {
}
echo'>
</div>
<div class="form-group input-group">
<span class="input-group-addon before"><i class="fa fa-lock"></i> </span>
<input type="password" name="password" autocomplete="current-password" class="form-control" placeholder="'.tr('Password').'">
</div>
<div class="form-group">
{[ "type": "password", "name": "password", "autocomplete": "current-password", "placeholder": "'.tr('Password').'", "icon-before": "<i class=\"fa fa-lock\"></i>" ]}
<div class="text-right">
<a href="'.ROOTDIR.'/reset.php">'.tr('Dimenticata la password?').'</a>
</div>
<hr>
<div class="text-center">
<input type="checkbox" name="keep_alive"';
if (filter('keep_alive') != null) {
echo ' checked';
}
echo '/> '.tr('Mantieni attiva la sessione').'
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" id="login" class="btn btn-danger btn-block">'.tr('Accedi').'</button>

View File

@ -248,11 +248,22 @@ $(document).ready(function () {
$('.nav-tabs').tabs();
// Entra nel tab indicato al caricamento della pagina
var hash = window.location.hash ? window.location.hash : getUrlVars().hash;
var hash = location.hash ? location.hash : getUrlVars().hash;
if (hash && hash != '#tab_0') {
$('ul.nav-tabs a[href="' + hash + '"]').tab('show').trigger('shown.bs.tab');
} else {
location.hash = '';
}
$(window).bind("hashchange", function(){
var hash = location.hash;
console.log(hash);
if (!hash || hash == '#tab_0') {
location.hash = '';
}
});
// Nel caso la navigazione sia da mobile, disabilito il ritorno al punto precedente
if (!isMobile.any()) {
// Salvo lo scroll per riportare qui l'utente al reload
@ -939,6 +950,73 @@ function openLink(event, link) {
}
}
function start_datepickers() {
var icons = {
time: 'fa fa-clock-o',
date: 'fa fa-calendar',
up: 'fa fa-chevron-up',
down: 'fa fa-chevron-down',
previous: 'fa fa-chevron-left',
next: 'fa fa-chevron-right',
today: 'fa fa-street-view',
clear: 'fa fa-trash',
close: 'fa fa-times'
};
$('.timestamp-picker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
collapse: false,
sideBySide: true,
useCurrent: false,
stepping: 5,
widgetPositioning: {
horizontal: 'left',
vertical: 'bottom'
},
minDate: moment($this.attr('min-date')).isValid() ? $this.attr('min-date') : false,
maxDate: moment($this.attr('max-date')).isValid() ? $this.attr('max-date') : false,
});
});
//fix per timestamp-picker non visibile con la classe table-responsive
$('.timestamp-picker').each(function () {
$this = $(this);
$this.on("dp.show", function (e) {
$('#tecnici > div').removeClass('table-responsive');
});
$this.on("dp.hide", function (e) {
$('#tecnici > div').addClass('table-responsive');
})
});
$('.datepicker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
useCurrent: false,
format: 'L',
minDate: moment($this.attr('min-date')).isValid() ? $this.attr('min-date') : false,
maxDate: moment($this.attr('max-date')).isValid() ? $this.attr('max-date') : false,
});
});
$('.timepicker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
useCurrent: false,
format: 'LT',
stepping: 5,
minDate: moment($this.attr('min-date')).isValid() ? $this.attr('min-date') : false,
maxDate: moment($this.attr('max-date')).isValid() ? $this.attr('max-date') : false,
});
});
}
// Select
function start_superselect() {
// Statico

View File

@ -34,71 +34,7 @@ $(document).ready(function () {
this.$element.removeClass('parsley-success');
});
var icons = {
time: 'fa fa-clock-o',
date: 'fa fa-calendar',
up: 'fa fa-chevron-up',
down: 'fa fa-chevron-down',
previous: 'fa fa-chevron-left',
next: 'fa fa-chevron-right',
today: 'fa fa-street-view',
clear: 'fa fa-trash',
close: 'fa fa-times'
};
$('.timestamp-picker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
collapse: false,
sideBySide: true,
useCurrent: false,
stepping: 5,
widgetPositioning: {
horizontal: 'left',
vertical: 'bottom'
},
minDate: moment($this.attr('min-date')).isValid() ? $this.attr('min-date') : false,
maxDate: moment($this.attr('max-date')).isValid() ? $this.attr('max-date') : false,
});
});
//fix per timestamp-picker non visibile con la classe table-responsive
$('.timestamp-picker').each(function () {
$this = $(this);
$this.on("dp.show", function (e) {
$('#tecnici > div').removeClass('table-responsive');
});
$this.on("dp.hide", function (e) {
$('#tecnici > div').addClass('table-responsive');
})
});
$('.datepicker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
useCurrent: false,
format: 'L',
minDate: moment($this.attr('min-date')).isValid() ? $this.attr('min-date') : false,
maxDate: moment($this.attr('max-date')).isValid() ? $this.attr('max-date') : false,
});
});
$('.timepicker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
useCurrent: false,
format: 'LT',
stepping: 5,
minDate: moment($this.attr('min-date')).isValid() ? $this.attr('min-date') : false,
maxDate: moment($this.attr('max-date')).isValid() ? $this.attr('max-date') : false,
});
});
start_datepickers();
// Aggiunta nell'URL del nome tab su cui tornare dopo il submit
// Blocco del pulsante di submit dopo il primo submit

View File

@ -45,6 +45,42 @@ if (!function_exists('array_clean')) {
}
}
if (!function_exists('array_deep_clean')) {
/**
* Pulisce i contenuti vuoti di un array.
*
* @param $array
*
* @since 2.4.11
*
* @return array
*/
function array_deep_clean($input)
{
// If it is an element, then just return it
if (!is_array($input)) {
return $input;
}
$non_empty_items = [];
foreach ($input as $key => $value) {
// Ignore empty cells
if ($value) {
$cleaned = array_deep_clean($value);
// Use recursion to evaluate cells
if (!empty($cleaned)) {
$non_empty_items[$key] = $cleaned;
}
}
}
// Finally return the array without empty items
return $non_empty_items;
}
}
if (!function_exists('starts_with')) {
/**
* Check if a string starts with the given string.

View File

@ -4101,7 +4101,7 @@ msgstr ""
#: templates/fatture/footer.php:119 templates/interventi/body.php:477
#: templates/ordini/body.php:236 templates/preventivi/body.php:226
#: templates/preventivi_cons/body.php:497
msgid "Imponibile scontato"
msgid "Totale imponibile"
msgstr ""
#: modules/contratti/widgets/contratti.pianificazionedashboard.interventi.php:91

View File

@ -4282,7 +4282,7 @@ msgstr "discount _TOT_ _TYPE_"
#: templates/fatture/footer.php:119 templates/interventi/body.php:477
#: templates/ordini/body.php:236 templates/preventivi/body.php:226
#: templates/preventivi_cons/body.php:497
msgid "Imponibile scontato"
msgid "Totale imponibile"
msgstr "Taxable discounted"
#: modules/contratti/widgets/contratti.pianificazionedashboard.interventi.php:91

View File

@ -1,20 +0,0 @@
<?php
switch ($resource) {
case 'allegato':
$module = Modules::get($request['module']);
$upload = Uploads::upload($_FILES['upload'], [
'name' => $request['name'],
'id_module' => $module['id'],
'id_record' => $request['id'],
]);
$response['filename'] = $upload;
break;
}
return [
'allegato',
];

View File

@ -1,64 +0,0 @@
<?php
switch ($resource) {
case 'updates':
$custom_where = !empty($updated) ? ' WHERE updated_at >= '.prepare($updated) : '';
$excluded = explode(',', setting('Tabelle escluse per la sincronizzazione API automatica'));
// Attenzione: query specifica per MySQL
$datas = $dbo->fetchArray("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA=".prepare($db_name));
if (!empty($datas)) {
foreach ($datas as $data) {
if (!in_array($data['TABLE_NAME'], $excluded)) {
$response[$data['TABLE_NAME']] = $dbo->fetchArray('SELECT * FROM '.$data['TABLE_NAME'].$custom_where);
}
}
}
break;
// Attualmente vengono considerate solo le tabelle che eseguono l'eliminazione fisica della riga
case 'deleted':
$excluded = explode(',', setting('Tabelle escluse per la sincronizzazione API automatica'));
// Attenzione: query specifica per MySQL
$datas = $dbo->fetchArray("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA=".prepare($db_name));
if (!empty($datas)) {
foreach ($datas as $data) {
$table_name = $data['TABLE_NAME'];
// Ottiene il nome della colonna di tipo AUTO_INCREMENT della tabella
$column = $dbo->fetchArray('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '.prepare($table_name)." AND EXTRA LIKE '%AUTO_INCREMENT%' AND TABLE_SCHEMA = ".prepare($db_name))[0]['COLUMN_NAME'];
if (!in_array($table_name, $excluded) && !empty($column)) {
// Ottiene il valore successivo della colonna di tipo AUTO_INCREMENT
$auto_inc = $dbo->fetchArray('SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '.prepare($table_name).' AND TABLE_SCHEMA = '.prepare($db_name))[0]['AUTO_INCREMENT'];
// Ottiene i vuoti all'interno della sequenza AUTO_INCREMENT
$steps = $dbo->fetchArray('SELECT (t1.'.$column.' + 1) as start, (SELECT MIN(t3.'.$column.') - 1 FROM '.$table_name.' t3 WHERE t3.'.$column.' > t1.'.$column.') as end FROM '.$table_name.' t1 WHERE NOT EXISTS (SELECT t2.'.$column.' FROM '.$table_name.' t2 WHERE t2.'.$column.' = t1.'.$column.' + 1) ORDER BY start');
$total = [];
foreach ($steps as $step) {
if ($step['end'] == null) {
$step['end'] = $auto_inc - 1;
}
if ($step['end'] >= $step['start']) {
$total = array_merge($total, range($step['start'], $step['end']));
}
}
$response[$table_name] = $total;
}
}
}
break;
}
/*
return [
'updates',
'deleted',
];
*/

View File

@ -1,22 +0,0 @@
<?php
switch ($resource) {
case 'add_anagrafica':
$rs = $dbo->fetchArray('SELECT codice FROM an_anagrafiche ORDER BY CAST(codice AS SIGNED) DESC LIMIT 0, 1');
$codice = Util\Generator::generate(setting('Formato codice anagrafica'), $rs[0]['codice']);
// Inserisco l'anagrafica
$dbo->insert('an_anagrafiche', [
'ragione_sociale' => $request['data']['ragione_sociale'],
'codice' => $codice,
]);
// Inserisco il rapporto dell'anagrafica (cliente, tecnico, ecc)
$dbo->sync('an_tipianagrafiche_anagrafiche', ['idanagrafica' => $dbo->lastInsertedID()], ['idtipoanagrafica' => (array) $request['data']['tipi']]);
break;
}
return [
'add_anagrafica',
];

View File

@ -1,20 +0,0 @@
<?php
switch ($resource) {
case 'delete_anagrafica':
$id_azienda = $dbo->fetchArray("SELECT idtipoanagrafica FROM an_tipianagrafiche WHERE descrizione='Azienda'")[0]['idtipoanagrafica'];
$anagrafica = $dbo->fetchArray('SELECT an_tipianagrafiche.idtipoanagrafica FROM an_tipianagrafiche INNER JOIN an_tipianagrafiche_anagrafiche ON an_tipianagrafiche.idtipoanagrafica=an_tipianagrafiche_anagrafiche.idtipoanagrafica WHERE idanagrafica='.prepare($request['id']));
$tipi = array_column($anagrafica, 'idtipoanagrafica');
// Se l'anagrafica non è l'azienda principale, la disattivo
if (!in_array($id_azienda, $tipi)) {
$dbo->query('UPDATE an_anagrafiche SET deleted_at = NOW() WHERE idanagrafica = '.prepare($request['id']));
}
break;
}
return [
'delete_anagrafica',
];

View File

@ -1,63 +0,0 @@
<?php
switch ($resource) {
case 'an_anagrafiche':
$table = 'an_anagrafiche';
if (empty($order)) {
$order[] = 'idanagrafica';
}
if (empty($where['deleted_at'])) {
$where['deleted_at'] = null;
}
break;
// Elenco clienti per l'applicazione
case 'clienti':
$query = "SELECT an_anagrafiche.idanagrafica AS id,
an_anagrafiche.ragione_sociale,
an_anagrafiche.piva,
an_anagrafiche.codice_fiscale,
an_anagrafiche.indirizzo,
an_anagrafiche.indirizzo2,
an_anagrafiche.citta,
an_anagrafiche.cap,
an_anagrafiche.provincia,
an_anagrafiche.km,
IFNULL(an_anagrafiche.lat, 0.00) AS latitudine,
IFNULL(an_anagrafiche.lng, 0.00) AS longitudine,
an_nazioni.nome AS nazione,
an_anagrafiche.telefono,
an_anagrafiche.fax,
an_anagrafiche.cellulare,
an_anagrafiche.email,
an_anagrafiche.sitoweb,
an_anagrafiche.note,
an_anagrafiche.idzona,
an_anagrafiche.deleted_at
FROM an_anagrafiche
LEFT OUTER JOIN an_nazioni ON an_anagrafiche.id_nazione=an_nazioni.id
WHERE
an_anagrafiche.deleted_at IS NULL AND
an_anagrafiche.idanagrafica IN (SELECT idanagrafica FROM an_tipianagrafiche_anagrafiche WHERE idtipoanagrafica = (SELECT idtipoanagrafica FROM an_tipianagrafiche WHERE descrizione = 'Cliente'))
ORDER BY an_anagrafiche.ragione_sociale";
break;
// Elenco sedi per l'applicazione
case 'sedi':
$table = 'an_sedi';
if (empty($order)) {
$order[] = 'id';
}
break;
}
return [
'an_anagrafiche',
'clienti',
'sedi',
];

View File

@ -1,28 +0,0 @@
<?php
switch ($resource) {
case 'update_anagrafica':
// Inserisco l'anagrafica
$dbo->update('an_anagrafiche', [
'ragione_sociale' => $request['data']['ragione_sociale'],
'piva' => $request['data']['piva'],
'codice_fiscale' => $request['data']['codice_fiscale'],
'indirizzo' => $request['data']['indirizzo'],
'citta' => $request['data']['citta'],
'provincia' => $request['data']['provincia'],
'id_nazione' => $request['data']['id_nazione'],
'telefono' => $request['data']['telefono'],
'fax' => $request['data']['fax'],
'cellulare' => $request['data']['cellulare'],
'email' => $request['data']['email'],
], ['idanagrafica' => $request['id']]);
// Inserisco il rapporto dell'anagrafica (cliente, tecnico, ecc)
$dbo->sync('an_tipianagrafiche_anagrafiche', ['idanagrafica' => $request['id']], ['idtipoanagrafica' => (array) $request['data']['tipi']]);
break;
}
return [
'update_anagrafica',
];

View File

@ -0,0 +1,107 @@
<?php
namespace Modules\Anagrafiche\API\v1;
use API\Interfaces\CreateInterface;
use API\Interfaces\DeleteInterface;
use API\Interfaces\RetrieveInterface;
use API\Interfaces\UpdateInterface;
use API\Resource;
use Modules;
use Modules\Anagrafiche\Anagrafica;
class Anagrafiche extends Resource implements RetrieveInterface, CreateInterface, UpdateInterface, DeleteInterface
{
public function retrieve($request)
{
$query = 'SELECT an_anagrafiche.idanagrafica AS id,
an_anagrafiche.ragione_sociale,
an_anagrafiche.piva,
an_anagrafiche.codice_fiscale,
an_anagrafiche.indirizzo,
an_anagrafiche.indirizzo2,
an_anagrafiche.citta,
an_anagrafiche.cap,
an_anagrafiche.provincia,
an_anagrafiche.km,
IFNULL(an_anagrafiche.lat, 0.00) AS latitudine,
IFNULL(an_anagrafiche.lng, 0.00) AS longitudine,
an_nazioni.nome AS nazione,
an_anagrafiche.telefono,
an_anagrafiche.fax,
an_anagrafiche.cellulare,
an_anagrafiche.email,
an_anagrafiche.sitoweb,
an_anagrafiche.note,
an_anagrafiche.idzona,
an_anagrafiche.deleted_at
FROM an_anagrafiche
LEFT OUTER JOIN an_nazioni ON an_anagrafiche.id_nazione=an_nazioni.id
WHERE
1=1 AND an_anagrafiche.deleted_at IS NULL';
$types = $request['filter']['type'];
$types = explode(',', $types);
$types = array_clean($types);
$filters = [];
foreach ($types as $type) {
$filters[] = 'an_anagrafiche.idanagrafica IN (SELECT idanagrafica FROM an_tipianagrafiche_anagrafiche WHERE idtipoanagrafica = (SELECT idtipoanagrafica FROM an_tipianagrafiche WHERE descrizione = '.prepare($type).'))';
}
$query .= !empty($filters) ? ' AND ('.implode('OR ', $filters).')' : '';
$query .= '
HAVING 2=2
ORDER BY an_anagrafiche.ragione_sociale';
$module = Modules::get('Anagrafiche');
$query = Modules::replaceAdditionals($module->id, $query);
return [
'query' => $query,
];
}
public function create($request)
{
$ragione_sociale = $request['data']['ragione_sociale'];
$id_tipo = (array) $request['data']['tipi'];
$anagrafica = Anagrafica::build($ragione_sociale, null, null, $id_tipo);
$id_record = $anagrafica->id;
return [
'id' => $id_record,
];
}
public function delete($request)
{
$anagrafica = Anagrafica::find($request['id']);
$result = $anagrafica->delete();
}
public function update($request)
{
$data = $request['data'];
$anagrafica = Anagrafica::find($request['id']);
$anagrafica->ragione_sociale = $data['ragione_sociale'];
$anagrafica->piva = $data['piva'];
$anagrafica->codice_fiscale = $data['codice_fiscale'];
$anagrafica->indirizzo = $data['indirizzo'];
$anagrafica->citta = $data['citta'];
$anagrafica->provincia = $data['provincia'];
$anagrafica->id_nazione = $data['id_nazione'];
$anagrafica->telefono = $data['telefono'];
$anagrafica->fax = $data['fax'];
$anagrafica->cellulare = $data['cellulare'];
$anagrafica->email = $data['email'];
$anagrafica->tipologie = (array) $data['tipi'];
$anagrafica->save();
}
}

View File

@ -261,6 +261,13 @@ class Anagrafica extends Model
return $this;
}
public function delete()
{
if (!$this->isAzienda()) {
return parent::delete();
}
}
// Metodi statici
/**

View File

@ -3,8 +3,8 @@
include_once __DIR__.'/../../core.php';
use Modules\Anagrafiche\Anagrafica;
$name = get('name');
$value = get('value');
$name = filter('name');
$value = filter('value');
switch ($name) {
case 'codice':

View File

@ -1,12 +0,0 @@
<?php
switch ($resource) {
case 'articoli':
$query = 'SELECT *, (SELECT nome FROM mg_categorie WHERE id = mg_articoli.id_categoria) AS categoria, (SELECT nome FROM mg_categorie WHERE id = mg_articoli.id_sottocategoria) AS sottocategoria FROM mg_articoli WHERE attivo = 1';
break;
}
return [
'articoli',
];

View File

@ -0,0 +1,21 @@
<?php
namespace Modules\Articoli\API\v1;
use API\Interfaces\RetrieveInterface;
use API\Resource;
class Articoli extends Resource implements RetrieveInterface
{
public function retrieve($request)
{
$query = 'SELECT *,
(SELECT nome FROM mg_categorie WHERE id = mg_articoli.id_categoria) AS categoria,
(SELECT nome FROM mg_categorie WHERE id = mg_articoli.id_sottocategoria) AS sottocategoria
FROM mg_articoli WHERE attivo = 1';
return [
'query' => $query,
];
}
}

View File

@ -1,17 +1,18 @@
<?php
namespace Modules\Articoli\API\v1;
use API\Interfaces\CreateInterface;
use API\Resource;
use Modules\Articoli\Articolo;
switch ($resource) {
case 'movimento_articolo':
class Movimenti extends Resource implements CreateInterface
{
public function create($request)
{
$data = $request['data'];
$articolo = Articolo::find($data['id_articolo']);
$articolo->movimenta($data['qta'], $data['descrizione'], $data['data'], true);
break;
}
}
return [
'movimento_articolo',
];

View File

@ -4,15 +4,6 @@ include_once __DIR__.'/../../core.php';
$_SESSION['superselect']['id_categoria'] = $record['id_categoria'];
$img = null;
if (!empty($record['immagine'])) {
$fileinfo = Uploads::fileInfo($record['immagine']);
$default_img = '/'.Uploads::getDirectory($id_module).'/'.$fileinfo['filename'].'_thumb600.'.$fileinfo['extension'];
$img = file_exists(DOCROOT.$default_img) ? ROOTDIR.$default_img : ROOTDIR.'/'.Uploads::getDirectory($id_module).'/'.$record['immagine'];
}
?><form action="" method="post" id="edit-form" enctype="multipart/form-data">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update">
@ -26,7 +17,7 @@ if (!empty($record['immagine'])) {
<div class="panel-body">
<div class="row">
<div class="col-md-3">
{[ "type": "image", "label": "<?php echo tr('Immagine'); ?>", "name": "immagine", "class": "img-thumbnail", "value": "<?php echo $img; ?>" ]}
{[ "type": "image", "label": "<?php echo tr('Immagine'); ?>", "name": "immagine", "class": "img-thumbnail", "value": "<?php echo $articolo->image; ?>" ]}
</div>
<div class="col-md-4">

View File

@ -3,7 +3,9 @@
namespace Modules\Articoli;
use Common\Model;
use Modules;
use Modules\Interventi\Components\Articolo as ArticoloIntervento;
use Uploads;
class Articolo extends Model
{
@ -65,8 +67,36 @@ class Articolo extends Model
return true;
}
public function articolo()
public function articoli()
{
return $this->hasMany(ArticoloIntervento::class, 'idarticolo');
}
public function getImageAttribute()
{
if (empty($this->immagine)) {
return null;
}
$module = Modules::get($this->module);
$fileinfo = Uploads::fileInfo($this->immagine);
$directory = '/'.$module->upload_directory.'/';
$image = $directory.$this->immagine;
$image_thumbnail = $directory.$fileinfo['filename'].'_thumb600.'.$fileinfo['extension'];
$url = file_exists(DOCROOT.$image_thumbnail) ? ROOTDIR.$image_thumbnail : ROOTDIR.$image;
return $url;
}
/**
* Restituisce il nome del modulo a cui l'oggetto è collegato.
*
* @return string
*/
public function getModuleAttribute()
{
return 'Articoli';
}
}

View File

@ -4,8 +4,8 @@ include_once __DIR__.'/../../core.php';
use Modules\Articoli\Articolo;
$name = get('name');
$value = get('value');
$name = filter('name');
$value = filter('value');
switch ($name) {
case 'codice':

View File

@ -3,7 +3,9 @@
include_once __DIR__.'/../../core.php';
use Modules\Anagrafiche\Anagrafica;
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Contratti\Components\Articolo;
use Modules\Contratti\Components\Descrizione;
use Modules\Contratti\Components\Riga;
use Modules\Contratti\Components\Sconto;
use Modules\Contratti\Contratto;
@ -67,27 +69,27 @@ switch (post('op')) {
}
// Salvataggio costi attività unitari del contratto
foreach (post('costo_ore') as $idtipointervento => $valore) {
$rs = $dbo->fetchArray('SELECT * FROM co_contratti_tipiintervento WHERE idcontratto='.prepare($id_record).' AND idtipointervento='.prepare($idtipointervento));
foreach (post('costo_ore') as $id_tipo => $valore) {
$rs = $dbo->fetchArray('SELECT * FROM co_contratti_tipiintervento WHERE idcontratto='.prepare($id_record).' AND idtipointervento='.prepare($id_tipo));
// Se non esiste il record lo inserisco...
if (sizeof($rs) == 0) {
// Se almeno un valore è diverso da 0 inserisco l'importo...
if (post('costo_ore')[$idtipointervento] != 0 || post('costo_km')[$idtipointervento] != 0 || post('costo_dirittochiamata')[$idtipointervento] != 0) {
$dbo->query('INSERT INTO co_contratti_tipiintervento(idcontratto, idtipointervento, costo_ore, costo_km, costo_dirittochiamata, costo_ore_tecnico, costo_km_tecnico, costo_dirittochiamata_tecnico) VALUES('.prepare($id_record).', '.prepare($idtipointervento).', '.prepare(post('costo_ore')[$idtipointervento]).', '.prepare(post('costo_km')[$idtipointervento]).', '.prepare(post('costo_dirittochiamata')[$idtipointervento]).', '.prepare(post('costo_ore_tecnico')[$idtipointervento]).', '.prepare(post('costo_km_tecnico')[$idtipointervento]).', '.prepare(post('costo_dirittochiamata_tecnico')[$idtipointervento]).')');
if (post('costo_ore')[$id_tipo] != 0 || post('costo_km')[$id_tipo] != 0 || post('costo_dirittochiamata')[$id_tipo] != 0) {
$dbo->query('INSERT INTO co_contratti_tipiintervento(idcontratto, idtipointervento, costo_ore, costo_km, costo_dirittochiamata, costo_ore_tecnico, costo_km_tecnico, costo_dirittochiamata_tecnico) VALUES('.prepare($id_record).', '.prepare($id_tipo).', '.prepare(post('costo_ore')[$id_tipo]).', '.prepare(post('costo_km')[$id_tipo]).', '.prepare(post('costo_dirittochiamata')[$id_tipo]).', '.prepare(post('costo_ore_tecnico')[$id_tipo]).', '.prepare(post('costo_km_tecnico')[$id_tipo]).', '.prepare(post('costo_dirittochiamata_tecnico')[$id_tipo]).')');
}
}
// ...altrimenti...
else {
// Aggiorno il nuovo valore se è diverso da 0...
if (post('costo_ore')[$idtipointervento] != 0 || post('costo_km')[$idtipointervento] != 0 || post('costo_dirittochiamata')[$idtipointervento] != 0) {
$dbo->query('UPDATE co_contratti_tipiintervento SET costo_ore='.prepare(post('costo_ore')[$idtipointervento]).', costo_km='.prepare(post('costo_km')[$idtipointervento]).', costo_dirittochiamata='.prepare(post('costo_dirittochiamata')[$idtipointervento]).', costo_ore_tecnico='.prepare(post('costo_ore_tecnico')[$idtipointervento]).', costo_km_tecnico='.prepare(post('costo_km_tecnico')[$idtipointervento]).', costo_dirittochiamata_tecnico='.prepare(post('costo_dirittochiamata_tecnico')[$idtipointervento]).' WHERE idcontratto='.prepare($id_record).' AND idtipointervento='.prepare($idtipointervento));
if (post('costo_ore')[$id_tipo] != 0 || post('costo_km')[$id_tipo] != 0 || post('costo_dirittochiamata')[$id_tipo] != 0) {
$dbo->query('UPDATE co_contratti_tipiintervento SET costo_ore='.prepare(post('costo_ore')[$id_tipo]).', costo_km='.prepare(post('costo_km')[$id_tipo]).', costo_dirittochiamata='.prepare(post('costo_dirittochiamata')[$id_tipo]).', costo_ore_tecnico='.prepare(post('costo_ore_tecnico')[$id_tipo]).', costo_km_tecnico='.prepare(post('costo_km_tecnico')[$id_tipo]).', costo_dirittochiamata_tecnico='.prepare(post('costo_dirittochiamata_tecnico')[$id_tipo]).' WHERE idcontratto='.prepare($id_record).' AND idtipointervento='.prepare($id_tipo));
}
// ...altrimenti cancello l'eventuale riga
else {
$dbo->query('DELETE FROM co_contratti_tipiintervento WHERE idcontratto='.prepare($id_record).' AND idtipointervento='.prepare($idtipointervento));
$dbo->query('DELETE FROM co_contratti_tipiintervento WHERE idcontratto='.prepare($id_record).' AND idtipointervento='.prepare($id_tipo));
}
}
}
@ -119,6 +121,42 @@ switch (post('op')) {
break;
case 'manage_articolo':
if (post('idriga') != null) {
$articolo = Articolo::find(post('idriga'));
} else {
$originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($contratto, $originale);
}
$qta = post('qta');
$articolo->descrizione = post('descrizione');
$articolo->um = post('um') ?: null;
$articolo->id_iva = post('idiva');
//$articolo->prezzo_unitario_acquisto = post('prezzo_acquisto') ?: 0;
$articolo->prezzo_unitario_vendita = post('prezzo');
$articolo->sconto_unitario = post('sconto');
$articolo->tipo_sconto = post('tipo_sconto');
try {
$articolo->qta = $qta;
} catch (UnexpectedValueException $e) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
}
$articolo->save();
if (post('idriga') != null) {
flash()->info(tr('Articolo modificato!'));
} else {
flash()->info(tr('Articolo aggiunto!'));
}
break;
case 'manage_sconto':
if (post('idriga') != null) {
$sconto = Sconto::find(post('idriga'));
@ -142,108 +180,69 @@ switch (post('op')) {
break;
// Aggiungo una riga al contratto
case 'addriga':
$idiva = post('idiva');
$idarticolo = post('idarticolo');
$descrizione = post('descrizione');
case 'manage_riga':
if (post('idriga') != null) {
$riga = Riga::find(post('idriga'));
} else {
$riga = Riga::build($contratto);
}
$qta = post('qta');
$prezzo = post('prezzo');
// Calcolo dello sconto
$sconto_unitario = post('sconto');
$tipo_sconto = post('tipo_sconto');
$sconto = calcola_sconto([
'sconto' => $sconto_unitario,
'prezzo' => $prezzo,
'tipo' => $tipo_sconto,
'qta' => $qta,
]);
$riga->descrizione = post('descrizione');
$riga->um = post('um') ?: null;
$subtot = $prezzo * $qta;
$riga->id_iva = post('idiva');
$um = post('um');
//$riga->prezzo_unitario_acquisto = post('prezzo_acquisto') ?: 0;
$riga->prezzo_unitario_vendita = post('prezzo');
$riga->sconto_unitario = post('sconto');
$riga->tipo_sconto = post('tipo_sconto');
// Lettura iva dell'articolo
$rs2 = $dbo->fetchArray('SELECT percentuale, descrizione, indetraibile FROM co_iva WHERE id='.prepare($idiva));
$iva = ($prezzo * $qta - $sconto) / 100 * $rs2[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $rs2[0]['indetraibile'];
$desc_iva = $rs2[0]['descrizione'];
$riga->qta = $qta;
$dbo->query('INSERT INTO co_righe_contratti(idcontratto, idarticolo, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, um, qta, sconto, sconto_unitario, tipo_sconto, is_descrizione, `order`) VALUES ('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($subtot).', '.prepare($um).', '.prepare($qta).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare(empty($qta)).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_contratti AS t WHERE idcontratto='.prepare($id_record).'))');
$riga->save();
// Messaggi informativi
if (!empty($idarticolo)) {
flash()->info(tr('Articolo aggiunto!'));
} elseif (!empty($qta)) {
if (post('idriga') != null) {
flash()->info(tr('Riga modificata!'));
} else {
flash()->info(tr('Riga aggiunta!'));
}
break;
case 'manage_descrizione':
if (post('idriga') != null) {
$riga = Descrizione::find(post('idriga'));
} else {
$riga = Descrizione::build($contratto);
}
$riga->descrizione = post('descrizione');
$riga->save();
if (post('idriga') != null) {
flash()->info(tr('Riga descrittiva modificata!'));
} else {
flash()->info(tr('Riga descrittiva aggiunta!'));
}
break;
case 'editriga':
$idriga = post('idriga');
$rs = $dbo->fetchArray("SELECT * FROM co_righe_contratti WHERE id='".$idriga."'");
$is_descrizione = $rs[0]['is_descrizione'];
$idarticolo = post('idarticolo');
$descrizione = post('descrizione');
$qta = post('qta');
$prezzo = post('prezzo');
$subtot = $prezzo * $qta;
// Calcolo dello sconto
$sconto_unitario = post('sconto');
$tipo_sconto = post('tipo_sconto');
$sconto = calcola_sconto([
'sconto' => $sconto_unitario,
'prezzo' => $prezzo,
'tipo' => $tipo_sconto,
'qta' => $qta,
]);
$idiva = post('idiva');
$um = post('um');
// Calcolo iva
$query = 'SELECT percentuale, descrizione, indetraibile FROM co_iva WHERE id='.prepare($idiva);
$rs = $dbo->fetchArray($query);
$iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $rs[0]['indetraibile'];
$desc_iva = $rs[0]['descrizione'];
// Modifica riga generica sul documento
if ($is_descrizione == 0) {
$query = 'UPDATE co_righe_contratti SET idarticolo='.prepare($idarticolo).', idiva='.prepare($idiva).', desc_iva='.prepare($desc_iva).', iva='.prepare($iva).', iva_indetraibile='.prepare($iva_indetraibile).', descrizione='.prepare($descrizione).', subtotale='.prepare($subtot).', sconto='.prepare($sconto).', sconto_unitario='.prepare($sconto_unitario).', tipo_sconto='.prepare($tipo_sconto).', um='.prepare($um).', qta='.prepare($qta).' WHERE id='.prepare($idriga);
} else {
$query = 'UPDATE co_righe_contratti SET descrizione='.prepare($descrizione).' WHERE id='.prepare($idriga);
}
$dbo->query($query);
flash()->info(tr('Riga modificata!'));
break;
// Eliminazione riga
case 'delriga':
if (post('idriga') !== null) {
$idriga = post('idriga');
case 'delete_riga':
$id_riga = post('idriga');
if ($id_riga !== null) {
$riga = Descrizione::find($id_riga) ?: Riga::find($id_riga);
$riga = $riga ? $riga : Articolo::find($id_riga);
$riga = $riga ? $riga : Sconto::find($id_riga);
$query = 'DELETE FROM `co_righe_contratti` WHERE idcontratto='.prepare($id_record).' AND id='.prepare($idriga);
$riga->delete();
if ($dbo->query($query)) {
flash()->info(tr('Riga eliminata!'));
}
flash()->info(tr('Riga eliminata!'));
}
// Ricalcolo il budget
$dbo->query('UPDATE co_contratti SET budget=( SELECT SUM(subtotale) FROM co_righe_contratti GROUP BY idcontratto HAVING idcontratto=co_contratti.id ) WHERE id='.prepare($id_record));
break;
// Scollegamento intervento da contratto
@ -261,22 +260,22 @@ switch (post('op')) {
}
break;
case 'update_position':
$orders = explode(',', $_POST['order']);
$order = 0;
case 'update_position':
$orders = explode(',', $_POST['order']);
$order = 0;
foreach ($orders as $idriga) {
$dbo->query('UPDATE `co_righe_contratti` SET `order`='.prepare($order).' WHERE id='.prepare($idriga));
++$order;
}
foreach ($orders as $idriga) {
$dbo->query('UPDATE `co_righe_contratti` SET `order`='.prepare($order).' WHERE id='.prepare($idriga));
++$order;
}
break;
break;
// eliminazione contratto
case 'delete':
$dbo->query('DELETE FROM co_contratti WHERE id='.prepare($id_record));
$dbo->query('DELETE FROM co_promemoria WHERE idcontratto='.prepare($id_record));
$dbo->query('DELETE FROM co_righe_contratti WHERE idcontratto='.prepare($id_record));
$contratto->delete();
flash()->info(tr('Contratto eliminato!'));

View File

@ -2,26 +2,17 @@
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
use Modules\Contratti\Contratto;
$documento = Contratto::find($id_record);
$options = [
'op' => 'add_contratto',
'id_importazione' => 'id_contratto',
'final_module' => 'Fatture di vendita',
'original_module' => $module['name'],
'sql' => [
'table' => 'co_contratti',
'rows' => 'co_righe_contratti',
'id_rows' => 'idcontratto',
],
'op' => 'add_documento',
'type' => 'contratto',
'module' => 'Fatture di vendita',
'button' => tr('Aggiungi'),
'dir' => 'entrata',
'create_document' => true,
'documento' => $documento,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
echo App::load('importa.php', [], $options, true);

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

@ -53,8 +53,8 @@ if (!empty($rsi)) {
// Tabella con i dati
foreach ($rsi as $int) {
$int = array_merge($int, get_costi_intervento($int['id']));
$totale_stato[$int['idstatointervento']] = sum($totale_stato[$int['idstatointervento']], $int['totale_scontato']);
$intervento = \Modules\Interventi\Intervento::find($int['id']);
$totale_stato[$int['idstatointervento']] = sum($totale_stato[$int['idstatointervento']], $intervento->totale_imponibile);
// Riga intervento singolo
echo '
@ -76,15 +76,15 @@ if (!empty($rsi)) {
</td>
<td class="text-right">
'.Translator::numberToLocale($int['totale_costo']).'
'.Translator::numberToLocale($intervento->spesa).'
</td>
<td class="text-right">
'.Translator::numberToLocale($int['totale_addebito']).'
'.Translator::numberToLocale($intervento->imponibile).'
</td>
<td class="text-right">
'.Translator::numberToLocale($int['totale_scontato']).'
'.Translator::numberToLocale($intervento->totale_imponibile).'
</td>
</tr>';

View File

@ -1,377 +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, 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[]", "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" 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>";
// Pianificazione
echo "
<button type='button' class='btn btn-primary' onclick=\"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

@ -1,251 +0,0 @@
<?php
include_once __DIR__.'/../../../core.php';
/*
Salvataggio voci di servizio
*/
if (filter('op') == 'save_ordineservizio') {
$n_errors = 0;
if (post('eseguito') !== null) {
foreach (post('eseguito') as $idvoceservizio => $eseguito) {
$presenza = post('presenza')[$idvoceservizio];
$esito = post('esito')[$idvoceservizio];
$priorita = post('priorita')[$idvoceservizio];
if (!$dbo->query('UPDATE co_ordiniservizio_vociservizio SET eseguito='.prepare($eseguito).', presenza='.prepare($presenza).', esito='.prepare($esito).', priorita='.prepare($priorita).', note='.prepare(post('note_ods')[$idvoceservizio]).' WHERE id='.prepare($idvoceservizio))) {
++$n_errors;
}
}
}
if ($n_errors == 0) {
flash()->info(tr('Voci di servizio salvate correttamente!'));
} else {
flash()->error(tr('Errore durante il salvataggio delle voci di servizio!'));
}
// Aggiornamento 4 spunte
$dbo->query('UPDATE co_ordiniservizio SET copia_centrale='.prepare(post('copia_centrale')).', copia_cliente='.prepare(post('copia_cliente')).', copia_amministratore='.prepare(post('copia_amministratore')).'", funzionamento_in_sicurezza='.prepare(post('funzionamento_in_sicurezza')).' WHERE idintervento='.prepare($id_record));
}
/*
Visualizzazione voci di servizio collegate a questo intervento
*/
// Info principali
$rs = $dbo->fetchArray('SELECT * FROM co_ordiniservizio WHERE idintervento='.prepare($idintervento));
$check_copia_centrale = $rs[0]['copia_centrale'];
$check_copia_cliente = $rs[0]['copia_cliente'];
$check_copia_amministratore = $rs[0]['copia_amministratore'];
$check_funzionamento_in_sicurezza = $rs[0]['funzionamento_in_sicurezza'];
if (sizeof($rs) == 0) {
echo '
<p>'.tr('Nessun collegamento a ordini di servizio')."...</p>\n";
} else {
echo '
<p>'.tr('Ordine di servizio numero _NUM_ (termine massimo _DATE_)', [
'_NUM_' => '<b>'.$rs[0]['id'].'</b>',
'_DATE_' => Translator::dateToLocale($rs[0]['data_scadenza']),
]).':</p>';
$rs = $dbo->fetchArray('SELECT * FROM co_ordiniservizio_vociservizio WHERE idordineservizio=(SELECT id FROM co_ordiniservizio WHERE idintervento='.prepare($idintervento).' LIMIT 0,1) ORDER BY categoria ASC');
echo '
<form action="'.$rootdir.'/editor.php?id_module='.Modules::get('Interventi')['id'].'&id_record='.$id_record.'&idordineservizio='.$rs[0]['idordineservizio'].'&op=save_ordineservizio" method="post" id="form-ordineservizio">
<div class="row">
<div class="col-md-9">
<table class="table table-hover table-striped">
<tr>
<th width="30%">'.tr('Voce di servizio').'</th>
<th>'.tr('Presenza').'</th>
<th>'.tr('Eseguito').'</th>
<th>'.tr('Esito').'</th>
<th>'.tr('Priorità').'</th>
<th width="30%">'.tr('Note').'</th>
</tr>';
$prev_cat = '';
for ($i = 0; $i < sizeof($rs); ++$i) {
if ($prev_cat != $rs[$i]['categoria']) {
echo '
<tr>
<th colspan="6">'.$rs[$i]['categoria'].'</th>
</tr>';
}
echo '
<tr>
<td>'.$rs[$i]['voce'].'</td>';
// Presenza SI
if ($rs[$i]['presenza'] == '1') {
$attr_si = 'checked="true"';
$attr_no = '';
}
// Presenza NO
elseif ($rs[$i]['presenza'] == '-1') {
$attr_si = '';
$attr_no = 'checked="true"';
}
// Nessuna spunta
else {
$attr_si = '';
$attr_no = '';
}
echo '
<td>
<div>
<input type="radio" name="presenza['.$rs[$i]['id'].']" value="1" '.$attr_si.'> '.tr('').'<br>
<input type="radio" name="presenza['.$rs[$i]['id'].']" value="-1" '.$attr_no.'> '.tr('No').'
</div>
</td>';
// Eseguito SI
if ($rs[$i]['eseguito'] == '1') {
$attr_si = 'checked="true"';
$attr_no = '';
}
// Eseguito NO
elseif ($rs[$i]['eseguito'] == '-1') {
$attr_si = '';
$attr_no = 'checked="true"';
}
// Nessuna spunta
else {
$attr_si = '';
$attr_no = '';
}
echo '
<td>
<div>
<input type="radio" name="eseguito['.$rs[$i]['id'].']" value="1" '.$attr_si.'> '.tr('').'<br>
<input type="radio" name="eseguito['.$rs[$i]['id'].']" value="-1" '.$attr_no.'> '.tr('No').'
</div>
</td>';
// Esito SI
if ($rs[$i]['esito'] == '1') {
$attr_si = 'checked="true"';
$attr_no = '';
}
// Esito NO
elseif ($rs[$i]['esito'] == '-1') {
$attr_si = '';
$attr_no = 'checked="true"';
}
// Nessuna spunta
else {
$attr_si = '';
$attr_no = '';
}
echo '
<td>
<div>
<input type="radio" name="esito['.$rs[$i]['id'].']" value="1" '.$attr_si.'> '.tr('Pos.').'<br>
<input type="radio" name="esito['.$rs[$i]['id'].']" value="-1" '.$attr_no.'> '.tr('Neg.').'
</div>
</td>';
// Priorità 1
if ($rs[$i]['priorita'] == '1') {
$attr_1 = 'checked="true"';
$attr_2 = '';
$attr_3 = '';
}
// Priorità 2
elseif ($rs[$i]['priorita'] == '2') {
$attr_1 = '';
$attr_2 = 'checked="true"';
$attr_3 = '';
}
// Priorità 3
elseif ($rs[$i]['priorita'] == '3') {
$attr_1 = '';
$attr_2 = '';
$attr_3 = 'checked="true"';
}
// Nessuna priorità
else {
$attr_1 = '';
$attr_2 = '';
$attr_3 = '';
}
echo '
<td>
<div>
<input type="radio" name="priorita['.$rs[$i]['id'].']" value="3" '.$attr_si.'> '.tr('A').'<br>
<input type="radio" name="priorita['.$rs[$i]['id'].']" value="2" '.$attr_no.'> '.tr('M').'
<input type="radio" name="priorita['.$rs[$i]['id'].']" value="-1" '.$attr_no.'> '.tr('B').'
</div>
</td>';
echo '
<td>
{[ "type": "text", "name": "note_ods['.$rs[$i]['id'].']", "value": "'.$rs[$i]['note'].'" ]}
</td>';
$prev_cat = $rs[$i]['categoria'];
}
echo '
</tr>
</table>
</div>';
// Parte destra
echo '
<div class="col-md-3">';
echo '
{[ "type": "checkbox", "label": "'.tr('Consegnata copia in centrale').'", "name": "copia_centrale", "value": "'.$check_copia_centrale.'" ]}';
echo '
{[ "type": "checkbox", "label": "'.tr('Consegnata copia al cliente').'", "name": "copia_cliente", "value": "'.$check_copia_cliente.'" ]}';
echo '
{[ "type": "checkbox", "label": "'.tr("Consegnata copia all'amministratore").'", "name": "copia_amministratore", "value": "'.$check_copia_amministratore.'" ]}';
if ($check_funzionamento_in_sicurezza == '1') {
$attr = 'checked="true"';
} else {
$attr = '';
}
echo '
{[ "type": "checkbox", "label": "'.tr("L'impianto può funzionare in sicurezza").'", "name": "funzionamento_in_sicurezza", "value": "'.$check_funzionamento_in_sicurezza.'" ]}';
echo '
</div>
</div>
<div class="clearfix"></div>
<button type="button" class="btn btn-success" onclick="if( confirm(\'Salvere le modifiche?\') ){ $(\'#form-ordineservizio\').submit(); }">
<i class="fa fa-check"></i> '.tr('Salva modifiche').'
</button>
</form>';
/*
Stampa intervento con voci di servizio
*/
echo '
<div class="text-center">
'.Prints::getLink('Ordine di servizio', $id_record, 'btn-primary', tr('Stampa ordine di servizio')).'
</div>';
}

View File

@ -1,361 +0,0 @@
<?php
include_once __DIR__.'/../../../core.php';
/*
GESTIONE ORDINI DI SERVIZIO
*/
// 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'),
];
// Generazione ordini di servizio
if (get('op') == 'add_ordineservizio') {
$prev_data = '';
// Ciclo fra le voci in arrivo dal form
foreach (post('voce') as $data_scadenza => $ordiniservizio) {
$data_scadenza = date_create_from_format('Ym', $data_scadenza)->format(Intl\Formatter::getStandardFormats()['date']);
// Ogni data può avere più voci di servizio da salvare
foreach ($ordiniservizio as $n => $idvoce) {
// Aggiunta ordine di servizio solo se la voce è spuntata
if (in_array($idvoce, post('idvoce'))) {
// Creazione ordine di servizio per data di scadenza
if ($prev_data != $data_scadenza) {
$dbo->query('INSERT INTO co_ordiniservizio(idcontratto, data_scadenza, idimpianto, stato) VALUES('.prepare($id_record).', '.prepare($data_scadenza).', '.prepare(post('matricola')).", 'aperto')");
$idordineservizio = $dbo->lastInsertedID();
}
$dbo->query('INSERT INTO co_ordiniservizio_vociservizio(idordineservizio, voce, categoria, eseguito) VALUES('.prepare($idordineservizio).', (SELECT descrizione FROM in_vociservizio WHERE id='.prepare($idvoce).'), (SELECT categoria FROM in_vociservizio WHERE id='.prepare($idvoce).'), 0 )');
}
$prev_data = $data_scadenza;
}
}
flash()->info(tr('Ordini di servizio generati correttamente!'));
}
// Eliminazione pianificazione specifica
elseif (get('op') == 'del_ordineservizio') {
$idordineservizio = get('idordineservizio');
$n = $dbo->fetchNum('SELECT id FROM co_ordiniservizio WHERE id='.prepare($idordineservizio)." AND stato='aperto'");
if ($n == 1) {
// Eliminazione ordine di servizio
if ($dbo->query('DELETE FROM co_ordiniservizio WHERE id='.prepare($idordineservizio))) {
// Eliminazione voci di servizio collegate
$dbo->query('DELETE FROM co_ordiniservizio_vociservizio WHERE idordineservizio='.prepare($idordineservizio));
flash()->info(tr('Ordine di servizio eliminato correttamente!'));
}
}
// Non si può eliminare l'ordine di servizio perché è chiuso
else {
flash()->info(tr('Ordine di servizio già chiuso, impossibile eliminarlo!'));
}
}
echo '
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Pianificazione ordini di servizio').'</h3>
</div>
<div class="box-body">';
echo '
<p>'.tr('Qui puoi programmare gli ordini di servizio del contratto').'.</p>';
/*
Ordini di servizio pianificati
*/
// (SELECT idsede FROM my_impianti WHERE idimpianto=co_ordiniservizio.idimpianto)
$rs = $dbo->fetchArray("SELECT *, (SELECT CONCAT_WS(' ', nomesede, citta) FROM an_sedi WHERE id=(SELECT idsede FROM my_impianti WHERE idimpianto=co_ordiniservizio.idimpianto LIMIT 0,1)) AS sede, (SELECT CONCAT_WS(' - ', matricola, nome) FROM my_impianti WHERE id=co_ordiniservizio.idimpianto) AS impianto, (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=co_ordiniservizio.idintervento) AS data_intervento FROM co_ordiniservizio WHERE idcontratto=".prepare($id_record).' ORDER BY data_scadenza ASC');
if (empty($rs)) {
echo '
<p>'.tr('Non sono ancora stati pianificati ordini di servizio').'...</p>';
} else {
echo '
<table class="table table-striped table-hover table-bordered table-condensed">
<tr>
<th width="10%">'.tr('Entro').'</th>
<th>'.tr('Sede').'</th>
<th width="20%">'.tr('Impianto').'</th>
<th width="10%">'.tr('Voci di servizio').'</th>
<th width="10%">'.tr('Stato').'</th>
<th width="3%"></th>
</tr>';
$prev_mese = '';
foreach ($rs as $r) {
echo '
<tr>
<td>';
// Data scadenza
if ($prev_mese != $r['data_scadenza']) {
echo '
<b>'.$mesi[intval(date('m', strtotime($r['data_scadenza']))) - 1].' '.date('Y', strtotime($r['data_scadenza'])).'</b>
</td>';
} else {
echo '
<small><em>'.$mesi[intval(date('m', strtotime($r['data_scadenza']))) - 1].' '.date('Y', strtotime($r['data_scadenza'])).'</em></small>';
}
// Sede
if ($r['sede'] == '') {
$sede = 'Sede legale';
} else {
$sede = $r['sede'];
}
echo '
<td>'.$sede.'</td>';
// Impianto
echo '
<td>
'.Modules::link('MyImpianti', $r['idimpianto'], $r['impianto']).'
</td>';
// Voci di servizio
$rs2 = $dbo->fetchArray('SELECT * FROM co_ordiniservizio_vociservizio WHERE idordineservizio='.prepare($r['id']).' ORDER BY categoria ASC');
echo '
<td class="text-center">
<button type="button" class="btn btn-primary btn-sm" onclick="launch_modal(\'Pianifica intervento\', \'#voci_'.$r['id'].'\' );">
<i class="fa fa-list"></i> '.tr('Visualizza').'... ('.sizeof($rs2).')
</button>';
// Popup voci di servizio
echo '
<div class="hide">
<div id="voci_'.$r['id'].'">';
if (empty($rs2)) {
echo '
<p>'.tr('Non sono state pianificate voci di servizio').'...</p>';
} else {
echo '
<table class="table table-bordered table-condensed table-hover table-striped">
<tr>
<th>'.tr('Voci di servizio').'</th>
<th width="40%">'.tr('Eseguito').'</th>
</tr>';
$prev_cat = '';
for ($v = 0; $v < sizeof($rs2); ++$v) {
if ($rs2[$v]['categoria'] != $prev_cat) {
echo '
<tr>
<th colspan="2">'.$rs2[$v]['categoria'].'</th>
</tr>';
}
echo '
<tr>
<td>'.$rs2[$v]['voce'].'</td>
<td>';
// intervento non ancora eseguito
if (empty($r['idintervento'])) {
echo '
<span class="text-warning">
<i class="fa fa-clock-o"></i> '.tr('non ancora eseguito').'
</span>';
} else {
$res = $dbo->fetchArray('SELECT codice FROM in_interventi WHERE id='.prepare($rsp[$i]['idintervento']));
echo '
<span class="text-success">
<i class="fa fa-check"></i>
'.Modules::link('Interventi', $r['idintervento'], tr('Intervento num. _NUM_ del _DATE_', [
'_NUM_' => $res['codice'],
'_DATE_' => Translator::dateToLocale($r[0]['data_intervento']),
])).'
</span>';
}
echo '
</td>
</tr>';
$prev_cat = $rs2[$v]['categoria'];
}
echo '
</table>';
}
echo '
</div>
</div>
</td>';
// Stato
echo '
<td class="text-center">';
if (empty($r['idintervento'])) {
echo '
<span class="text-warning"><i class="fa fa-clock-o"></i> '.tr('aperto').'</span>';
} else {
echo '
<span class="text-success"><i class="fa fa-check"></i> '.tr('chiuso').'/span>';
}
echo '
</td>';
// Funzioni
echo '
<td>';
if (empty($r['idintervento'])) {
echo '
<a class="btn btn-danger ask" data-backto="record-edit" data-method="get" data-op="del_ordineservizio" data-idordineservizio="'.$r['id'].'" data-msg="'.tr('Vuoi eliminare questa pianificazione?').'">
<i class="fa fa-trash"></i>
</a>';
}
echo '
</td>
</tr>';
$prev_mese = $r['data_scadenza'];
}
echo '
</table>';
}
echo '
<br><br>';
/*
Schema per aggiungere ordini di servizio
*/
$rs = $dbo->fetchArray('SELECT * FROM in_vociservizio ORDER BY categoria ASC');
if (empty($rs)) {
echo '
<p>
'.tr('Non sono ancora state inserite voci di servizio').'.
<a href="'.$rootdir.'/controller.php?id_module='.Modules::get('Voci di servizio')['id'].'">'.tr('Inizia ora').'...</a>
</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));
if (!empty($rs2[0]['data_accettazione']) && !empty($rs2[0]['data_conclusione'])) {
$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().removeClass(\'hide\'); $(this).remove();">
<i class="fa fa-calendar"></i> '.tr('Pianifica nuovi ordini di servizio').'
</button>
<form action="'.$rootdir.'/editor.php?id_module='.Modules::get('Contratti')['id'].'&id_record='.$id_record.'&op=add_ordineservizio" id="plan_form" method="post" class="no-check hide">
<input type="hidden" name="backto" value="record-edit">';
// Selezione impianto
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Impianto').'", "name": "matricola", "values": "query=SELECT my_impianti.id, CONCAT(my_impianti.matricola, \" - \", my_impianti.nome) AS descrizione, an_sedi.optgroup FROM my_impianti INNER JOIN (SELECT id, CONCAT(an_sedi.nomesede, \"(\", an_sedi.citta, \")\") AS optgroup FROM an_sedi WHERE idanagrafica='.prepare($record['idanagrafica']).' UNION SELECT 0, \'Sede legale\') AS an_sedi ON my_impianti.idsede = an_sedi.id WHERE my_impianti.idanagrafica='.prepare($record['idanagrafica']).' AND my_impianti.id NOT IN(SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto='.prepare($id_record).') ORDER BY idsede ASC, matricola ASC" ]}
</div>';
// Indice voci di servizio
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Voci di servizio da pianificare').'", "name": "idvoce[]", "values": "query=SELECT id, descrizione, categoria AS optgroup FROM in_vociservizio ORDER BY categoria ASC", "multiple": 1, "extra": "onchange=\"$(this).find(\'option\').each( function(){ if( $(this).is(\':selected\') ){ $(\'#voce_\'+$(this).val()).removeClass(\'hide\'); }else{ $(\'#voce_\'+$(this).val()).addClass(\'hide\'); } });\"" ]}
</div>
</div>';
// voci di servizio
foreach ($rs as $r) {
echo '
<div class="col-md-3 hide" id="voce_'.$r['id'].'">
<big><b>'.$r['id'].' - '.$r['descrizione'].'</b></big>
<hr>';
for ($j = 0; $j < $n_mesi; ++$j) {
$id_mese = date('Ym', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month'));
$nome_mese = $mesi[intval(date('m', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month'))) - 1].' '.date('Y', strtotime($rs2[0]['data_accettazione'].' +'.$j.' month'));
echo '
<small>
<label for="m_'.$id_mese.'_'.$r['id'].'">
<input type="checkbox" id="m_'.$id_mese.'_'.$r['id'].'" name="voce['.$id_mese.'][]" value="'.$r['id'].'">
'.$nome_mese.'
</label>
</small><br>';
}
echo '
</div>';
}
echo '
<div class="clearfix"></div><br>';
echo '
<button type="button" class="btn btn-primary" onclick="if($(\'#matricola\').val() && $(\'#idvoce\').val() ){ if( confirm(\'Pianificare questo ordine di servizio?\') ){ $(\'#plan_form\').submit(); } } else { if ( !$(\'#matricola\').val()) {alert (\'Seleziona un impianto.\'); $(\'#matricola\').focus();}else { alert (\'Seleziona le voci di servizio da pianificare.\'); $(\'#idvoce\').focus(); } }">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>';
/*
Copia pianificazione da una già fatta per un impianto ad un'altra
*/
// Opzione di copia pianificazione solo se ci sono ancora impianti non pianificati
$query2 = 'SELECT * FROM my_impianti WHERE idanagrafica='.prepare($record['idanagrafica']).' AND id IN (SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto='.prepare($id_record).')';
$cont = $dbo->fetchNum($query2);
if ($cont > 0) {
// Elenco impianti già pianificati
echo '
<hr>
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Copiare la pianificazione da un altro impianto').'", "name": "matricola_src", "values": "query=SELECT my_impianti.id, CONCAT(my_impianti.matricola, \" - \", my_impianti.nome) AS descrizione, an_sedi.optgroup FROM my_impianti INNER JOIN (SELECT id, CONCAT(an_sedi.nomesede, \"(\", an_sedi.citta, \")\") AS optgroup FROM an_sedi WHERE idanagrafica='.prepare($record['idanagrafica']).' UNION SELECT 0, \'Sede legale\') AS an_sedi ON my_impianti.idsede = an_sedi.id WHERE my_impianti.idanagrafica='.prepare($record['idanagrafica']).' AND my_impianti.id IN(SELECT idimpianto FROM co_ordiniservizio WHERE idcontratto='.prepare($id_record).') ORDER BY idsede ASC, matricola ASC" ]}
</div>
</div>';
echo '
<div class="clearfix"></div><br>';
echo '
<button type="button" class="btn btn-primary" onclick="copia_pianificazione_os( \''.$id_record.'\', $(\'#matricola_src option:selected\').val() );">
<i class="fa fa-upload"></i>'.tr('Carica questa pianificazione').'
</button>';
}
echo '
</form>';
} else {
echo '
<p>'.tr('Le date di accettazione e conclusione del contratto non sono ancora state impostate').'</p>';
}
}
echo '
</div>
</div>';

View File

@ -9,11 +9,11 @@ $documento = Contratto::find($id_record);
// Impostazioni per la gestione
$options = [
'op' => 'addriga',
'op' => 'manage_riga',
'action' => 'add',
'dir' => $documento->direzione,
'idanagrafica' => $documento['idanagrafica'],
'imponibile_scontato' => $documento->imponibile_scontato,
'totale_imponibile' => $documento->totale_imponibile,
];
// Dati di default
@ -35,6 +35,8 @@ $result['idiva'] = $iva[0]['idiva'] ?: setting('Iva predefinita');
$file = 'riga';
if (get('is_descrizione') !== null) {
$file = 'descrizione';
$options['op'] = 'manage_descrizione';
} elseif (get('is_articolo') !== null) {
$file = 'articolo';
@ -45,6 +47,8 @@ if (get('is_descrizione') !== null) {
$result['sconto_unitario'] = $listino['prc_guadagno'];
$result['tipo_sconto'] = 'PRC';
}
$options['op'] = 'manage_articolo';
} elseif (get('is_sconto') !== null) {
$file = 'sconto';

View File

@ -9,11 +9,11 @@ $documento = Contratto::find($id_record);
// Impostazioni per la gestione
$options = [
'op' => 'editriga',
'op' => 'manage_riga',
'action' => 'edit',
'dir' => $documento->direzione,
'idanagrafica' => $documento['idanagrafica'],
'imponibile_scontato' => $documento->imponibile_scontato,
'totale_imponibile' => $documento->totale_imponibile,
];
// Dati della riga
@ -23,14 +23,16 @@ $riga = $documento->getRighe()->find($id_riga);
$result = $riga->toArray();
$result['prezzo'] = $riga->prezzo_unitario_vendita;
// Importazione della gestione dedicata
// Importazione della gestione dedicata
$file = 'riga';
if ($riga->isDescrizione()) {
$file = 'descrizione';
$options['op'] = 'manage_descrizione';
} elseif ($riga->isArticolo()) {
$file = 'articolo';
$options['op'] = 'manage_articolo';
} elseif ($riga->isSconto()) {
$file = 'sconto';

View File

@ -2,10 +2,8 @@
include_once __DIR__.'/../../core.php';
/*
ARTICOLI + RIGHE GENERICHE
*/
$rs = $dbo->fetchArray('SELECT *, round(sconto_unitario,'.setting('Cifre decimali per importi').') AS sconto_unitario, round(sconto,'.setting('Cifre decimali per importi').') AS sconto, round(subtotale,'.setting('Cifre decimali per importi').') AS subtotale, IFNULL((SELECT codice FROM mg_articoli WHERE id=idarticolo), "") AS codice FROM co_righe_contratti WHERE idcontratto='.prepare($id_record).' ORDER BY `order`');
// Righe documento
$righe = $contratto->getRighe();
echo '
<table class="table table-striped table-hover table-condensed table-bordered">
@ -22,79 +20,71 @@ echo '
</thead>
<tbody class="sortable">';
foreach ($rs as $r) {
foreach ($righe as $riga) {
echo '
<tr data-id="'.$riga->id.'">';
// Descrizione
$descrizione = nl2br($riga->descrizione);
if ($riga->isArticolo()) {
$descrizione = Modules::link('Articoli', $riga->idarticolo, $riga->articolo->codice.' - '.$descrizione);
}
echo '
<tr data-id="'.$r['id'].'">
<td>';
if (!empty($r['idarticolo'])) {
echo Modules::link('Articoli', $r['idarticolo'], $r['codice'].' - '.$r['descrizione']);
<td>
'.$descrizione.'
</td>';
if ($riga->isDescrizione()) {
echo '
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>';
} else {
echo nl2br($r['descrizione']);
}
echo '
// Q.tà
echo '
<td class="text-center">
'.Translator::numberToLocale($riga->qta_rimanente, 'qta').' / '.Translator::numberToLocale($riga->qta, 'qta').'
</td>';
// Q.tà
echo '
<td class="text-center">';
if (empty($r['is_descrizione'])) {
// Unità di misura
echo '
<span >'.Translator::numberToLocale($r['qta'] - $r['qta_evasa'], 'qta').' / '.Translator::numberToLocale($r['qta'], 'qta').'</span>';
}
echo '
<td class="text-center">
'.$riga->um.'
</td>';
// um
echo '
<td class="text-center">';
if (empty($r['is_descrizione'])) {
// Costo unitario
echo '
'.$r['um'];
}
echo '
</td>';
<td class="text-right">
'.moneyFormat($riga->prezzo_unitario_vendita);
// Costo unitario
echo '
<td class="text-right">';
if (empty($r['is_descrizione'])) {
echo '
'.moneyFormat($r['subtotale'] / $r['qta']);
if (abs($riga->sconto_unitario) > 0) {
$text = $riga->sconto_unitario > 0 ? tr('sconto _TOT_ _TYPE_') : tr('maggiorazione _TOT_ _TYPE_');
if (abs($r['sconto_unitario']) > 0) {
echo '
<br><small class="label label-danger">'.tr('sconto _TOT_ _TYPE_', [
'_TOT_' => Translator::numberToLocale($r['sconto_unitario']),
'_TYPE_' => ($r['tipo_sconto'] == 'PRC' ? '%' : currency()),
<br><small class="label label-danger">'.replace($text, [
'_TOT_' => Translator::numberToLocale(abs($riga->sconto_unitario)),
'_TYPE_' => ($riga->tipo_sconto == 'PRC' ? '%' : currency()),
]).'</small>';
}
}
echo'
echo'
</td>';
// IVA
echo '
<td class="text-right">';
if (empty($r['is_descrizione'])) {
// IVA
echo '
'.moneyFormat($r['iva'])."<br>
<small class='help-block'>".$r['desc_iva'].'</small>';
}
echo '
<td class="text-right">
'.moneyFormat($riga->iva).'<br>
<small class="help-block">'.$riga->aliquota->descrizione.(($riga->aliquota->esente) ? ' ('.$riga->aliquota->codice_natura_fe.')' : null).'</small>
</td>';
// Imponibile
echo '
<td class="text-right">';
if (empty($r['is_descrizione'])) {
// Imponibile
echo '
'.moneyFormat($r['subtotale'] - $r['sconto']);
}
echo '
<td class="text-right">
'.moneyFormat($riga->imponibile_scontato).'
</td>';
}
// Possibilità di rimuovere una riga solo se il preventivo non è stato pagato
echo '
@ -102,20 +92,14 @@ foreach ($rs as $r) {
if ($record['stato'] != 'Pagato') {
echo '
<form action="'.$rootdir.'/editor.php?id_module='.Modules::get('Contratti')['id'].'&id_record='.$id_record.'" method="post" id="delete-form-'.$r['id'].'" role="form">
<form action="" method="post" id="delete-form-'.$riga->id.'" role="form">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="id_record" value="'.$id_record.'">
<input type="hidden" name="op" value="delriga">
<input type="hidden" name="idriga" value="'.$r['id'].'">
<input type="hidden" name="idarticolo" value="'.$r['idarticolo'].'">
<input type="hidden" name="op" value="delete_riga">
<input type="hidden" name="idriga" value="'.$riga->id.'">
<div class="btn-group">';
echo "
<a class='btn btn-xs btn-warning' onclick=\"launch_modal('Modifica riga', '".$rootdir.'/modules/contratti/row-edit.php?id_module='.$id_module.'&id_record='.$id_record.'&idriga='.$r['id']."', 1 );\"><i class='fa fa-edit'></i></a>
<a href='javascript:;' class='btn btn-xs btn-danger' title='Rimuovi questa riga' onclick=\"if( confirm('Rimuovere questa riga dal contratto?') ){ $('#delete-form-".$r['id']."').submit(); }\"><i class='fa fa-trash'></i></a>";
echo '
<div class="btn-group">
<a class="btn btn-xs btn-warning" onclick="editRow('.$riga->id.')"><i class="fa fa-edit"></i></a>
<a class="btn btn-xs btn-danger" onclick="deleteRow('.$riga->id.')"><i class="fa fa-trash"></i></a>
</div>
</form>';
}
@ -130,66 +114,62 @@ foreach ($rs as $r) {
</tr>';
}
// Calcoli
$imponibile = sum(array_column($rs, 'subtotale'));
$sconto = sum(array_column($rs, 'sconto'));
$iva = sum(array_column($rs, 'iva'));
echo '
<script>
function editRow(id){
launch_modal("'.tr('Modifica riga').'", "'.$module->fileurl('row-edit.php').'?id_module=" + globals.id_module + "&id_record=" + globals.id_record + "&idriga=" + id);
}
$imponibile_scontato = sum($imponibile, -$sconto);
$totale = sum([
$imponibile_scontato,
$iva,
]);
function deleteRow(id){
if(confirm("'.tr('Rimuovere questa riga dal documento?').'")){
$("#delete-form-" + id).submit();
}
}
</script>';
echo '
</tbody>';
// Calcoli
$imponibile = abs($contratto->imponibile);
$sconto = $contratto->sconto;
$totale_imponibile = abs($contratto->totale_imponibile);
$iva = abs($contratto->iva);
$totale = abs($contratto->totale);
// Totale totale imponibile
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Imponibile', [], ['upper' => true]).':</b>
</td>
<td class="text-right">
'.moneyFormat($contratto->imponibile, 2).'
</td>
<td></td>
</tr>';
// SCONTO
if (abs($sconto) > 0) {
// Totale imponibile scontato
if (!empty($sconto)) {
echo '
<tr>
<td colspan="5"" class="text-right">
<b>'.tr('Imponibile', [], ['upper' => true]).':</b>
<td colspan="5" class="text-right">
<b><span class="tip" title="'.tr('Un importo positivo indica uno sconto, mentre uno negativo indica una maggiorazione').'"> <i class="fa fa-question-circle-o"></i> '.tr('Sconto/maggiorazione', [], ['upper' => true]).':</span></b>
</td>
<td class="text-right">
<span id="budget">'.moneyFormat($imponibile, 2).'</span>
'.moneyFormat($contratto->sconto, 2).'
</td>
<td></td>
</tr>';
// Totale totale imponibile
echo '
<tr>
<td colspan="5"" class="text-right">
<b>'.tr('Sconto', [], ['upper' => true]).':</b>
<td colspan="5" class="text-right">
<b>'.tr('Totale imponibile', [], ['upper' => true]).':</b>
</td>
<td class="text-right">
'.moneyFormat($sconto, 2).'
</td>
<td></td>
</tr>';
// Totale imponibile scontato
echo '
<tr>
<td colspan="5"" class="text-right">
<b>'.tr('Imponibile scontato', [], ['upper' => true]).':</b>
</td>
<td class="text-right">
'.moneyFormat($imponibile_scontato, 2).'
</td>
<td></td>
</tr>';
} else {
// Totale imponibile
echo '
<tr>
<td colspan="5"" class="text-right">
<b>'.tr('Imponibile', [], ['upper' => true]).':</b>
</td>
<td class="text-right">
<span id="budget">'.moneyFormat($imponibile, 2).'</span>
'.moneyFormat($totale_imponibile, 2).'
</td>
<td></td>
</tr>';
@ -198,11 +178,11 @@ if (abs($sconto) > 0) {
// Totale iva
echo '
<tr>
<td colspan="5"" class="text-right">
<td colspan="5" class="text-right">
<b>'.tr('Iva', [], ['upper' => true]).':</b>
</td>
<td class="text-right">
'.moneyFormat($iva, 2).'
'.moneyFormat($contratto->iva, 2).'
</td>
<td></td>
</tr>';
@ -210,11 +190,11 @@ echo '
// Totale contratto
echo '
<tr>
<td colspan="5"" class="text-right">
<td colspan="5" class="text-right">
<b>'.tr('Totale', [], ['upper' => true]).':</b>
</td>
<td class="text-right">
'.moneyFormat($totale, 2).'
'.moneyFormat($contratto->totale, 2).'
</td>
<td></td>
</tr>';
@ -238,7 +218,7 @@ $(document).ready(function(){
order += ","+$(this).data("id");
});
order = order.replace(/^,/, "");
$.post("'.$rootdir.'/actions.php", {
id: ui.item.data("id"),
id_module: '.$id_module.',

View File

@ -10,6 +10,8 @@ class Articolo extends Article
{
use RelationTrait;
public $movimenta_magazzino = false;
protected $table = 'co_righe_contratti';
/**
@ -27,7 +29,7 @@ class Articolo extends Article
return $model;
}
public function movimenta($qta)
public function movimentaMagazzino($qta)
{
return;
}

View File

@ -20,4 +20,12 @@ trait RelationTrait
{
return $this->parent();
}
public function delete()
{
$parent = $this->parent;
$parent->save();
return parent::delete();
}
}

View File

@ -3,6 +3,7 @@
namespace Modules\Contratti;
use Carbon\Carbon;
use Common\Components\Description;
use Common\Document;
use Modules\Anagrafiche\Anagrafica;
use Modules\Interventi\Intervento;
@ -60,15 +61,6 @@ class Contratto extends Document
return $model;
}
public function save(array $options = [])
{
$result = parent::save($options);
$this->fixTipiSessioni();
return $result;
}
public function fixTipiSessioni()
{
$database = database();
@ -142,6 +134,60 @@ class Contratto extends Document
return $this->hasMany(Intervento::class, 'id_contratto');
}
public function fixBudget()
{
$this->budget = $this->imponibile_scontato ?: 0;
}
public function save(array $options = [])
{
$this->fixBudget();
$result = parent::save($options);
$this->fixTipiSessioni();
return $result;
}
/**
* Effettua un controllo sui campi del documento.
* Viene richiamatp dalle modifiche alle righe del documento.
*
* @param Description $trigger
*/
public function fixStato(Description $trigger)
{
parent::fixStato($trigger);
$righe = $this->getRighe();
$qta_evasa = $righe->sum('qta_evasa');
$qta = $righe->sum('qta');
$parziale = $qta != $qta_evasa;
// Impostazione del nuovo stato
if ($qta_evasa == 0) {
$descrizione = 'In lavorazione';
$descrizione_intervento = 'Completato';
} else {
$descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato';
$descrizione_intervento = 'Fatturato';
}
$stato = Stato::where('descrizione', $descrizione)->first();
$this->stato()->associate($stato);
$this->save();
// Trasferimento degli interventi collegati
$interventi = $this->interventi;
$stato_intervento = \Modules\Interventi\Stato::where('descrizione', $descrizione_intervento)->first();
foreach ($interventi as $intervento) {
$intervento->stato()->associate($stato_intervento);
$intervento->save();
}
}
// Metodi statici
/**

View File

@ -3,6 +3,7 @@
include_once __DIR__.'/../../core.php';
use Modules\Anagrafiche\Anagrafica;
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\DDT\Components\Articolo;
use Modules\DDT\Components\Descrizione;
use Modules\DDT\Components\Riga;
@ -88,6 +89,11 @@ switch (post('op')) {
'bollo' => 0,
'rivalsainps' => 0,
'ritenutaacconto' => 0,
'id_documento_fe' => post('id_documento_fe'),
'codice_cup' => post('codice_cup'),
'codice_cig' => post('codice_cig'),
'num_item' => post('num_item'),
], ['id' => $id_record]);
$query = 'SELECT descrizione FROM dt_statiddt WHERE id='.prepare($idstatoddt);
@ -110,75 +116,35 @@ switch (post('op')) {
}
break;
case 'addarticolo':
if (post('idarticolo') !== null) {
$dir = post('dir');
$idarticolo = post('idarticolo');
$descrizione = post('descrizione');
$idiva = post('idiva');
$qta = post('qta');
$prezzo = post('prezzo');
// Calcolo dello sconto
$sconto_unitario = post('sconto');
$tipo_sconto = post('tipo_sconto');
$sconto = calcola_sconto([
'sconto' => $sconto_unitario,
'prezzo' => $prezzo,
'tipo' => $tipo_sconto,
'qta' => $qta,
]);
add_articolo_inddt($id_record, $idarticolo, $descrizione, $idiva, $qta, post('um'), $prezzo * $qta, $sconto, $sconto_unitario, $tipo_sconto);
// Ricalcolo inps, ritenuta e bollo
ricalcola_costiagg_ddt($id_record);
aggiorna_sedi_movimenti('ddt', $id_record);
flash()->info(tr('Articolo aggiunto!'));
}
break;
case 'addriga':
// Selezione costi da intervento
$descrizione = post('descrizione');
$idiva = post('idiva');
$um = post('um');
$prezzo = post('prezzo');
$qta = post('qta');
// Calcolo dello sconto
$sconto_unitario = post('sconto');
$tipo_sconto = post('tipo_sconto');
$sconto = calcola_sconto([
'sconto' => $sconto_unitario,
'prezzo' => $prezzo,
'tipo' => $tipo_sconto,
'qta' => $qta,
]);
$subtot = $prezzo * $qta;
// Calcolo iva
$query = 'SELECT descrizione, percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva);
$rs = $dbo->fetchArray($query);
$iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $rs[0]['indetraibile'];
$query = 'INSERT INTO dt_righe_ddt(idddt, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, is_descrizione, `order`) VALUES('.prepare($id_record).', '.prepare($idiva).', '.prepare($rs[0]['descrizione']).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', '.prepare(empty($qta)).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM dt_righe_ddt AS t WHERE idddt='.prepare($id_record).'))';
$dbo->query($query);
// Messaggi informativi
if (!empty($idarticolo)) {
flash()->info(tr('Articolo aggiunto!'));
} elseif (!empty($qta)) {
flash()->info(tr('Riga aggiunta!'));
case 'manage_articolo':
if (post('idriga') != null) {
$articolo = Articolo::find(post('idriga'));
} else {
flash()->info(tr('Riga descrittiva aggiunta!'));
$originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($ddt, $originale);
}
$articolo->descrizione = post('descrizione');
$articolo->um = post('um') ?: null;
$articolo->id_iva = post('idiva');
$articolo->prezzo_unitario_acquisto = post('prezzo_acquisto') ?: 0;
$articolo->prezzo_unitario_vendita = post('prezzo');
$articolo->sconto_unitario = post('sconto');
$articolo->tipo_sconto = post('tipo_sconto');
try {
$articolo->qta = post('qta');
} catch (UnexpectedValueException $e) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
}
$articolo->save();
if (post('idriga') != null) {
flash()->info(tr('Articolo modificato!'));
} else {
flash()->info(tr('Articolo aggiunto!'));
}
// Ricalcolo inps, ritenuta e bollo
@ -212,9 +178,59 @@ switch (post('op')) {
break;
case 'manage_riga':
if (post('idriga') != null) {
$riga = Riga::find(post('idriga'));
} else {
$riga = Riga::build($ddt);
}
$riga->descrizione = post('descrizione');
$riga->um = post('um') ?: null;
$riga->id_iva = post('idiva');
$riga->prezzo_unitario_acquisto = post('prezzo_acquisto') ?: 0;
$riga->prezzo_unitario_vendita = post('prezzo');
$riga->sconto_unitario = post('sconto');
$riga->tipo_sconto = post('tipo_sconto');
$riga->qta = post('qta');
$riga->save();
if (post('idriga') != null) {
flash()->info(tr('Riga modificata!'));
} else {
flash()->info(tr('Riga aggiunta!'));
}
// Ricalcolo inps, ritenuta e bollo
ricalcola_costiagg_ddt($id_record);
break;
case 'manage_descrizione':
if (post('idriga') != null) {
$riga = Descrizione::find(post('idriga'));
} else {
$riga = Descrizione::build($ddt);
}
$riga->descrizione = post('descrizione');
$riga->save();
if (post('idriga') != null) {
flash()->info(tr('Riga descrittiva modificata!'));
} else {
flash()->info(tr('Riga descrittiva aggiunta!'));
}
break;
// Aggiunta di un ordine in ddt
case 'add_ordine':
$ordine = \Modules\Ordini\Ordine::find(post('id_ordine'));
$ordine = \Modules\Ordini\Ordine::find(post('id_documento'));
// Creazione della fattura al volo
if (post('create_document') == 'on') {
@ -222,12 +238,17 @@ switch (post('op')) {
$ddt = DDT::build($ordine->anagrafica, $tipo, post('data'));
$ddt->idpagamento = $ordine->idpagamento;
$ddt->id_documento_fe = $ordine->id_documento_fe;
$ddt->codice_cup = $ordine->codice_cup;
$ddt->codice_cig = $ordine->codice_cig;
$ddt->num_item = $ordine->num_item;
$ddt->save();
$id_record = $ddt->id;
}
$parziale = false;
$righe = $ordine->getRighe();
foreach ($righe as $riga) {
if (post('evadere')[$riga->id] == 'on') {
@ -246,22 +267,10 @@ switch (post('op')) {
$copia->save();
}
if ($riga->qta != $riga->qta_evasa) {
$parziale = true;
}
}
// Impostazione del nuovo stato
$descrizione = $parziale ? 'Parzialmente evaso' : 'Evaso';
$stato = \Modules\Ordini\Stato::where('descrizione', $descrizione)->first();
$ordine->stato()->associate($stato);
$ordine->save();
ricalcola_costiagg_ddt($id_record);
aggiorna_sedi_movimenti('ddt', $id_record);
flash()->info(tr('Ordine _NUM_ aggiunto!', [
'_NUM_' => $ordine->numero,
]));
@ -286,8 +295,6 @@ switch (post('op')) {
ricalcola_costiagg_ddt($id_record, 0, 0, 0);
}
aggiorna_sedi_movimenti('ddt', $id_record);
flash()->info(tr('Articolo rimosso!'));
break;
@ -324,139 +331,18 @@ switch (post('op')) {
}
break;
// Modifica riga
case 'editriga':
if (post('idriga') !== null) {
// Selezione costi da intervento
$idriga = post('idriga');
$descrizione = post('descrizione');
$prezzo = post('prezzo');
$qta = post('qta');
// Calcolo dello sconto
$sconto_unitario = post('sconto');
$tipo_sconto = post('tipo_sconto');
$sconto = calcola_sconto([
'sconto' => $sconto_unitario,
'prezzo' => $prezzo,
'tipo' => $tipo_sconto,
'qta' => $qta,
]);
$idiva = post('idiva');
$um = post('um');
$subtot = $prezzo * $qta;
// Lettura idarticolo dalla riga ddt
$rs = $dbo->fetchArray('SELECT * FROM dt_righe_ddt WHERE id='.prepare($idriga));
$idarticolo = $rs[0]['idarticolo'];
$idordine = $rs[0]['idordine'];
$old_qta = $rs[0]['qta'];
$is_descrizione = $rs[0]['is_descrizione'];
// Controllo per gestire i serial
if (!empty($idarticolo)) {
if (!controlla_seriali('id_riga_ddt', $idriga, $old_qta, $qta, $dir)) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
return;
}
}
// Se c'è un collegamento ad un ordine, aggiorno la quantità evasa
if (!empty($idordine)) {
$dbo->query('UPDATE or_righe_ordini SET qta_evasa=qta_evasa-'.$old_qta.' + '.$qta.' WHERE descrizione='.prepare($rs[0]['descrizione']).' AND idarticolo='.prepare($rs[0]['idarticolo']).' AND idordine='.prepare($idordine).' AND idiva='.prepare($rs[0]['idiva']));
}
// Calcolo iva
$query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva);
$rs = $dbo->fetchArray($query);
$iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $rs[0]['indetraibile'];
$desc_iva = $rs[0]['descrizione'];
// Modifica riga generica sul ddt
if ($is_descrizione == 0) {
$query = 'UPDATE dt_righe_ddt SET idiva='.prepare($idiva).', desc_iva='.prepare($desc_iva).', iva='.prepare($iva).', iva_indetraibile='.prepare($iva_indetraibile).', descrizione='.prepare($descrizione).', subtotale='.prepare($subtot).', sconto='.prepare($sconto).', sconto_unitario='.prepare($sconto_unitario).', tipo_sconto='.prepare($tipo_sconto).', um='.prepare($um).', qta='.prepare($qta).' WHERE id='.prepare($idriga);
} else {
$query = 'UPDATE dt_righe_ddt SET descrizione='.prepare($descrizione).' WHERE id='.prepare($idriga);
}
if ($dbo->query($query)) {
if (!empty($idarticolo)) {
// Controlli aggiuntivi sulle quantità evase degli ordini
if (!empty($idordine) && $qta > 0) {
$rs = $dbo->fetchArray('SELECT qta_evasa, qta FROM or_righe_ordini WHERE idordine='.prepare($idordine).' AND idarticolo='.prepare($idarticolo));
$qta_ordine = $qta;
if ($qta > $rs[0]['qta_evasa']) {
$qta_ordine = ($qta > $rs[0]['qta']) ? $rs[0]['qta'] : $qta;
}
$dbo->query('UPDATE or_righe_ordini SET qta_evasa = '.prepare($qta_ordine).' WHERE idordine='.prepare($idordine).' AND idarticolo='.prepare($idarticolo));
}
$new_qta = $qta - $old_qta;
$new_qta = ($dir == 'entrata') ? -$new_qta : $new_qta;
add_movimento_magazzino($idarticolo, $new_qta, ['idddt' => $id_record]);
}
flash()->info(tr('Riga modificata!'));
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_ddt($id_record);
} else {
ricalcola_costiagg_ddt($id_record);
}
}
}
aggiorna_sedi_movimenti('ddt', $id_record);
break;
// eliminazione ddt
case 'delete':
// Se ci sono degli articoli collegati
$rs = $dbo->fetchArray('SELECT id, idarticolo FROM dt_righe_ddt WHERE idddt='.prepare($id_record));
try {
$ddt->delete();
foreach ($rs as $value) {
$non_rimovibili = seriali_non_rimuovibili('id_riga_ddt', $value['id'], $dir);
if (!empty($non_rimovibili)) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
$dbo->query('DELETE FROM mg_movimenti WHERE idddt='.prepare($id_record));
return;
}
flash()->info(tr('Ddt eliminato!'));
} catch (InvalidArgumentException $e) {
flash()->error(tr('Sono stati utilizzati alcuni serial number nel documento: impossibile procedere!'));
}
for ($i = 0; $i < sizeof($rs); ++$i) {
if ($rs[$i]['idarticolo']) {
rimuovi_articolo_daddt($rs[$i]['idarticolo'], $id_record, $rs[$i]['id']);
}
}
// Se delle righe sono state create da un ordine, devo riportare la quantità evasa nella tabella degli ordini
// al valore di prima, riaggiungendo la quantità che sto togliendo
$rs = $dbo->fetchArray('SELECT qta, descrizione, idarticolo, idordine, idiva FROM dt_righe_ddt WHERE idddt='.prepare($id_record).' AND idarticolo="0"');
// Rimpiazzo la quantità negli ordini
for ($i = 0; $i < sizeof($rs); ++$i) {
$dbo->query('UPDATE or_righe_ordini SET qta_evasa=qta_evasa-'.$rs[$i]['qta'].' WHERE descrizione='.prepare($rs[$i]['descrizione']).' AND idarticolo='.prepare($rs[$i]['idarticolo']).' AND idordine='.prepare($rs[$i]['idordine']).' AND idiva='.prepare($rs[$i]['idiva']));
}
$dbo->query('DELETE FROM dt_ddt WHERE id='.prepare($id_record));
$dbo->query('DELETE FROM dt_righe_ddt WHERE idddt='.prepare($id_record));
$dbo->query('DELETE FROM mg_movimenti WHERE idddt='.prepare($id_record));
//Aggiorno gli stati degli ordini
if (setting('Cambia automaticamente stato ordini fatturati')) {
for ($i = 0; $i < sizeof($rs); ++$i) {
$dbo->query('UPDATE or_ordini SET idstatoordine=(SELECT id FROM or_statiordine WHERE descrizione="'.get_stato_ordine($rs[$i]['idordine']).'") WHERE id = '.prepare($rs[$i]['idordine']));
}
}
flash()->info(tr('Ddt eliminato!'));
break;
case 'add_serial':

View File

@ -2,33 +2,24 @@
include_once __DIR__.'/../../core.php';
use Modules\DDT\DDT;
$documento = DDT::find($id_record);
$module = Modules::get($id_module);
$final_module = $module['name'] == 'Ddt di vendita' ? 'Fatture di vendita' : 'Fatture di acquisto';
$dir = $module['name'] == 'Ddt di vendita' ? 'entrata' : 'uscita';
$options = [
'op' => 'add_ddt',
'id_importazione' => 'id_ddt',
'final_module' => $final_module,
'original_module' => $module['name'],
'sql' => [
'table' => 'dt_ddt',
'rows' => 'dt_righe_ddt',
'id_rows' => 'idddt',
],
'serials' => [
'id_riga' => 'id_riga_ddt',
'condition' => '(id_riga_documento IS NOT NULL)',
],
'op' => 'add_documento',
'type' => 'ddt',
'module' => $final_module,
'serials' => true,
'button' => tr('Aggiungi'),
'dir' => $dir,
'create_document' => true,
'documento' => $documento,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
echo App::load('importa.php', [], $options, true);

View File

@ -12,6 +12,7 @@ if ($module['name'] == 'Ddt di vendita') {
unset($_SESSION['superselect']['idanagrafica']);
unset($_SESSION['superselect']['idsede_partenza']);
unset($_SESSION['superselect']['idsede_destinazione']);
unset($_SESSION['superselect']['codice_modalita_pagamento_fe']);
$_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
$_SESSION['superselect']['idsede_partenza'] = $record['idsede_partenza'];
$_SESSION['superselect']['idsede_destinazione'] = $record['idsede_destinazione'];
@ -152,7 +153,7 @@ $_SESSION['superselect']['idsede_destinazione'] = $record['idsede_destinazione']
<div class="row">
<div class="col-md-3">
{[ "type": "select", "label": "<?php echo tr('Pagamento'); ?>", "name": "idpagamento", "values": "query=SELECT id, descrizione FROM co_pagamenti GROUP BY descrizione ORDER BY descrizione ASC", "value": "$idpagamento$", "readonly": "<?php echo $record['flag_completato']; ?>" ]}
{[ "type": "select", "label": "<?php echo tr('Pagamento'); ?>", "name": "idpagamento", "ajax-source": "pagamenti", "value": "$idpagamento$", "readonly": "<?php echo $record['flag_completato']; ?>" ]}
</div>
<div class="col-md-3">
@ -203,8 +204,35 @@ $_SESSION['superselect']['idsede_destinazione'] = $record['idsede_destinazione']
</div>
</div>
</div>
</form>
<!-- Fatturazione Elettronica PA-->
<div class="panel panel-primary <?php echo ($record['tipo_anagrafica'] == 'Ente pubblico' || $record['tipo_anagrafica'] == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Dati appalto'); ?></h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
{[ "type": "text", "label": "<?php echo tr('Identificatore Documento'); ?>", "name": "id_documento_fe", "required": 0, "help": "<?php echo tr('<span>Obbligatorio per valorizzare CIG/CUP. &Egrave; possible inserire: </span><ul><li>N. determina</li><li>RDO</li><li>Ordine MEPA</li></ul>'); ?>", "value": "$id_documento_fe$", "maxlength": 20, "readonly": "<?php echo $record['flag_completato']; ?>" ]}
</div>
<div class="col-md-6">
{[ "type": "text", "label": "<?php echo tr('Numero Riga'); ?>", "name": "num_item", "required": 0, "value": "$num_item$", "maxlength": 15, "readonly": "<?php echo $record['flag_completato']; ?>" ]}
</div>
</div>
<div class="row">
<div class="col-md-6">
{[ "type": "text", "label": "<?php echo tr('Codice CIG'); ?>", "name": "codice_cig", "required": 0, "value": "$codice_cig$", "maxlength": 15, "readonly": "<?php echo $record['flag_completato']; ?>" ]}
</div>
<div class="col-md-6">
{[ "type": "text", "label": "<?php echo tr('Codice CUP'); ?>", "name": "codice_cup", "required": 0, "value": "$codice_cup$", "maxlength": 15, "readonly": "<?php echo $record['flag_completato']; ?>" ]}
</div>
</div>
</div>
</div>
</form>
<!-- RIGHE -->
<div class="panel panel-primary">

View File

@ -14,11 +14,12 @@ if (isset($id_record)) {
$ddt = DDT::with('tipo', 'stato')->find($id_record);
$record = $dbo->fetchOne('SELECT *, dt_ddt.note, dt_ddt.idpagamento, dt_ddt.id AS idddt, dt_statiddt.descrizione AS `stato`, dt_tipiddt.descrizione AS `descrizione_tipodoc`,
(SELECT tipo FROM an_anagrafiche WHERE idanagrafica = dt_ddt.idanagrafica) AS tipo_anagrafica,
(SELECT completato FROM dt_statiddt WHERE dt_statiddt.id=dt_ddt.idstatoddt) AS flag_completato
FROM dt_ddt
LEFT OUTER JOIN dt_statiddt ON dt_ddt.idstatoddt=dt_statiddt.id
INNER JOIN an_anagrafiche ON dt_ddt.idanagrafica=an_anagrafiche.idanagrafica
INNER JOIN dt_tipiddt ON dt_ddt.idtipoddt=dt_tipiddt.id
LEFT OUTER JOIN dt_statiddt ON dt_ddt.idstatoddt=dt_statiddt.id
INNER JOIN an_anagrafiche ON dt_ddt.idanagrafica=an_anagrafiche.idanagrafica
INNER JOIN dt_tipiddt ON dt_ddt.idtipoddt=dt_tipiddt.id
WHERE dt_ddt.id='.prepare($id_record));
if (!empty($record)) {

View File

@ -10,11 +10,11 @@ $dir = $documento->direzione;
// Impostazioni per la gestione
$options = [
'op' => 'addriga',
'op' => 'manage_riga',
'action' => 'add',
'dir' => $documento->direzione,
'idanagrafica' => $documento['idanagrafica'],
'imponibile_scontato' => $documento->imponibile_scontato,
'totale_imponibile' => $documento->totale_imponibile,
];
// Dati di default
@ -36,6 +36,8 @@ $result['idiva'] = $iva[0]['idiva'] ?: setting('Iva predefinita');
$file = 'riga';
if (get('is_descrizione') !== null) {
$file = 'descrizione';
$options['op'] = 'manage_descrizione';
} elseif (get('is_articolo') !== null) {
$file = 'articolo';
@ -47,7 +49,7 @@ if (get('is_descrizione') !== null) {
$result['tipo_sconto'] = 'PRC';
}
$options['op'] = 'addarticolo';
$options['op'] = 'manage_articolo';
} elseif (get('is_sconto') !== null) {
$file = 'sconto';

View File

@ -9,11 +9,11 @@ $documento = DDT::find($id_record);
// Impostazioni per la gestione
$options = [
'op' => 'editriga',
'op' => 'manage_riga',
'action' => 'edit',
'dir' => $documento->direzione,
'idanagrafica' => $documento['idanagrafica'],
'imponibile_scontato' => $documento->imponibile_scontato,
'totale_imponibile' => $documento->totale_imponibile,
];
// Dati della riga
@ -27,8 +27,12 @@ $result['prezzo'] = $riga->prezzo_unitario_vendita;
$file = 'riga';
if ($riga->isDescrizione()) {
$file = 'descrizione';
$options['op'] = 'manage_descrizione';
} elseif ($riga->isArticolo()) {
$file = 'articolo';
$options['op'] = 'manage_articolo';
} elseif ($riga->isSconto()) {
$file = 'sconto';

View File

@ -102,9 +102,11 @@ if (!empty($rs)) {
'.moneyFormat($r['subtotale'] / $r['qta']);
if (abs($r['sconto_unitario']) > 0) {
$text = $r['sconto_unitario'] > 0 ? tr('sconto _TOT_ _TYPE_') : tr('maggiorazione _TOT_ _TYPE_');
echo '
<br><small class="label label-danger">'.tr('sconto _TOT_ _TYPE_', [
'_TOT_' => Translator::numberToLocale($r['sconto_unitario']),
<br><small class="label label-danger">'.replace($text, [
'_TOT_' => Translator::numberToLocale(abs($r['sconto_unitario'])),
'_TYPE_' => ($r['tipo_sconto'] == 'PRC' ? '%' : currency()),
]).'</small>';
}
@ -190,25 +192,11 @@ echo '
</tbody>';
// Calcoli
$imponibile = sum(array_column($rs, 'subtotale'));
$sconto = sum(array_column($rs, 'sconto'));
$iva = sum(array_column($rs, 'iva'));
$imponibile_scontato = sum($imponibile, -$sconto);
$totale_iva = sum($iva, $record['iva_rivalsainps']);
$totale = sum([
$imponibile_scontato,
$record['rivalsainps'],
$totale_iva,
]);
$netto_a_pagare = sum([
$totale,
//$marca_da_bollo, // Variabile non inizializzata!
-$record['ritenutaacconto'],
]);
$imponibile = abs($ddt->imponibile);
$sconto = $ddt->sconto;
$totale_imponibile = abs($ddt->totale_imponibile);
$iva = abs($ddt->iva);
$totale = abs($ddt->totale);
// IMPONIBILE
echo '
@ -224,12 +212,12 @@ echo '
<td></td>
</tr>';
if (abs($sconto) > 0) {
// SCONTO
// SCONTO
if (!empty($sconto)) {
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Sconto', [], ['upper' => true]).':</b>
<b><span class="tip" title="'.tr('Un importo positivo indica uno sconto, mentre uno negativo indica una maggiorazione').'"> <i class="fa fa-question-circle-o"></i> '.tr('Sconto/maggiorazione', [], ['upper' => true]).':</span></b>
</td>
<td align="right">
@ -239,51 +227,34 @@ if (abs($sconto) > 0) {
<td></td>
</tr>';
// IMPONIBILE SCONTATO
// TOTALE IMPONIBILE
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Imponibile scontato', [], ['upper' => true]).':</b>
<b>'.tr('Totale imponibile', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($imponibile_scontato, 2).'
'.moneyFormat($totale_imponibile, 2).'
</td>
<td></td>
</tr>';
}
// RIVALSA INPS
if (abs($record['rivalsainps']) > 0) {
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Rivalsa', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($record['rivalsainps'], 2).'
</td>
<td></td>
</tr>';
}
if (abs($totale_iva) > 0) {
echo '
// IVA
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('IVA', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($totale_iva, 2).'
'.moneyFormat($iva, 2).'
</td>
<td></td>
</tr>';
}
// TOTALE
echo '
@ -299,54 +270,6 @@ echo '
<td></td>
</tr>';
// Mostra marca da bollo se c'è
if (abs($record['bollo']) > 0) {
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Marca da bollo', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($record['bollo'], 2).'
</td>
<td></td>
</tr>';
}
// RITENUTA D'ACCONTO
if (abs($record['ritenutaacconto']) > 0) {
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr("Ritenuta d'acconto", [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($record['ritenutaacconto'], 2).'
</td>
<td></td>
</tr>';
}
// NETTO A PAGARE
if ($totale != $netto_a_pagare) {
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Netto a pagare', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($netto_a_pagare, 2).'
</td>
<td></td>
</tr>';
}
echo '
</table>';

View File

@ -28,7 +28,7 @@ class Articolo extends Article
return $model;
}
public function movimenta($qta)
public function movimentaMagazzino($qta)
{
$ddt = $this->ddt;
$tipo = $ddt->tipo;
@ -47,8 +47,13 @@ class Articolo extends Article
'_NUM_' => $numero,
]);
$partenza = $ddt->direzione == 'uscita' ? $ddt->idsede_destinazione : $ddt->idsede_partenza;
$arrivo = $ddt->direzione == 'uscita' ? $ddt->idsede_partenza : $ddt->idsede_destinazione;
$this->articolo->movimenta(-$qta, $movimento, $data, false, [
'idddt' => $ddt->id,
'idsede_azienda' => $partenza,
'idsede_controparte' => $arrivo,
]);
}

View File

@ -3,6 +3,7 @@
namespace Modules\DDT;
use Auth;
use Common\Components\Description;
use Common\Document;
use Modules\Anagrafiche\Anagrafica;
use Traits\RecordTrait;
@ -130,6 +131,36 @@ class DDT extends Document
return $this->hasMany(Components\Descrizione::class, 'idddt');
}
/**
* Effettua un controllo sui campi del documento.
* Viene richiamatp dalle modifiche alle righe del documento.
*
* @param Description $trigger
*/
public function fixStato(Description $trigger)
{
parent::fixStato($trigger);
if (setting('Cambia automaticamente stato ddt fatturati')) {
$righe = $this->getRighe();
$qta_evasa = $righe->sum('qta_evasa');
$qta = $righe->sum('qta');
$parziale = $qta != $qta_evasa;
// Impostazione del nuovo stato
if ($qta_evasa == 0) {
$descrizione = 'Bozza';
} else {
$descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato';
}
$stato = Stato::where('descrizione', $descrizione)->first();
$this->stato()->associate($stato);
$this->save();
}
}
// Metodi statici
/**

View File

@ -32,7 +32,6 @@ switch (post('op')) {
$fattura = Fattura::build($anagrafica, $tipo, $data, $id_segment);
$id_record = $fattura->id;
aggiorna_sedi_movimenti('documenti', $id_record);
flash()->info(tr('Aggiunta fattura numero _NUM_!', [
'_NUM_' => $fattura->numero,
]));
@ -151,47 +150,20 @@ switch (post('op')) {
// eliminazione documento
case 'delete':
$righe = $dbo->fetchArray('SELECT id FROM co_righe_documenti WHERE iddocumento='.prepare($id_record));
try {
$fattura->delete();
// Controllo sui seriali
foreach ($righe as $r) {
$non_rimovibili = seriali_non_rimuovibili('id_riga_documento', $r['id'], $dir);
if (!empty($non_rimovibili)) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
$dbo->query('DELETE FROM co_scadenziario WHERE iddocumento='.prepare($id_record));
$dbo->query('DELETE FROM co_movimenti WHERE iddocumento='.prepare($id_record));
return;
}
// Azzeramento collegamento della rata contrattuale alla pianificazione
$dbo->query('UPDATE co_ordiniservizio_pianificazionefatture SET iddocumento=0 WHERE iddocumento='.prepare($id_record));
flash()->info(tr('Fattura eliminata!'));
} catch (InvalidArgumentException $e) {
flash()->error(tr('Sono stati utilizzati alcuni serial number nel documento: impossibile procedere!'));
}
// Se ci sono dei preventivi collegati li rimetto nello stato "In attesa di pagamento"
$rs = $dbo->fetchArray('SELECT idpreventivo FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND idpreventivo IS NOT NULL');
for ($i = 0; $i < sizeof($rs); ++$i) {
$dbo->query("UPDATE co_preventivi SET idstato=(SELECT id FROM co_statipreventivi WHERE descrizione='In lavorazione') WHERE id=".prepare($rs[$i]['idpreventivo']));
}
// Se ci sono degli interventi collegati li rimetto nello stato "Completato"
$rs = $dbo->fetchArray('SELECT idintervento FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND idintervento IS NOT NULL');
for ($i = 0; $i < sizeof($rs); ++$i) {
$dbo->query("UPDATE in_interventi SET idstatointervento = (SELECT idstatointervento FROM in_statiintervento WHERE descrizione = 'Completato') WHERE id=".prepare($rs[$i]['idintervento']));
}
// Rimozione righe
foreach ($righe as $r) {
rimuovi_riga_fattura($id_record, $r['id'], $dir);
}
elimina_scadenza($id_record);
elimina_movimento($id_record);
$dbo->query('DELETE FROM co_documenti WHERE id='.prepare($id_record));
$dbo->query('DELETE FROM co_scadenziario WHERE iddocumento='.prepare($id_record));
$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));
flash()->info(tr('Fattura eliminata!'));
break;
// Duplicazione fattura
@ -269,6 +241,61 @@ switch (post('op')) {
}
break;
case 'manage_documento_fe':
$data = Filter::getPOST();
$ignore = [
'id_plugin',
'id_module',
'id_record',
'backto',
'hash',
'op',
'idriga',
'dir',
];
foreach ($ignore as $name) {
unset($data[$name]);
}
$fattura->dati_aggiuntivi_fe = $data;
$fattura->save();
flash()->info(tr('Dati FE aggiornati correttamente!'));
break;
case 'manage_riga_fe':
$id_riga = post('id_riga');
if ($id_riga != null) {
$riga = Articolo::find($id_riga) ?: Riga::find($id_riga);
$riga = $riga ?: Descrizione::find($id_riga);
$riga = $riga ?: Sconto::find($id_riga);
$data = Filter::getPOST();
$ignore = [
'id_plugin',
'id_module',
'id_record',
'backto',
'hash',
'op',
'idriga',
'dir',
];
foreach ($ignore as $name) {
unset($data[$name]);
}
$riga->dati_aggiuntivi_fe = $data;
$riga->save();
flash()->info(tr('Dati FE aggiornati correttamente!'));
}
break;
case 'manage_articolo':
if (post('idriga') != null) {
$articolo = Articolo::find(post('idriga'));
@ -304,15 +331,8 @@ switch (post('op')) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
}
// Informazioni aggiuntive FE
$articolo->data_inizio_periodo = post('data_inizio_periodo') ?: null;
$articolo->data_fine_periodo = post('data_fine_periodo') ?: null;
$articolo->riferimento_amministrazione = post('riferimento_amministrazione');
$articolo->tipo_cessione_prestazione = post('tipo_cessione_prestazione');
$articolo->save();
aggiorna_sedi_movimenti('documenti', $id_record);
if (post('idriga') != null) {
flash()->info(tr('Articolo modificato!'));
} else {
@ -387,12 +407,6 @@ switch (post('op')) {
$riga->qta = $qta;
// Informazioni aggiuntive FE
$riga->data_inizio_periodo = post('data_inizio_periodo') ?: null;
$riga->data_fine_periodo = post('data_fine_periodo') ?: null;
$riga->riferimento_amministrazione = post('riferimento_amministrazione');
$riga->tipo_cessione_prestazione = post('tipo_cessione_prestazione');
$riga->save();
if (post('idriga') != null) {
@ -430,37 +444,15 @@ switch (post('op')) {
if (!empty($id_record) && post('idriga') !== null) {
$idriga = post('idriga');
// Lettura preventivi collegati
$query = 'SELECT iddocumento, idintervento FROM co_righe_documenti WHERE id='.prepare($idriga);
$rsp = $dbo->fetchArray($query);
$id_record = $rsp[0]['iddocumento'];
$idintervento = $rsp[0]['idintervento'];
$righe = $fattura->getRighe();
$riga = $righe->find($id_riga);
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_fattura($id_record);
} else {
ricalcola_costiagg_fattura($id_record);
$righe_intervento = $righe->where('idintervento', $riga->idintervento);
foreach ($righe_intervento as $r) {
$r->delete();
}
// Lettura interventi collegati
// $query = 'SELECT id, idintervento FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND idintervento IS NOT NULL';
// $rs = $dbo->fetchArray($query);
// Se ci sono degli interventi collegati li rimetto nello stato "Completato"
// for ($i = 0; $i < sizeof($rs); ++$i) {
$dbo->query("UPDATE in_interventi SET idstatointervento = (SELECT idstatointervento FROM in_statiintervento WHERE descrizione = 'Completato') WHERE id=".prepare($idintervento));
// Rimuovo dalla fattura gli articoli collegati all'intervento
$rs2 = $dbo->fetchArray('SELECT idarticolo FROM mg_articoli_interventi WHERE idintervento='.prepare($idintervento));
for ($j = 0; $j < sizeof($rs2); ++$j) {
rimuovi_articolo_dafattura($rs[0]['idarticolo'], $id_record, $rs[0]['idrigadocumento']);
}
// }
// rimuovo riga da co_righe_documenti
$query = 'DELETE FROM `co_righe_documenti` WHERE iddocumento='.prepare($id_record).' AND id='.prepare($idriga);
$dbo->query($query);
//$dbo->query("UPDATE in_interventi SET idstatointervento = (SELECT idstatointervento FROM in_statiintervento WHERE descrizione = 'Completato') WHERE id=".prepare($idintervento));
flash()->info(tr('Intervento _NUM_ rimosso!', [
'_NUM_' => $idintervento,
@ -468,132 +460,23 @@ switch (post('op')) {
}
break;
// Scollegamento articolo da documento
case 'unlink_articolo':
if (!empty($id_record)) {
$idriga = post('idriga');
if (!rimuovi_riga_fattura($id_record, $idriga, $dir)) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
return;
}
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_fattura($id_record);
} else {
ricalcola_costiagg_fattura($id_record);
}
aggiorna_sedi_movimenti('documenti', $id_record);
flash()->info(tr('Articolo rimosso!'));
}
break;
// Scollegamento preventivo da documento
case 'unlink_preventivo':
if (post('idriga') !== null) {
$idriga = post('idriga');
// Lettura preventivi collegati
$query = 'SELECT iddocumento, idpreventivo, idarticolo, id, qta, descrizione FROM co_righe_documenti WHERE id='.prepare($idriga);
$rsp = $dbo->fetchArray($query);
$id_record = $rsp[0]['iddocumento'];
$idpreventivo = $rsp[0]['idpreventivo'];
$idarticolo = $rsp[0]['idarticolo'];
$qta = $rsp[0]['qta'];
if (!empty($idarticolo)) {
rimuovi_articolo_dafattura($rsp[0]['idarticolo'], $id_record, $idriga);
}
// Ripristino le quantità da evadere nel preventivo
$query = 'UPDATE co_righe_preventivi SET qta_evasa = qta_evasa - '.$rsp[0]['qta'].' WHERE idarticolo='.prepare($rsp[0]['idarticolo']).' AND descrizione='.prepare($rsp[0]['descrizione']).' AND idpreventivo = '.prepare($idpreventivo);
$dbo->query($query);
$query = 'DELETE FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND id='.prepare($idriga);
$dbo->query($query);
$rs_righe = $dbo->fetchArray('SELECT * FROM co_righe_documenti WHERE idpreventivo='.prepare($idpreventivo));
if (empty($rs_righe)) {
// Se ci sono dei preventivi collegati li rimetto nello stato "In attesa di pagamento"
$dbo->query("UPDATE co_preventivi SET idstato=(SELECT id FROM co_statipreventivi WHERE descrizione='In lavorazione') WHERE id=".prepare($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($idpreventivo));
}
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_fattura($id_record);
} else {
ricalcola_costiagg_fattura($id_record);
}
flash()->info(tr('Preventivo rimosso!'));
}
break;
// Scollegamento contratto da documento
case 'unlink_contratto':
if (post('idriga') !== null) {
$idriga = post('idriga');
// Lettura contratti collegati
$query = 'SELECT iddocumento, idcontratto, idarticolo, id, qta, descrizione FROM co_righe_documenti WHERE id='.prepare($idriga);
$rsp = $dbo->fetchArray($query);
$id_record = $rsp[0]['iddocumento'];
$idcontratto = $rsp[0]['idcontratto'];
$idarticolo = $rsp[0]['idarticolo'];
if (!empty($idarticolo)) {
rimuovi_articolo_dafattura($rsp[0]['idarticolo'], $id_record, $idriga);
}
// Ripristino le quantità da evadere nel contratto
$query = 'UPDATE co_righe_contratti SET qta_evasa = qta_evasa - '.$rsp[0]['qta'].' WHERE idarticolo='.prepare($rsp[0]['idarticolo']).' AND descrizione='.prepare($rsp[0]['descrizione']).' AND idcontratto = '.prepare($idcontratto);
$dbo->query($query);
$query = 'DELETE FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND id='.prepare($idriga);
$dbo->query($query);
$rs_righe = $dbo->fetchArray('SELECT * FROM co_righe_documenti WHERE idcontratto='.prepare($idcontratto));
if (empty($rs_righe)) { // Se ci sono dei preventivi collegati li rimetto nello stato "In attesa di pagamento"
$dbo->query("UPDATE co_contratti SET idstato=(SELECT id FROM co_staticontratti WHERE descrizione='In lavorazione') WHERE id=".prepare($idcontratto));
// Aggiorno anche lo stato degli interventi collegati ai contratti
$dbo->query("UPDATE in_interventi SET idstatointervento = (SELECT idstatointervento FROM in_statiintervento WHERE descrizione = 'Completato') WHERE id IN (SELECT idintervento FROM co_promemoria WHERE idcontratto=".prepare($idcontratto).')');
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_fattura($id_record);
} else {
ricalcola_costiagg_fattura($id_record);
}
flash()->info(tr('Contratto rimosso!'));
}
}
break;
// Scollegamento riga generica da documento
case 'unlink_riga':
if (post('idriga') !== null) {
$idriga = post('idriga');
$id_riga = post('idriga');
rimuovi_riga_fattura($id_record, $idriga, $dir);
if (!empty($id_riga)) {
$riga = $fattura->getRighe()->find($id_riga);
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_fattura($id_record);
} else {
try {
$riga->delete();
// Ricalcolo inps, ritenuta e bollo
ricalcola_costiagg_fattura($id_record);
flash()->info(tr('Riga rimossa!'));
} catch (InvalidArgumentException $e) {
flash()->error(tr('Alcuni serial number sono già stati utilizzati!'));
}
flash()->info(tr('Riga rimossa!'));
}
break;
@ -618,33 +501,43 @@ switch (post('op')) {
break;
// Aggiunta di un ordine in fattura
case 'add_ordine':
$ordine = \Modules\Ordini\Ordine::find(post('id_ordine'));
// Aggiunta di un documento in fattura
case 'add_documento':
$id_documento = post('id_documento');
$type = post('type');
$movimenta = true;
if ($type == 'ordine') {
$documento = \Modules\Ordini\Ordine::find($id_documento);
} elseif ($type == 'ddt') {
$documento = \Modules\DDT\DDT::find($id_documento);
$movimenta = false;
} elseif ($type == 'preventivo') {
$documento = \Modules\Preventivi\Preventivo::find($id_documento);
} elseif ($type == 'contratto') {
$documento = \Modules\Contratti\Contratto::find($id_documento);
}
// Creazione della fattura al volo
if (post('create_document') == 'on') {
$descrizione = ($dir == 'entrata') ? 'Fattura immediata di vendita' : 'Fattura immediata di acquisto';
$tipo = Tipo::where('descrizione', $descrizione)->first();
$fattura = Fattura::build($ordine->anagrafica, $tipo, post('data'), post('id_segment'));
$fattura->idpagamento = $ordine->idpagamento;
$fattura = Fattura::build($documento->anagrafica, $tipo, post('data'), post('id_segment'));
$fattura->idpagamento = $documento->idpagamento;
$fattura->id_ritenuta_contributi = post('id_ritenuta_contributi') ?: null;
$fattura->save();
$id_record = $fattura->id;
}
$id_rivalsa_inps = setting('Percentuale rivalsa');
if ($dir == 'uscita') {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti;
} else {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto");
}
$calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito");
$calcolo_ritenuta_acconto = post('calcolo_ritenuta_acconto') ?: null;
$id_ritenuta_acconto = post('id_ritenuta_acconto') ?: null;
$ritenuta_contributi = boolval(post('ritenuta_contributi'));
$id_rivalsa_inps = post('id_rivalsa_inps') ?: null;
$id_conto = post('id_conto');
$parziale = false;
$righe = $ordine->getRighe();
$righe = $documento->getRighe();
foreach ($righe as $riga) {
if (post('evadere')[$riga->id] == 'on') {
$qta = post('qta_da_evadere')[$riga->id];
@ -655,10 +548,13 @@ switch (post('op')) {
$copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
$copia->id_ritenuta_acconto = $id_ritenuta_acconto;
$copia->id_rivalsa_inps = $id_rivalsa_inps;
$copia->ritenuta_contributi = $ritenuta_contributi;
// Aggiornamento seriali dalla riga dell'ordine
if ($copia->isArticolo()) {
$copia->movimenta($copia->qta);
if ($movimenta) {
$copia->movimenta($copia->qta);
}
$serials = is_array(post('serial')[$riga->id]) ? post('serial')[$riga->id] : [];
@ -667,238 +563,30 @@ switch (post('op')) {
$copia->save();
}
if ($riga->qta != $riga->qta_evasa) {
$parziale = true;
}
}
// Impostazione del nuovo stato
$descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato';
$stato = \Modules\Ordini\Stato::where('descrizione', $descrizione)->first();
$ordine->stato()->associate($stato);
$ordine->save();
ricalcola_costiagg_fattura($id_record);
aggiorna_sedi_movimenti('documenti', $id_record);
flash()->info(tr('Ordine _NUM_ aggiunto!', [
'_NUM_' => $ordine->numero,
]));
break;
// Aggiunta di un ddt in fattura
case 'add_ddt':
$ddt = \Modules\DDT\DDT::find(post('id_ddt'));
// Creazione della fattura al volo
if (post('create_document') == 'on') {
$descrizione = ($dir == 'entrata') ? 'Fattura differita di vendita' : 'Fattura differita di acquisto';
$tipo = Tipo::where('descrizione', $descrizione)->first();
$fattura = Fattura::build($ddt->anagrafica, $tipo, post('data'), post('id_segment'));
$fattura->idpagamento = $ddt->idpagamento;
$fattura->save();
$id_record = $fattura->id;
}
$id_rivalsa_inps = setting('Percentuale rivalsa');
if ($dir == 'uscita') {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti;
} else {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto");
}
$calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito");
$id_conto = post('id_conto');
$parziale = false;
$righe = $ddt->getRighe();
foreach ($righe as $riga) {
if (post('evadere')[$riga->id] == 'on') {
$qta = post('qta_da_evadere')[$riga->id];
$copia = $riga->copiaIn($fattura, $qta);
$copia->id_conto = $id_conto;
$copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
$copia->id_ritenuta_acconto = $id_ritenuta_acconto;
$copia->id_rivalsa_inps = $id_rivalsa_inps;
// Aggiornamento seriali dalla riga dell'ordine
if ($copia->isArticolo()) {
$serials = is_array(post('serial')[$riga->id]) ? post('serial')[$riga->id] : [];
$copia->serials = $serials;
}
$copia->save();
}
if ($riga->qta != $riga->qta_evasa) {
$parziale = true;
}
}
// Impostazione del nuovo stato
$descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato';
$stato = \Modules\DDT\Stato::where('descrizione', $descrizione)->first();
$ddt->stato()->associate($stato);
$ddt->save();
ricalcola_costiagg_fattura($id_record);
aggiorna_sedi_movimenti('documenti', $id_record);
flash()->info(tr('DDT _NUM_ aggiunto!', [
'_NUM_' => $ddt->numero,
]));
break;
// Aggiunta di un preventivo in fattura
case 'add_preventivo':
$preventivo = \Modules\Preventivi\Preventivo::find(post('id_preventivo'));
// Creazione della fattura al volo
if (post('create_document') == 'on') {
$tipo = Tipo::where('descrizione', 'Fattura immediata di vendita')->first();
$fattura = Fattura::build($preventivo->anagrafica, $tipo, post('data'), post('id_segment'));
$fattura->idpagamento = $preventivo->idpagamento;
$fattura->save();
$id_record = $fattura->id;
}
$id_rivalsa_inps = setting('Percentuale rivalsa');
if ($dir == 'uscita') {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti;
} else {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto");
}
$calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito");
$id_conto = post('id_conto');
$parziale = false;
$righe = $preventivo->getRighe();
foreach ($righe as $riga) {
if (post('evadere')[$riga->id] == 'on') {
$qta = post('qta_da_evadere')[$riga->id];
$copia = $riga->copiaIn($fattura, $qta);
$copia->id_conto = $id_conto;
$copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
$copia->id_ritenuta_acconto = $id_ritenuta_acconto;
$copia->id_rivalsa_inps = $id_rivalsa_inps;
// Aggiornamento seriali dalla riga dell'ordine
if ($copia->isArticolo()) {
$copia->movimenta($copia->qta);
}
$copia->save();
}
if ($riga->qta != $riga->qta_evasa) {
$parziale = true;
}
}
// Impostazione del nuovo stato
$descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato';
$stato = \Modules\Preventivi\Stato::where('descrizione', $descrizione)->first();
$preventivo->stato()->associate($stato);
$preventivo->save();
// Trasferimento degli interventi collegati
$interventi = $preventivo->interventi;
$stato_intervento = \Modules\Interventi\Stato::where('descrizione', 'Fatturato')->first();
foreach ($interventi as $intervento) {
$intervento->stato()->associate($stato_intervento);
$intervento->save();
}
ricalcola_costiagg_fattura($id_record);
aggiorna_sedi_movimenti('documenti', $id_record);
flash()->info(tr('Preventivo _NUM_ aggiunto!', [
'_NUM_' => $preventivo->numero,
]));
break;
// Aggiunta di un contratto in fattura
case 'add_contratto':
$contratto = \Modules\Contratti\Contratto::find(post('id_contratto'));
// Creazione della fattura al volo
if (post('create_document') == 'on') {
$tipo = Tipo::where('descrizione', 'Fattura immediata di vendita')->first();
$fattura = Fattura::build($contratto->anagrafica, $tipo, post('data'), post('id_segment'));
$fattura->idpagamento = $contratto->idpagamento;
$fattura->save();
$id_record = $fattura->id;
$message = '';
if ($type == 'ordine') {
$message = tr('Ordine _NUM_ aggiunto!', [
'_NUM_' => $ordine->numero,
]);
} elseif ($type == 'ddt') {
$message = tr('DDT _NUM_ aggiunto!', [
'_NUM_' => $ordine->numero,
]);
} elseif ($type == 'preventivo') {
$message = tr('Preventivo _NUM_ aggiunto!', [
'_NUM_' => $ordine->numero,
]);
} elseif ($type == 'contratto') {
$message = tr('Contratto _NUM_ aggiunto!', [
'_NUM_' => $ordine->numero,
]);
}
$id_rivalsa_inps = setting('Percentuale rivalsa');
if ($dir == 'uscita') {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti;
} else {
$id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto");
}
$calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito");
$id_conto = post('id_conto');
$parziale = false;
$righe = $contratto->getRighe();
foreach ($righe as $riga) {
if (post('evadere')[$riga->id] == 'on') {
$qta = post('qta_da_evadere')[$riga->id];
$copia = $riga->copiaIn($fattura, $qta);
$copia->id_conto = $id_conto;
$copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
$copia->id_ritenuta_acconto = $id_ritenuta_acconto;
$copia->id_rivalsa_inps = $id_rivalsa_inps;
// Aggiornamento seriali dalla riga dell'ordine
if ($copia->isArticolo()) {
$copia->movimenta($copia->qta);
}
$copia->save();
}
if ($riga->qta != $riga->qta_evasa) {
$parziale = true;
}
}
// Impostazione del nuovo stato
$descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato';
$stato = \Modules\Contratti\Stato::where('descrizione', $descrizione)->first();
$contratto->stato()->associate($stato);
$contratto->save();
// Trasferimento degli interventi collegati
$interventi = $contratto->interventi;
$stato_intervento = \Modules\Interventi\Stato::where('descrizione', 'Fatturato')->first();
foreach ($interventi as $intervento) {
$intervento->stato()->associate($stato_intervento);
$intervento->save();
}
ricalcola_costiagg_fattura($id_record);
aggiorna_sedi_movimenti('documenti', $id_record);
flash()->info(tr('Contratto _NUM_ aggiunto!', [
'_NUM_' => $contratto->numero,
]));
flash()->info($message);
break;

View File

@ -2,34 +2,32 @@
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
use Modules\Contratti\Contratto;
use Modules\Fatture\Fattura;
$documento_finale = Fattura::find($id_record);
$dir = $documento_finale->direzione;
$id_documento = get('id_documento');
if (!empty($id_documento)) {
$documento = Contratto::find($id_documento);
if (get('op')) {
$options = [
'op' => 'add_contratto',
'id_importazione' => 'id_contratto',
'final_module' => $module['name'],
'original_module' => 'Contratti',
'sql' => [
'table' => 'co_contratti',
'rows' => 'co_righe_contratti',
'id_rows' => 'idcontratto',
],
'serials' => false,
'op' => 'add_documento',
'type' => 'contratto',
'button' => tr('Aggiungi'),
'dir' => 'entrata',
'documento' => $documento,
'documento_finale' => $documento_finale,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
echo App::load('importa.php', [], $options, true);
return;
}
$id_anagrafica = $documento_finale->idanagrafica;
$_SESSION['superselect']['idanagrafica'] = $id_anagrafica;
$_SESSION['superselect']['stato'] = 'is_fatturabile';
echo '
@ -39,12 +37,8 @@ echo '
</div>
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
<div id="righe_documento">
</div>
<div class="alert alert-info" id="box-loading">
@ -56,30 +50,21 @@ echo '
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
});
$("#id_documento").on("change", function(){
loader.show();
box.hide();
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
content.html("");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record='.$id_record.'&id_documento=" + id, function() {
loader.hide();
});
});
</script>';

View File

@ -2,55 +2,41 @@
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
use Modules\DDT\DDT;
use Modules\Fatture\Fattura;
$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita';
$documento_finale = Fattura::find($id_record);
$dir = $documento_finale->direzione;
$id_documento = get('id_documento');
if (!empty($id_documento)) {
$documento = DDT::find($id_documento);
if (get('op')) {
$options = [
'op' => 'add_ddt',
'id_importazione' => 'id_ddt',
'final_module' => $module['name'],
'original_module' => $module['name'] == 'Fatture di vendita' ? 'Ddt di vendita' : 'Ddt di acquisto',
'sql' => [
'table' => 'dt_ddt',
'rows' => 'dt_righe_ddt',
'id_rows' => 'idddt',
],
'serials' => [
'id_riga' => 'id_riga_ddt',
'condition' => '(id_riga_documento IS NOT NULL)',
],
'op' => 'add_documento',
'type' => 'ddt',
'serials' => true,
'button' => tr('Aggiungi'),
'dir' => $dir,
'documento' => $documento,
'documento_finale' => $documento_finale,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
echo App::load('importa.php', [], $options, true);
return;
}
$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record));
$idanagrafica = $info['idanagrafica'];
$id_anagrafica = $documento_finale->idanagrafica;
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Ddt').'", "name": "id_documento", "values": "query=SELECT dt_ddt.id, CONCAT(\'DDT num. \', IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM dt_ddt WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoddt IN (SELECT id FROM dt_statiddt WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoddt=(SELECT id FROM dt_tipiddt WHERE dir='.prepare($dir).') AND dt_ddt.id IN (SELECT idddt FROM dt_righe_ddt WHERE dt_righe_ddt.idddt = dt_ddt.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
{[ "type": "select", "label": "'.tr('Ddt').'", "name": "id_documento", "values": "query=SELECT dt_ddt.id, CONCAT(\'DDT num. \', IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM dt_ddt WHERE idanagrafica='.prepare($id_anagrafica).' AND idstatoddt IN (SELECT id FROM dt_statiddt WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoddt=(SELECT id FROM dt_tipiddt WHERE dir='.prepare($dir).') AND dt_ddt.id IN (SELECT idddt FROM dt_righe_ddt WHERE dt_righe_ddt.idddt = dt_ddt.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
<div id="righe_documento">
</div>
<div class="alert alert-info" id="box-loading">
@ -62,30 +48,21 @@ echo '
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
});
$("#id_documento").on("change", function(){
loader.show();
box.hide();
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
content.html("");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record='.$id_record.'&id_documento=" + id, function() {
loader.hide();
});
});
</script>';

View File

@ -46,7 +46,9 @@ $rs = $dbo->fetchArray('SELECT
AND in_interventi.id_preventivo IS NULL
AND NOT in_interventi.id IN (SELECT idintervento FROM co_promemoria WHERE idintervento IS NOT NULL)');
foreach ($rs as $key => $value) {
$prezzo = get_costi_intervento($value['id'])['totale'];
$intervento = \Modules\Interventi\Intervento::find($value['id']);
$prezzo = $intervento->totale;
$rs[$key]['prezzo'] = Translator::numberToLocale($prezzo);
$rs[$key]['descrizione_intervento'] = strip_tags($rs[$key]['descrizione_intervento']);

View File

@ -2,55 +2,41 @@
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
use Modules\Fatture\Fattura;
use Modules\Ordini\Ordine;
$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita';
$documento_finale = Fattura::find($id_record);
$dir = $documento_finale->direzione;
$id_documento = get('id_documento');
if (!empty($id_documento)) {
$documento = Ordine::find($id_documento);
if (get('op')) {
$options = [
'op' => 'add_ordine',
'id_importazione' => 'id_ordine',
'final_module' => $module['name'],
'original_module' => $module['name'] == 'Fatture di vendita' ? 'Ordini cliente' : 'Ordini fornitore',
'sql' => [
'table' => 'or_ordini',
'rows' => 'or_righe_ordini',
'id_rows' => 'idordine',
],
'serials' => [
'id_riga' => 'id_riga_ddt',
'condition' => '(id_riga_documento IS NOT NULL)',
],
'op' => 'add_documento',
'type' => 'ordine',
'serials' => true,
'button' => tr('Aggiungi'),
'dir' => $dir,
'documento' => $documento,
'documento_finale' => $documento_finale,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
echo App::load('importa.php', [], $options, true);
return;
}
$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record));
$idanagrafica = $info['idanagrafica'];
$id_anagrafica = $documento_finale->idanagrafica;
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_documento", "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
{[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_documento", "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($id_anagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
<div id="righe_documento">
</div>
<div class="alert alert-info" id="box-loading">
@ -62,30 +48,21 @@ echo '
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
});
$("#id_documento").on("change", function(){
loader.show();
box.hide();
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
content.html("");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record='.$id_record.'&id_documento=" + id, function() {
loader.hide();
});
});
</script>';

View File

@ -2,34 +2,33 @@
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
use Modules\Fatture\Fattura;
use Modules\Preventivi\Preventivo;
$documento_finale = Fattura::find($id_record);
$dir = $documento_finale->direzione;
$id_documento = get('id_documento');
if (!empty($id_documento)) {
$documento = Preventivo::find($id_documento);
if (get('op')) {
$options = [
'op' => 'add_preventivo',
'id_importazione' => 'id_preventivo',
'final_module' => $module['name'],
'original_module' => 'Preventivi',
'sql' => [
'table' => 'co_preventivi',
'rows' => 'co_righe_preventivi',
'id_rows' => 'idpreventivo',
],
'serials' => false,
'op' => 'add_documento',
'type' => 'preventivo',
'button' => tr('Aggiungi'),
'dir' => 'entrata',
'documento' => $documento,
'documento_finale' => $documento_finale,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
echo App::load('importa.php', [], $options, true);
return;
}
$id_anagrafica = $documento_finale->idanagrafica;
$_SESSION['superselect']['idanagrafica'] = $id_anagrafica;
echo '
<div class="row">
<div class="col-md-12">
@ -37,12 +36,8 @@ echo '
</div>
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
<div id="righe_documento">
</div>
<div class="alert alert-info" id="box-loading">
@ -54,30 +49,21 @@ echo '
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
});
$("#id_documento").on("change", function(){
loader.show();
box.hide();
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
content.html("");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record='.$id_record.'&id_documento=" + id, function() {
loader.hide();
});
});
</script>';

View File

@ -131,7 +131,7 @@ switch (post('op')) {
$dst = $src;
} else {
$src = basename($fattura->uploads()->where('name', 'Fattura Elettronica')->first()->filepath);
$dst = basename($fattura->uploads()->where('name', 'Fattura Elettronica')->first()->original);
$dst = basename($fattura->uploads()->where('name', 'Fattura Elettronica')->first()->original_name);
}
$file = slashes($module->upload_directory.'/'.$src);

View File

@ -13,6 +13,15 @@ echo '
<i class="fa fa-copy"></i> '.tr('Duplica fattura').'
</button>';
if ($module->name == 'Fatture di vendita') {
$attributi_visibili = $record['stato'] != 'Emessa' && $record['stato'] != 'Parzialmente pagato' && $record['stato'] != 'Pagato';
echo '
<a class="btn btn-info '.($attributi_visibili ? '' : 'disabled').'" data-toggle="modal" data-title="'.tr('Dati Fattura Elettronica').'" data-href="'.$structure->fileurl('fe/document-fe.php').'?id_module='.$id_module.'&id_record='.$id_record.'" '.($attributi_visibili ? '' : 'disabled').'>
<i class="fa fa-file-code-o"></i> '.tr('Attributi avanzati').'
</a>';
}
if ($dir == 'entrata') {
echo '
<div class="btn-group">
@ -73,4 +82,4 @@ if (!empty($record['is_fiscale'])) {
<?php
}
}
?>
?>

View File

@ -11,6 +11,7 @@ $tipodoc = $rs[0]['descrizione'];
unset($_SESSION['superselect']['idanagrafica']);
unset($_SESSION['superselect']['idsede_partenza']);
unset($_SESSION['superselect']['idsede_destinazione']);
unset($_SESSION['superselect']['codice_modalita_pagamento_fe']);
$_SESSION['superselect']['idsede_partenza'] = $record['idsede_partenza'];
$_SESSION['superselect']['idsede_destinazione'] = $record['idsede_destinazione'];
$_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
@ -116,8 +117,21 @@ if (empty($record['is_fiscale'])) {
</div>
<div class="col-md-2">
{[ "type": "date", "label": "<?php echo tr('Data competenza'); ?>", "name": "data_competenza", "required": 0, "value": "$data_competenza$" ]}
{[ "type": "date", "label": "<?php echo tr('Data competenza'); ?>", "name": "data_competenza", "required": 0, "value": "$data_competenza$", "min-date": "$data_registrazione$" ]}
</div>
<script type="text/javascript">
$(document).ready(function () {
$("#data_registrazione").on("dp.change", function (e) {
var data = $("#data_competenza");
data.data("DateTimePicker").minDate(e.date);
if(data.data("DateTimePicker").date() < e.date){
data.data("DateTimePicker").date(e.date);
}
})
});
</script>
<?php
} ?>
@ -126,7 +140,7 @@ if (empty($record['is_fiscale'])) {
<?php
if ($dir == 'entrata') {
?>
{[ "type": "select", "label": "<?php echo tr('Stato FE'); ?>", "name": "codice_stato_fe", "required": 0, "values": "query=SELECT codice as id, CONCAT_WS(' - ',codice,descrizione) as text FROM fe_stati_documento", "value": "$codice_stato_fe$", "disabled": <?php echo intval(Plugins\ExportFE\Connection::isEnabled()); ?>, "class": "unblockable", "help": "<?php echo (!empty($record['data_stato_fe'])) ? Translator::timestampToLocale($record['data_stato_fe']) : ''; ?>" ]}
{[ "type": "select", "label": "<?php echo tr('Stato FE'); ?>", "name": "codice_stato_fe", "required": 0, "values": "query=SELECT codice as id, CONCAT_WS(' - ',codice,descrizione) as text FROM fe_stati_documento", "value": "$codice_stato_fe$", "disabled": <?php echo intval(API\Services::isEnabled()); ?>, "class": "unblockable", "help": "<?php echo (!empty($record['data_stato_fe'])) ? Translator::timestampToLocale($record['data_stato_fe']) : ''; ?>" ]}
<?php
}
?>
@ -201,7 +215,7 @@ if (empty($record['is_fiscale'])) {
</div>
<div class="col-md-3">
{[ "type": "select", "label": "<?php echo tr('Pagamento'); ?>", "name": "idpagamento", "required": 1, "values": "query=SELECT id, CONCAT_WS(' - ', codice_modalita_pagamento_fe, descrizione) AS descrizione, (SELECT id FROM co_banche WHERE id_pianodeiconti3 = co_pagamenti.idconto_<?php echo $conto; ?> LIMIT 0,1) AS idbanca FROM co_pagamenti GROUP BY descrizione ORDER BY descrizione ASC", "value": "$idpagamento$", "extra": "onchange=\"$('#idbanca').val( $(this).find('option:selected').data('idbanca') ).change(); \" " ]}
{[ "type": "select", "label": "<?php echo tr('Pagamento'); ?>", "name": "idpagamento", "required": 1, "ajax-source": "pagamenti", "value": "$idpagamento$", "extra": "onchange=\"$('#idbanca').val($(this).selectData().id_banca_<?php echo $conto; ?>).change(); \" " ]}
</div>
<div class="col-md-3">

View File

@ -0,0 +1,58 @@
<?php
// Altri dati gestionali
echo '
<tbody>
<tr class="fourth-level">
<th colspan="2">
'.str_repeat($space, 3).'2.2.1.16 AltriDatiGestionali - '.tr('Riga _NUM_', [
'_NUM_' => $key,
]);
if ($key == 1) {
echo '
<button type="button" class="btn btn-xs btn-info pull-right" onclick="add_altri_dati(this)" id="add-altri_dati">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>';
}
echo '
</th>
</tr>';
// Tipo Dato
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).'2.2.1.16.1 TipoDato</td>
<td>
{[ "type": "text", "name": "altri_dati['.$key.'][tipo_dato]", "value": "'.$dato['tipo_dato'].'", "maxlength": 10 ]}
</td>
</tr>';
// Riferimento Testo
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).'2.2.1.16.2 RiferimentoTesto</td>
<td>
{[ "type": "text", "name": "altri_dati['.$key.'][riferimento_testo]", "value": "'.$dato['riferimento_testo'].'", "maxlength": 60 ]}
</td>
</tr>';
// Riferimento Numero
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).'2.2.1.16.3 RiferimentoNumero</td>
<td>
{[ "type": "number", "name": "altri_dati['.$key.'][riferimento_numero]", "value": "'.$dato['riferimento_numero'].'" ]}
</td>
</tr>';
// Riferimento Data
echo '
<tr class="fifth-level" id="last-altri_dati-'.$key.'">
<td style="vertical-align: middle;">'.str_repeat($space, 4).'2.2.1.16.4 RiferimentoData</td>
<td>
{[ "type": "date", "name": "altri_dati['.$key.'][riferimento_data]", "value": "'.$dato['riferimento_data'].'"]}
</td>
</tr>
</tbody>';

View File

@ -0,0 +1,107 @@
<?php
// Altri dati gestionali
echo '
<tbody>
<tr class="fourth-level">
<th colspan="2">
'.str_repeat($space, 3).$info['code'].' '.$info['name'].' - '.tr('Riga _NUM_', [
'_NUM_' => $key,
]);
if ($key == 1) {
echo '
<button type="button" class="btn btn-xs btn-info pull-right" onclick="add_blocco(this, \''.$nome.'\')">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>';
}
echo '
</th>
</tr>';
// RiferimentoNumeroLinea
if (empty($dato['riferimento_linea'])) {
$dato['riferimento_linea'][] = 0;
}
$index = 1;
foreach ($dato['riferimento_linea'] as $linea) {
echo '
<tr class="fifth-level" title="RiferimentoNumeroLinea-'.$nome.'-'.$key.'">
<td style="vertical-align: middle;">
'.str_repeat($space, 4).$info['code'].'.1 RiferimentoNumeroLinea - '.tr('Riga _NUM_', [
'_NUM_' => $index,
]);
if ($index == 1) {
echo '
<button type="button" class="btn btn-xs btn-info pull-right" onclick="add_riferimento(this, \''.$nome.'\', \''.$key.'\')">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>';
}
echo '
</td>
<td>
{[ "type": "number", "name": "'.$nome.'['.$key.'][riferimento_linea][]", "value": "'.$linea.'", "maxlength": 4, "decimals": 0 ]}
</td>
</tr>';
++$index;
}
// IdDocumento
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).$info['code'].'.2 IdDocumento</td>
<td>
{[ "type": "text", "name": "'.$nome.'['.$key.'][id_documento]", "value": "'.$dato['id_documento'].'", "maxlength": 20 ]}
</td>
</tr>';
// Data
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).$info['code'].'.3 Data</td>
<td>
{[ "type": "date", "name": "'.$nome.'['.$key.'][data]", "value": "'.$dato['data'].'" ]}
</td>
</tr>';
// NumItem
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).$info['code'].'.4 NumItem</td>
<td>
{[ "type": "text", "name": "'.$nome.'['.$key.'][num_item]", "value": "'.$dato['num_item'].'", "maxlength": 20 ]}
</td>
</tr>';
// CodiceCommessaConvenzione
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).$info['code'].'.5 CodiceCommessaConvenzione</td>
<td>
{[ "type": "text", "name": "'.$nome.'['.$key.'][codice_commessa]", "value": "'.$dato['codice_commessa'].'", "maxlength": 100 ]}
</td>
</tr>';
// CodiceCUP
echo '
<tr class="fifth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 4).$info['code'].'.6 CodiceCUP</td>
<td>
{[ "type": "text", "name": "'.$nome.'['.$key.'][codice_cup]", "value": "'.$dato['codice_cup'].'", "maxlength": 15 ]}
</td>
</tr>';
// CodiceCIG
echo '
<tr class="fifth-level" id="last-'.$nome.'-'.$key.'">
<td style="vertical-align: middle;">'.str_repeat($space, 4).$info['code'].'.7 CodiceCIG</td>
<td>
{[ "type": "text", "name": "'.$nome.'['.$key.'][codice_cig]", "value": "'.$dato['codice_cig'].'", "maxlength": 15 ]}
</td>
</tr>
</tbody>';

View File

@ -0,0 +1,182 @@
<?php
include_once __DIR__.'/../../../core.php';
use Modules\Fatture\Fattura;
$space = str_repeat('&nbsp;', 6);
$documento = Fattura::find($id_record);
$result = $documento->toArray();
$result = array_merge($result, $documento->dati_aggiuntivi_fe);
echo '
<link rel="stylesheet" type="text/css" media="all" href="'.$structure->fileurl('fe/style.css').'"/>';
echo '
<form action="" method="post">
<input type="hidden" name="op" value="manage_documento_fe">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="id_module" value="'.$id_module.'">
<input type="hidden" name="id_record" value="'.$id_record.'">';
echo '
<table class="table">
<tbody>
<tr class="first-level">
<th colspan="2">
2 FatturaElettronicaBody
<button type="submit" class="btn btn-primary pull-right">
<i class="fa fa-edit"></i> '.tr('Salva').'
</button>
</th>
</tr>
<tr class="second-level">
<th colspan="2">'.str_repeat($space, 1).'2.1 DatiGenerali</th>
</tr>
<tr class="third-level">
<th colspan="2">'.str_repeat($space, 2).'2.1.1 DatiGeneraliDocumento</th>
</tr>';
// Art73
echo '
<tr class="fourth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 3).'2.1.1.12 Art73</td>
<td>
{[ "type": "checkbox", "name": "art73", "value": "'.$result['art73'].'", "placeholder": "'.tr("Emesso ai sensi dell'articolo 73 del DPR 633/72").'" ]}
</td>
</tr>
</tbody>';
echo '
<script>
var keys = {};
var ref_keys = {};
</script>';
$documenti = [
'dati_ordine' => [
'code' => '2.1.2',
'name' => 'DatiOrdineAcquisto',
],
'dati_contratto' => [
'code' => '2.1.3',
'name' => 'DatiContratto',
],
'dati_convenzione' => [
'code' => '2.1.4',
'name' => 'DatiConvenzione',
],
'dati_ricezione' => [
'code' => '2.1.5',
'name' => 'DatiRicezione',
],
'dati_fatture' => [
'code' => '2.1.6',
'name' => 'DatiFattureCollegate',
],
];
foreach ($documenti as $nome => $info) {
if (empty($result[$nome])) {
$result[$nome][] = [];
}
$key = 1;
foreach ($result[$nome] as $dato) {
include __DIR__.'/components/dati_documento.php';
echo '
<script>
ref_keys["'.$nome.$key.'"] = '.($index - 1).';
</script>';
++$key;
}
echo '
<script>
keys["'.$nome.'"] = '.($key - 1).';
</script>';
}
echo '
</table>';
foreach ($documenti as $nome => $info) {
echo '
<table class="hide" id="'.$nome.'-templace">';
$dato = [];
$key = '-id-';
include __DIR__.'/components/dati_documento.php';
echo '
</table>
<table class="hide">
<tbody id="riferimento_'.$nome.'-templace">
<tr class="fifth-level" title="RiferimentoNumeroLinea-'.$nome.'--id-">
<td style="vertical-align: middle;">
'.str_repeat($space, 4).$info['code'].'.1 RiferimentoNumeroLinea - '.tr('Riga _NUM_', [
'_NUM_' => '-num-',
]).'
</td>
<td>
{[ "type": "number", "name": "'.$nome.'[-id-][riferimento_linea][]", "value": "", "maxlength": 4, "decimals": 0 ]}
</td>
</tr>
</tbody>
</table>';
}
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary">
<i class="fa fa-edit"></i> '.tr('Salva').'
</button>
</div>
</div>';
echo '
</form>';
echo '
<script>
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, "g"), replace);
}
function add_blocco(btn, nome){
$("#template .superselect, #template .superselectajax").select2().select2("destroy");
var last = $(btn).closest("table").find("tr[id^=last-" + nome + "]").parent().last();
keys[nome]++;
var text = replaceAll($("#" + nome + "-templace").html(), "-id-", "" + keys[nome]);
ref_keys[nome + keys[nome]] = 1;
last.after(text);
start_superselect();
start_datepickers();
}
function add_riferimento(btn, nome, key) {
$("#template .superselect, #template .superselectajax").select2().select2("destroy");
var last = $(btn).closest("table").find("tr[title=RiferimentoNumeroLinea-" + nome + "-" + key + "]").last();
ref_keys[nome + key]++;
var text = replaceAll($("#riferimento_" + nome + "-templace").html(), "-id-", "" + key);
text = replaceAll(text, "-num-", "" + ref_keys[nome + key]);
last.after(text);
start_superselect();
start_datepickers();
}
</script>
<script src="'.ROOTDIR.'/lib/init.js"></script>';

View File

@ -0,0 +1,161 @@
<?php
include_once __DIR__.'/../../../core.php';
use Modules\Fatture\Fattura;
$tipi_cessione_prestazione = [
[
'id' => 'SC',
'text' => 'SC - '.tr('Sconto'),
],
[
'id' => 'PR',
'text' => 'PR - '.tr('Premio'),
],
[
'id' => 'AB',
'text' => 'AB - '.tr('Abbuono'),
],
[
'id' => 'AC',
'text' => 'AC - '.tr('Spesa accessoria'),
],
];
$space = str_repeat('&nbsp;', 6);
$documento = Fattura::find($id_record);
// Dati della riga
$id_riga = get('idriga');
$riga = $documento->getRighe()->find($id_riga);
$result = $riga->toArray();
$result = array_merge($result, $riga->dati_aggiuntivi_fe);
echo '
<link rel="stylesheet" type="text/css" media="all" href="'.$structure->fileurl('fe/style.css').'"/>';
echo '
<form action="" method="post">
<input type="hidden" name="op" value="manage_riga_fe">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="id_module" value="'.$id_module.'">
<input type="hidden" name="id_record" value="'.$id_record.'">
<input type="hidden" name="id_riga" value="'.$id_riga.'">';
echo '
<table class="table">
<tbody>
<tr class="first-level">
<th colspan="2">
2 FatturaElettronicaBody
<button type="submit" class="btn btn-primary pull-right">
<i class="fa fa-edit"></i> '.tr('Salva').'
</button>
</th>
</tr>
<tr class="second-level">
<th colspan="2">'.str_repeat($space, 1).'2.2 DatiBeniServizi</th>
</tr>
<tr class="third-level">
<th colspan="2">'.str_repeat($space, 2).'2.2.1 DettaglioLinee</th>
</tr>';
// Tipo Cessione Prestazione
echo '
<tr class="fourth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 3).'2.2.1.2 TipoCessionePrestazione</td>
<td>
{[ "type": "select", "name": "tipo_cessione_prestazione", "value": "'.$result['tipo_cessione_prestazione'].'", "values": '.json_encode($tipi_cessione_prestazione).' ]}
</td>
</tr>';
// Data inizio periodo
echo '
<tr class="fourth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 3).'2.2.1.7 DataInizioPeriodo</td>
<td>
{[ "type": "date", "name": "data_inizio_periodo", "value": "'.$result['data_inizio_periodo'].'" ]}
</td>
</tr>';
// Data fine periodo
echo '
<tr class="fourth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 3).'2.2.1.8 DataFinePeriodo</td>
<td>
{[ "type": "date", "name": "data_fine_periodo", "value": "'.$result['data_fine_periodo'].'" ]}
</td>
</tr>';
// Riferimento amministrazione
echo '
<tr class="fourth-level">
<td style="vertical-align: middle;">'.str_repeat($space, 3).'2.2.1.15 RiferimentoAmministrazione</td>
<td>
{[ "type": "text", "name": "riferimento_amministrazione", "value": "'.$result['riferimento_amministrazione'].'", "maxlength": 20 ]}
</td>
</tr>
</tbody>';
if (empty($result['altri_dati'])) {
$result['altri_dati'][] = [];
}
$key = 1;
foreach ($result['altri_dati'] as $dato) {
include __DIR__.'/components/altri_dati.php';
++$key;
}
echo '
</table>';
echo '
<script>
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, "g"), replace);
}
var n = '.($key - 1).';
function add_altri_dati(btn){
$("#template .superselect, #template .superselectajax").select2().select2("destroy");
var last = $(btn).closest("table").find("tr[id^=last-altri_dati]").parent().last();
n++;
var text = replaceAll($("#altri_dati-templace").html(), "-id-", "" + n);
last.after(text);
start_superselect();
};
</script>
<table class="hide" id="altri_dati-templace">';
$dato = [];
$key = '-id-';
include __DIR__.'/components/altri_dati.php';
echo '
</table>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary">
<i class="fa fa-edit"></i> '.tr('Salva').'
</button>
</div>
</div>';
echo '
</form>';
echo '
<script src="'.ROOTDIR.'/lib/init.js"></script>';

View File

@ -0,0 +1,22 @@
.first-level{
background-color: #ffffff;
}
.second-level{
background-color: rgba(192,192,192, 0.1);
}
.third-level{
background-color: rgba(192,192,192, 0.15);
}
.fourth-level{
background-color: rgba(192,192,192, 0.25);
}
.fifth-level{
background-color: rgba(192,192,192, 0.4);
}
.first-level td,
.second-level td,
.third-level td,
.fourth-level td{
vertical-align: middle;
}

186
modules/fatture/modutil.php Executable file → Normal file
View File

@ -554,189 +554,3 @@ function add_articolo_infattura($iddocumento, $idarticolo, $descrizione, $idiva,
return $idriga;
}
/**
* Questa funzione rimuove un articolo dalla fattura data e lo riporta in magazzino nel primo lotto libero
* a partire dal lotto più vecchio
* $idarticolo integer codice dell'articolo da scollegare dalla fattura
* $iddocumento integer codice della fattura da cui scollegare l'articolo.
*/
function rimuovi_articolo_dafattura($idarticolo, $iddocumento, $idrigadocumento)
{
global $dir;
$dbo = database();
// Leggo la quantità di questo articolo in fattura
$query = 'SELECT qta, idintervento, idpreventivo, idordine, idddt, subtotale, descrizione FROM co_righe_documenti WHERE id='.prepare($idrigadocumento);
$rs = $dbo->fetchArray($query);
$idintervento = $rs[0]['idintervento'];
$idpreventivo = $rs[0]['idpreventivo'];
$idddt = $rs[0]['idddt'];
$idordine = $rs[0]['idordine'];
$qta = $rs[0]['qta'];
$subtotale = $rs[0]['subtotale'];
$descrizione = $rs[0]['descrizione'];
$lotto = $rs[0]['lotto'];
$serial = $rs[0]['serial'];
$altro = $rs[0]['altro'];
$non_rimovibili = seriali_non_rimuovibili('id_riga_documento', $idrigadocumento, $dir);
if (!empty($non_rimovibili)) {
return false;
}
// Se l'articolo è stato aggiunto in fattura perché era collegato ad un intervento o
// preventivo o ddt o ordine non devo riportarlo in magazzino quando lo tolgo dalla fattura, perché
// se lo scollegassi poi anche dall'intervento aggiungerei in magazzino la quantità 2 volte!!
if ($qta > 0) {
if (empty($idintervento) && empty($idddt)) {
// Fatture di vendita
if ($dir == 'entrata') {
add_movimento_magazzino($idarticolo, $qta, ['iddocumento' => $iddocumento]);
}
// Fatture di acquisto
else {
add_movimento_magazzino($idarticolo, -$qta, ['iddocumento' => $iddocumento]);
}
}
// TODO: possibile ambiguità tra righe molto simili tra loro
// Se l'articolo è stato inserito in fattura tramite un ddt devo sanare la qta_evasa
if (!empty($idddt)) {
$dbo->query('UPDATE dt_righe_ddt SET qta_evasa=qta_evasa-'.$qta.' WHERE qta='.prepare($qta).' AND idarticolo='.prepare($idarticolo).' AND idddt='.prepare($idddt));
}
// TODO: possibile ambiguità tra righe molto simili tra loro
// Se l'articolo è stato inserito in fattura tramite un ordine devo sanare la qta_evasa
if (!empty($idordine)) {
$dbo->query('UPDATE or_righe_ordini SET qta_evasa=qta_evasa-'.$qta.' WHERE qta='.prepare($qta).' AND idarticolo='.prepare($idarticolo).' AND idordine='.prepare($idordine));
}
}
// Elimino la riga dal documento
$dbo->query('DELETE FROM `co_righe_documenti` WHERE id='.prepare($idrigadocumento).' AND iddocumento='.prepare($iddocumento));
// Aggiorno lo stato dell'ordine
if (setting('Cambia automaticamente stato ordini fatturati') && !empty($idordine)) {
$dbo->query('UPDATE or_ordini SET idstatoordine=(SELECT id FROM or_statiordine WHERE descrizione="'.get_stato_ordine($idordine).'") WHERE id = '.prepare($idordine));
}
// Aggiorno lo stato del ddt
if (setting('Cambia automaticamente stato ddt fatturati') && !empty($idddt)) {
$dbo->query('UPDATE dt_ddt SET idstatoddt=(SELECT id FROM dt_statiddt WHERE descrizione="'.get_stato_ddt($idddt).'") WHERE id = '.prepare($idddt));
}
// Elimino i movimenti avvenuti nel magazzino per questo articolo lotto, serial, altro
$dbo->query('DELETE FROM `mg_movimenti` WHERE idarticolo = '.prepare($idarticolo).' AND iddocumento = '.prepare($iddocumento).' AND id = '.prepare($idrigadocumento));
// Elimino i seriali utilizzati dalla riga
$dbo->query('DELETE FROM `mg_prodotti` WHERE id_articolo = '.prepare($idarticolo).' AND id_riga_documento = '.prepare($idrigadocumento));
return true;
}
function rimuovi_riga_fattura($id_documento, $id_riga, $dir)
{
$dbo = database();
// Leggo la quantità di questo articolo in fattura
$riga = $dbo->fetchOne('SELECT * FROM co_righe_documenti WHERE id='.prepare($id_riga));
$non_rimovibili = seriali_non_rimuovibili('id_riga_documento', $id_riga, $dir);
if (!empty($non_rimovibili)) {
return false;
}
$serials = $dbo->fetchArray('SELECT serial FROM mg_prodotti WHERE serial IS NOT NULL AND id_riga_documento='.prepare($id_riga));
// Elimino la riga dal documento
$dbo->query('DELETE FROM `co_righe_documenti` WHERE id='.prepare($id_riga).' AND iddocumento='.prepare($id_documento));
if (empty($riga['qta'])) {
return true;
}
// Operazioni per la rimozione degli articoli
if (!empty($riga['idarticolo'])) {
// Movimentazione articoli se da interventi o ddt
if (empty($riga['idintervento']) && empty($riga['idddt'])) {
add_movimento_magazzino($riga['idarticolo'], ($dir == 'entrata') ? $riga['qta'] : -$riga['qta'], ['iddocumento' => $id_documento]);
}
// Se l'articolo è stato inserito in fattura tramite un preventivo devo sanare la qta_evasa
if (!empty($riga['idpreventivo'])) {
$dbo->query('UPDATE co_righe_preventivi SET qta_evasa=qta_evasa-'.$riga['qta'].' WHERE qta='.prepare($riga['qta']).' AND idarticolo='.prepare($riga['idarticolo']).' AND idpreventivo='.prepare($riga['idpreventivo']).' AND qta_evasa > 0 LIMIT 1');
}
// Se l'articolo è stato inserito in fattura tramite un ddt devo sanare la qta_evasa
if (!empty($riga['idddt'])) {
$dbo->query('UPDATE dt_righe_ddt SET qta_evasa=qta_evasa-'.$riga['qta'].' WHERE qta='.prepare($riga['qta']).' AND idarticolo='.prepare($riga['idarticolo']).' AND idddt='.prepare($riga['idddt']).' AND qta_evasa > 0 LIMIT 1');
}
// Se l'articolo è stato inserito in fattura tramite un ordine devo sanare la qta_evasa
elseif (!empty($riga['idordine'])) {
$dbo->query('UPDATE or_righe_ordini SET qta_evasa=qta_evasa-'.$riga['qta'].' WHERE qta='.prepare($riga['qta']).' AND idarticolo='.prepare($riga['idarticolo']).' AND idordine='.prepare($riga['idordine']).' AND qta_evasa > 0 LIMIT 1');
}
}
// Nota di credito
if (!empty($riga['ref_riga_documento'])) {
$dbo->query('UPDATE co_righe_documenti SET qta_evasa = qta_evasa+'.$riga['qta'].' WHERE id='.prepare($riga['ref_riga_documento']));
if (!empty($riga['idarticolo'])) {
$serials = array_column($serials, 'serial');
$serials = array_clean($serials);
$dbo->attach('mg_prodotti', ['id_riga_documento' => $riga['ref_riga_documento'], 'dir' => $dir, 'id_articolo' => $riga['idarticolo']], ['serial' => $serials]);
}
}
// Rimozione articoli collegati ad un preventivo importato con riga unica
if ($riga['idpreventivo']) {
$query = 'UPDATE co_righe_preventivi SET qta_evasa = qta_evasa - '.$riga['qta'].' WHERE idarticolo='.prepare($riga['idarticolo']).' AND descrizione = '.prepare($riga['descrizione']).' AND idpreventivo = '.prepare($riga['idpreventivo']);
$dbo->query($query);
}
// Rimozione articoli collegati ad un contratto importato con riga unica
if ($riga['idcontratto']) {
$query = 'UPDATE co_righe_contratti SET qta_evasa = qta_evasa - '.$riga['qta'].' WHERE idarticolo='.prepare($riga['idarticolo']).' AND descrizione = '.prepare($riga['descrizione']).' AND idcontratto = '.prepare($riga['idcontratto']);
$dbo->query($query);
}
//Rimozione righe generiche
if (empty($riga['idarticolo'])) {
// TODO: possibile ambiguità tra righe molto simili tra loro
// Se l'articolo è stato inserito in fattura tramite un ddt devo sanare la qta_evasa
if (!empty($riga['idddt'])) {
$dbo->query('UPDATE dt_righe_ddt SET qta_evasa=qta_evasa-'.$riga['qta'].' WHERE qta='.prepare($riga['qta']).' AND descrizione='.prepare($riga['descrizione']).' AND idddt='.prepare($riga['idddt']));
}
// TODO: possibile ambiguità tra righe molto simili tra loro
// Se l'articolo è stato inserito in fattura tramite un ordine devo sanare la qta_evasa
if (!empty($riga['idordine'])) {
$dbo->query('UPDATE or_righe_ordini SET qta_evasa=qta_evasa-'.$riga['qta'].' WHERE qta='.prepare($riga['qta']).' AND descrizione='.prepare($riga['descrizione']).' AND idordine='.prepare($riga['idordine']));
}
}
// Aggiorno lo stato dell'ordine
if (!empty($riga['idordine']) && setting('Cambia automaticamente stato ordini fatturati')) {
$dbo->query('UPDATE or_ordini SET idstatoordine = (SELECT id FROM or_statiordine WHERE descrizione = '.prepare(get_stato_ordine($riga['idordine'])).') WHERE id = '.prepare($riga['idordine']));
}
// Aggiorno lo stato del ddt
if (!empty($riga['idddt']) && setting('Cambia automaticamente stato ddt fatturati')) {
$dbo->query('UPDATE dt_ddt SET idstatoddt = (SELECT id FROM dt_statiddt WHERE descrizione = '.prepare(get_stato_ddt($riga['idddt'])).') WHERE id = '.prepare($riga['idddt']));
}
// Elimino i movimenti avvenuti nel magazzino per questo articolo lotto, serial, altro
$dbo->query('DELETE FROM `mg_movimenti` WHERE idarticolo = '.prepare($riga['idarticolo']).' AND iddocumento = '.prepare($id_documento).' AND id = '.prepare($id_riga));
// Elimino i seriali utilizzati dalla riga
$dbo->query('DELETE FROM `mg_prodotti` WHERE id_articolo = '.prepare($riga['idarticolo']).' AND id_riga_documento = '.prepare($id_riga));
return true;
}

View File

@ -15,7 +15,7 @@ $options = [
'conti' => $documento->direzione == 'entrata' ? 'conti-vendite' : 'conti-acquisti',
'idanagrafica' => $documento['idanagrafica'],
'show-ritenuta-contributi' => !empty($documento['id_ritenuta_contributi']),
'imponibile_scontato' => $documento->imponibile_scontato,
'totale_imponibile' => $documento->totale_imponibile,
];
// Conto dalle impostazioni

View File

@ -14,7 +14,7 @@ $options = [
'conti' => $documento->direzione == 'entrata' ? 'conti-vendite' : 'conti-acquisti',
'idanagrafica' => $documento['idanagrafica'],
'show-ritenuta-contributi' => !empty($documento['id_ritenuta_contributi']),
'imponibile_scontato' => $documento->imponibile_scontato,
'totale_imponibile' => $documento->totale_imponibile,
];
// Dati della riga

View File

@ -2,9 +2,7 @@
include_once __DIR__.'/../../core.php';
use Modules\Fatture\Components\Riga;
// Righe fattura
// Righe documento
$righe = $fattura->getRighe();
echo '
@ -28,7 +26,7 @@ foreach ($righe as $row) {
// Valori assoluti
$riga['qta'] = abs($riga['qta']);
$riga['prezzo_unitario_acquisto'] = abs($riga['prezzo_unitario_acquisto']);
$riga['imponibile_scontato'] = ($fattura->isNota() ? -$row->imponibile_scontato : $row->imponibile_scontato);
$riga['totale_imponibile'] = ($fattura->isNota() ? -$row->totale_imponibile : $row->totale_imponibile);
$riga['sconto_unitario'] = abs($riga['sconto_unitario']);
$riga['sconto'] = abs($riga['sconto']);
$riga['iva'] = abs($riga['iva']);
@ -39,26 +37,18 @@ foreach ($righe as $row) {
$extra = '';
$delete = 'unlink_riga';
// Articoli
if ($row->isArticolo()) {
$riga['descrizione'] = (!empty($row->articolo) ? $row->articolo->codice.' - ' : '').$riga['descrizione'];
$delete = 'unlink_articolo';
// Preventivi
if (!empty($riga['idpreventivo'])) {
$delete = 'unlink_preventivo';
}
// Contratti
elseif (!empty($riga['idcontratto'])) {
$delete = 'unlink_contratto';
}
$extra = '';
$mancanti = 0;
}
// Intervento
elseif (!empty($riga['idintervento'])) {
if (!empty($riga['idintervento'])) {
$intervento = $dbo->fetchOne('SELECT num_item,codice_cig,codice_cup,id_documento_fe FROM in_interventi WHERE id = '.prepare($riga['idintervento']));
$riga['num_item'] = $intervento['num_item'];
$riga['codice_cig'] = $intervento['codice_cig'];
@ -74,8 +64,6 @@ foreach ($righe as $row) {
$riga['codice_cig'] = $preventivo['codice_cig'];
$riga['codice_cup'] = $preventivo['codice_cup'];
$riga['id_documento_fe'] = $preventivo['id_documento_fe'];
$delete = 'unlink_preventivo';
}
// Contratti
elseif (!empty($riga['idcontratto'])) {
@ -84,8 +72,6 @@ foreach ($righe as $row) {
$riga['codice_cig'] = $contratto['codice_cig'];
$riga['codice_cup'] = $contratto['codice_cup'];
$riga['id_documento_fe'] = $contratto['id_documento_fe'];
$delete = 'unlink_contratto';
}
// Ordini (IDDOCUMENTO,CIG,CUP)
elseif (!empty($riga['idordine'])) {
@ -94,12 +80,6 @@ foreach ($righe as $row) {
$riga['codice_cig'] = $ordine['codice_cig'];
$riga['codice_cup'] = $ordine['codice_cup'];
$riga['id_documento_fe'] = $ordine['id_documento_fe'];
$delete = 'unlink_riga';
}
// Righe generiche
else {
$delete = 'unlink_riga';
}
// Individuazione dei seriali
@ -154,7 +134,7 @@ foreach ($righe as $row) {
]);
echo '
<br>'.Modules::link('Fatture di vendita', $record['ref_documento'], $text, $text);
<br>'.Modules::link($id_module, $record['ref_documento'], $text, $text);
}
$ref = doc_references($riga, $dir, ['iddocumento']);
@ -197,7 +177,7 @@ foreach ($righe as $row) {
echo '
'.moneyFormat($row->prezzo_unitario_vendita);
if ($dir == 'entrata') {
if ($dir == 'entrata' && $row->prezzo_unitario_acquisto != 0) {
echo '
<br><small>
'.tr('Acquisto').': '.moneyFormat($row->prezzo_unitario_acquisto).'
@ -205,9 +185,11 @@ foreach ($righe as $row) {
}
if (abs($row->sconto_unitario) > 0) {
$text = $row->sconto_unitario > 0 ? tr('sconto _TOT_ _TYPE_') : tr('maggiorazione _TOT_ _TYPE_');
echo '
<br><small class="label label-danger">'.tr('sconto _TOT_ _TYPE_', [
'_TOT_' => Translator::numberToLocale($row->sconto_unitario),
<br><small class="label label-danger">'.replace($text, [
'_TOT_' => Translator::numberToLocale(abs($row->sconto_unitario)),
'_TYPE_' => ($row->tipo_sconto == 'PRC' ? '%' : currency()),
]).'</small>';
}
@ -234,7 +216,7 @@ foreach ($righe as $row) {
<td class="text-right">';
if (!$row->isDescrizione()) {
echo '
'.moneyFormat($riga['imponibile_scontato']);
'.moneyFormat($riga['totale_imponibile']);
/*
<br><small class="text-'.($row->guadagno > 0 ? 'success' : 'danger').'">
'.tr('Guadagno').': '.moneyFormat($row->guadagno).'
@ -269,9 +251,17 @@ foreach ($righe as $row) {
}
echo "
<a class='btn btn-xs btn-warning' title='Modifica questa riga...' onclick=\"launch_modal( 'Modifica riga', '".$structure->fileurl('row-edit.php').'?id_module='.$id_module.'&id_record='.$id_record.'&idriga='.$riga['id']."', 1 );\"><i class='fa fa-edit'></i></a>
<a class='btn btn-xs btn-info' data-toggle='modal' data-title='".tr('Dati Fattura Elettronica')."' data-href='".$structure->fileurl('fe/row-fe.php').'?id_module='.$id_module.'&id_record='.$id_record.'&idriga='.$riga['id']."'>
<i class='fa fa-file-code-o '></i>
</a>
<a class='btn btn-xs btn-danger' title='Rimuovi questa riga...' onclick=\"if( confirm('Rimuovere questa riga dalla fattura?') ){ $('#delete-form-".$riga['id']."').submit(); }\"><i class='fa fa-trash'></i></a>
<a class='btn btn-xs btn-warning' title='Modifica questa riga...' onclick=\"launch_modal( 'Modifica riga', '".$structure->fileurl('row-edit.php').'?id_module='.$id_module.'&id_record='.$id_record.'&idriga='.$riga['id']."', 1 );\">
<i class='fa fa-edit'></i>
</a>
<a class='btn btn-xs btn-danger' title='Rimuovi questa riga...' onclick=\"if( confirm('Rimuovere questa riga dalla fattura?') ){ $('#delete-form-".$riga['id']."').submit(); }\">
<i class='fa fa-trash'></i>
</a>
</div>
</form>";
}
@ -291,8 +281,8 @@ echo '
</tbody>';
$imponibile = abs($fattura->imponibile);
$sconto = abs($fattura->sconto);
$imponibile_scontato = abs($fattura->imponibile_scontato);
$sconto = $fattura->sconto;
$totale_imponibile = abs($fattura->totale_imponibile);
$iva = abs($fattura->iva);
$totale = abs($fattura->totale);
$netto_a_pagare = abs($fattura->netto);
@ -315,7 +305,7 @@ if (!empty($sconto)) {
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Sconto', [], ['upper' => true]).':</b>
<b><span class="tip" title="'.tr('Un importo positivo indica uno sconto, mentre uno negativo indica una maggiorazione').'"><i class="fa fa-question-circle-o"></i> '.tr('Sconto/maggiorazione', [], ['upper' => true]).':</span></b>
</td>
<td align="right">
'.moneyFormat($sconto, 2).'
@ -323,14 +313,14 @@ if (!empty($sconto)) {
<td></td>
</tr>';
// IMPONIBILE SCONTATO
// TOTALE IMPONIBILE
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Imponibile scontato', [], ['upper' => true]).':</b>
<b>'.tr('Totale imponibile', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($imponibile_scontato, 2).'
'.moneyFormat($totale_imponibile, 2).'
</td>
<td></td>
</tr>';

View File

@ -28,7 +28,7 @@ class Articolo extends Article
return $model;
}
public function movimenta($qta)
public function movimentaMagazzino($qta)
{
// Se il documento è generato da un ddt o intervento allora **non** movimento il magazzino
if (!empty($this->idddt) || !empty($this->idintervento)) {
@ -52,8 +52,13 @@ class Articolo extends Article
'_NUM_' => $numero,
]);
$partenza = $fattura->direzione == 'uscita' ? $fattura->idsede_destinazione : $fattura->idsede_partenza;
$arrivo = $fattura->direzione == 'uscita' ? $fattura->idsede_partenza : $fattura->idsede_destinazione;
$this->articolo->movimenta(-$qta, $movimento, $data, false, [
'iddocumento' => $fattura->id,
'idsede_azienda' => $partenza,
'idsede_controparte' => $arrivo,
]);
}

View File

@ -34,6 +34,29 @@ trait RelationTrait
return $result;
}
/**
* Restituisce i dati aggiuntivi per la fattura elettronica dell'elemento.
*
* @return array
*/
public function getDatiAggiuntiviFEAttribute()
{
$result = json_decode($this->attributes['dati_aggiuntivi_fe'], true);
return (array) $result;
}
/**
* Imposta i dati aggiuntivi per la fattura elettronica dell'elemento.
*/
public function setDatiAggiuntiviFEAttribute($values)
{
$values = (array) $values;
$dati = array_deep_clean($values);
$this->attributes['dati_aggiuntivi_fe'] = json_encode($dati);
}
/**
* Restituisce il totale (imponibile + iva + rivalsa_inps + iva_rivalsainps) dell'elemento.
*
@ -41,12 +64,12 @@ trait RelationTrait
*/
public function getTotaleAttribute()
{
return $this->imponibile_scontato + $this->iva + $this->rivalsa_inps + $this->iva_rivalsa_inps;
return $this->totale_imponibile + $this->iva + $this->rivalsa_inps + $this->iva_rivalsa_inps;
}
public function getRivalsaINPSAttribute()
{
return $this->imponibile_scontato / 100 * $this->rivalsa->percentuale;
return $this->totale_imponibile / 100 * $this->rivalsa->percentuale;
}
public function getIvaRivalsaINPSAttribute()
@ -56,7 +79,7 @@ trait RelationTrait
public function getRitenutaAccontoAttribute()
{
$result = $this->imponibile_scontato;
$result = $this->totale_imponibile;
if ($this->calcolo_ritenuta_acconto == 'IMP+RIV') {
$result += $this->rivalsainps;
@ -71,7 +94,7 @@ trait RelationTrait
public function getRitenutaContributiAttribute()
{
if ($this->attributes['ritenuta_contributi']) {
$result = $this->imponibile_scontato;
$result = $this->totale_imponibile;
$ritenuta = $this->parent->ritenutaContributi;
$result = $result * $ritenuta->percentuale_imponibile / 100;
@ -139,6 +162,17 @@ trait RelationTrait
return parent::save($options);
}
public function delete()
{
$result = parent::delete();
if (!empty($this->idintervento)) {
database()->query("UPDATE in_interventi SET idstatointervento = (SELECT idstatointervento FROM in_statiintervento WHERE descrizione = 'Completato') WHERE id=".prepare($this->idintervento));
}
return $result;
}
/**
* Effettua i conti per la Rivalsa INPS.
*/

View File

@ -210,6 +210,29 @@ class Fattura extends Document
return $this->calcola('ritenuta_contributi');
}
/**
* Restituisce i dati aggiuntivi per la fattura elettronica dell'elemento.
*
* @return array
*/
public function getDatiAggiuntiviFEAttribute()
{
$result = json_decode($this->attributes['dati_aggiuntivi_fe'], true);
return (array) $result;
}
/**
* Imposta i dati aggiuntivi per la fattura elettronica dell'elemento.
*/
public function setDatiAggiuntiviFEAttribute($values)
{
$values = (array) $values;
$dati = array_deep_clean($values);
$this->attributes['dati_aggiuntivi_fe'] = json_encode($dati);
}
// Relazioni Eloquent
public function anagrafica()
@ -344,7 +367,7 @@ class Fattura extends Document
*/
public static function registraScadenza(Fattura $fattura, $importo, $scadenza, $is_pagato, $type = 'fattura')
{
//Calcolo la descrizione
// Individuazione della descrizione
$descrizione = database()->fetchOne("SELECT CONCAT(co_tipidocumento.descrizione, CONCAT(' numero ', IF(numero_esterno!='', numero_esterno, numero))) AS descrizione FROM co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id='".$fattura->id."'")['descrizione'];
database()->insert('co_scadenziario', [
@ -418,6 +441,16 @@ class Fattura extends Document
return parent::save($options);
}
public function delete()
{
$result = parent::delete();
$this->rimuoviScadenze();
elimina_movimento($this->id);
return $result;
}
/**
* Restituisce l'elenco delle note di credito collegate.
*

View File

@ -6,8 +6,12 @@ $r = $dbo->fetchOne('SELECT co_documenti.*,
an_anagrafiche.idconto_fornitore,
an_anagrafiche.pec,
an_anagrafiche.ragione_sociale,
co_tipidocumento.descrizione AS tipo_documento,
(SELECT pec FROM zz_smtps WHERE zz_smtps.id='.prepare($template['id_smtp']).') AS is_pec
FROM co_documenti INNER JOIN an_anagrafiche ON co_documenti.idanagrafica=an_anagrafiche.idanagrafica WHERE co_documenti.id='.prepare($id_record));
FROM co_documenti
INNER JOIN an_anagrafiche ON co_documenti.idanagrafica=an_anagrafiche.idanagrafica
INNER JOIN co_tipidocumento ON co_tipidocumento.id=co_documenti.idtipodocumento
WHERE co_documenti.id='.prepare($id_record));
$logo_azienda = str_replace(DOCROOT, BASEURL, App::filepath('templates/base|custom|/logo_azienda.jpg'));
@ -31,6 +35,7 @@ return [
'id_anagrafica' => $r['idanagrafica'],
'ragione_sociale' => $r['ragione_sociale'],
'numero' => empty($r['numero_esterno']) ? $r['numero'] : $r['numero_esterno'],
'tipo_documento' => $r['tipo_documento'],
'note' => $r['note'],
'data' => Translator::dateToLocale($r['data']),
'logo_azienda' => !empty($logo_azienda) ? '<img src="'.$logo_azienda.'" />' : '',

View File

@ -7,6 +7,7 @@ use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Interventi\Components\Articolo;
use Modules\Interventi\Components\Riga;
use Modules\Interventi\Components\Sconto;
use Modules\Interventi\Components\Sessione;
use Modules\Interventi\Intervento;
use Modules\Interventi\Stato;
use Modules\TipiIntervento\Tipo as TipoSessione;
@ -544,102 +545,29 @@ switch (post('op')) {
case 'edit_sessione':
$id_sessione = post('id_sessione');
$sessione = Sessione::find($id_sessione);
// Lettura delle date di inizio e fine intervento
$orario_inizio = post('orario_inizio');
$orario_fine = post('orario_fine');
$sessione->orario_inizio = post('orario_inizio');
$sessione->orario_fine = post('orario_fine');
$sessione->km = post('km');
// Ricalcolo le ore lavorate
$ore = calcola_ore_intervento($orario_inizio, $orario_fine);
$id_tipo = post('idtipointerventot');
$sessione->setTipo($id_tipo);
$km = post('km');
// Prezzi
$sessione->prezzo_ore_unitario = post('prezzo_ore_unitario');
$sessione->prezzo_km_unitario = post('prezzo_km_unitario');
$sessione->prezzo_dirittochiamata = post('prezzo_dirittochiamata');
// Lettura tariffe in base al tipo di intervento ed al tecnico
$idtipointervento_tecnico = post('idtipointerventot');
$rs = $dbo->fetchArray('SELECT * FROM in_interventi_tecnici WHERE idtecnico='.prepare(post('idtecnico')).' AND idintervento='.prepare($id_record));
// Sconto orario
$sessione->sconto_unitario = post('sconto');
$sessione->tipo_sconto = post('tipo_sconto');
if ($idtipointervento_tecnico != $rs[0]['idtipointervento']) {
$rsc = $dbo->fetchArray('SELECT * FROM in_tariffe WHERE idtecnico='.prepare(post('idtecnico')).' AND idtipointervento='.prepare($idtipointervento_tecnico));
// Sconto chilometrico
$sessione->scontokm_unitario = post('sconto_km');
$sessione->tipo_scontokm = post('tipo_sconto_km');
$prezzo_ore_unitario = $rsc[0]['costo_ore'];
$prezzo_km_unitario = $rsc[0]['costo_km'];
$prezzo_dirittochiamata = $rsc[0]['costo_dirittochiamata'];
$prezzo_ore_unitario_tecnico = $rsc[0]['costo_ore_tecnico'];
$prezzo_km_unitario_tecnico = $rsc[0]['costo_km_tecnico'];
$prezzo_dirittochiamata_tecnico = $rsc[0]['costo_dirittochiamata_tecnico'];
} else {
$prezzo_ore_unitario = post('prezzo_ore_unitario');
$prezzo_km_unitario = post('prezzo_km_unitario');
$prezzo_dirittochiamata = post('prezzo_dirittochiamata');
$prezzo_ore_unitario_tecnico = $rs[0]['prezzo_ore_unitario_tecnico'];
$prezzo_km_unitario_tecnico = $rs[0]['prezzo_km_unitario_tecnico'];
$prezzo_dirittochiamata_tecnico = $rs[0]['prezzo_dirittochiamata_tecnico'];
}
// Totali
$prezzo_ore_consuntivo = $prezzo_ore_unitario * $ore;
$prezzo_km_consuntivo = $prezzo_km_unitario * $km;
$prezzo_ore_consuntivo_tecnico = $prezzo_ore_unitario_tecnico * $ore;
$prezzo_km_consuntivo_tecnico = $prezzo_km_unitario_tecnico * $km;
// Sconti ore
$sconto_unitario = post('sconto');
$tipo_sconto = post('tipo_sconto');
if ($tipo_sconto == 'UNT') {
$sconto = $sconto_unitario * $ore;
} else {
$sconto = calcola_sconto([
'sconto' => $sconto_unitario,
'prezzo' => $prezzo_ore_consuntivo,
'tipo' => $tipo_sconto,
]);
}
// Sconti km
$scontokm_unitario = post('sconto_km');
$tipo_scontokm = post('tipo_sconto_km');
if ($tipo_scontokm == 'UNT') {
$scontokm = $scontokm_unitario * $km;
} else {
$scontokm = calcola_sconto([
'sconto' => $scontokm_unitario,
'prezzo' => $prezzo_km_consuntivo,
'tipo' => $tipo_scontokm,
]);
}
$dbo->update('in_interventi_tecnici', [
'idtipointervento' => $idtipointervento_tecnico,
'orario_inizio' => $orario_inizio,
'orario_fine' => $orario_fine,
'ore' => $ore,
'km' => $km,
'prezzo_ore_unitario' => $prezzo_ore_unitario,
'prezzo_km_unitario' => $prezzo_km_unitario,
'prezzo_dirittochiamata' => $prezzo_dirittochiamata,
'prezzo_ore_unitario_tecnico' => $prezzo_ore_unitario_tecnico,
'prezzo_km_unitario_tecnico' => $prezzo_km_unitario_tecnico,
'prezzo_dirittochiamata_tecnico' => $prezzo_dirittochiamata_tecnico,
'prezzo_ore_consuntivo' => $prezzo_ore_consuntivo,
'prezzo_km_consuntivo' => $prezzo_km_consuntivo,
'prezzo_ore_consuntivo_tecnico' => $prezzo_ore_consuntivo_tecnico,
'prezzo_km_consuntivo_tecnico' => $prezzo_km_consuntivo_tecnico,
'sconto' => $sconto,
'sconto_unitario' => $sconto_unitario,
'tipo_sconto' => $tipo_sconto,
'scontokm' => $scontokm,
'scontokm_unitario' => $scontokm_unitario,
'tipo_scontokm' => $tipo_scontokm,
], ['id' => $id_sessione]);
$sessione->save();
break;
}

View File

@ -219,8 +219,8 @@ echo '
success: function(){
$('#bs-popup').modal('hide');
// Ricarico gli articoli
$('#articoli').load(globals.rootdir + '/modules/interventi/ajax_articoli.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>');
// Ricarico le righe
$('#righe').load(globals.rootdir + '/modules/interventi/ajax_righe.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>');
// Ricarico la tabella dei costi
$('#costi').load(globals.rootdir + '/modules/interventi/ajax_costi.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>');

View File

@ -1,160 +0,0 @@
<?php
include_once __DIR__.'/../../core.php';
$show_prezzi = Auth::user()['gruppo'] != 'Tecnici' || (Auth::user()['gruppo'] == 'Tecnici' && setting('Mostra i prezzi al tecnico'));
$query = 'SELECT *, (SELECT id FROM mg_articoli WHERE mg_articoli_interventi.idarticolo = mg_articoli.id) ref_articolo, (SELECT codice FROM mg_articoli WHERE id=mg_articoli_interventi.idarticolo) AS codice, mg_articoli_interventi.id AS idriga, (SELECT prc_guadagno FROM mg_listini WHERE id=(SELECT idlistino_vendite FROM an_anagrafiche WHERE idanagrafica=(SELECT idanagrafica FROM in_interventi WHERE id=mg_articoli_interventi.idintervento) ) ) AS prc_guadagno FROM mg_articoli_interventi WHERE idintervento='.prepare($id_record);
$rs = $dbo->fetchArray($query);
if (!empty($rs)) {
echo '
<table class="table table-striped table-condensed table-hover table-bordered">
<tr>
<th>'.tr('Articolo').'</th>
<th width="8%">'.tr('Q.').'</th>';
if ($show_prezzi) {
echo '
<th width="15%">'.tr('Prezzo di acquisto').'</th>';
}
if ($show_prezzi) {
echo '
<th width="15%">'.tr('Prezzo di vendita').'</th>
<th width="10%">'.tr('Iva').'</th>
<th width="15%">'.tr('Imponibile').'</th>';
}
if (!$record['flag_completato']) {
echo '
<th width="120" class="text-center">'.tr('#').'</th>';
}
echo '
</tr>';
foreach ($rs as $r) {
$extra = '';
$mancanti = 0;
// Individuazione dei seriali
if (!empty($r['idarticolo']) && !empty($r['abilita_serial'])) {
$serials = array_column($dbo->fetchArray('SELECT serial FROM mg_prodotti WHERE serial IS NOT NULL AND id_riga_intervento='.prepare($r['id'])), 'serial');
$mancanti = $r['qta'] - count($serials);
if ($mancanti > 0) {
$extra = 'class="warning"';
} else {
$mancanti = 0;
}
}
echo '
<tr '.$extra.'>
<td>
<input type="hidden" name="id" value="'.$r['id'].'">
'.((!empty($r['ref_articolo'])) ? Modules::link('Articoli', $r['idarticolo'], (!empty($r['codice']) ? $r['codice'].' - ' : '').$r['descrizione']) : $r['descrizione'].' '.tr('[ELIMINATO]'));
// Info extra (lotto, serial, altro)
if (!empty($r['abilita_serial'])) {
if (!empty($mancanti)) {
echo '
<br><b><small class="text-danger">'.tr('_NUM_ serial mancanti', [
'_NUM_' => $mancanti,
]).'</small></b>';
}
if (!empty($serials)) {
echo '
<br>'.tr('SN').': '.implode(', ', $serials);
}
}
echo '
</td>';
// Quantità
echo '
<td class="text-right">
'.Translator::numberToLocale($r['qta'], 'qta').' '.$r['um'].'
</td>';
if ($show_prezzi) {
echo '
<td class="text-right">
'.moneyFormat($r['prezzo_acquisto']).'
</td>';
}
if ($show_prezzi) {
// Prezzo unitario
echo '
<td class="text-right">
'.moneyFormat($r['prezzo_vendita']);
if ($r['sconto_unitario'] > 0) {
echo '
<br><span class="label label-danger">
- '.tr('sconto _TOT_ _TYPE_', [
'_TOT_' => Translator::numberToLocale($r['sconto_unitario']),
'_TYPE_' => ($r['tipo_sconto'] == 'PRC' ? '%' : currency()),
]).'
</span>';
}
echo '
</td>';
echo '
<td class="text-right">
'.moneyFormat($r['iva']).'
</td>';
// Prezzo di vendita
echo '
<td class="text-right">
<span class="prezzo_articolo">'.Translator::numberToLocale(sum($r['prezzo_vendita'] * $r['qta'], -$r['sconto'])).'</span> '.currency().'
</td>';
}
// Pulsante per riportare nel magazzino centrale.
// Visibile solo se l'intervento non è stato nè fatturato nè completato.
if (!$record['flag_completato']) {
echo '
<td class="text-center">';
if ($r['abilita_serial']) {
echo '
<button type="button" class="btn btn-info btn-xs" data-toggle="tooltip" onclick="launch_modal(\''.tr('Modifica articoli').'\', \''.$rootdir.'/modules/fatture/add_serial.php?id_module='.$id_module.'&id_record='.$id_record.'&idarticolo='.$r['idriga'].'&idriga='.$r['id'].'\', 1);"><i class="fa fa-barcode"></i></button>';
}
echo '
<button type="button" class="btn btn-warning btn-xs" data-toggle="tooltip" onclick="launch_modal(\''.tr('Modifica articoli').'\', \''.$rootdir.'/modules/interventi/add_articolo.php?id_module='.$id_module.'&id_record='.$id_record.'&idriga='.$r['idriga'].'\', 1);"><i class="fa fa-edit"></i></button>
<button type="button" class="btn btn-danger btn-xs" data-toggle="tooltip" title="Riporta in magazzino" onclick="if(confirm(\''.tr('Riportare questo articolo in magazzino?').'\') ){ ritorna_al_magazzino(\''.$r['id'].'\'); }"><i class="fa fa-angle-double-left"></i> <i class="fa fa-truck"></i></button>
</td>';
}
echo '
</tr>';
}
echo '
</table>';
} else {
echo '
<p>'.tr('Nessun articolo presente').'.</p>';
}
?>
<script type="text/javascript">
function ritorna_al_magazzino( id ){
$.post(globals.rootdir + '/modules/interventi/actions.php', {op: 'unlink_articolo', idriga: id, id_record: '<?php echo $id_record; ?>', id_module: '<?php echo $id_module; ?>' }, function(data, result){
if( result == 'success' ){
// ricarico l'elenco degli articoli
$('#articoli').load(globals.rootdir + '/modules/interventi/ajax_articoli.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>');
$('#costi').load(globals.rootdir + '/modules/interventi/ajax_costi.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>');
}
});
}
</script>

View File

@ -6,15 +6,15 @@ if (file_exists(__DIR__.'/../../../core.php')) {
include_once __DIR__.'/../../core.php';
}
use Modules\Interventi\Intervento;
$intervento = Intervento::find($id_record);
$sessioni = $intervento->sessioni;
$righe = $intervento->getRighe();
$show_prezzi = Auth::user()['gruppo'] != 'Tecnici' || (Auth::user()['gruppo'] == 'Tecnici' && setting('Mostra i prezzi al tecnico'));
$idiva = setting('Iva predefinita');
$rs_iva = $dbo->fetchArray('SELECT descrizione, percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva));
($rs_iva[0]['percentuale'] > 0) ? $hide = '' : $hide = 'hide';
if ($show_prezzi) {
$costi = get_costi_intervento($id_record);
$rss = $dbo->fetchArray('SELECT in_statiintervento.completato AS flag_completato FROM in_statiintervento INNER JOIN in_interventi ON in_statiintervento.idstatointervento=in_interventi.idstatointervento WHERE in_interventi.id='.prepare($id_record));
if ($rss[0]['flag_completato']) {
@ -26,77 +26,109 @@ if ($show_prezzi) {
echo '
<!-- Riepilogo dei costi -->
<table class="table table condensed table-striped table-hover table-bordered">
<thead>
<tr>
<th width="40%"></th>
<th width="20%" class="text-center">'.tr('Costo', [], ['upper' => true]).' <span class="tip" title="'.tr('Costo interno').'"><i class="fa fa-question-circle-o"></i></span></th>
<th width="20%" class="text-center">'.tr('Addebito', [], ['upper' => true]).' <span class="tip" title="'.tr('Addebito al cliente').'"><i class="fa fa-question-circle-o"></i></span></th>
<th width="20%" class="text-center">'.tr('Tot. Scontato', [], ['upper' => true]).' <span class="tip" title="'.tr('Addebito scontato al cliente').'"><i class="fa fa-question-circle-o"></i></span></th>
</tr>
</thead>
<tbody>
<tr>
<th>'.tr('Totale manodopera', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($sessioni->sum('costo_manodopera'), 2).'</td>
<td class="text-right">'.moneyFormat($sessioni->sum('prezzo_manodopera'), 2).'</td>
<td class="text-right">'.moneyFormat($sessioni->sum('prezzo_manodopera_scontato'), 2).'</td>
</tr>
<tr>
<th>'.tr('Totale diritto di chiamata', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($sessioni->sum('costo_diritto_chiamata'), 2).'</td>
<td class="text-right">'.moneyFormat($sessioni->sum('prezzo_diritto_chiamata'), 2).'</td>
<td class="text-right">'.moneyFormat($sessioni->sum('prezzo_diritto_chiamata'), 2).'</td>
</tr>
<tr>
<th>'.tr('Totale viaggio', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($sessioni->sum('costo_viaggio'), 2).'</td>
<td class="text-right">'.moneyFormat($sessioni->sum('prezzo_viaggio'), 2).'</td>
<td class="text-right">'.moneyFormat($sessioni->sum('prezzo_viaggio_scontato'), 2).'</td>
</tr>
<tr>
<th>'.tr('Totale righe', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($righe->sum('spesa'), 2).'</td>
<td class="text-right">'.moneyFormat($righe->sum('imponibile'), 2).'</td>
<td class="text-right">'.moneyFormat($righe->sum('totale_imponibile'), 2).'</td>
</tr>
</tbody>';
// Calcoli
$imponibile = abs($intervento->imponibile);
$sconto = $intervento->sconto;
$totale_imponibile = abs($intervento->totale_imponibile);
$iva = abs($intervento->iva);
$totale = abs($intervento->totale);
echo '
<tr>
<th width="40%"></th>
<th width="20%" class="text-center">'.tr('Costo', [], ['upper' => true]).' <span class="tip" title="'.tr('Costo interno').'"><i class="fa fa-question-circle-o"></i></span></th>
<th width="20%" class="text-center">'.tr('Addebito', [], ['upper' => true]).' <span class="tip" title="'.tr('Addebito al cliente').'"><i class="fa fa-question-circle-o"></i></span></th>
<th width="20%" class="text-center">'.tr('Tot. Scontato', [], ['upper' => true]).' <span class="tip" title="'.tr('Addebito scontato al cliente').'"><i class="fa fa-question-circle-o"></i></span></th>
</tr>
<td colspan="3" class="text-right">
<b>'.tr('Imponibile', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($imponibile, 2).'
</td>
</tr>';
// SCONTO
if (!empty($sconto)) {
echo '
<tr>
<th>'.tr('Totale manodopera', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($costi['manodopera_costo'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['manodopera_addebito'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['manodopera_scontato'], 2).'</td>
</tr>
<td colspan="3" class="text-right">
<b><span class="tip" title="'.tr('Un importo positivo indica uno sconto, mentre uno negativo indica una maggiorazione').'"> <i class="fa fa-question-circle-o"></i> '.tr('Sconto/maggiorazione', [], ['upper' => true]).':</span></b>
</td>
<td align="right">
'.moneyFormat($sconto, 2).'
</td>
</tr>';
// Totale imponibile
echo '
<tr>
<th>'.tr('Totale diritto di chiamata', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($costi['dirittochiamata_costo'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['dirittochiamata_addebito'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['dirittochiamata_scontato'], 2).'</td>
</tr>
<td colspan="3" class="text-right">
<b>'.tr('Totale imponibile', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($totale_imponibile, 2).'
</td>
</tr>';
}
// Totale iva
echo '
<tr>
<th>'.tr('Totale viaggio', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($costi['viaggio_costo'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['viaggio_addebito'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['viaggio_scontato'], 2).'</td>
</tr>
<td colspan="3" class="text-right">
<b>'.tr('IVA', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($iva, 2).'
</td>
</tr>';
// Totale preventivo
echo '
<tr>
<th>'.tr('Totale articoli', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($costi['ricambi_costo'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['ricambi_addebito'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['ricambi_scontato'], 2).'</td>
</tr>
<td colspan="3" class="text-right">
<b>'.tr('Totale', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.moneyFormat($totale, 2).'
</td>
</tr>';
<tr>
<th>'.tr('Totale altre spese', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($costi['altro_costo'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['altro_addebito'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['altro_scontato'], 2).'</td>
</tr>
<tr>
<th>'.tr('Sconto incondizionato', [], ['upper' => true]).'</th>
<td class="text-right">-</td>
<td class="text-right">-</td>
<td class="text-right">'.moneyFormat(-$costi['sconto_globale'], 2).'</td>
</tr>
<tr class='.$hide.' >
<th>'.tr('Imponibile', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($costi['totale_costo'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['totale_addebito'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['totale_scontato'], 2).'</td>
</tr>
<tr class='.$hide.' >
<th>'.tr('IVA', [], ['upper' => true]).'</th>
<td class="text-right">'.moneyFormat($costi['iva_costo'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['iva_addebito'], 2).'</td>
<td class="text-right">'.moneyFormat($costi['iva_totale'], 2).'</td>
</tr>
<tr>
<th>'.tr('Totale', [], ['upper' => true]).'</th>
<th class="text-right">'.moneyFormat($costi['totaleivato_costo'], 2).'</th>
<th class="text-right">'.moneyFormat($costi['totaleivato_addebito'], 2).'</th>
<th class="text-right">'.moneyFormat($costi['totale'], 2).'</th>
</tr>
echo '
</table>';
}

View File

@ -1,5 +1,7 @@
<?php
use Modules\Interventi\Intervento;
if (file_exists(__DIR__.'/../../../core.php')) {
include_once __DIR__.'/../../../core.php';
} else {
@ -8,104 +10,147 @@ if (file_exists(__DIR__.'/../../../core.php')) {
$show_prezzi = Auth::user()['gruppo'] != 'Tecnici' || (Auth::user()['gruppo'] == 'Tecnici' && setting('Mostra i prezzi al tecnico'));
$query = 'SELECT * FROM in_righe_interventi WHERE idintervento='.prepare($id_record).' ORDER BY id ASC';
$rs2 = $dbo->fetchArray($query);
$intervento = Intervento::find($id_record);
$righe = $intervento->getRighe();
if (count($rs2) > 0) {
if (!$righe->isEmpty()) {
echo '
<table class="table table-striped table-condensed table-hover table-bordered">
<tr>
<th>'.tr('Descrizione').'</th>
<th width="8%">'.tr('Q.').'</th>
<th width="15%">'.tr('Prezzo di acquisto').'</th>';
<table class="table table-striped table-hover table-condensed table-bordered">
<thead>
<tr>
<th>'.tr('Descrizione').'</th>
<th class="text-center" width="8%">'.tr('Q.').'</th>
<th class="text-center" width="15%">'.tr('Prezzo di acquisto').'</th>';
if ($show_prezzi) {
echo '
<th width="15%">'.tr('Prezzo di vendita').'</th>
<th width="10%">'.tr('Iva').'</th>
<th width="15%">'.tr('Subtotale').'</th>';
<th class="text-center" width="15%">'.tr('Prezzo di vendita').'</th>
<th class="text-center" width="10%">'.tr('Iva').'</th>
<th class="text-center" width="15%">'.tr('Imponibile').'</th>';
}
if (!$record['flag_completato']) {
echo '
<th width="120" class="text-center">'.tr('#').'</th>';
<th class="text-center" width="120" class="text-center">'.tr('#').'</th>';
}
echo '
</tr>';
</tr>
</thead>
<tbody>';
foreach ($righe as $riga) {
$r = $riga->toArray();
$extra = '';
$mancanti = $riga->isArticolo() ? $riga->missing_serials_number : 0;
if ($mancanti > 0) {
$extra = 'class="warning"';
}
$descrizione = (!empty($riga->articolo) ? $riga->articolo->codice.' - ' : '').$riga['descrizione'];
foreach ($rs2 as $r) {
echo '
<tr>
<td>
<input type="hidden" name="id" value="'.$r['id'].'">
'.nl2br($r['descrizione']).'
</td>';
<tr '.$extra.'>
<td>
'.Modules::link($riga->isArticolo() ? Modules::get('Articoli')['id'] : null, $riga->isArticolo() ? $riga['idarticolo'] : null, $descrizione);
if ($riga->isArticolo()) {
if (!empty($mancanti)) {
echo '
<br><b><small class="text-danger">'.tr('_NUM_ serial mancanti', [
'_NUM_' => $mancanti,
]).'</small></b>';
}
$serials = $riga->serials;
if (!empty($serials)) {
echo '
<br>'.tr('SN').': '.implode(', ', $serials);
}
}
echo '
</td>';
// Quantità
echo '
<td class="text-right">
'.Translator::numberToLocale($r['qta'], 'qta').' '.$r['um'].'
</td>';
<td class="text-right">
'.Translator::numberToLocale($r['qta'], 'qta').' '.$r['um'].'
</td>';
//Costo unitario
echo '
<td class="text-right">
'.moneyFormat($r['prezzo_acquisto']).'
</td>';
<td class="text-right">
'.moneyFormat($riga->prezzo_unitario_acquisto).'
</td>';
if ($show_prezzi) {
// Prezzo unitario
$netto = $r['prezzo_vendita'] - $r['sconto_unitario'];
echo '
<td class="text-right">
'.moneyFormat($r['prezzo_vendita']);
<td class="text-right">
'.moneyFormat($riga->prezzo_unitario_vendita);
if (abs($r['sconto_unitario']) > 0) {
$text = $r['sconto_unitario'] > 0 ? tr('sconto _TOT_ _TYPE_') : tr('maggiorazione _TOT_ _TYPE_');
echo '
<br><span class="label label-danger">
- '.tr('sconto _TOT_ _TYPE_', [
'_TOT_' => Translator::numberToLocale($r['sconto_unitario']),
<br><small class="label label-danger">'.replace($text, [
'_TOT_' => Translator::numberToLocale(abs($r['sconto_unitario'])),
'_TYPE_' => ($r['tipo_sconto'] == 'PRC' ? '%' : currency()),
]).'
</span>';
]).'</small>';
}
echo '
</td>';
</td>';
echo '
<td class="text-right">
'.moneyFormat($r['iva']).'
</td>';
<td class="text-right">
'.moneyFormat($r['iva']).'
</td>';
// Prezzo di vendita
echo '
<td class="text-right">
'.moneyFormat(sum($r['prezzo_vendita'] * $r['qta'], -$r['sconto'])).'
</td>';
<td class="text-right">
'.moneyFormat($riga->imponibile).'
</td>';
}
// Pulsante per riportare nel magazzino centrale.
// Visibile solo se l'intervento non è stato nè fatturato nè completato.
if (!$record['flag_completato']) {
$link = $r['is_sconto'] == 1 ? $structure->fileurl('row-edit.php') : $structure->fileurl('add_righe.php');
$link = $riga->isSconto() ? $structure->fileurl('row-edit.php') : $structure->fileurl('add_righe.php');
$link = $riga->isArticolo() ? $structure->fileurl('add_articolo.php') : $link;
echo '
<td class="text-center">
<button type="button" class="btn btn-warning btn-xs" data-toggle="tooltip" onclick="launch_modal(\''.tr('Modifica spesa').'\', \''.$link.'?id_module='.$id_module.'&id_record='.$id_record.'&idriga='.$r['id'].'\', 1);"><i class="fa fa-edit"></i></button>
<button type="button" class="btn btn-danger btn-xs" data-toggle="tooltip" onclick="if(confirm(\''.tr('Eliminare questa spesa?').'\')){ elimina_riga( \''.$r['id'].'\' ); }"><i class="fa fa-trash"></i></button>
</td>';
<td class="text-center">';
if ($r['abilita_serial']) {
echo '
<button type="button" class="btn btn-info btn-xs" data-toggle="tooltip" onclick="launch_modal(\''.tr('Modifica articoli').'\', \''.$rootdir.'/modules/fatture/add_serial.php?id_module='.$id_module.'&id_record='.$id_record.'&idarticolo='.$r['idriga'].'&idriga='.$r['id'].'\', 1);">
<i class="fa fa-barcode"></i>
</button>';
}
echo '
<button type="button" class="btn btn-warning btn-xs" data-toggle="tooltip" onclick="launch_modal(\''.tr('Modifica').'\', \''.$link.'?id_module='.$id_module.'&id_record='.$id_record.'&idriga='.$r['id'].'\', 1);">
<i class="fa fa-edit"></i>
</button>
<button type="button" class="btn btn-danger btn-xs" data-toggle="tooltip" onclick="if(confirm(\''.tr('Eliminare questa riga?').'\')){ '.($riga->isArticolo() ? 'ritorna_al_magazzino' : 'elimina_riga').'( \''.$r['id'].'\' ); }">
<i class="fa fa-trash"></i>
</button>
</td>';
}
echo '
</tr>';
</tr>';
}
echo '
</tbody>
</table>';
} else {
echo '
<p>'.tr('Nessuna spesa presente').'.</p>';
<p>'.tr('Nessuna riga presente').'.</p>';
}
?>
@ -121,4 +166,15 @@ if (count($rs2) > 0) {
}
});
}
function ritorna_al_magazzino( id ){
$.post(globals.rootdir + '/modules/interventi/actions.php', {op: 'unlink_articolo', idriga: id, id_record: '<?php echo $id_record; ?>', id_module: '<?php echo $id_module; ?>' }, function(data, result){
if( result == 'success' ){
// ricarico l'elenco degli articoli
$('#righe').load( globals.rootdir + '/modules/interventi/ajax_righe.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>');
$('#costi').load(globals.rootdir + '/modules/interventi/ajax_costi.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>');
}
});
}
</script>

View File

@ -1,79 +0,0 @@
<?php
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Interventi\Components\Articolo;
use Modules\Interventi\Intervento;
switch ($resource) {
case 'intervento':
$data = $request['data'];
// Se l'idintervento non esiste, creo un nuovo intervento
$formato = setting('Formato codice intervento');
$template = str_replace('#', '%', $formato);
$rs = $dbo->fetchArray('SELECT codice FROM in_interventi WHERE codice=(SELECT MAX(CAST(codice AS SIGNED)) FROM in_interventi) AND codice LIKE '.prepare($template).' ORDER BY codice DESC LIMIT 0,1');
$codice = Util\Generator::generate($formato, $rs[0]['codice']);
if (empty($codice)) {
$rs = $dbo->fetchArray('SELECT codice FROM in_interventi WHERE codice LIKE '.prepare($template).' ORDER BY codice DESC LIMIT 0,1');
$codice = Util\Generator::generate($formato, $rs[0]['codice']);
}
if (!empty($codice) && !empty($data['id_anagrafica']) && !empty($data['id_tipo_intervento'])) {
// Salvataggio modifiche intervento
$dbo->insert('in_interventi', [
'idanagrafica' => $data['id_anagrafica'],
'idclientefinale' => 0,
'idstatointervento' => $data['id_stato_intervento'],
'idtipointervento' => $data['id_tipo_intervento'],
'idsede' => 0,
'codice' => $codice,
'data_richiesta' => $data['data_richiesta'],
'richiesta' => $data['richiesta'],
'descrizione' => $data['descrizione'],
'informazioniaggiuntive' => $data['informazioni_aggiuntive'],
]);
$response['id'] = $dbo->lastInsertedID();
$response['codice'] = $codice;
/*
$start = date('Y-m-d H:i:s');
$end = date('Y-m-d H:i:s', strtotime('+1 hour', strtotime($start)));
add_tecnico($response['id'], $user['idanagrafica'], $start, $end);
*/
}
break;
case 'sessione':
$data = $request['data'];
add_tecnico($data['id_intervento'], $user['idanagrafica'], $data['orario_inizio'], $data['orario_fine']);
break;
case 'articolo_intervento':
$data = $request['data'];
$originale = ArticoloOriginale::find($data['id_articolo']);
$intervento = Intervento::find($data['id_intervento']);
$articolo = Articolo::build($intervento, $originale);
$articolo->qta = $data['qta'];
$articolo->um = $data['um'];
$articolo->save();
break;
}
return [
'intervento',
'sessione',
'articolo_intervento',
];

View File

@ -1,26 +0,0 @@
<?php
switch ($resource) {
case 'sessioni_intervento':
$dbo->query('DELETE FROM `in_interventi_tecnici` WHERE `idintervento` = :id_intervento AND `idtecnico` = :id_tecnico', [
':id_intervento' => $request['id_intervento'],
':id_tecnico' => $user['idanagrafica'],
]);
break;
case 'articoli_intervento':
$dbo->query('DELETE FROM `mg_articoli_interventi` WHERE `idintervento` = :id_intervento', [
':id_intervento' => $request['id_intervento'],
]);
// TODO: prevedere la modifica di quantità!
// TODO: prevedere causali
break;
}
return [
'sessioni_intervento',
//'articoli_intervento',
];

View File

@ -1,130 +0,0 @@
<?php
switch ($resource) {
case 'sync':
// Normalizzazione degli interventi a database
$dbo->query('UPDATE in_interventi_tecnici SET summary = (SELECT ragione_sociale FROM an_anagrafiche INNER JOIN in_interventi ON an_anagrafiche.idanagrafica=in_interventi.idanagrafica WHERE in_interventi.id=in_interventi_tecnici.idintervento) WHERE summary IS NULL');
$dbo->query('UPDATE in_interventi_tecnici SET uid = id WHERE uid IS NULL');
// Individuazione degli interventi
$query = 'SELECT in_interventi_tecnici.id AS idriga, in_interventi_tecnici.idintervento, (SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica=in_interventi.idanagrafica) AS cliente, richiesta, orario_inizio, orario_fine, (SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica=idtecnico) AS nome_tecnico, summary FROM in_interventi_tecnici INNER JOIN in_interventi ON in_interventi_tecnici.idintervento=in_interventi.id WHERE DATE(orario_inizio) BETWEEN CURDATE() - INTERVAL 7 DAY AND CURDATE() + INTERVAL 3 MONTH AND deleted_at IS NULL';
if (!empty($user['idanagrafica'])) {
$query .= ' AND in_interventi_tecnici.idtecnico = '.prepare($user['idanagrafica']);
}
$rs = $dbo->fetchArray($query);
$response['custom'] = '';
$response['custom'] .= "BEGIN:VCALENDAR\n";
$response['custom'] .= 'VERSION:'.Update::getVersion()."\n";
$response['custom'] .= "PRODID:-// OpenSTAManager\n";
foreach ($rs as $r) {
$richiesta = str_replace("\r\n", "\n", $r['richiesta']);
$richiesta = str_replace("\r", "\n", $richiesta);
$richiesta = str_replace("\n", '\\n', $richiesta);
$r['summary'] = str_replace("\r\n", "\n", $r['summary']);
$response['custom'] .= "BEGIN:VEVENT\n";
$response['custom'] .= 'UID:'.$r['idriga']."\n";
$response['custom'] .= 'DTSTAMP:'.date('Ymd').'T'.date('His')."\n";
//$response['custom'] .= 'ORGANIZER;CN='.$azienda.':MAILTO:'.$email."\n";
$response['custom'] .= 'DTSTART:'.date('Ymd', strtotime($r['orario_inizio'])).'T'.date('His', strtotime($r['orario_inizio']))."\n";
$response['custom'] .= 'DTEND:'.date('Ymd', strtotime($r['orario_fine'])).'T'.date('His', strtotime($r['orario_fine']))."\n";
$response['custom'] .= 'SUMMARY:'.html_entity_decode($r['summary'])."\n";
$response['custom'] .= 'DESCRIPTION:'.html_entity_decode($richiesta, ENT_QUOTES, 'UTF-8')."\n";
$response['custom'] .= "END:VEVENT\n";
}
$response['custom'] .= "END:VCALENDAR\n";
break;
// Elenco interventi per l'applicazione (recupero sempre tutti gli interventi che non vengono chiusi)
case 'interventi':
// Periodo per selezionare interventi
$today = date('Y-m-d');
$period_end = date('Y-m-d', strtotime($today.' +7 days'));
$period_start = date('Y-m-d', strtotime($today.' -2 months'));
$query = "SELECT `in_interventi`.`id`,
`in_interventi`.`codice`,
`in_interventi`.`data_richiesta`,
`in_interventi`.`richiesta`,
`in_interventi`.`descrizione`,
`in_interventi`.`idtipointervento`,
`in_interventi`.`idanagrafica`,
`in_interventi`.`idsede`,
`in_interventi`.`idstatointervento`,
`in_interventi`.`informazioniaggiuntive`,
`in_interventi`.`idclientefinale`,
`in_interventi`.`firma_file`,
IF(firma_data = '0000-00-00 00:00:00', '', firma_data) AS `firma_data`,
`in_interventi`.firma_nome,
(SELECT GROUP_CONCAT(CONCAT(my_impianti.matricola, ' - ', my_impianti.nome) SEPARATOR ', ') FROM (my_impianti_interventi INNER JOIN my_impianti ON my_impianti_interventi.idimpianto=my_impianti.id) WHERE my_impianti_interventi.idintervento = `in_interventi`.`id`) AS `impianti`,
(SELECT MAX(`orario_fine`) FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `data`,
(SELECT GROUP_CONCAT(DISTINCT ragione_sociale SEPARATOR ', ') FROM `in_interventi_tecnici` INNER JOIN `an_anagrafiche` ON `in_interventi_tecnici`.`idtecnico` = `an_anagrafiche`.`idanagrafica` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `tecnici`,
`in_statiintervento`.`colore` AS `bgcolor`,
`in_statiintervento`.`descrizione` AS `stato`,
`in_interventi`.`idtipointervento` AS `tipo`
FROM `in_interventi`
INNER JOIN `in_statiintervento` ON `in_interventi`.`idstatointervento` = `in_statiintervento`.`idstatointervento`
INNER JOIN `an_anagrafiche` ON `in_interventi`.`idanagrafica` = `an_anagrafiche`.`idanagrafica`
LEFT JOIN `an_sedi` ON `in_interventi`.`idsede` = `an_sedi`.`id`
WHERE EXISTS(SELECT `orario_fine` FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id` AND `orario_fine` BETWEEN :period_start AND :period_end)";
// TODO: rimosse le seguenti clausole
// WHERE `in_interventi`.idstatointervento IN(SELECT idstatointervento FROM in_statiintervento WHERE app_download=1)
// nel database ufficiale manca in_statiintervento.app_download
// AND `in_interventi_tecnici`.`idtecnico`='".$tecnico[0]['idanagrafica']."'
// nell'inner join con in_interventi_tecnici -> ad oggi 16-05-2018 non gestisco ancora idtecnico
$parameters = [
':period_end' => $period_end,
':period_start' => $period_start,
];
break;
// Elenco sessioni dell'intervento per l'applicazione
case 'sessioni_intervento':
$query = 'SELECT id, idintervento AS id_intervento, orario_inizio, orario_fine FROM in_interventi_tecnici WHERE `idintervento` = :id_intervento';
// TODO: rimosse seguenti clausole:
// WHERE `in_interventi`.idstatointervento IN(SELECT idstatointervento FROM in_statiintervento WHERE app_download=1)
// nel database ufficiale manca in_statiintervento.app_download
$parameters = [
':id_intervento' => $request['id_intervento'],
];
if ($user['gruppo'] == 'Tecnici') {
$query .= ' AND `idtecnico` = :id_tecnico';
$parameters[':id_tecnico'] = $user['idanagrafica'];
}
break;
// Elenco articoli dell'intervento per l'applicazione
case 'articoli_intervento':
$query = 'SELECT id, idarticolo AS id_articolo, idintervento AS id_intervento, qta, created_at as data FROM mg_articoli_interventi WHERE `idintervento` = :id_intervento';
$parameters = [
':id_intervento' => $request['id_intervento'],
];
break;
}
return [
'sync',
'interventi',
'sessioni_intervento',
'articoli_intervento',
];

View File

@ -1,135 +0,0 @@
<?php
use Carbon\Carbon;
switch ($resource) {
case 'sync':
// Normalizzazione degli interventi a database
$dbo->query('UPDATE in_interventi_tecnici SET summary = (SELECT ragione_sociale FROM an_anagrafiche INNER JOIN in_interventi ON an_anagrafiche.idanagrafica=in_interventi.idanagrafica WHERE in_interventi.id=in_interventi_tecnici.idintervento) WHERE summary IS NULL');
$dbo->query('UPDATE in_interventi_tecnici SET uid = id WHERE uid IS NULL');
// Interpretazione degli eventi
$idtecnico = $user['idanagrafica'];
$response = API::getRequest(true);
$ical = new iCalEasyReader();
$events = $ical->load($response);
foreach ($events['VEVENT'] as $event) {
$description = $event['DESCRIPTION'];
// Individuazione idriga di in_interventi_tecnici
if (str_contains($event['UID'], '-')) {
$idriga = 'NEW';
} else {
$idriga = $event['UID'];
}
// Timestamp di inizio
$orario_inizio = DateTime::createFromFormat('Ymd\\THi', $event['DTSTART'])->format(Intl\Formatter::getStandardFormats()['timestamp']);
// Timestamp di fine
$orario_fine = DateTime::createFromFormat('Ymd\\THi', $event['DTEND'])->format(Intl\Formatter::getStandardFormats()['timestamp']);
// Descrizione
$richiesta = $event['DESCRIPTION'];
$richiesta = str_replace('\\r\\n', "\n", $richiesta);
$richiesta = str_replace('\\n', "\n", $richiesta);
$summary = trim($event['SUMMARY']);
$summary = str_replace('\\r\\n', "\n", $summary);
$summary = str_replace('\\n', "\n", $summary);
// Nuova attività
if ($idriga == 'NEW') {
$rs_copie = $dbo->fetchArray('SELECT * FROM in_interventi_tecnici WHERE uid = '.prepare($event['UID']));
if (!empty($rs_copie)) {
$idintervento = $rs_copie[0]['idintervento'];
$dbo->update('in_interventi_tecnici', [
'orario_inizio' => $orario_inizio,
'orario_fine' => $orario_fine,
'summary' => $summary,
], [
'uid' => $event['UID'],
'idtecnico' => $idtecnico,
]);
$dbo->query('UPDATE in_interventi SET richiesta='.prepare($richiesta).', oggetto='.prepare($summary).' WHERE idintervento = (SELECT idintervento FROM in_interventi_tecnici WHERE idintervento = '.prepare($idintervento).' AND idtecnico = '.prepare($idtecnico).' LIMIT 0,1)');
$idriga = $rs_copie[0]['id'];
} else {
$idintervento = get_new_idintervento();
$stato = $dbo->fetchArray("SELECT * FROM in_statiintervento WHERE descrizione = 'Chiamata'");
$dbo->insert('in_interventi', [
'idintervento' => $idintervento,
'idanagrafica' => setting('Azienda predefinita'),
'data_richiesta' => Carbon::now(),
'richiesta' => $richiesta,
'idtipointervento' => 0,
'idstatointervento' => $stato['idstatointerventoWIP'],
'oggetto' => $summary,
]);
$dbo->insert('in_interventi', [
'idintervento' => $idintervento,
'idtecnico' => $idtecnico,
'orario_inizio' => $orario_inizio,
'orario_fine' => $orario_fine,
'summary' => $summary,
'uid' => $event['UID'],
]);
$idriga = $dbo->lastInsertedID();
}
}
// Modifica attività esistente
else {
$dbo->update('in_interventi_tecnici', [
'orario_inizio' => $orario_inizio,
'orario_fine' => $orario_fine,
'summary' => $summary,
], [
'id' => $idriga,
'idtecnico' => $idtecnico,
]);
$query = 'UPDATE in_interventi SET richiesta='.prepare($richiesta).', oggetto='.prepare($summary).' WHERE idintervento = (SELECT idintervento FROM in_interventi_tecnici WHERE id = '.prepare($idriga).' AND idtecnico = '.prepare($idtecnico).' LIMIT 0,1)';
$dbo->query($query);
}
}
break;
case 'intervento':
$data = $request['data'];
$dbo->update('in_interventi', [
'idstatointervento' => $data['id_stato_intervento'],
'descrizione' => $data['descrizione'],
'informazioniaggiuntive' => $data['informazioni_aggiuntive'],
], ['id' => $data['id']]);
break;
case 'firma_intervento':
$data = $request['data'];
$dbo->update('in_interventi', [
'firma_file' => $data['firma_file'],
'firma_data' => $data['firma_data'],
'firma_nome' => $data['firma_nome'],
], ['id' => $data['id']]);
break;
}
return [
'sync',
'intervento',
'firma_intervento',
];

View File

@ -0,0 +1,50 @@
<?php
namespace Modules\Interventi\API\v1;
use API\Interfaces\CreateInterface;
use API\Interfaces\RetrieveInterface;
use API\Resource;
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Interventi\Components\Articolo;
use Modules\Interventi\Intervento;
class Articoli extends Resource implements RetrieveInterface, CreateInterface
{
public function retrieve($request)
{
$query = 'SELECT id, idarticolo AS id_articolo, idintervento AS id_intervento, qta, created_at as data FROM mg_articoli_interventi WHERE `idintervento` = :id_intervento';
$parameters = [
':id_intervento' => $request['id_intervento'],
];
return [
'query' => $query,
'parameters' => $parameters,
];
}
public function create($request)
{
$data = $request['data'];
$originale = ArticoloOriginale::find($data['id_articolo']);
$intervento = Intervento::find($data['id_intervento']);
$articolo = Articolo::build($intervento, $originale);
$articolo->qta = $data['qta'];
$articolo->um = $data['um'];
$articolo->save();
}
public function delete($request)
{
$database = database();
$database->query('DELETE FROM `mg_articoli_interventi` WHERE `idintervento` = :id_intervento', [
':id_intervento' => $request['id_intervento'],
]);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Modules\Interventi\API\v1;
use API\Interfaces\UpdateInterface;
use API\Resource;
class Firma extends Resource implements UpdateInterface
{
public function update($request)
{
$database = database();
$data = $request['data'];
$database->update('in_interventi', [
'firma_file' => $data['firma_file'],
'firma_data' => $data['firma_data'],
'firma_nome' => $data['firma_nome'],
], ['id' => $data['id']]);
}
}

View File

@ -0,0 +1,92 @@
<?php
namespace Modules\Interventi\API\v1;
use API\Interfaces\CreateInterface;
use API\Interfaces\RetrieveInterface;
use API\Interfaces\UpdateInterface;
use API\Resource;
use Modules\Anagrafiche\Anagrafica;
use Modules\Interventi\Intervento;
use Modules\Interventi\Stato;
use Modules\TipiIntervento\Tipo as TipoSessione;
class Interventi extends Resource implements RetrieveInterface, CreateInterface, UpdateInterface
{
public function retrieve($request)
{
// Periodo per selezionare interventi
$today = date('Y-m-d');
$period_end = date('Y-m-d', strtotime($today.' +7 days'));
$period_start = date('Y-m-d', strtotime($today.' -2 months'));
$query = "SELECT `in_interventi`.`id`,
`in_interventi`.`codice`,
`in_interventi`.`data_richiesta`,
`in_interventi`.`richiesta`,
`in_interventi`.`descrizione`,
`in_interventi`.`idtipointervento`,
`in_interventi`.`idanagrafica`,
`in_interventi`.`idsede_destinazione`,
`in_interventi`.`idstatointervento`,
`in_interventi`.`informazioniaggiuntive`,
`in_interventi`.`idclientefinale`,
`in_interventi`.`firma_file`,
IF(firma_data = '0000-00-00 00:00:00', '', firma_data) AS `firma_data`,
`in_interventi`.firma_nome,
(SELECT GROUP_CONCAT(CONCAT(my_impianti.matricola, ' - ', my_impianti.nome) SEPARATOR ', ') FROM (my_impianti_interventi INNER JOIN my_impianti ON my_impianti_interventi.idimpianto=my_impianti.id) WHERE my_impianti_interventi.idintervento = `in_interventi`.`id`) AS `impianti`,
(SELECT MAX(`orario_fine`) FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `data`,
(SELECT GROUP_CONCAT(DISTINCT ragione_sociale SEPARATOR ', ') FROM `in_interventi_tecnici` INNER JOIN `an_anagrafiche` ON `in_interventi_tecnici`.`idtecnico` = `an_anagrafiche`.`idanagrafica` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `tecnici`,
`in_statiintervento`.`colore` AS `bgcolor`,
`in_statiintervento`.`descrizione` AS `stato`,
`in_interventi`.`idtipointervento` AS `tipo`
FROM `in_interventi`
INNER JOIN `in_statiintervento` ON `in_interventi`.`idstatointervento` = `in_statiintervento`.`idstatointervento`
INNER JOIN `an_anagrafiche` ON `in_interventi`.`idanagrafica` = `an_anagrafiche`.`idanagrafica`
LEFT JOIN `an_sedi` ON `in_interventi`.`idsede_destinazione` = `an_sedi`.`id`
WHERE EXISTS(SELECT `orario_fine` FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id` AND `orario_fine` BETWEEN :period_start AND :period_end)";
$parameters = [
':period_end' => $period_end,
':period_start' => $period_start,
];
return [
'query' => $query,
'parameters' => $parameters,
];
}
public function create($request)
{
$data = $request['data'];
$anagrafica = Anagrafica::find($data['id_anagrafica']);
$tipo = TipoSessione::find($data['id_tipo_intervento']);
$stato = Stato::find($data['id_stato_intervento']);
$intervento = Intervento::build($anagrafica, $tipo, $stato, $data['data_richiesta']);
$intervento->richiesta = $data['richiesta'];
$intervento->descrizione = $data['descrizione'];
$intervento->informazioniaggiuntive = $data['informazioni_aggiuntive'];
$intervento->save();
return [
'id' => $intervento->id,
'codice' => $intervento->codice,
];
}
public function update($request)
{
$data = $request['data'];
$intervento = Intervento::find($data['id']);
$intervento->idstatointervento = $data['id_stato_intervento'];
$intervento->descrizione = $data['descrizione'];
$intervento->informazioniaggiuntive = $data['informazioni_aggiuntive'];
$intervento->save();
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace Modules\Interventi\API\v1;
use API\Interfaces\CreateInterface;
use API\Interfaces\DeleteInterface;
use API\Interfaces\RetrieveInterface;
use API\Resource;
class Sessioni extends Resource implements RetrieveInterface, CreateInterface, DeleteInterface
{
public function retrieve($request)
{
$user = $this->getUser();
$query = 'SELECT id, idtecnico AS id_tecnico, idintervento AS id_intervento, orario_inizio, orario_fine FROM in_interventi_tecnici WHERE `idintervento` = :id_intervento';
$parameters = [
':id_intervento' => $request['id_intervento'],
];
if ($user['gruppo'] == 'Tecnici') {
$query .= ' AND `idtecnico` = :id_tecnico';
$parameters[':id_tecnico'] = $user['idanagrafica'];
}
return [
'query' => $query,
'parameters' => $parameters,
];
}
public function create($request)
{
$user = $this->getUser();
$data = $request['data'];
add_tecnico($data['id_intervento'], $user['idanagrafica'], $data['orario_inizio'], $data['orario_fine']);
}
public function delete($request)
{
$database = database();
$user = $this->getUser();
$database->query('DELETE FROM `in_interventi_tecnici` WHERE `idintervento` = :id_intervento AND `idtecnico` = :id_tecnico', [
':id_intervento' => $request['id_intervento'],
':id_tecnico' => $user['idanagrafica'],
]);
}
}

View File

@ -0,0 +1,168 @@
<?php
namespace Modules\Interventi\API\v1;
use API\Interfaces\RetrieveInterface;
use API\Interfaces\UpdateInterface;
use API\Resource;
use Carbon\Carbon;
use DateTime;
use iCalEasyReader;
use Update;
class Sync extends Resource implements RetrieveInterface, UpdateInterface
{
public function retrieve($request)
{
$database = database();
$user = $this->getUser();
// Normalizzazione degli interventi a database
$database->query('UPDATE in_interventi_tecnici SET summary = (SELECT ragione_sociale FROM an_anagrafiche INNER JOIN in_interventi ON an_anagrafiche.idanagrafica=in_interventi.idanagrafica WHERE in_interventi.id=in_interventi_tecnici.idintervento) WHERE summary IS NULL');
$database->query('UPDATE in_interventi_tecnici SET uid = id WHERE uid IS NULL');
// Individuazione degli interventi
$query = 'SELECT in_interventi_tecnici.id AS idriga, in_interventi_tecnici.idintervento, (SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica=in_interventi.idanagrafica) AS cliente, richiesta, orario_inizio, orario_fine, (SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica=idtecnico) AS nome_tecnico, summary FROM in_interventi_tecnici INNER JOIN in_interventi ON in_interventi_tecnici.idintervento=in_interventi.id WHERE DATE(orario_inizio) BETWEEN CURDATE() - INTERVAL 7 DAY AND CURDATE() + INTERVAL 3 MONTH AND deleted_at IS NULL';
if ($user->anagrafica->isTipo('Tecnico')) {
$query .= ' AND in_interventi_tecnici.idtecnico = '.prepare($user['idanagrafica']);
}
$rs = $database->fetchArray($query);
$result = '';
$result .= "BEGIN:VCALENDAR\n";
$result .= 'VERSION:'.Update::getVersion()."\n";
$result .= "PRODID:-// OpenSTAManager\n";
foreach ($rs as $r) {
$richiesta = str_replace("\r\n", "\n", $r['richiesta']);
$richiesta = str_replace("\r", "\n", $richiesta);
$richiesta = str_replace("\n", '\\n', $richiesta);
$r['summary'] = str_replace("\r\n", "\n", $r['summary']);
$result .= "BEGIN:VEVENT\n";
$result .= 'UID:'.$r['idriga']."\n";
$result .= 'DTSTAMP:'.date('Ymd').'T'.date('His')."\n";
//$result .= 'ORGANIZER;CN='.$azienda.':MAILTO:'.$email."\n";
$result .= 'DTSTART:'.date('Ymd', strtotime($r['orario_inizio'])).'T'.date('His', strtotime($r['orario_inizio']))."\n";
$result .= 'DTEND:'.date('Ymd', strtotime($r['orario_fine'])).'T'.date('His', strtotime($r['orario_fine']))."\n";
$result .= 'SUMMARY:'.html_entity_decode($r['summary'])."\n";
$result .= 'DESCRIPTION:'.html_entity_decode($richiesta, ENT_QUOTES, 'UTF-8')."\n";
$result .= "END:VEVENT\n";
}
$result .= "END:VCALENDAR\n";
return [
'custom' => $result,
];
}
public function update($request)
{
$database = database();
$user = $this->getUser();
// Normalizzazione degli interventi a database
$database->query('UPDATE in_interventi_tecnici SET summary = (SELECT ragione_sociale FROM an_anagrafiche INNER JOIN in_interventi ON an_anagrafiche.idanagrafica=in_interventi.idanagrafica WHERE in_interventi.id=in_interventi_tecnici.idintervento) WHERE summary IS NULL');
$database->query('UPDATE in_interventi_tecnici SET uid = id WHERE uid IS NULL');
// Interpretazione degli eventi
$idtecnico = $user['idanagrafica'];
$response = API\Response::getRequest(true);
$ical = new iCalEasyReader();
$events = $ical->load($response);
foreach ($events['VEVENT'] as $event) {
$description = $event['DESCRIPTION'];
// Individuazione idriga di in_interventi_tecnici
if (str_contains($event['UID'], '-')) {
$idriga = 'NEW';
} else {
$idriga = $event['UID'];
}
// Timestamp di inizio
$orario_inizio = DateTime::createFromFormat('Ymd\\THi', $event['DTSTART'])->format(Intl\Formatter::getStandardFormats()['timestamp']);
// Timestamp di fine
$orario_fine = DateTime::createFromFormat('Ymd\\THi', $event['DTEND'])->format(Intl\Formatter::getStandardFormats()['timestamp']);
// Descrizione
$richiesta = $event['DESCRIPTION'];
$richiesta = str_replace('\\r\\n', "\n", $richiesta);
$richiesta = str_replace('\\n', "\n", $richiesta);
$summary = trim($event['SUMMARY']);
$summary = str_replace('\\r\\n', "\n", $summary);
$summary = str_replace('\\n', "\n", $summary);
// Nuova attività
if ($idriga == 'NEW') {
$rs_copie = $database->fetchArray('SELECT * FROM in_interventi_tecnici WHERE uid = '.prepare($event['UID']));
if (!empty($rs_copie)) {
$idintervento = $rs_copie[0]['idintervento'];
$database->update('in_interventi_tecnici', [
'orario_inizio' => $orario_inizio,
'orario_fine' => $orario_fine,
'summary' => $summary,
], [
'uid' => $event['UID'],
'idtecnico' => $idtecnico,
]);
$database->query('UPDATE in_interventi SET richiesta='.prepare($richiesta).', oggetto='.prepare($summary).' WHERE idintervento = (SELECT idintervento FROM in_interventi_tecnici WHERE idintervento = '.prepare($idintervento).' AND idtecnico = '.prepare($idtecnico).' LIMIT 0,1)');
$idriga = $rs_copie[0]['id'];
} else {
$idintervento = get_new_idintervento();
$stato = $database->fetchArray("SELECT * FROM in_statiintervento WHERE descrizione = 'Chiamata'");
$database->insert('in_interventi', [
'idintervento' => $idintervento,
'idanagrafica' => setting('Azienda predefinita'),
'data_richiesta' => Carbon::now(),
'richiesta' => $richiesta,
'idtipointervento' => 0,
'idstatointervento' => $stato['idstatointerventoWIP'],
'oggetto' => $summary,
]);
$database->insert('in_interventi', [
'idintervento' => $idintervento,
'idtecnico' => $idtecnico,
'orario_inizio' => $orario_inizio,
'orario_fine' => $orario_fine,
'summary' => $summary,
'uid' => $event['UID'],
]);
$idriga = $database->lastInsertedID();
}
}
// Modifica attività esistente
else {
$database->update('in_interventi_tecnici', [
'orario_inizio' => $orario_inizio,
'orario_fine' => $orario_fine,
'summary' => $summary,
], [
'id' => $idriga,
'idtecnico' => $idtecnico,
]);
$query = 'UPDATE in_interventi SET richiesta='.prepare($richiesta).', oggetto='.prepare($summary).' WHERE idintervento = (SELECT idintervento FROM in_interventi_tecnici WHERE id = '.prepare($idriga).' AND idtecnico = '.prepare($idtecnico).' LIMIT 0,1)';
$database->query($query);
}
}
}
}

View File

@ -212,64 +212,45 @@ $_SESSION['superselect']['idsede_destinazione'] = $record['idsede_destinazione']
</div>
</div>
<?php
// Conteggio numero articoli intervento per eventuale blocco della sede di partenza
$articoli = $dbo->fetchArray('SELECT mg_articoli_interventi.id FROM mg_articoli_interventi INNER JOIN in_interventi ON in_interventi.id=mg_articoli_interventi.idintervento WHERE in_interventi.id='.prepare($id_record));
?>
<!-- ARTICOLI -->
<!-- RIGHE -->
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Materiale utilizzato'); ?></h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-3">
{[ "type": "select", "label": "<?php echo tr('Partenza merce'); ?>", "name": "idsede_partenza", "ajax-source": "sedi_azienda", "value": "$idsede_partenza$", "readonly": "<?php echo ($record['flag_completato'] || sizeof($articoli)) ? 1 : 0; ?>" ]}
</div>
</div>
<div id="articoli">
<?php
if (file_exists($docroot.'/modules/interventi/custom/ajax_articoli.php')) {
include $docroot.'/modules/interventi/custom/ajax_articoli.php';
} else {
include $docroot.'/modules/interventi/ajax_articoli.php';
}
?>
</div>
<?php if (!$record['flag_completato']) {
?>
<button type="button" class="btn btn-primary" onclick="launch_modal( '<?php echo tr('Aggiungi articolo'); ?>', '<?php echo $rootdir; ?>/modules/interventi/add_articolo.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>&idriga=0', 1);"><i class="fa fa-plus"></i> <?php echo tr('Aggiungi articolo'); ?>...</button>
<?php
} ?>
</div>
</div>
<!-- SPESE AGGIUNTIVE -->
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Altre spese'); ?></h3>
<h3 class="panel-title"><?php echo tr('Righe'); ?></h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-9">
<?php
if (!$record['flag_completato']) {
echo '
<a class="btn btn-sm btn-primary" data-href="'.$structure->fileurl('add_righe.php').'?id_module='.$id_module.'&id_record='.$id_record.'&is_sconto" data-toggle="tooltip" data-title="'.tr('Aggiungi altre spese').'">
<i class="fa fa-plus"></i> '.tr('Altre spese').'...
</a>';
<a class="btn btn-sm btn-primary" data-href="'.$structure->fileurl('add_articolo.php').'?id_module='.$id_module.'&id_record='.$id_record.'&is_articolo&idriga=0" data-toggle="tooltip" data-title="'.tr('Aggiungi articolo').'">
<i class="fa fa-plus"></i> '.tr('Articolo').'
</a>';
echo '
<a class="btn btn-sm btn-primary" data-href="'.$structure->fileurl('row-add.php').'?id_module='.$id_module.'&id_record='.$id_record.'&is_sconto" data-toggle="tooltip" data-title="'.tr('Aggiungi sconto/maggiorazione').'">
<i class="fa fa-plus"></i> '.tr('Sconto/maggiorazione').'
</a>';
<a class="btn btn-sm btn-primary" data-href="'.$structure->fileurl('add_righe.php').'?id_module='.$id_module.'&id_record='.$id_record.'&is_riga" data-toggle="tooltip" data-title="'.tr('Aggiungi altre spese').'">
<i class="fa fa-plus"></i> '.tr('Riga').'
</a>';
echo '
<a class="btn btn-sm btn-primary" data-href="'.$structure->fileurl('row-add.php').'?id_module='.$id_module.'&id_record='.$id_record.'&is_sconto" data-toggle="tooltip" data-title="'.tr('Aggiungi sconto/maggiorazione').'">
<i class="fa fa-plus"></i> '.tr('Sconto/maggiorazione').'
</a>';
}
// Conteggio numero articoli intervento per eventuale blocco della sede di partenza
$articoli = $dbo->fetchArray('SELECT mg_articoli_interventi.id FROM mg_articoli_interventi INNER JOIN in_interventi ON in_interventi.id=mg_articoli_interventi.idintervento WHERE in_interventi.id='.prepare($id_record));
?>
<div class="clearfix"></div>
<br>
</div>
<div class="col-md-3">
{[ "type": "select", "label": "<?php echo tr('Partenza merce'); ?>", "name": "idsede_partenza", "ajax-source": "sedi_azienda", "value": "$idsede_partenza$", "readonly": "<?php echo ($record['flag_completato'] || !empty($articoli)) ? 1 : 0; ?>" ]}
</div>
</div>
<div id="righe">
<?php

View File

@ -2,6 +2,10 @@
include_once __DIR__.'/../../core.php';
use Modules\Anagrafiche\Anagrafica;
use Modules\Interventi\Components\Sessione;
use Modules\Interventi\Intervento;
/**
* Recupera il totale delle ore spese per un intervento.
*
@ -54,105 +58,17 @@ function add_tecnico($idintervento, $idtecnico, $inizio, $fine, $idcontratto = n
{
$dbo = database();
// Controllo sull'identità del tecnico
$tecnico = $dbo->fetchOne('SELECT an_anagrafiche.idanagrafica, an_anagrafiche.email FROM an_anagrafiche INNER JOIN an_tipianagrafiche_anagrafiche ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica INNER JOIN an_tipianagrafiche ON an_tipianagrafiche.idtipoanagrafica=an_tipianagrafiche_anagrafiche.idtipoanagrafica WHERE an_anagrafiche.idanagrafica = '.prepare($idtecnico)." AND an_tipianagrafiche.descrizione = 'Tecnico'");
if (empty($tecnico)) {
return false;
}
$intervento = Intervento::find($idintervento);
$anagrafica = Anagrafica::find($idtecnico);
$rs = $dbo->fetchArray('SELECT idanagrafica, idsede_destinazione, idtipointervento FROM in_interventi WHERE id='.prepare($idintervento));
$idanagrafica = $rs[0]['idanagrafica'];
$idsede_destinazione = $rs[0]['idsede_destinazione'];
$idtipointervento = $rs[0]['idtipointervento'];
// Calcolo km in base a quelli impostati nell'anagrafica
// Nessuna sede
if ($idsede_destinazione == '-1') {
$km = 0;
}
// Sede legale
elseif (empty($idsede_destinazione)) {
$rs2 = $dbo->fetchArray('SELECT km FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica));
$km = $rs2[0]['km'];
}
// Sede secondaria
else {
$rs2 = $dbo->fetchArray('SELECT km FROM an_sedi WHERE id='.prepare($idsede_destinazione));
$km = $rs2[0]['km'];
}
$km = empty($km) ? 0 : $km;
// Calcolo il totale delle ore lavorate
$diff = date_diff(date_create($inizio), date_create($fine));
$ore = calcola_ore_intervento($inizio, $fine);
// Leggo i costi unitari dalle tariffe se almeno un valore è stato impostato
$rsc = $dbo->fetchArray('SELECT * FROM in_tariffe WHERE idtecnico='.prepare($idtecnico).' AND idtipointervento='.prepare($idtipointervento));
$costo_ore = $rsc[0]['costo_ore'];
$costo_km = $rsc[0]['costo_km'];
$costo_dirittochiamata = $rsc[0]['costo_dirittochiamata'];
$costo_ore_tecnico = $rsc[0]['costo_ore_tecnico'];
$costo_km_tecnico = $rsc[0]['costo_km_tecnico'];
$costo_dirittochiamata_tecnico = $rsc[0]['costo_dirittochiamata_tecnico'];
// Sovrascrivo i costi unitari da contratto se l'intervento è legato ad un contratto e c'è almeno un record...
if (!empty($idcontratto)) {
$rsc = $dbo->fetchArray('SELECT * FROM co_contratti_tipiintervento WHERE idcontratto='.prepare($idcontratto).' AND idtipointervento='.prepare($idtipointervento));
if (!empty($rsc)) {
$costo_ore = $rsc[0]['costo_ore'];
$costo_km = $rsc[0]['costo_km'];
$costo_dirittochiamata = $rsc[0]['costo_dirittochiamata'];
//per le attività collegate a contratti, i costi interni del tecnico vengono sempre presi da quelli globali o da quelli specificati per il singolo tecnico
//$costo_ore_tecnico = $rsc[0]['costo_ore_tecnico'];
//$costo_km_tecnico = $rsc[0]['costo_km_tecnico'];
//$costo_dirittochiamata_tecnico = $rsc[0]['costo_dirittochiamata_tecnico'];
}
}
// Azzeramento forzato del diritto di chiamata nel caso questa non sia la prima sessione dell'intervento per il giorno di inizio [Luca]
$rs = $dbo->fetchArray('SELECT id FROM in_interventi_tecnici WHERE (DATE(orario_inizio)=DATE('.prepare($inizio).') OR DATE(orario_fine)=DATE('.prepare($inizio).')) AND idintervento='.prepare($idintervento));
if (!empty($rs)) {
$costo_dirittochiamata_tecnico = 0;
$costo_dirittochiamata = 0;
}
// Inserisco le ore dei tecnici nella tabella "in_interventi_tecnici"
$dbo->insert('in_interventi_tecnici', [
'idintervento' => $idintervento,
'idtipointervento' => $idtipointervento,
'idtecnico' => $idtecnico,
'km' => $km,
'orario_inizio' => $inizio,
'orario_fine' => $fine,
'ore' => $ore,
'prezzo_ore_unitario' => $costo_ore,
'prezzo_km_unitario' => $costo_km,
'prezzo_ore_consuntivo' => $costo_ore * $ore + $costo_dirittochiamata,
'prezzo_km_consuntivo' => 0,
'prezzo_dirittochiamata' => $costo_dirittochiamata,
'prezzo_ore_unitario_tecnico' => $costo_ore_tecnico,
'prezzo_km_unitario_tecnico' => $costo_km_tecnico,
'prezzo_ore_consuntivo_tecnico' => $costo_ore_tecnico * $ore + $costo_dirittochiamata_tecnico,
'prezzo_km_consuntivo_tecnico' => 0,
'prezzo_dirittochiamata_tecnico' => $costo_dirittochiamata_tecnico,
]);
$sessione = Sessione::build($intervento, $anagrafica, $inizio, $fine);
// Notifica nuovo intervento al tecnico
if (!empty($tecnico['email'])) {
$n = new Notifications\EmailNotification();
$n->setTemplate('Notifica intervento', $idintervento);
$n->setReceivers($tecnico['email']);
$n->setReceivers($anagrafica['email']);
$n->send();
}
@ -160,159 +76,6 @@ function add_tecnico($idintervento, $idtecnico, $inizio, $fine, $idcontratto = n
return true;
}
function get_costi_intervento($id_intervento)
{
$dbo = database();
$decimals = setting('Cifre decimali per importi');
$idiva = setting('Iva predefinita');
$rs_iva = $dbo->fetchArray('SELECT descrizione, percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva));
$tecnici = $dbo->fetchArray('SELECT
COALESCE(SUM(
ROUND(prezzo_ore_unitario_tecnico*ore, '.$decimals.')
), 0) AS manodopera_costo,
COALESCE(SUM(
ROUND(prezzo_ore_unitario*ore, '.$decimals.')
), 0) AS manodopera_addebito,
COALESCE(SUM(
ROUND(prezzo_ore_unitario*ore, '.$decimals.') - ROUND(sconto, '.$decimals.')
), 0) AS manodopera_scontato,
COALESCE(SUM(
ROUND(prezzo_dirittochiamata_tecnico, '.$decimals.')
), 0) AS dirittochiamata_costo,
COALESCE(SUM(
ROUND(prezzo_dirittochiamata, '.$decimals.')
), 0) AS dirittochiamata_addebito,
COALESCE(SUM(
ROUND(prezzo_dirittochiamata, '.$decimals.')
), 0) AS dirittochiamata_scontato,
COALESCE(SUM(
ROUND(prezzo_km_consuntivo_tecnico, '.$decimals.')
), 0) AS viaggio_costo,
COALESCE(SUM(
ROUND(prezzo_km_consuntivo, '.$decimals.')
), 0) viaggio_addebito,
COALESCE(SUM(
ROUND(prezzo_km_consuntivo, '.$decimals.') - ROUND(scontokm, '.$decimals.')
), 0) AS viaggio_scontato
FROM in_interventi_tecnici WHERE idintervento='.prepare($id_intervento));
$articoli = $dbo->fetchArray('SELECT
COALESCE(SUM(
ROUND(prezzo_acquisto, '.$decimals.') * ROUND(qta, '.$decimals.')
), 0) AS ricambi_costo,
COALESCE(SUM(
ROUND(prezzo_vendita, '.$decimals.') * ROUND(qta, '.$decimals.')
), 0) AS ricambi_addebito,
COALESCE(SUM(
ROUND(prezzo_vendita, '.$decimals.') * ROUND(qta, '.$decimals.') - ROUND(sconto, '.$decimals.')
), 0) AS ricambi_scontato,
ROUND(
(SELECT percentuale FROM co_iva WHERE co_iva.id=mg_articoli_interventi.idiva), '.$decimals.'
) AS ricambi_iva
FROM mg_articoli_interventi WHERE idintervento='.prepare($id_intervento));
$altro = $dbo->fetchArray('SELECT
COALESCE(SUM(
ROUND(prezzo_acquisto, '.$decimals.') * ROUND(qta, '.$decimals.')
), 0) AS altro_costo,
COALESCE(SUM(
ROUND(prezzo_vendita, '.$decimals.') * ROUND(qta, '.$decimals.')
), 0) AS altro_addebito,
COALESCE(SUM(
ROUND(prezzo_vendita, '.$decimals.') * ROUND(qta, '.$decimals.') - ROUND(sconto, '.$decimals.')
), 0) AS altro_scontato,
ROUND(
(SELECT percentuale FROM co_iva WHERE co_iva.id=in_righe_interventi.idiva), '.$decimals.'
) AS altro_iva
FROM in_righe_interventi WHERE idintervento='.prepare($id_intervento));
$result = array_merge($tecnici[0], $articoli[0], $altro[0]);
$result['totale_costo'] = sum([
$result['manodopera_costo'],
$result['dirittochiamata_costo'],
$result['viaggio_costo'],
$result['ricambi_costo'],
$result['altro_costo'],
]);
$result['totale_addebito'] = sum([
$result['manodopera_addebito'],
$result['dirittochiamata_addebito'],
$result['viaggio_addebito'],
$result['ricambi_addebito'],
$result['altro_addebito'],
]);
$result['totale_scontato'] = sum([
$result['manodopera_scontato'],
$result['dirittochiamata_scontato'],
$result['viaggio_scontato'],
$result['ricambi_scontato'],
$result['altro_scontato'],
]);
$result['iva_costo'] = sum([
$result['manodopera_costo'] * $rs_iva[0]['percentuale'] / 100,
$result['dirittochiamata_costo'] * $rs_iva[0]['percentuale'] / 100,
$result['viaggio_costo'] * $rs_iva[0]['percentuale'] / 100,
$result['ricambi_costo'] * $result['ricambi_iva'] / 100,
$result['altro_costo'] * $result['altro_iva'] / 100,
]);
$result['iva_addebito'] = sum([
$result['manodopera_addebito'] * $rs_iva[0]['percentuale'] / 100,
$result['dirittochiamata_addebito'] * $rs_iva[0]['percentuale'] / 100,
$result['viaggio_addebito'] * $rs_iva[0]['percentuale'] / 100,
$result['ricambi_addebito'] * $result['ricambi_iva'] / 100,
$result['altro_addebito'] * $result['altro_iva'] / 100,
]);
$result['iva_totale'] = sum([
$result['manodopera_scontato'] * $rs_iva[0]['percentuale'] / 100,
$result['dirittochiamata_scontato'] * $rs_iva[0]['percentuale'] / 100,
$result['viaggio_scontato'] * $rs_iva[0]['percentuale'] / 100,
$result['ricambi_scontato'] * $result['ricambi_iva'] / 100,
$result['altro_scontato'] * $result['altro_iva'] / 100,
]);
$result['totaleivato_costo'] = sum([
$result['manodopera_costo'] + ($result['manodopera_costo'] * $rs_iva[0]['percentuale'] / 100),
$result['dirittochiamata_costo'] + ($result['dirittochiamata_costo'] * $rs_iva[0]['percentuale'] / 100),
$result['viaggio_costo'] + ($result['viaggio_costo'] * $rs_iva[0]['percentuale'] / 100),
$result['ricambi_costo'] + ($result['ricambi_costo'] * $result['ricambi_iva'] / 100),
$result['altro_costo'] + ($result['altro_costo'] * $result['altro_iva'] / 100),
]);
$result['totaleivato_addebito'] = sum([
$result['manodopera_addebito'] + ($result['manodopera_addebito'] * $rs_iva[0]['percentuale'] / 100),
$result['dirittochiamata_addebito'] + ($result['dirittochiamata_addebito'] * $rs_iva[0]['percentuale'] / 100),
$result['viaggio_addebito'] + ($result['viaggio_addebito'] * $rs_iva[0]['percentuale'] / 100),
$result['ricambi_addebito'] + ($result['ricambi_addebito'] * $result['ricambi_iva'] / 100),
$result['altro_addebito'] + ($result['altro_addebito'] * $result['altro_iva'] / 100),
]);
$result['totale'] = sum([
$result['manodopera_scontato'] + ($result['manodopera_scontato'] * $rs_iva[0]['percentuale'] / 100),
$result['dirittochiamata_scontato'] + ($result['dirittochiamata_scontato'] * $rs_iva[0]['percentuale'] / 100),
$result['viaggio_scontato'] + ($result['viaggio_scontato'] * $rs_iva[0]['percentuale'] / 100),
$result['ricambi_scontato'] + ($result['ricambi_scontato'] * $result['ricambi_iva'] / 100),
$result['altro_scontato'] + ($result['altro_scontato'] * $result['altro_iva'] / 100),
]);
return $result;
}
/**
* Calcola le ore presenti tra due date.
*
@ -387,7 +150,7 @@ function aggiungi_intervento_in_fattura($id_intervento, $id_fattura, $descrizion
}
}
$costi_intervento = get_costi_intervento($id_intervento);
$intervento = \Modules\Interventi\Intervento::find($id_intervento);
// Fatturo i diritti di chiamata raggruppati per costo
$rst = $dbo->fetchArray('SELECT COUNT(id) AS qta, SUM(prezzo_dirittochiamata) AS tot_prezzo_dirittochiamata FROM in_interventi_tecnici WHERE idintervento='.prepare($id_intervento).' AND prezzo_dirittochiamata > 0 GROUP BY prezzo_dirittochiamata');
@ -479,14 +242,14 @@ function aggiungi_intervento_in_fattura($id_intervento, $id_fattura, $descrizion
}
// Aggiunta km come "Trasferta" (se c'è)
if ($costi_intervento['viaggio_addebito'] > 0) {
if ($intervento->prezzo_viaggio > 0) {
// Calcolo iva
$query = 'SELECT * FROM co_iva WHERE id='.prepare($id_iva);
$dati = $dbo->fetchArray($query);
$desc_iva = $dati[0]['descrizione'];
$subtot = $costi_intervento['viaggio_addebito'];
$sconto = $costi_intervento['viaggio_addebito'] - $costi_intervento['viaggio_scontato'];
$subtot = $intervento->prezzo_viaggio;
$sconto = $intervento->sconto_totale_viaggio;
$iva = ($subtot - $sconto) / 100 * $dati[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $dati[0]['indetraibile'];
@ -508,37 +271,6 @@ function aggiungi_intervento_in_fattura($id_intervento, $id_fattura, $descrizion
$dbo->query($query);
}
// Aggiunta sconto
if (!empty($costi_intervento['sconto_globale'])) {
$subtot = 0;
$sconto = $costi_intervento['sconto_globale'];
// Calcolo iva
$query = 'SELECT * FROM co_iva WHERE id='.prepare($id_iva);
$rs = $dbo->fetchArray($query);
$desc_iva = $rs[0]['descrizione'];
$iva = ($subtot) / 100 * $rs[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $rs[0]['indetraibile'];
// Calcolo rivalsa inps
$query = 'SELECT * FROM co_rivalse WHERE id='.prepare($id_rivalsa_inps);
$rs = $dbo->fetchArray($query);
$rivalsainps = ($subtot) / 100 * $rs[0]['percentuale'];
// Calcolo ritenuta d'acconto
$query = 'SELECT * FROM co_ritenutaacconto WHERE id='.prepare($id_ritenuta_acconto);
$rs = $dbo->fetchArray($query);
if ($calcolo_ritenuta_acconto == 'Imponibile') {
$ritenutaacconto = $subtot / 100 * $rs[0]['percentuale'];
} else {
$ritenutaacconto = ($subtot + $rivalsainps) / 100 * $rs[0]['percentuale'];
}
$query = 'INSERT INTO co_righe_documenti(iddocumento, idintervento, idconto, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto_unitario, tipo_sconto, qta, idrivalsainps, rivalsainps, idritenutaacconto, ritenutaacconto, calcolo_ritenuta_acconto, `order`) VALUES('.prepare($id_fattura).', NULL, '.prepare($id_conto).', '.prepare($id_iva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare('Sconto '.$descrizione).', '.prepare($subtot).', '.$sconto.', "UNT", 1, '.prepare($id_rivalsa_inps).', '.prepare($rivalsainps).', '.prepare($id_ritenuta_acconto).', '.prepare($ritenutaacconto).', '.prepare($calcolo_ritenuta_acconto).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_fattura).'))';
$dbo->query($query);
}
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_fattura($id_fattura);

View File

@ -23,8 +23,9 @@ if (!empty($results)) {
</tr>';
foreach ($results as $result) {
$costi_intervento = get_costi_intervento($result['id']);
$totale_interventi += $costi_intervento['totale'];
$intervento = \Modules\Interventi\Intervento::find($result['id']);
$totale_interventi += $intervento->totale;
echo '
<tr>
<td>

Some files were not shown because too many files have changed in this diff Show More