diff --git a/.htaccess b/.htaccess index e55b8b83b..5c061d1a4 100755 --- a/.htaccess +++ b/.htaccess @@ -90,3 +90,7 @@ ServerSignature Off mod_gzip_item_exclude mime ^image/.* mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.* + + + AddType text/javascript mjs + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 15591ae73..4d045c95e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Tutti i maggiori cambiamenti di questo progetto saranno documentati in questo fi Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://keepachangelog.com/), e il progetto segue il [Semantic Versioning](http://semver.org/) per definire le versioni delle release. +- [2.4.52 ](#2452) - [2.4.51 (2023-10-30)](#2451-2023-10-30) - [2.4.50 (2023-10-06)](#2450-2023-10-06) - [2.4.49 (2023-09-22)](#2449-2023-09-25) @@ -62,6 +63,17 @@ Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://k - [2.2 (2016-11-10)](#22-2016-11-10) - [2.1 (2015-04-02)](#21-2015-04-02) + +## 2.4.52 +### Aggiunto (Added) +- Aggiunta la gestione delle sedi definite come automezzi con pratico modulo per il carico/scarico degli articoli nell'automezzo, l'assegnazione di tecnici/autisti con date di validità e stampe di carico filtrabili +### Modificato (Changed) +- Aggiunta una limitazione sulle quantità scaricabili nei documenti di vendita in modo da non poter vendere più articoli di quelli presenti fisicamente nel magazzino selezionato. Questa limitazione è legata all'impostazione **Permetti selezione articoli con quantità minore o uguale a zero in Documenti di Vendita** + +### Fixed +- Risolto il problema di visualizzazione dei PDF negli allegati +- Risolto un problema di movimentazione magazzino: gli articoli nelle attività venivano sempre movimentati da sede legale anche se specificata diversa sede di partenza nel documento (solo da popup di modifica articolo) + ## 2.4.51 (2023-10-30) ### Aggiunto (Added) - Aggiunta la gestione checklist nel plugin impianti diff --git a/assets/src/js/base/custom.js b/assets/src/js/base/custom.js index 875b7c783..1835a4d61 100644 --- a/assets/src/js/base/custom.js +++ b/assets/src/js/base/custom.js @@ -39,7 +39,7 @@ $(document).ready(function () { "debug": false, "newestOnTop": false, "progressBar": true, - "positionClass": "toast-top-right", + "positionClass": "toast-bottom-right", //"preventDuplicates": true, "onclick": null, "showDuration": "300", diff --git a/assets/src/js/functions/functions.js b/assets/src/js/functions/functions.js index 542d49211..f951d4ba6 100755 --- a/assets/src/js/functions/functions.js +++ b/assets/src/js/functions/functions.js @@ -383,11 +383,6 @@ function renderMessages() { let info = messages.info ? messages.info : []; info.forEach(function (element) { if (element) toastr["success"](element); - Toast.fire({ - icon: "success", - title: element, - position: 'top', - }); }); let warning = messages.warning ? messages.warning : []; @@ -456,17 +451,17 @@ function alertPush() { $('.alert-success.push').each(function () { i++; - tops = 60 * i + 95; + bottoms = 60 * i; $(this).css({ 'position': 'fixed', - 'z-index': 3000, - 'right': '10px', - 'top': -100, + 'z-index': 300000, + 'right': '10px', + 'bottom': -100, }).delay(1000).animate({ - 'top': tops, + 'bottom': bottoms, }).delay(3000).animate({ - 'top': -100, + 'bottom': -100, }); }); } @@ -474,7 +469,7 @@ function alertPush() { // Nascondo la notifica se passo sopra col mouse $('.alert-success.push').on('mouseover', function () { $(this).stop().animate({ - 'top': -100, + 'bottom': -100, 'opacity': 0 }); }); diff --git a/gulpfile.js b/gulpfile.js index ee6e5dd76..09d21826c 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -396,17 +396,24 @@ function csrf() { } function pdfjs() { + // Elenca tutte le cartelle dentro public e salva in una variabile l'ultima + const nodeModules = fs.readdirSync(config.nodeDirectory + '/pdf.js/public/',) + .filter(function (x) { + return x.indexOf('.') !== 0 && fs.statSync(config.nodeDirectory + '/pdf.js/public/' + x).isDirectory(); + }) + distDirectory = config.nodeDirectory + '/pdf.js/public/' + nodeModules[nodeModules.length - 1]; + const web = gulp.src([ - config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/**/*', - '!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/cmaps/*', - '!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/*.map', - '!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/*.pdf', + distDirectory + '/web/**/*', + '!' + distDirectory + '/web/cmaps/*', + '!' + distDirectory + '/web/*.map', + '!' + distDirectory + '/web/*.pdf', ]) .pipe(gulp.dest(config.production + '/pdfjs/web')); const build = gulp.src([ - config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/build/*', - '!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/build/*.map', + distDirectory + '/build/*', + '!' + distDirectory + '/build/*.map', ]) .pipe(gulp.dest(config.production + '/pdfjs/build')); diff --git a/include/top.php b/include/top.php index c6eacf230..7a3468012 100755 --- a/include/top.php +++ b/include/top.php @@ -630,10 +630,12 @@ if (Auth::check()) { // Infomazioni if (!empty($messages['info'])) { foreach ($messages['info'] as $value) { - echo ' -
- '.$value.' -
'; + echo ' + '; } } diff --git a/modules/anagrafiche/src/Sede.php b/modules/anagrafiche/src/Sede.php index 4e2e7d5b5..fa0219d6c 100644 --- a/modules/anagrafiche/src/Sede.php +++ b/modules/anagrafiche/src/Sede.php @@ -62,4 +62,26 @@ class Sede extends Model { return $this->belongsTo(Nazione::class, 'id_nazione'); } + + public function save(array $options = []) + { + $this->fixRappresentanteFiscale(); + + return parent::save($options); + } + + protected function fixRappresentanteFiscale() + { + $rappresentante_fiscale = post('is_rappresentante_fiscale'); + + if (!empty($rappresentante_fiscale)) { + self::where('idanagrafica', $this->idanagrafica) + ->where('id', '!=', $this->id) + ->update([ + 'is_rappresentante_fiscale' => 0, + ]); + + $this->attributes['is_rappresentante_fiscale'] = $rappresentante_fiscale; + } + } } diff --git a/modules/articoli/src/Import/CSV.php b/modules/articoli/src/Import/CSV.php index 4bfd97af8..39eaa06a5 100644 --- a/modules/articoli/src/Import/CSV.php +++ b/modules/articoli/src/Import/CSV.php @@ -444,16 +444,8 @@ class CSV extends CSVImporter public static function getExample() { return [ - ['Codice', 'Barcode', 'Immagine', 'Import immagine', 'Descrizione', 'Fornitore predefinito', 'Quantità', 'Unità di misura', 'Prezzo acquisto', 'Prezzo vendita', 'Peso lordo (KG)', 'Volume (M3)', 'Categoria', 'Sottocategoria', 'Ubicazione', 'Note', 'Anagrafica listino', 'Codice fornitore', 'Barcode fornitore', 'Descrizione fornitore', 'Qta minima', 'Qta massima', 'Prezzo listino', 'Sconto listino', 'Cliente/Fornitore listino', 'Sede'], - ['00004', '719376861871', 'https://immagini.com/immagine.jpg', '1', 'Articolo', 'Mario Rossi', '10', 'Kg', '5.25', '12.72', '10.2', '500', 'Categoria4', 'Sottocategoria2', 'Scaffale 1', 'Articolo di prova', 'Mario Rossi', 'artforn01', '384574557484', 'Articolo di prova fornitore', '', '', '10', '5', 'Fornitore', 'Sede2'], - ['00004', '719376861871', 'https://immagini.com/immagine.jpg', '2', 'Articolo', 'Mario Rossi', '10', 'Kg', '5.25', '12.72', '10.2', '500', 'Categoria4', 'Sottocategoria2', 'Scaffale 1', 'Articolo di prova', 'Mario Rossi', 'artforn01', '384574557484', 'Articolo di prova fornitore', '1', '10', '9', '', 'Fornitore', 'Sede2'], - ['00004', '719376861871', 'https://immagini.com/immagine.jpg', '3', 'Articolo', 'Mario Rossi', '10', 'Kg', '5.25', '12.72', '10.2', '500', 'Categoria4', 'Sottocategoria2', 'Scaffale 1', 'Articolo di prova', 'Mario Rossi', 'artforn01', '384574557484', 'Articolo di prova fornitore', '11', '20', '8', '5', 'Fornitore', 'Sede2'], - ['00004', '719376861871', '', '', 'Articolo', 'Mario Rossi', '10', 'Kg', '5.25', '12.72', '10.2', '500', 'Categoria4', 'Sottocategoria2', 'Scaffale 1', 'Articolo di prova', 'Mario Verdi', '', '', '', '1', '10', '20', '10', 'Cliente', 'Sede2'], - [], - ['Import immagine = 1 -> Permette di importare l\'immagine come principale dell\'articolo mantenendo gli altri allegati già presenti'], - ['Import immagine = 2 -> Permette di importare l\'immagine come principale dell\'articolo rimuovendo tutti gli allegati presenti'], - ['Import immagine = 3 -> Permette di importare l\'immagine come allegato dell\'articolo mantenendo gli altri allegati già presenti'], - ['Import immagine = 4 -> Permette di importare l\'immagine come allegato dell\'articolo rimuovendo tutti gli allegati presenti'], + ['Codice', 'Immagine', 'Import immagine', 'Descrizione', 'Quantità', 'Data inventario', 'Unità misura', 'Prezzo acquisto', 'Prezzo vendita', 'Peso', 'Volume', 'Categoria', 'Sottocategoria', 'Barcode', 'Fornitore', 'Partita IVA', 'Codice IVA vendita', 'Ubicazione', 'Note', 'Anagrafica listino', 'Codice fornitore', 'Barcode fornitore', 'Descrizione fornitore', 'Qta minima', 'Qta massima', 'Prezzo listino', 'Sconto listino', 'Cliente/Fornitore listino', 'Sede'], + ['001', 'https://openstamanager.com/moduli/budget/budget.webp', '2', 'Modulo Budget', '1', '2023-11-28', 'PZ', '180.00', '180.00', '', '', 'Licenze', 'Moduli aggiuntivi', '0001', 'DevCode s.r.l.', '05024030289', '', '', '', '', 'Budget', '', 'Modulo Budget', '', '', '', '', 'Fornitore', 'Sede'], ]; } diff --git a/modules/automezzi/actions.php b/modules/automezzi/actions.php new file mode 100644 index 000000000..5c2060dd7 --- /dev/null +++ b/modules/automezzi/actions.php @@ -0,0 +1,191 @@ +fetchNum('SELECT targa FROM an_sedi WHERE targa='.prepare($targa).' AND NOT id='.prepare($id_record)) == 0) { + $query = 'UPDATE an_sedi SET targa='.prepare($targa).', descrizione='.prepare($descrizione).', nome='.prepare($nome).' WHERE id='.prepare($id_record); + if ($dbo->query($query)) { + flash()->info(tr('Informazioni salvate correttamente!')); + } + } else { + flash()->error(tr('Esiste già un automezzo con questa targa!')); + } + + break; + + // Aggiunta automezzo + case 'add': + $targa = post('targa'); + $nome = post('nome'); + + // Inserisco l'automezzo solo se non esiste un altro articolo con stesso targa + if ($dbo->fetchNum('SELECT targa FROM an_sedi WHERE targa='.prepare($targa)) == 0) { + $dbo->insert('an_sedi', [ + 'idanagrafica' => setting('Azienda predefinita'), + 'nomesede' => $nome.' - '.$targa, + 'is_automezzo' => 1, + 'targa' => $targa, + 'nome' => $nome, + ]); + $id_record = $dbo->lastInsertedID(); + + flash()->info(tr('Aggiunto un nuovo automezzo!')); + } else { + flash()->error(tr('Esiste già un automezzo con questa targa!')); + } + break; + + // Aggiunta tecnico + case 'addtech': + $idtecnico = post('idtecnico'); + $data_inizio = post('data_inizio'); + $data_fine = null; + + // Controllo sull'effettivo inserimento di una data di fine successiva a quella di inizio + if (!empty(post('data_fine'))) { + if (new DateTime(post('data_fine')) >= new DateTime($data_inizio)) { + $data_fine = post('data_fine'); + } + } + $data_fine = isset($data_fine) ? $data_fine : '0000-00-00'; + + // Inserisco il tecnico + $dbo->insert('an_sedi_tecnici', [ + 'idtecnico' => $idtecnico, + 'idsede' => $id_record, + 'data_inizio' => $data_inizio, + 'data_fine' => $data_fine, + ]); + + flash()->info(tr('Collegato un nuovo tecnico!')); + break; + + // Salvataggio tecnici collegati + case 'savetech': + $errors = 0; + + foreach (post('data_inizio') as $idautomezzotecnico => $data) { + $idautomezzotecnico = $idautomezzotecnico; + $data_inizio = post('data_inizio')[$idautomezzotecnico]; + $data_fine = null; + + // Controllo sull'effettivo inserimento di una data di fine successiva a quella di inizio + if (!empty(post('data_fine')[$idautomezzotecnico])) { + if (new DateTime(post('data_fine')[$idautomezzotecnico]) >= new DateTime($data_inizio)) { + $data_fine = post('data_fine')[$idautomezzotecnico]; + } + } + $data_fine = isset($data_fine) ? $data_fine : '0000-00-00'; + + $dbo->update('an_sedi_tecnici', [ + 'idtecnico' => $idtecnico, + 'idsede' => $id_record, + 'data_inizio' => $data_inizio, + 'data_fine' => $data_fine, + ], ['id' => $idautomezzotecnico]); + + if (!$dbo->query($query)) { + ++$errors; + } + } + + if ($errors == 0) { + flash()->info(tr('Informazioni salvate correttamente!')); + } else { + flash()->error(tr('Errore durante il salvataggio del tecnico!')); + } + break; + + // Eliminazione associazione con tecnico + case 'deltech': + $idautomezzotecnico = post('id'); + + $query = 'DELETE FROM an_sedi_tecnici WHERE id='.prepare($idautomezzotecnico); + + if ($dbo->query($query)) { + flash()->info(tr('Tecnico rimosso!')); + } + break; + + // Aggiunta quantità nell'automezzo + case 'addrow': + $idarticolo = post('idarticolo'); + $qta = post('qta'); + + $articolo = Articolo::find($idarticolo); + $automezzo = $dbo->table('an_sedi')->where('id', $id_record)->first(); + + // Registrazione del movimento verso la sede di destinazione + $articolo->registra($qta, tr('Carico dal magazzino sull\'automezzo _SEDE_', ['_SEDE_' => $automezzo->nomesede]), Carbon::now(), 1, [ + 'idsede' => $id_record, + ]); + + // Registrazione del movimento dalla sede di origine + $articolo->registra(-$qta, tr('Scarico nel magazzino dall\'automezzo _SEDE_', ['_SEDE_' => $automezzo->nomesede]), Carbon::now(), 1, [ + 'idsede' => 0, + ]); + + flash()->info(tr("Caricato il magazzino dell'automezzo!")); + break; + + case 'editrow': + $idarticolo = post('idarticolo'); + + $articolo = Articolo::find($idarticolo); + $automezzo = $dbo->table('an_sedi')->where('id', $id_record)->first(); + + $qta = post('qta') - $dbo->fetchOne('SELECT SUM(mg_movimenti.qta) AS qta FROM mg_movimenti WHERE mg_movimenti.idarticolo='.prepare($idarticolo).' AND mg_movimenti.idsede='.prepare($id_record))['qta']; + + // Registrazione del movimento verso la sede di destinazione + $articolo->registra($qta, tr('Carico dal magazzino sull\'automezzo _SEDE_', ['_SEDE_' => $automezzo->nomesede]), Carbon::now(), 1, [ + 'idsede' => $id_record, + ]); + + // Registrazione del movimento dalla sede di origine + $articolo->registra(-$qta, tr('Scarico nel magazzino dall\'automezzo _SEDE_', ['_SEDE_' => $automezzo->nomesede]), Carbon::now(), 1, [ + 'idsede' => 0, + ]); + + flash()->info(tr("Caricato il magazzino dell'automezzo!")); + break; + + // Spostamento scorta da automezzo a magazzino generale + case 'moverow': + $idarticolo = post('idarticolo'); + $idautomezzotecnico = post('idautomezzotecnico'); + + $articolo = Articolo::find($idarticolo); + $automezzo = $dbo->table('an_sedi')->where('id', $idautomezzotecnico)->first(); + $qta = $dbo->fetchOne('SELECT SUM(qta) AS qta FROM mg_movimenti WHERE idarticolo='.prepare($idarticolo).' AND idsede='.prepare($idautomezzotecnico))['qta']; + + // Registrazione del movimento verso la sede di destinazione + $articolo->registra($qta, tr('Carico nel magazzino dall\'automezzo _SEDE_', ['_SEDE_' => $automezzo->nomesede]), Carbon::now(), 1, [ + 'idsede' => 0, + ]); + + // Registrazione del movimento dalla sede di origine + $descrizione = tr('Scarico dall\'automezzo _SEDE_ nel magazzino', [ + '_SEDE_' => $automezzo->nomesede, + ]); + $articolo->registra(-$qta, $descrizione, Carbon::now(), 1, [ + 'idsede' => $idautomezzotecnico, + ]); + + break; + + case 'delete': + $dbo->query('DELETE FROM `an_sedi` WHERE `id`='.prepare($id_record)); + + flash()->info(tr('Automezzo eliminato e articoli riportati in magazzino!')); + + break; +} diff --git a/modules/automezzi/add.php b/modules/automezzi/add.php new file mode 100644 index 000000000..bcc30a839 --- /dev/null +++ b/modules/automezzi/add.php @@ -0,0 +1,25 @@ +
+ + + +
+
+ {[ "type": "text", "label": "", "name": "nome", "required": 1 ]} +
+ +
+ {[ "type": "text", "label": "", "name": "targa", "required": 1, "maxlength": 10, "class": "alphanumeric-mask" ]} +
+ +
+ + +
+
+ +
+
+
diff --git a/modules/automezzi/add_articolo.php b/modules/automezzi/add_articolo.php new file mode 100644 index 000000000..d7eeb1e1d --- /dev/null +++ b/modules/automezzi/add_articolo.php @@ -0,0 +1,48 @@ +fetchOne('SELECT SUM(mg_movimenti.qta) AS qta FROM mg_movimenti WHERE mg_movimenti.idarticolo='.prepare($idarticolo).' AND mg_movimenti.idsede='.prepare($idautomezzo))['qta']; + $op = 'editrow'; +} + +/* + Form di inserimento riga documento +*/ +echo ' +'; + +echo ' +'; diff --git a/modules/automezzi/add_tecnico.php b/modules/automezzi/add_tecnico.php new file mode 100644 index 000000000..77e0fa229 --- /dev/null +++ b/modules/automezzi/add_tecnico.php @@ -0,0 +1,58 @@ + + + + + +
'; + +// Tecnico +echo ' +
+ {[ "type": "select", "label": "'.tr('Tecnico').'", "name": "idtecnico", "required": 1, "values": "query=SELECT an_anagrafiche.idanagrafica AS id, ragione_sociale AS descrizione FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica WHERE (descrizione=\'Tecnico\') AND deleted_at IS NULL ORDER BY ragione_sociale", "value": "'.$idtecnico.'" ]} +
'; + +// Data di partenza +echo ' +
+ {[ "type": "date", "label": "'.tr('Data dal').'", "name": "data_inizio", "required": 1, "value": "-now-" ]} +
'; + +// Data di fine +echo ' +
+ {[ "type": "date", "label": "'.tr('Data al').'", "name": "data_fine", "min-date": "-now-" ]} +
'; + +echo ' +
+ + +
+
+ +
+
+'; + +echo ' +'; diff --git a/modules/automezzi/ajax/search.php b/modules/automezzi/ajax/search.php new file mode 100644 index 000000000..62c6c3a7f --- /dev/null +++ b/modules/automezzi/ajax/search.php @@ -0,0 +1,47 @@ + 'nome', + 'Descrizione' => 'descrizione', + 'Targa' => 'targa', +]; + +$query = 'SELECT *'; + +foreach ($fields as $name => $value) { + $query .= ', '.$value." AS '".str_replace("'", "\'", $name)."'"; +} + +$query .= ' FROM dt_automezzi WHERE 1=0 '; + +foreach ($fields as $name => $value) { + $query .= ' OR '.$value.' LIKE "%'.$term.'%"'; +} + +$query .= Modules::getAdditionalsQuery('Automezzi'); + +$rs = $dbo->fetchArray($query); + +foreach ($rs as $r) { + $result = []; + + $result['link'] = ROOTDIR.'/editor.php?id_module='.$link_id.'&id_record='.$r['id']; + $result['title'] = $r['nome']; + $result['category'] = 'Automezzi'; + + // Campi da evidenziare + $result['labels'] = []; + foreach ($fields as $name => $value) { + if (str_contains($r[$name], $term)) { + $text = str_replace($term, "".$term.'', $r[$name]); + + $result['labels'][] = $name.': '.$text.'
'; + } + } + + $results[] = $result; +} diff --git a/modules/automezzi/edit.php b/modules/automezzi/edit.php new file mode 100644 index 000000000..f7e60443e --- /dev/null +++ b/modules/automezzi/edit.php @@ -0,0 +1,115 @@ +
+ + + + + +
+
+

