-
+
+ {[ "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 "
+
+
+
+ Codice |
+ Descrizione |
+ Sub.Cat. |
+ Quantità |
+ P. Ven. |
+ Totale |
+ Utente |
+
";
+ $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 "
+ ".$rs[$r]['codice']." |
+ ".$rs[$r]['descrizione']." |
+ ".$rs[$r]['subcategoria']." |
+ ".$qta." |
+ ".number_format($prz_vendita, 2, ',', '.')." € |
+ ".number_format($totv, 2, ',', '.')." € |
+ ".ucfirst($rs[$r]['username']).' |
+
';
+
+ $totale_ven = $totale_ven + $totv;
+ if ($rs[$r]['um'] == 'kg') {
+ $totale_qta = $totale_qta + $rs[$r]['qta'];
+ }
+ }
+
+ echo '
+
';
+
+ 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']." |
+
+
+
+
+
+
+ Codice |
+ Descrizione |
+ Sub.Cat. |
+ Q.tà |
+ |
+
";
+ $targa = $rs[$r]['targa'];
+ }
+ echo '
+ ';
+
+ $qta = number_format($rs[$r]['qta'], 3, ',', '.').' '.$rs[$r]['um'];
+
+ echo "
+ ".$rs[$r]['codice']." |
+ ".$rs[$r]['descrizione']." |
+ ".$rs[$r]['subcategoria']." |
+ ".$qta." |
+ |
+
";
+ }
+ if ($targa != '') {
+ echo '
+
';
+ }
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