+
+ +
+
+
+ {[ "type": "text", "label": "", "name": "nome", "required": 1, "value": "$nome$" ]} +
+
+ {[ "type": "text", "label": "", "name": "targa", "required": 1, "maxlength": 10, "class": "alphanumeric-mask", "value": "$targa$" ]} +
+ +
+
+
+ {[ "type": "textarea", "label": "", "name": "descrizione", "value": "$descrizione$" ]} +
+
+
+
+
+ + +
+ + +
+
+
+
+
+

+
+
+
+ +
+
+
+
+ + + + + +
+ + + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+

+
+
+
+ +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+ + + + + + diff --git a/modules/automezzi/init.php b/modules/automezzi/init.php new file mode 100644 index 000000000..18efdfb9f --- /dev/null +++ b/modules/automezzi/init.php @@ -0,0 +1,7 @@ +fetchOne('SELECT * FROM an_sedi WHERE an_sedi.id='.prepare($id_record)); +} diff --git a/modules/automezzi/row-list-articoli.php b/modules/automezzi/row-list-articoli.php new file mode 100644 index 000000000..946c4b702 --- /dev/null +++ b/modules/automezzi/row-list-articoli.php @@ -0,0 +1,66 @@ +fetchArray('SELECT mg_movimenti.idsede AS id, mg_articoli.codice AS codice, idarticolo, SUM(mg_movimenti.qta) AS qta_automezzo, mg_articoli.qta AS qta_magazzino, mg_articoli.descrizione, mg_articoli.prezzo_vendita, (SELECT percentuale FROM co_iva WHERE id=mg_articoli.idiva_vendita) AS prciva_vendita FROM mg_movimenti INNER JOIN mg_articoli ON mg_movimenti.idarticolo=mg_articoli.id WHERE mg_movimenti.idsede='.prepare($id_record).' GROUP BY idarticolo HAVING qta_automezzo>0 ORDER BY mg_articoli.descrizione'); + +if (!empty($rs2)) { + echo ' +
+ + + + + + + '; + + foreach ($rs2 as $r) { + echo ' + '; + // Articolo + echo ' + '; + + // Quantità + echo ' + '; + + // Prezzo di vendita + $netto = $r['prezzo_vendita']; + $iva = $r['prezzo_vendita'] / 100 * $r['prciva_vendita']; + echo ' + '; + + // Pulsanti + echo ' + + '; + + $tot_articoli += $r['qta_automezzo']; + } + + echo ' +
'.tr('Articolo').''.tr('Q.tà').''.tr('Prezzo di vendita').'
+ '.Modules::link('Articoli', $r['idarticolo'], $r['codice'].' - '.$r['descrizione']).' + + '.Translator::numberToLocale($r['qta_automezzo']).'
+ '.tr('Q.tà magazzino').': '.Translator::numberToLocale($r['qta_magazzino']).'
+
+ '.Translator::numberToLocale($netto + $iva).' €
+ '.tr('Netto').': '.Translator::numberToLocale($netto).' €
+ '.tr('Iva').': '.Translator::numberToLocale($iva).' €
+
+ + + + + + +
+
'; +} else { + echo ' +

'.tr('Nessun articolo presente').'...

'; +} diff --git a/modules/automezzi/row-list-tecnici.php b/modules/automezzi/row-list-tecnici.php new file mode 100644 index 000000000..3dfd56c64 --- /dev/null +++ b/modules/automezzi/row-list-tecnici.php @@ -0,0 +1,59 @@ +fetchArray($q_art); + +if (!empty($rs_art)) { + echo ' +
+ + + + + + + '; + + foreach ($rs_art as $r) { + // Tecnico + echo ' + + '; + + // Data di inizio + echo ' + '; + + // Data di fine + echo ' + '; + + // Pulsanti per aggiornamento date tecnici + echo ' + + '; + } + + echo ' +
'.tr('Tecnico').''.tr('Dal').''.tr('Al').'
+ + '.$r['ragione_sociale'].' + + {[ "type": "date", "name": "data_inizio['.$r['id'].']", "required": 1, "value": "'.$r['data_inizio'].'" ]} + + {[ "type": "date", "name": "data_fine['.$r['id'].']", "required": 1, "value": "'.$r['data_fine'].'", "min-date": "'.$r['data_inizio'].'" ]} + + + + +
+
'; +} else { + echo ' +

'.tr('Nessun tecnico inserito').'...

'; +} diff --git a/modules/contratti/actions.php b/modules/contratti/actions.php index 3b698b810..3f427c882 100644 --- a/modules/contratti/actions.php +++ b/modules/contratti/actions.php @@ -285,7 +285,11 @@ switch (post('op')) { $riga = null; } - flash()->info(tr('Righe eliminate!')); + if (count($id_righe) == 1) { + flash()->info(tr('Riga eliminata!')); + } else { + flash()->info(tr('Righe eliminate!')); + } break; diff --git a/modules/contratti/bulk.php b/modules/contratti/bulk.php index 64a949309..46474f494 100755 --- a/modules/contratti/bulk.php +++ b/modules/contratti/bulk.php @@ -275,7 +275,7 @@ $operations['cambia_stato'] = [ 'text' => ' '.tr('Cambia stato'), 'data' => [ 'title' => tr('Vuoi davvero aggiornare lo stato di questi contratti?'), - 'msg' => '
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione FROM co_staticontratti ORDER BY descrizione" ]}', + 'msg' => '
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione, colore as _bgcolor_ FROM co_staticontratti ORDER BY descrizione" ]}', 'button' => tr('Procedi'), 'class' => 'btn btn-lg btn-warning', 'blank' => false, diff --git a/modules/ddt/actions.php b/modules/ddt/actions.php index b0f0d229b..0300afda1 100755 --- a/modules/ddt/actions.php +++ b/modules/ddt/actions.php @@ -392,7 +392,12 @@ switch (filter('op')) { } ricalcola_costiagg_ddt($id_record); - flash()->info(tr('Righe eliminate!')); + + if (count($id_righe) == 1) { + flash()->info(tr('Riga eliminata!')); + } else { + flash()->info(tr('Righe eliminate!')); + } break; @@ -408,12 +413,13 @@ switch (filter('op')) { $new_riga = $riga->replicate(); $new_riga->setDocument($ddt); $new_riga->qta_evasa = 0; - $new_riga->save(); if ($new_riga->isArticolo()) { $new_riga->movimenta($new_riga->qta); } + $new_riga->save(); + $riga = null; } @@ -502,12 +508,12 @@ switch (filter('op')) { $copia_riga->original_id = null; $copia_riga->original_type = null; - $copia_riga->save(); - // Movimentazione forzata in direzione del documento if ($copia_riga->isArticolo()) { $copia_riga->movimenta($copia_riga->qta); } + + $copia_riga->save(); } // Salvataggio riferimento @@ -539,11 +545,12 @@ switch (filter('op')) { $new_riga->qta_evasa = 0; $new_riga->idordine = 0; - $new_riga->save(); if ($new_riga->isArticolo()) { $new_riga->movimenta($new_riga->qta); } + + $new_riga->save(); } flash()->info(tr('DDT duplicato correttamente!')); diff --git a/modules/ddt/bulk.php b/modules/ddt/bulk.php index ad097906d..97c27fe98 100755 --- a/modules/ddt/bulk.php +++ b/modules/ddt/bulk.php @@ -195,7 +195,7 @@ $operations['crea_fattura'] = [ 'data' => [ 'title' => tr('Vuoi davvero cambiare lo stato per questi DDT?'), 'msg' => tr('Seleziona lo stato in cui spostare tutti i DDT').'.
-
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione FROM dt_statiddt" ]}', +
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione, colore as _bgcolor_ FROM dt_statiddt" ]}', 'button' => tr('Procedi'), 'class' => 'btn btn-lg btn-warning', 'blank' => false, diff --git a/modules/ddt/row-list.php b/modules/ddt/row-list.php index 483f39fd9..b6f802df2 100755 --- a/modules/ddt/row-list.php +++ b/modules/ddt/row-list.php @@ -160,10 +160,12 @@ foreach ($righe as $riga) { $evasione_bar['or_righe_ordini'] = 'success'; foreach ($evasione_bar as $table => $color) { $righe_ev = $dbo->table($table)->where('original_id', $riga->id)->where('original_type', get_class($riga))->get(); - $perc_ev = $righe_ev->sum('qta') * 100 / $riga->qta; - if ($perc_ev > 0) { - echo ' -
'; + if ($righe_ev->count() > 0) { + $perc_ev = $righe_ev->sum('qta') * 100 / $riga->qta; + if ($perc_ev > 0) { + echo ' +
'; + } } } echo ' diff --git a/modules/fatture/actions.php b/modules/fatture/actions.php index ba8c4d854..6c514c763 100755 --- a/modules/fatture/actions.php +++ b/modules/fatture/actions.php @@ -31,6 +31,7 @@ use Modules\Fatture\Fattura; use Modules\Fatture\Stato; use Modules\Fatture\Tipo; use Modules\Iva\Aliquota; +use Plugins\ExportFE\Interaction; use Util\XML; $module = Modules::get($id_module); @@ -46,10 +47,26 @@ $stato_fe = $dbo->fetchOne('SELECT codice_stato_fe FROM co_documenti WHERE id = $ops = ['update', 'add_intervento', 'manage_documento_fe', 'manage_riga_fe', 'manage_articolo', 'manage_sconto', 'manage_riga', 'manage_descrizione', 'unlink_intervento', 'delete_riga', 'copy_riga', 'add_serial', 'add_articolo', 'edit-price']; -if ($dir == 'entrata' && $stato_fe['codice_stato_fe'] == 'WAIT' && setting('OSMCloud Services API Token') != '' && in_array($op, $ops)) { - flash()->warning(tr('La fattura numero _NUM_ è già stata inviata allo SDI, non è possibile effettuare modifiche!', [ - '_NUM_' => $fattura->numero_esterno, - ])); +if ($dir === 'entrata' && in_array($stato_fe['codice_stato_fe'], ['WAIT', 'RC', 'MC', 'QUEUE', 'DT', 'EC01', 'NE']) && Interaction::isEnabled() && in_array($op, $ops)) { + //Permetto sempre la modifica delle note aggiuntive e/o della data di competenza della fattura di vendita + if ($op == 'update' && ($fattura->note_aggiuntive != post('note_aggiuntive') || $fattura->data_competenza != post('data_competenza'))) { + if ($fattura->note_aggiuntive != post('note_aggiuntive')) { + $fattura->note_aggiuntive = post('note_aggiuntive'); + $fattura->save(); + flash()->info(tr('Note interne modificate correttamente.')); + } + + if ($fattura->data_competenza != post('data_competenza')) { + $fattura->data_competenza = post('data_competenza'); + $fattura->save(); + flash()->info(tr('Data competenza modificata correttamente.')); + } + } else { + flash()->warning(tr('La fattura numero _NUM_ è già stata inviata allo SDI, non è possibile effettuare modifiche.', [ + '_NUM_' => $fattura->numero_esterno, + ])); + } + $op = null; } @@ -372,11 +389,12 @@ switch ($op) { $new_riga->idintervento = 0; $new_riga->idddt = 0; $new_riga->idordine = 0; - $new_riga->save(); if ($new_riga->isArticolo()) { $new_riga->movimenta($new_riga->qta); } + + $new_riga->save(); } flash()->info(tr('Fattura duplicata correttamente!')); @@ -655,6 +673,11 @@ switch ($op) { } $riga = null; + } + + if (count($id_righe) == 1) { + flash()->info(tr('Riga eliminata!')); + } else { flash()->info(tr('Righe eliminate!')); } @@ -672,12 +695,13 @@ switch ($op) { $new_riga = $riga->replicate(); $new_riga->setDocument($fattura); $new_riga->qta_evasa = 0; - $new_riga->save(); if ($new_riga->isArticolo()) { $new_riga->movimenta($new_riga->qta); } + $new_riga->save(); + $riga = null; } diff --git a/modules/fatture/src/Gestori/Scadenze.php b/modules/fatture/src/Gestori/Scadenze.php index 0495b3158..0b7e6f357 100644 --- a/modules/fatture/src/Gestori/Scadenze.php +++ b/modules/fatture/src/Gestori/Scadenze.php @@ -74,10 +74,12 @@ class Scadenze $ultima_scadenza = $this->fattura->scadenze->last(); $scadenza = $ultima_scadenza->scadenza->copy()->startOfMonth()->addMonth(); $scadenza->setDate($scadenza->year, $scadenza->month, 15); - + $id_pagamento = $this->fattura->idpagamento; + $id_banca_azienda = $this->fattura->id_banca_azienda; + $id_banca_controparte = $this->fattura->id_banca_controparte; $importo = -$ritenuta_acconto; - self::registraScadenza($this->fattura, $importo, $scadenza, $is_pagato, 'ritenutaacconto'); + self::registraScadenza($this->fattura, $importo, $scadenza, $is_pagato, $id_pagamento, $id_banca_azienda, $id_banca_controparte, 'ritenutaacconto'); } } @@ -134,12 +136,15 @@ class Scadenze foreach ($pagamenti as $pagamento) { $rate = $pagamento['DettaglioPagamento']; $rate = isset($rate[0]) ? $rate : [$rate]; + $id_banca_azienda = $this->fattura->id_banca_azienda; + $id_banca_controparte = $this->fattura->id_banca_controparte; + $id_pagamento = $this->fattura->idpagamento; foreach ($rate as $rata) { $scadenza = !empty($rata['DataScadenzaPagamento']) ? FatturaElettronicaImport::parseDate($rata['DataScadenzaPagamento']) : $this->fattura->data; $importo = $this->fattura->isNota() ? $rata['ImportoPagamento'] : -$rata['ImportoPagamento']; - self::registraScadenza($this->fattura, $importo, $scadenza, $is_pagato); + self::registraScadenza($this->fattura, $importo, $scadenza, $is_pagato, $id_pagamento, $id_banca_azienda, $id_banca_controparte); } } diff --git a/modules/impianti/src/Import/CSV.php b/modules/impianti/src/Import/CSV.php index 41a6d1724..d7f0d60d6 100644 --- a/modules/impianti/src/Import/CSV.php +++ b/modules/impianti/src/Import/CSV.php @@ -169,7 +169,7 @@ class CSV extends CSVImporter 'id_record' => $impianto->id, ]); - $database->update('mg_articoli', [ + $database->update('my_impianti', [ 'immagine' => '', ], [ 'id' => $impianto->id, @@ -191,7 +191,7 @@ class CSV extends CSVImporter if ($record['import_immagine'] == 1 || $record['import_immagine'] == 2) { if (!empty($filename)) { - $database->update('mg_articoli', [ + $database->update('my_impianti', [ 'immagine' => $filename, ], [ 'id' => $impianto->id, @@ -208,16 +208,11 @@ class CSV extends CSVImporter public static function getExample() { return [ - ['Matricola', 'Nome', 'Categoria', 'Immagine', 'Data installazione', 'Cliente', 'Telefono', 'Sede'], - ['00001', 'Marca', 'Lavatrice', 'https://immagini.com/immagine.jpg', '01/10/2023', 'Mario Rossi', '04444444', 'Sede2'], - ['00002', 'Marca2', 'Lavastoviglie', 'https://immagini.com/immagine2.jpg', '12/09/2023', 'Mario Rossi', '04444444', 'Sede2'], - ['00003', 'Marca3', 'Frigorifero', 'https://immagini.com/immagine3.jpg', '20/09/2023', 'Mario Rossi', '04444444', 'Sede2'], - ['00004', 'Marca4', 'Caldaia', 'https://immagini.com/immagine4.jpg', '06/11/2023', 'Mario Rossi', '04444444', 'Sede2'], - [], - ['Import immagine = 1 -> Permette di importare l\'immagine come principale dell\'impianto mantenendo gli altri allegati già presenti'], - ['Import immagine = 2 -> Permette di importare l\'immagine come principale dell\'impianto rimuovendo tutti gli allegati presenti'], - ['Import immagine = 3 -> Permette di importare l\'immagine come allegato dell\'impianto mantenendo gli altri allegati già presenti'], - ['Import immagine = 4 -> Permette di importare l\'immagine come allegato dell\'impianto rimuovendo tutti gli allegati presenti'], + ['Matricola', 'Immagine', 'Import immagine', 'Nome', 'Cliente', 'Telefono', 'Categoria', 'Sottocategoria', 'Sede', 'Descrizione', 'Data installazione'], + ['00001', 'https://openstamanager.com/moduli/budget/budget.webp', '2', 'Lavatrice', 'Mario Rossi', '04444444', 'Elettrodomestici', 'Marca1', '', '', '2023-01-01'], + ['00002', 'https://openstamanager.com/moduli/3cx/3cx.webp', '2', 'Caldaia', 'Mario Rossi', '04444444', 'Elettrodomestici', 'Marca2', '', '', '2023-03-06'], + ['00003', 'https://openstamanager.com/moduli/disponibilita-tecnici/tecnici.webp', '2', 'Forno', 'Mario Rossi', '04444444', 'Elettrodomestici', 'Marca3', '', '', '2023-04-01'], + ['00004', 'https://openstamanager.com/moduli/distinta-base/distinta.webp', '2', 'Lavastoviglie', 'Mario Rossi', '04444444', 'Elettrodomestici', 'Marca4', '', '', '2023-08-06'], ]; } } diff --git a/modules/import/add.php b/modules/import/add.php index 1a50892b3..5bbf1a3af 100755 --- a/modules/import/add.php +++ b/modules/import/add.php @@ -29,7 +29,7 @@ include_once __DIR__.'/../../core.php';
- {[ "type": "select", "label": "", "name": "id_import", "required": 1, "values": "query=SELECT id, name AS text FROM zz_imports" ]} + {[ "type": "select", "label": "", "name": "id_import", "required": 1, "values": "query=SELECT id, name AS text FROM zz_imports ORDER BY name" ]}
diff --git a/modules/interventi/actions.php b/modules/interventi/actions.php index a2c967a17..d6bc64994 100644 --- a/modules/interventi/actions.php +++ b/modules/interventi/actions.php @@ -440,7 +440,11 @@ switch (post('op')) { $riga = null; } - flash()->info(tr('Righe eliminate!')); + if (count($id_righe) == 1) { + flash()->info(tr('Riga eliminata!')); + } else { + flash()->info(tr('Righe eliminate!')); + } break; @@ -455,12 +459,13 @@ switch (post('op')) { $new_riga = $riga->replicate(); $new_riga->setDocument($intervento); $new_riga->qta_evasa = 0; - $new_riga->save(); if ($new_riga->isArticolo()) { $new_riga->movimenta($new_riga->qta); } + $new_riga->save(); + $riga = null; } @@ -976,11 +981,12 @@ switch (post('op')) { $new_riga->setDocument($new); $new_riga->qta_evasa = 0; - $new_riga->save(); if ($new_riga->isArticolo()) { $new_riga->movimenta($new_riga->qta); } + + $new_riga->save(); } } @@ -1153,6 +1159,7 @@ switch (post('op')) { break; case 'update_inline': + $qta = post('qta'); $id_riga = post('riga_id'); $riga = $riga ?: Riga::find($id_riga); $riga = $riga ?: Articolo::find($id_riga); @@ -1162,7 +1169,7 @@ switch (post('op')) { if ($riga->isSconto()) { $riga->setScontoUnitario(post('sconto'), $riga->idiva); } else { - $riga->qta = post('qta'); + $riga->qta = $qta; $riga->setPrezzoUnitario(post('prezzo'), $riga->idiva); $riga->setSconto(post('sconto'), post('tipo_sconto')); $riga->costo_unitario = post('costo') ?: 0; diff --git a/modules/interventi/src/Import/CSV.php b/modules/interventi/src/Import/CSV.php index 4cd69aef5..c208a214b 100644 --- a/modules/interventi/src/Import/CSV.php +++ b/modules/interventi/src/Import/CSV.php @@ -107,7 +107,7 @@ class CSV extends CSVImporter $impianto = Impianto::where('matricola', $record['impianto'])->first(); } - if (!empty($anagrafica) && !empty($impianto)) { + if (!empty($anagrafica)) { $intervento = null; // Ricerca sulla base della chiave primaria se presente @@ -128,6 +128,10 @@ class CSV extends CSVImporter } else { $stato = Stato::where('descrizione', $record['stato'])->first(); } + + if (empty($stato)) { + $stato = Stato::build($record['stato']); + } unset($record['stato']); // Crea l'intervento @@ -139,13 +143,15 @@ class CSV extends CSVImporter unset($record['ora_inizio']); unset($record['telefono']); - $collegamento = $database->table('my_impianti_interventi')->where('idimpianto', $impianto['id'])->where('idintervento', $intervento['id'])->first(); + if (!empty($impianto)) { + $collegamento = $database->table('my_impianti_interventi')->where('idimpianto', $impianto['id'])->where('idintervento', $intervento['id'])->first(); - if (empty($collegamento)) { - // Collega l'impianto all'intervento - $database->query('INSERT INTO my_impianti_interventi(idimpianto, idintervento) VALUES('.prepare($impianto['id']).', '.prepare($intervento['id']).')'); + if (empty($collegamento)) { + // Collega l'impianto all'intervento + $database->query('INSERT INTO my_impianti_interventi(idimpianto, idintervento) VALUES('.prepare($impianto['id']).', '.prepare($intervento['id']).')'); + } + unset($record['impianto']); } - unset($record['impianto']); // Inserisce la data richiesta e la richiesta $intervento->data_richiesta = $record['data_richiesta']; @@ -185,9 +191,9 @@ class CSV extends CSVImporter public static function getExample() { return [ - ['Codice', 'Telefono', 'Data', 'Data richiesta', 'Ora', 'Tecnico', 'Tipo', 'Note', 'Impianto', 'Richiesta', 'Descrizione', 'Stato'], - ['001', '044444444', '07/11/2023', '03/11/2023', '18:30', 'Stefano Bianchi', '', '', '00000000001', 'Manutenzione ordinaria', 'eseguito intervento di manutenzione', 'Bozza'], - ['002', '044444444', '08/11/2023', '04/11/2023', '11:20', 'Stefano Bianchi', '', '', '00000000002', 'Manutenzione ordinaria', 'eseguito intervento di manutenzione', ''], + ['Codice', 'Telefono', 'Data', 'Data richiesta', 'Ora inizio', 'Tecnico', 'Tipo', 'Note', 'Impianto', 'Richiesta', 'Descrizione', 'Stato'], + ['001', '04444444', '07/11/2023', '03/11/2023', '18:30', 'Stefano Bianchi', '', '', '00001', 'Manutenzione ordinaria', 'eseguito intervento di manutenzione', 'Bozza'], + ['002', '04444444', '08/11/2023', '04/11/2023', '11:20', 'Stefano Bianchi', '', '', '00002', 'Manutenzione ordinaria', 'eseguito intervento di manutenzione', ''], ]; } } diff --git a/modules/interventi/src/Stato.php b/modules/interventi/src/Stato.php index 5aeef4c5f..005388484 100755 --- a/modules/interventi/src/Stato.php +++ b/modules/interventi/src/Stato.php @@ -33,4 +33,15 @@ class Stato extends Model { return $this->hasMany(Intervento::class, 'idstatointervento'); } + + public static function build($nome) + { + $model = new static(); + + $model->codice = 'NEW'; + $model->descrizione = $nome; + $model->save(); + + return $model; + } } diff --git a/modules/ordini/actions.php b/modules/ordini/actions.php index 5320b788d..5b3107a12 100755 --- a/modules/ordini/actions.php +++ b/modules/ordini/actions.php @@ -342,7 +342,11 @@ switch (post('op')) { ricalcola_costiagg_ordine($id_record); - flash()->info(tr('Righe eliminate!')); + if (count($id_righe) == 1) { + flash()->info(tr('Riga eliminata!')); + } else { + flash()->info(tr('Righe eliminate!')); + } break; diff --git a/modules/ordini/bulk.php b/modules/ordini/bulk.php index 45ce8db9c..bf7186c35 100644 --- a/modules/ordini/bulk.php +++ b/modules/ordini/bulk.php @@ -231,7 +231,7 @@ $operations['cambia_stato'] = [ 'data' => [ 'title' => tr('Vuoi davvero cambiare lo stato per questi ordini?'), 'msg' => tr('Seleziona lo stato in cui spostare tutti gli ordini').'.
-
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione FROM or_statiordine" ]}', +
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione, colore as _bgcolor_ FROM or_statiordine" ]}', 'button' => tr('Procedi'), 'class' => 'btn btn-lg btn-warning', 'blank' => false, diff --git a/modules/preventivi/actions.php b/modules/preventivi/actions.php index 696ac5e4e..00629c7f2 100755 --- a/modules/preventivi/actions.php +++ b/modules/preventivi/actions.php @@ -349,7 +349,11 @@ switch (post('op')) { $riga = null; } - flash()->info(tr('Righe eliminate!')); + if (count($id_righe) == 1) { + flash()->info(tr('Riga eliminata!')); + } else { + flash()->info(tr('Righe eliminate!')); + } break; diff --git a/modules/preventivi/bulk.php b/modules/preventivi/bulk.php index 226649f3c..e78294de6 100755 --- a/modules/preventivi/bulk.php +++ b/modules/preventivi/bulk.php @@ -167,7 +167,7 @@ $operations['cambia_stato'] = [ 'text' => ' '.tr('Cambia stato'), 'data' => [ 'title' => tr('Vuoi davvero aggiornare lo stato di questi preventivi?'), - 'msg' => '
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione FROM co_statipreventivi ORDER BY descrizione" ]}', + 'msg' => '
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione, colore as _bgcolor_ FROM co_statipreventivi ORDER BY descrizione" ]}', 'button' => tr('Procedi'), 'class' => 'btn btn-lg btn-warning', 'blank' => false, diff --git a/modules/preventivi/row-list.php b/modules/preventivi/row-list.php index c360c614c..1efa37ea6 100755 --- a/modules/preventivi/row-list.php +++ b/modules/preventivi/row-list.php @@ -175,10 +175,12 @@ foreach ($righe as $key => $riga) { $evasione_bar['or_righe_ordini'] = 'success'; foreach ($evasione_bar as $table => $color) { $righe_ev = $dbo->table($table)->where('original_id', $riga->id)->where('original_type', get_class($riga))->get(); - $perc_ev = $righe_ev->sum('qta') * 100 / $riga->qta; - if ($perc_ev > 0) { - echo ' -
'; + if ($righe_ev->count() > 0) { + $perc_ev = $righe_ev->sum('qta') * 100 / $riga->qta; + if ($perc_ev > 0) { + echo ' +
'; + } } } echo ' diff --git a/modules/statistiche/edit.php b/modules/statistiche/edit.php index a8bed06e8..5daa9a3f7 100755 --- a/modules/statistiche/edit.php +++ b/modules/statistiche/edit.php @@ -209,7 +209,7 @@ if (!empty($clienti)) { '.Modules::link('Anagrafiche', $cliente['idanagrafica'], $cliente['ragione_sociale']).' '.intval($cliente['qta']).' '.moneyFormat($cliente['totale'], 2).' - '.Translator::numberToLocale($cliente['totale'] * 100 / $totale[0]['totale'], 2).' % + '.Translator::numberToLocale($cliente['totale'] * 100 / ($totale[0]['totale'] != 0 ? $totale[0]['totale'] : 1), 2).' % '; } echo ' @@ -256,7 +256,7 @@ if (!empty($articoli)) {
'.Modules::link('Articoli', $articolo['id'], $articolo['codice'].' - '.$articolo['descrizione']).'
'.Translator::numberToLocale($articolo['qta'], 'qta').' '.$articolo['um'].' - '.Translator::numberToLocale($articolo['qta'] * 100 / $totale[0]['totale_qta'], 2).' % + '.Translator::numberToLocale($articolo['qta'] * 100 / ($totale[0]['totale_qta'] != 0 ? $totale[0]['totale_qta'] : 1), 2).' % '.moneyFormat($articolo['totale'], 2).' '; } diff --git a/plugins/exportFE/src/FatturaElettronica.php b/plugins/exportFE/src/FatturaElettronica.php index b645c3d70..2f2174326 100755 --- a/plugins/exportFE/src/FatturaElettronica.php +++ b/plugins/exportFE/src/FatturaElettronica.php @@ -23,6 +23,7 @@ use FluidXml\FluidXml; use GuzzleHttp\Client; use Modules; use Modules\Anagrafiche\Anagrafica; +use Modules\Anagrafiche\Sede; use Modules\Banche\Banca; use Modules\Fatture\Fattura; use Modules\Fatture\Gestori\Bollo; @@ -829,6 +830,24 @@ class FatturaElettronica return $result; } + /** + * Restituisce l'array responsabile per la generazione del tag RappresentanteFiscale (1.3). + * + * @return array + */ + protected static function getRappresentanteFiscale($fattura) + { + //Fattura per conto terzi, il cliente diventa il cedente al posto della mia Azienda (fornitore) + $cliente = $fattura->getCliente(); + $azienda = Sede::where('idanagrafica', $cliente->id)->where('is_rappresentante_fiscale', 1)->selectRaw('*, nomesede AS ragione_sociale')->first(); + + $result = [ + 'DatiAnagrafici' => static::getDatiAnagrafici($azienda, true), + ]; + + return $result; + } + /** * Restituisce l'array responsabile per la generazione del tag CessionarioCommittente (Cliente) (1.4). * @@ -1757,11 +1776,31 @@ class FatturaElettronica */ protected static function getHeader($fattura) { - $result = [ - 'DatiTrasmissione' => static::getDatiTrasmissione($fattura), - 'CedentePrestatore' => static::getCedentePrestatore($fattura), - 'CessionarioCommittente' => static::getCessionarioCommittente($fattura), - ]; + $documento = $fattura->getDocumento(); + $rappresentante_fiscale = null; + + //Fattura per conto terzi, il cliente diventa il cedente al posto della mia Azienda (fornitore) + if ($documento['is_fattura_conto_terzi']) { + $azienda = $fattura->getCliente(); + $rappresentante_fiscale = Sede::where('idanagrafica', $azienda->id)->where('is_rappresentante_fiscale', 1)->first(); + } else { + $azienda = static::getAzienda(); + } + + if ($rappresentante_fiscale) { + $result = [ + 'DatiTrasmissione' => static::getDatiTrasmissione($fattura), + 'CedentePrestatore' => static::getCedentePrestatore($fattura), + 'RappresentanteFiscale' => static::getRappresentanteFiscale($fattura), + 'CessionarioCommittente' => static::getCessionarioCommittente($fattura), + ]; + } else { + $result = [ + 'DatiTrasmissione' => static::getDatiTrasmissione($fattura), + 'CedentePrestatore' => static::getCedentePrestatore($fattura), + 'CessionarioCommittente' => static::getCessionarioCommittente($fattura), + ]; + } // 1.5 Terzo Intermediario if (!empty(setting('Terzo intermediario'))) { diff --git a/plugins/importFE/src/FatturaOrdinaria.php b/plugins/importFE/src/FatturaOrdinaria.php index b5305668d..03d004611 100755 --- a/plugins/importFE/src/FatturaOrdinaria.php +++ b/plugins/importFE/src/FatturaOrdinaria.php @@ -404,7 +404,7 @@ class FatturaOrdinaria extends FatturaElettronica $diff = round(abs($totale_righe) + $totale_arrotondamento - abs($fattura->totale_imponibile), 2); // Aggiunta della riga di arrotondamento nel caso in cui ci sia una differenza tra i totali, o tra l'imponibile dell'XML e quello ricavato dalla somma delle righe - if (($diff != 0 && $diff != $totale_arrotondamento) || (($fattura->totale_imponibile + $fattura->rivalsa_inps) != $totale_imp)) { + if (($diff != 0 && $diff != $totale_arrotondamento) || (($fattura->totale_imponibile + $fattura->rivalsa_inps) != abs($totale_imp))) { // Rimozione dell'IVA calcolata automaticamente dal gestionale $iva_arrotondamento = database()->fetchOne('SELECT * FROM co_iva WHERE percentuale=0 AND deleted_at IS NULL'); if ($diff != 0) { diff --git a/plugins/sedi/actions.php b/plugins/sedi/actions.php index f09712195..f556e9dd5 100755 --- a/plugins/sedi/actions.php +++ b/plugins/sedi/actions.php @@ -19,75 +19,84 @@ include_once __DIR__.'/../../core.php'; +use Modules\Anagrafiche\Sede; + $operazione = filter('op'); switch ($operazione) { case 'addsede': - if (!empty(post('nomesede'))) { - $opt_out_newsletter = post('disable_newsletter'); - $dbo->insert('an_sedi', [ + if (!empty(post('nomesede'))) { + $opt_out_newsletter = post('disable_newsletter'); + $dbo->insert('an_sedi', [ 'idanagrafica' => $id_parent, 'nomesede' => post('nomesede'), 'indirizzo' => post('indirizzo'), - 'codice_destinatario' => post('codice_destinatario'), 'citta' => post('citta'), 'cap' => post('cap'), 'provincia' => strtoupper(post('provincia')), 'km' => post('km'), + 'id_nazione' => !empty(post('id_nazione')) ? post('id_nazione') : null, + 'idzona' => !empty(post('idzona')) ? post('idzona') : 0, 'cellulare' => post('cellulare'), 'telefono' => post('telefono'), 'email' => post('email'), - 'id_nazione' => !empty(post('id_nazione')) ? post('id_nazione') : null, - 'idzona' => !empty(post('idzona')) ? post('idzona') : 0, 'enable_newsletter' => empty($opt_out_newsletter), + 'codice_destinatario' => post('codice_destinatario'), + 'is_automezzo' => post('is_automezzo'), + 'is_rappresentante_fiscale' => post('is_rappresentante_fiscale'), ]); - $id_record = $dbo->lastInsertedID(); - $id_referenti = (array) post('id_referenti'); - foreach ($id_referenti as $id_referente) { - $dbo->update('an_referenti', [ - 'idsede' => $id_record, - ], [ - 'id' => $id_referente, - ]); - } + $id_record = $dbo->lastInsertedID(); - if (isAjaxRequest() && !empty($id_record)) { - echo json_encode(['id' => $id_record, 'text' => post('nomesede').' - '.post('citta')]); - } + $id_referenti = (array) post('id_referenti'); + foreach ($id_referenti as $id_referente) { + $dbo->update('an_referenti', [ + 'idsede' => $id_record, + ], [ + 'id' => $id_referente, + ]); + } - flash()->info(tr('Aggiunta una nuova sede!')); - } else { - flash()->warning(tr('Errore durante aggiunta della sede')); - } + if (isAjaxRequest() && !empty($id_record)) { + echo json_encode(['id' => $id_record, 'text' => post('nomesede').' - '.post('citta')]); + } + + flash()->info(tr('Aggiunta una nuova sede!')); + } else { + flash()->warning(tr('Errore durante aggiunta della sede')); + } + + $sede = Sede::find($id_record); + $sede->save(); break; case 'updatesede': $opt_out_newsletter = post('disable_newsletter'); + $sede = Sede::find($id_record); $dbo->update('an_sedi', [ 'nomesede' => post('nomesede'), 'indirizzo' => post('indirizzo'), - 'codice_destinatario' => post('codice_destinatario'), - 'piva' => post('piva'), - 'codice_fiscale' => post('codice_fiscale'), 'citta' => post('citta'), 'cap' => post('cap'), 'provincia' => strtoupper(post('provincia')), - 'km' => post('km'), - 'cellulare' => post('cellulare'), - 'telefono' => post('telefono'), - 'email' => post('email'), - 'fax' => post('fax'), 'id_nazione' => !empty(post('id_nazione')) ? post('id_nazione') : null, + 'telefono' => post('telefono'), + 'cellulare' => post('cellulare'), + 'email' => post('email'), + 'enable_newsletter' => empty($opt_out_newsletter), + 'codice_destinatario' => post('codice_destinatario'), + 'is_rappresentante_fiscale' => post('is_rappresentante_fiscale'), + 'piva' => post('piva'), + 'codice_fiscale' => post('codice_fiscale'), + 'is_automezzo' => post('is_automezzo'), 'idzona' => post('idzona'), + 'km' => post('km'), 'note' => post('note'), 'gaddress' => post('gaddress'), 'lat' => post('lat'), 'lng' => post('lng'), - - 'enable_newsletter' => empty($opt_out_newsletter), ], ['id' => $id_record]); $referenti = $dbo->fetchArray('SELECT id FROM an_referenti WHERE idsede = '.$id_record); @@ -110,6 +119,8 @@ switch ($operazione) { ]); } + $sede->save(); + flash()->info(tr('Salvataggio completato!')); break; diff --git a/plugins/sedi/add.php b/plugins/sedi/add.php index e683b53ff..cce665f23 100755 --- a/plugins/sedi/add.php +++ b/plugins/sedi/add.php @@ -42,18 +42,11 @@ echo '
{[ "type": "text", "label": "'.tr('Indirizzo').'", "name": "indirizzo", "required": 0 ]}
- -
- {[ "type": "text", "label": "'.($record['tipo_anagrafica'] == 'Ente pubblico' ? tr('Codice unico ufficio') : tr('Codice destinatario')).'", "name": "codice_destinatario", "required": 0, "class": "text-center text-uppercase alphanumeric-mask", "value": "$codice_destinatario$", "maxlength": '.($record['tipo_anagrafica'] == 'Ente pubblico' ? '6' : '7').', "help": "'.tr('Attenzione: per impostare il codice specificare prima \'Tipologia\' e \'Nazione\' dell\'anagrafica:
  • Ente pubblico (B2G/PA) - Codice Univoco Ufficio (www.indicepa.gov.it), 6 caratteri
  • Azienda (B2B) - Codice Destinatario, 7 caratteri
  • Privato (B2C) - viene utilizzato il Codice Fiscale
').'", "readonly": "'.intval($record['iso2'] ? $record['iso2'] != 'IT' : 0).'" ]} -
- - - -
{[ "type": "text", "label": "'.tr('Città').'", "name": "citta", "required": 1 ]}
- +
+
{[ "type": "text", "label": "'.tr('C.A.P.').'", "name": "cap" ]}
@@ -65,37 +58,41 @@ echo '
{[ "type": "text", "label": "'.tr('Km').'", "name": "km" ]}
-
- -
-
+
{[ "type": "select", "label": "'.tr('Nazione').'", "name": "id_nazione", "ajax-source": "nazioni", "required": 1 ]}
-
+
{[ "type": "select", "label": "'.tr('Zona').'", "name": "idzona", "ajax-source": "zone", "placeholder": "'.tr('Nessuna zona').'", "icon-after": "add|'.Modules::get('Zone')['id'].'" ]}
-
+
{[ "type": "telefono", "label": "'.tr('Cellulare').'", "name": "cellulare" ]}
-
+
{[ "type": "telefono", "label": "'.tr('Telefono').'", "name": "telefono" ]}
-
+
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "class": "email-mask", "validation": "email" ]}
-
- -
-
+
{[ "type": "checkbox", "label": "'.tr('Opt-out per newsletter').'", "name": "disable_newsletter", "id": "disable_newsletter_m", "value": "0", "help": "'.tr("Blocco per l'invio delle email.").'" ]}
- +
+
+ {[ "type": "text", "label": "'.($record['tipo_anagrafica'] == 'Ente pubblico' ? tr('Codice unico ufficio') : tr('Codice destinatario')).'", "name": "codice_destinatario", "required": 0, "class": "text-center text-uppercase alphanumeric-mask", "value": "$codice_destinatario$", "maxlength": '.($record['tipo_anagrafica'] == 'Ente pubblico' ? '6' : '7').', "help": "'.tr('Attenzione: per impostare il codice specificare prima \'Tipologia\' e \'Nazione\' dell\'anagrafica:
  • Ente pubblico (B2G/PA) - Codice Univoco Ufficio (www.indicepa.gov.it), 6 caratteri
  • Azienda (B2B) - Codice Destinatario, 7 caratteri
  • Privato (B2C) - viene utilizzato il Codice Fiscale
').'", "readonly": "'.intval($record['iso2'] ? $record['iso2'] != 'IT' : 0).'" ]} +
+
+ {[ "type": "checkbox", "label": "'.tr('Automezzo').'", "name": "is_automezzo", "id": "is_automezzo", "value": "0", "help": "'.tr('Seleziona se questa sede rappresenta un automezzo.').'" ]} +
+
+ {[ "type": "checkbox", "label": "'.tr('Rappresentante fiscale').'", "name": "is_rappresentante_fiscale", "value": "'.($record['is_rappresentante_fiscale']).'", "help": "'.tr("Utilizza questa sede come rappresentante fiscale per l'anagrafica.").'" ]} +
+
{[ "type": "select", "multiple": "1", "label": "'.tr('Referenti').'", "name": "id_referenti[]", "ajax-source": "referenti", "select-options": {"idanagrafica": '.$id_parent.'}, "icon-after": "add|'.Modules::get('Anagrafiche')['id'].'|id_plugin='.Plugins::get('Referenti')['id'].'&id_parent='.$id_parent.'" ]} diff --git a/plugins/sedi/edit.php b/plugins/sedi/edit.php index 7e62b7022..8f5054721 100755 --- a/plugins/sedi/edit.php +++ b/plugins/sedi/edit.php @@ -40,72 +40,70 @@ echo '
{[ "type": "text", "label": "'.tr('Indirizzo').'", "name": "indirizzo", "id": "indirizzo_", "required": 0, "value": "$indirizzo$" ]}
- -
- {[ "type": "text", "label": "'.($record['tipo_anagrafica'] == 'Ente pubblico' ? tr('Codice unico ufficio') : tr('Codice destinatario')).'", "name": "codice_destinatario", "required": 0, "class": "text-center text-uppercase alphanumeric-mask", "value": "$codice_destinatario$", "maxlength": '.($record['tipo_anagrafica'] == 'Ente pubblico' ? '6' : '7').', "help": "'.tr('Attenzione: per impostare il codice specificare prima \'Tipologia\' e \'Nazione\' dell\'anagrafica:
  • Ente pubblico (B2G/PA) - Codice Univoco Ufficio (www.indicepa.gov.it), 6 caratteri
  • Azienda (B2B) - Codice Destinatario, 7 caratteri
  • Privato (B2C) - viene utilizzato il Codice Fiscale
').'", "readonly": "'.intval($record['iso2'] ? $record['iso2'] != 'IT' : 0).'" ]} -
-
- -
{[ "type": "text", "label": "'.tr('Città').'", "name": "citta", "id": "citta_", "value": "$citta$", "required": 1 ]}
+
-
- {[ "type": "text", "label": "'.tr('C.A.P.').'", "name": "cap", "value": "$cap$" ]} +
+
+ {[ "type": "text", "label": "'.tr('C.A.P.').'", "name": "cap", "value": "$cap$", "required":1 ]}
-
+
{[ "type": "text", "label": "'.tr('Provincia').'", "name": "provincia", "value": "$provincia$", "maxlength": 2, "class": "text-center provincia-mask text-uppercase", "extra": "onkeyup=\"this.value = this.value.toUpperCase();\"" ]}
- -
- {[ "type": "number", "label": "'.tr('Km').'", "name": "km", "value": "$km$" ]} -
-
- -
-
+
{[ "type": "select", "label": "'.tr('Nazione').'", "name": "id_nazione", "value": "$id_nazione$", "ajax-source": "nazioni", "required": 1 ]}
- -
+
+
+
{[ "type": "telefono", "label": "'.tr('Telefono').'", "name": "telefono", "value": "$telefono$" ]}
-
- -
-
- {[ "type": "text", "label": "'.tr('Fax').'", "name": "fax", "value": "$fax$" ]} -
- -
+
{[ "type": "telefono", "label": "'.tr('Cellulare').'", "name": "cellulare", "value": "$cellulare$" ]}
-
- -
-
+
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "value": "$email$", "class": "email-mask", "validation": "email" ]}
-
{[ "type": "checkbox", "label": "'.tr('Opt-out per newsletter').'", "name": "disable_newsletter", "id": "disable_newsletter_m", "value": "'.empty($record['enable_newsletter']).'", "help": "'.tr("Blocco per l'invio delle email.").'" ]}
+
+
+
+ {[ "type": "text", "label": "'.($record['tipo_anagrafica'] == 'Ente pubblico' ? tr('Codice unico ufficio') : tr('Codice destinatario')).'", "name": "codice_destinatario", "required": 0, "class": "text-center text-uppercase alphanumeric-mask", "value": "$codice_destinatario$", "maxlength": '.($record['tipo_anagrafica'] == 'Ente pubblico' ? '6' : '7').', "help": "'.tr('Attenzione: per impostare il codice specificare prima \'Tipologia\' e \'Nazione\' dell\'anagrafica:
  • Ente pubblico (B2G/PA) - Codice Univoco Ufficio (www.indicepa.gov.it), 6 caratteri
  • Azienda (B2B) - Codice Destinatario, 7 caratteri
  • Privato (B2C) - viene utilizzato il Codice Fiscale
').'", "readonly": "'.intval($record['iso2'] ? $record['iso2'] != 'IT' : 0).'" ]} +
+ {[ "type": "checkbox", "label": "'.tr('Rappresentante fiscale').'", "name": "is_rappresentante_fiscale", "value": "'.($record['is_rappresentante_fiscale']).'", "help": "'.tr("Utilizza questa sede come rappresentante fiscale per l'anagrafica.").'" ]} +
+ +
+ {[ "type": "text", "label": "'.tr('Partita IVA').'", "name": "piva", "value": "'.($record['piva']).'", "help": "'.tr('Partita IVA del rappresentante fiscale.').'", "disabled":"disabled"]} +
+
+ {[ "type": "text", "label": "'.tr('Codice fiscale').'", "name": "codice_fiscale", "value": "'.($record['codice_fiscale']).'", "help": "'.tr('Codice fiscale del rappresentante fiscale.').'", "disabled":"disabled" ]} +
+
+
+
+ {[ "type": "checkbox", "label": "'.tr('Automezzo').'", "name": "is_automezzo", "id": "is_automezzo", "value": "'.$record['is_automezzo'].'", "help": "'.tr('Seleziona se questa sede rappresenta un automezzo.').'" ]} +
+ +
{[ "type": "select", "label": "'.tr('Zona').'", "name": "idzona", "ajax-source": "zone", "value": "$idzona$", "placeholder": "'.tr('Nessuna zona').'", "icon-after": "add|'.Modules::get('Zone')['id'].'" ]}
-
- -
-
- {[ "type": "select", "multiple": "1", "label": "'.tr('Referenti').'", "name": "id_referenti[]", "value": "'.$referenti.'", "ajax-source": "referenti", "select-options": {"idanagrafica": '.$id_parent.'}, "icon-after": "add|'.Modules::get('Anagrafiche')['id'].'|id_plugin='.Plugins::get('Referenti')['id'].'&id_parent='.$id_parent.'" ]} +
+ {[ "type": "number", "label": "'.tr('Km').'", "name": "km", "value": "$km$" ]}
-
-
+
+ {[ "type": "select", "multiple": "1", "label": "'.tr('Referenti').'", "name": "id_referenti[]", "value": "'.$referenti.'", "ajax-source": "referenti", "select-options": {"idanagrafica": '.$id_parent.'}, "icon-after": "add|'.Modules::get('Anagrafiche')['id'].'|id_plugin='.Plugins::get('Referenti')['id'].'&id_parent='.$id_parent.'" ]} +
+
{[ "type": "textarea", "label": "'.tr('Note').'", "name": "note", "value": "$note$" ]}
@@ -210,6 +208,29 @@ echo ' '; diff --git a/src/Common/Components/Article.php b/src/Common/Components/Article.php index ad1f64f0d..c471d2db4 100755 --- a/src/Common/Components/Article.php +++ b/src/Common/Components/Article.php @@ -293,19 +293,48 @@ abstract class Article extends Accounting $movimento = Movimento::descrizioneMovimento($qta_movimento, $documento->direzione).' - '.$documento->getReference(); if ($documento instanceof \Modules\Interventi\Intervento) { - $id_sede = $this->idsede_partenza; + $id_sede = $documento->idsede_partenza; } else { $id_sede = $documento->direzione == 'uscita' ? $documento->idsede_destinazione : $documento->idsede_partenza; } // Fix per valori di sede a NULL $id_sede = $id_sede ?: 0; + $qta_finale = $qta_movimento; - $this->articolo->movimenta($qta_movimento, $movimento, $data, false, [ + if (!setting('Permetti selezione articoli con quantità minore o uguale a zero in Documenti di Vendita') && $documento->direzione == 'entrata') { + $qta_sede = Movimento::where('idarticolo', $this->articolo->id) + ->where('idsede', $id_sede) + ->groupBy('idarticolo') + ->sum('qta'); + + $qta_modifica = $this->attributes['qta']-$this->original['qta']; + + //Se la quantità supera la giacenza in sede allora movimento solo quello che resta + if (($qta_sede + $qta_finale) < 0 && $qta_sede >= 0) { + $qta_finale = -$qta_sede; + $this->attributes['qta'] = $qta_sede + ($qta_modifica != 0 ? $this->original['qta'] : 0); + } + + // Se la quantità sede per qualche motivo è negativa correggo la quantità della riga con la differenza + elseif ($qta_sede < 0 && $this->original['qta'] >= abs($qta_sede)) { + $qta_finale = abs($qta_sede); + $this->attributes['qta'] = $this->original['qta'] - abs($qta_sede); + } + + // Se la quantità sede per qualche motivo è negativa e supera la quantità della riga azzero quest'ultima + elseif ($qta_sede < 0 && $this->original['qta'] < abs($qta_sede)) { + $qta_finale = $this->original['qta']; + $this->attributes['qta'] = 0; + } + } + + $this->articolo->movimenta($qta_finale, $movimento, $data, false, [ 'reference_type' => get_class($documento), 'reference_id' => $documento->id, 'idsede' => $id_sede, ]); + } protected static function boot() diff --git a/templates/automezzi_carico/body.php b/templates/automezzi_carico/body.php new file mode 100644 index 000000000..d3a1d77ef --- /dev/null +++ b/templates/automezzi_carico/body.php @@ -0,0 +1,93 @@ +
CARICO SUGLI AUTOMEZZI IL '.date('d/m/Y', strtotime($dt_carico)).'
'; + + $targa = ''; + $totale_qta = 0.000; + $totale_ven = 0.00; + for ($r = 0; $r < sizeof($rs); ++$r) { + if ($targa != $rs[$r]['targa']) { + if ($targa != '') { + echo " + + + + + + + + + + + +
".' '."".' '."".' '."".number_format($totale_qta, 3, ',', '.')." kg".' '."".number_format($totale_ven, 2, ',', '.')." €".' '.'
'; + } + + echo " +
+ + + + + + +
Targa: ".$rs[$r]['targa']."Automezzo: ".$rs[$r]['nome'].'
'; + + echo " + + + + + + + + + + + "; + $targa = $rs[$r]['targa']; + $totale_qta = 0.000; + $totale_ven = 0.00; + } + echo ' + '; + $qta = number_format($rs[$r]['qta'], 3, ',', '.').' '.$rs[$r]['um']; + + $prz_vendita = number_format($rs[$r]['prezzo_vendita'], 2); + $prz_vendita += ($prz_vendita / 100) * $rs[$r]['iva']; + $totv = number_format($prz_vendita, 2) * $rs[$r]['qta']; + + echo " + + + + + + + + '; + + $totale_ven = $totale_ven + $totv; + if ($rs[$r]['um'] == 'kg') { + $totale_qta = $totale_qta + $rs[$r]['qta']; + } + } + + echo ' +
CodiceDescrizioneSub.Cat.QuantitàP. Ven.TotaleUtente
".$rs[$r]['codice']."".$rs[$r]['descrizione']."".$rs[$r]['subcategoria']."".$qta."".number_format($prz_vendita, 2, ',', '.')." €".number_format($totv, 2, ',', '.')." €".ucfirst($rs[$r]['username']).'
'; + + if ($targa != '') { + echo " + + + + + + + + + + +
".' '."".' '."".' '."".number_format($totale_qta, 3, ',', '.')." kg".' '."".number_format($totale_ven, 2, ',', '.')." €".' '.'
'; + } diff --git a/templates/automezzi_carico/footer.php b/templates/automezzi_carico/footer.php new file mode 100644 index 000000000..ed0d05b26 --- /dev/null +++ b/templates/automezzi_carico/footer.php @@ -0,0 +1,39 @@ +. + */ + +/* + * Footer di default. + * I contenuti di questo file vengono utilizzati per generare il footer delle stampe nel caso non esista un file footer.php all'interno della stampa. + * + * Per modificare il footer della stampa basta aggiungere un file footer.php all'interno della cartella della stampa con i contenuti da mostrare (vedasi templates/fatture/footer.php). + * + * La personalizzazione specifica del footer deve comunque seguire lo standard della cartella custom: anche se il file footer.php non esiste nella stampa originaria, se si vuole personalizzare il footer bisogna crearlo all'interno della cartella custom. + */ + +echo ' + + + + +
+ '.tr('Pagina _PAGE_ di _TOTAL_', [ + '_PAGE_' => '{PAGENO}', + '_TOTAL_' => '{nb}', + ]).' +
'; diff --git a/templates/automezzi_carico/init.php b/templates/automezzi_carico/init.php new file mode 100644 index 000000000..2491209d5 --- /dev/null +++ b/templates/automezzi_carico/init.php @@ -0,0 +1,60 @@ +. + */ + +include_once __DIR__.'/../../core.php'; + +$search_targa = get('search_targa'); +$search_nome = get('search_nome'); +$dt_carico = get('data_carico'); +$data_carico = strtotime(str_replace('/', '-', $dt_carico)); +$startTM = date('Y-m-d', $data_carico).' 00:00:00'; +$endTM = date('Y-m-d', $data_carico).' 23:59:59'; + +$query = " + SELECT + mg_movimenti.data, + an_sedi.targa, + an_sedi.nome, + mg_articoli.codice, + mg_articoli.prezzo_vendita, + co_iva.percentuale AS 'iva', + (SELECT mg_categorie.nome FROM mg_categorie WHERE mg_categorie.id=mg_articoli.id_sottocategoria) AS subcategoria, + (SELECT mg_articoli.descrizione FROM mg_articoli WHERE mg_articoli.id=mg_movimenti.idarticolo) AS 'descrizione', + IF( mg_movimenti.movimento LIKE '%Scarico%', mg_movimenti.qta*(-1), mg_movimenti.qta) AS qta, + mg_movimenti.idutente, + zz_users.username, + mg_articoli.um, + zz_groups.nome as 'gruppo' + FROM + mg_movimenti + INNER JOIN mg_articoli ON mg_movimenti.idarticolo=mg_articoli.id + INNER JOIN co_iva ON mg_articoli.idiva_vendita = co_iva.id + INNER JOIN zz_users ON mg_movimenti.idutente=zz_users.id + INNER JOIN zz_groups ON zz_users.idgruppo=zz_groups.id + INNER JOIN an_sedi ON mg_movimenti.idsede=an_sedi.id + WHERE + (mg_movimenti.idsede > 0) AND (mg_movimenti.idintervento IS NULL) AND + ((mg_movimenti.data BETWEEN ".prepare($startTM).' AND '.prepare($endTM).") AND (zz_groups.nome IN ('Titolari', 'Amministratori')))"; + +$query .= ' AND (an_sedi.targa LIKE '.prepare('%'.$search_targa.'%').') AND (an_sedi.nome LIKE '.prepare('%'.$search_nome.'%').') '; +$query .= ' ORDER BY an_sedi.targa, mg_articoli.descrizione'; + +$rs = $dbo->fetchArray($query); +$totrows = sizeof($rs); +$azienda = $dbo->fetchOne('SELECT * FROM an_anagrafiche WHERE idanagrafica='.prepare(setting('Azienda predefinita'))); diff --git a/templates/automezzi_inventario/body.php b/templates/automezzi_inventario/body.php new file mode 100644 index 000000000..f63e3efc7 --- /dev/null +++ b/templates/automezzi_inventario/body.php @@ -0,0 +1,51 @@ +'; + + $targa = ''; + for ($r = 0; $r < sizeof($rs); ++$r) { + if ($targa != $rs[$r]['targa']) { + if ($targa != '') { + echo ' + +
'; + } + echo " + + + + + + +
Targa: ".$rs[$r]['targa']."Automezzo: ".$rs[$r]['nome']."
+ + + + + + + + + + "; + $targa = $rs[$r]['targa']; + } + echo ' + '; + + $qta = number_format($rs[$r]['qta'], 3, ',', '.').' '.$rs[$r]['um']; + + echo " + + + + + + "; + } + if ($targa != '') { + echo ' +
CodiceDescrizioneSub.Cat.Q.tà
".$rs[$r]['codice']."".$rs[$r]['descrizione']."".$rs[$r]['subcategoria']."".$qta."
'; + } diff --git a/templates/automezzi_inventario/footer.php b/templates/automezzi_inventario/footer.php new file mode 100644 index 000000000..ed0d05b26 --- /dev/null +++ b/templates/automezzi_inventario/footer.php @@ -0,0 +1,39 @@ +. + */ + +/* + * Footer di default. + * I contenuti di questo file vengono utilizzati per generare il footer delle stampe nel caso non esista un file footer.php all'interno della stampa. + * + * Per modificare il footer della stampa basta aggiungere un file footer.php all'interno della cartella della stampa con i contenuti da mostrare (vedasi templates/fatture/footer.php). + * + * La personalizzazione specifica del footer deve comunque seguire lo standard della cartella custom: anche se il file footer.php non esiste nella stampa originaria, se si vuole personalizzare il footer bisogna crearlo all'interno della cartella custom. + */ + +echo ' + + + + +
+ '.tr('Pagina _PAGE_ di _TOTAL_', [ + '_PAGE_' => '{PAGENO}', + '_TOTAL_' => '{nb}', + ]).' +
'; diff --git a/templates/automezzi_inventario/init.php b/templates/automezzi_inventario/init.php new file mode 100644 index 000000000..7c99c06f3 --- /dev/null +++ b/templates/automezzi_inventario/init.php @@ -0,0 +1,54 @@ +. + */ + +include_once __DIR__.'/../../core.php'; + +$azienda = $dbo->fetchOne('SELECT * FROM an_anagrafiche WHERE idanagrafica='.prepare(setting('Azienda predefinita'))); + +$where = []; +$search_targa = get('search_targa'); +$search_nome = get('search_nome'); + +$where[] = 'movimenti.qta > 0'; +$where[] = 'movimenti.qta > 0'; +if ($search_targa) { + $where[] = 'an_sedi.targa like '.prepare('%'.$search_targa.'%'); +} +if ($search_nome) { + $where[] = 'an_sedi.nome like '.prepare('%'.$search_nome.'%'); +} + +//Ciclo tra gli articoli selezionati +$query = ' + SELECT + an_sedi.targa, an_sedi.nome, + mg_articoli.codice, mg_articoli.descrizione, + (SELECT mg_categorie.nome FROM mg_categorie WHERE mg_categorie.id=mg_articoli.id_sottocategoria) AS subcategoria, + movimenti.qta, + mg_articoli.um + FROM an_sedi + INNER JOIN (SELECT SUM(mg_movimenti.qta) AS qta, idarticolo, idsede FROM mg_movimenti GROUP BY idsede,idarticolo) AS movimenti ON movimenti.idsede = an_sedi.id + INNER JOIN mg_articoli ON movimenti.idarticolo = mg_articoli.id + WHERE + '.implode(' AND ', $where).' + ORDER BY + an_sedi.targa, an_sedi.descrizione'; + +$rs = $dbo->fetchArray($query); +$totrows = sizeof($rs); diff --git a/update/2_4_52.sql b/update/2_4_52.sql index 4627d3597..6c3154648 100644 --- a/update/2_4_52.sql +++ b/update/2_4_52.sql @@ -39,4 +39,55 @@ ALTER TABLE `zz_files` ADD INDEX(`id_record`); ALTER TABLE `co_scadenziario` ADD `id_pagamento` INT NOT NULL; ALTER TABLE `co_scadenziario` ADD `id_banca_azienda` INT NULL; -ALTER TABLE `co_scadenziario` ADD `id_banca_controparte` INT NULL; \ No newline at end of file +ALTER TABLE `co_scadenziario` ADD `id_banca_controparte` INT NULL; + +-- Aggiunta nuovi campi in sedi per gestione automezzi +ALTER TABLE `an_sedi` + ADD `nome` VARCHAR(225) NULL DEFAULT NULL , + ADD `descrizione` VARCHAR(225) NULL DEFAULT NULL AFTER `nome` , + ADD `targa` VARCHAR(225) NULL DEFAULT NULL AFTER `descrizione` , + ADD `is_automezzo` TINYINT NOT NULL DEFAULT '0' AFTER `targa` ; + + +-- Creazione modulo Automezzi +INSERT INTO `zz_modules` (`id`, `name`, `title`, `directory`, `options`, `options2`, `icon`, `version`, `compatibility`, `order`, `parent`, `default`, `enabled`, `use_notes`, `use_checklists`) VALUES (NULL, 'Automezzi', 'Automezzi', 'automezzi', 'SELECT |select| FROM an_sedi INNER JOIN zz_settings ON (zz_settings.valore=an_sedi.idanagrafica AND zz_settings.nome=\'Azienda predefinita\' ) WHERE 1=1 AND an_sedi.is_automezzo=1 HAVING 2=2 ORDER BY nomesede ASC', '', 'fa fa-angle-right', '1.0', '2.4.16', '100', (SELECT `t`.`id` FROM `zz_modules` AS `t` WHERE `t`.`name` = 'Magazzino'), '0', '1', '0', '0'); + +--Viste modulo automezzi +INSERT INTO `zz_views` (`id_module`, `name`, `query`, `order`, `search`, `slow`, `format`, `search_inside`, `order_by`, `visible`, `summable`, `default`) VALUES +((SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), 'id', 'an_sedi.id', 0, 1, 0, 0, '', '', 0, 0, 0), +((SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), 'Targa', 'an_sedi.targa', 2, 1, 0, 0, '', '', 1, 0, 0), +((SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), 'Nome', 'an_sedi.nome', 3, 1, 0, 0, '', '', 1, 0, 0), +((SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), 'Descrizione', 'an_sedi.descrizione', 4, 1, 0, 0, '', '', 1, 0, 0); + +-- Tabella per associazione automezzi-tecnici +CREATE TABLE `an_sedi_tecnici` ( + `id` INT NOT NULL AUTO_INCREMENT , + `idsede` INT NOT NULL , + `idtecnico` INT NOT NULL , + `data_inizio` DATE NULL DEFAULT NULL, + `data_fine` DATE NULL DEFAULT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , + `updated_at` TIMESTAMP on UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , +PRIMARY KEY (`id`)) ENGINE = InnoDB; + +-- Aggiunta indici +ALTER TABLE `an_sedi_tecnici` + ADD INDEX(`idsede`), + ADD INDEX(`idtecnico`); + +ALTER TABLE `an_sedi_tecnici` ADD CONSTRAINT `an_sedi_tecnici_ibfk_1` FOREIGN KEY (`idsede`) REFERENCES `an_sedi`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION; + +ALTER TABLE `an_sedi_tecnici` ADD CONSTRAINT `an_sedi_tecnici_ibfk_2` FOREIGN KEY (`idtecnico`) REFERENCES `an_anagrafiche`(`idanagrafica`) ON DELETE CASCADE ON UPDATE NO ACTION; + +-- Aggiunta stampe automezzi +INSERT INTO `zz_prints` (`id`, `id_module`, `is_record`, `name`, `title`, `filename`, `directory`, `previous`, `options`, `icon`, `version`, `compatibility`, `order`, `predefined`, `default`, `enabled`) VALUES +(NULL, (SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), '0', 'Giacenza automezzi', 'Giacenza automezzi', 'giacenza automezzo', 'automezzi_inventario', '', '', '', '', '', '1', '0', '0', '1'), +(NULL, (SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), '0', 'Giacenza odierna automezzi', 'Giacenza odierna automezzi', 'giacenza automezzo', 'automezzi_carico', '', '', '', '', '', '1', '0', '0', '1'); + +-- Widget modulo automezzi +INSERT INTO `zz_widgets` (`id`, `name`, `type`, `id_module`, `location`, `class`, `query`, `bgcolor`, `icon`, `print_link`, `more_link`, `more_link_type`, `php_include`, `text`, `enabled`, `order`, `help`) VALUES +(NULL, 'Stampa carico odierno', 'print', (SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), 'controller_top', 'col-md-4', '', '#37a02d', 'fa fa-print', '', 'var data_carico = prompt(\'Data del carico da stampare?\', moment(new Date()).format(\'DD/MM/YYYY\'));\r\nif ( data_carico != null){ \r\nwindow.open(\'pdfgen.php?id_print=54&search_targa=\'+$(\'#th_Targa input\').val()+\'&search_nome=\'+$(\'#th_Nome input\').val()+\'&data_carico=\'+data_carico); \r\n}', 'javascript', '', 'Stampa carico odierno', '1', '2', NULL), +(NULL, 'Stampa giacenza', 'print', (SELECT `id` FROM `zz_modules` WHERE name='Automezzi'), 'controller_top', 'col-md-4', '', '#45a9f1', 'fa fa-truck', '', 'if( confirm(\'Stampare la giacenza attuale sugli automezzi?\') ){ window.open(\'pdfgen.php?id_print=53&search_targa=\'+$(\'#th_Targa input\').val()+\'&search_nome=\'+$(\'#th_Nome input\').val()); }', 'javascript', '', 'Stampa giacenza', '1', '1', NULL); + +-- Aggiunta flag rappresentante fiscale per sede +ALTER TABLE `an_sedi` ADD `is_rappresentante_fiscale` BOOLEAN NULL DEFAULT FALSE; \ No newline at end of file