diff --git a/README.md b/README.md index dd45cadf8..a5b5a8b91 100755 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ La documentazione ufficiale è disponibile all'indirizzo -## Requisiti +## Requisiti software L'installazione del gestionale richiede la presenza di un server web con abilitato il [DBMS MySQL](https://www.mysql.com) e il linguaggio di programmazione [PHP](https://php.net). @@ -85,6 +85,18 @@ L'installazione del gestionale richiede la presenza di un server web con abilita Per ulteriori informazioni sui pacchetti che forniscono questi elementi di default, visitare la sezione [Installazione](https://docs.openstamanager.com/configurazione/installazione) della documentazione. +### Requisiti hardware + +Minimi: +- 1 CPU +- 2GB di ram +- 200MB di spazio per il gestionale + +Consigliati: +- 2 CPU +- 4GB di ram +- 2GB di spazio per il gestionale + ## Installazione rapida ```bash git clone https://github.com/devcode-it/openstamanager.git diff --git a/assets/src/css/style.css b/assets/src/css/style.css index e47f4de6c..63c31d6ea 100755 --- a/assets/src/css/style.css +++ b/assets/src/css/style.css @@ -1238,3 +1238,7 @@ kbd{ .read-more-target:target { display: block; } + +.fc-day-today { + background:#fafad2 !important; +} \ No newline at end of file diff --git a/modules/anagrafiche/src/Import/CSV.php b/modules/anagrafiche/src/Import/CSV.php index 135242ac0..7d03299fa 100644 --- a/modules/anagrafiche/src/Import/CSV.php +++ b/modules/anagrafiche/src/Import/CSV.php @@ -91,10 +91,6 @@ class CSV extends CSVImporter 'field' => 'indirizzo', 'label' => 'Indirizzo', ], - [ - 'field' => 'indirizzo2', - 'label' => 'Civico', - ], [ 'field' => 'cap', 'label' => 'CAP', @@ -131,8 +127,9 @@ class CSV extends CSVImporter 'field' => 'sitoweb', 'label' => 'Sito Web', 'names' => [ - 'Sito', + 'Sito web', 'Website', + 'Sito', ], ], [ @@ -211,13 +208,8 @@ class CSV extends CSVImporter [ 'field' => 'tipo', 'label' => 'Tipologia (Privato, Ente pubblico, Azienda)', - ], - [ - 'field' => 'codice_destinatario', - 'label' => 'Codice Destinatario FE', 'names' => [ - 'Codice Destinatario FE', - 'codice destinatario FE', + 'Tipologia', ], ], [ @@ -246,6 +238,13 @@ class CSV extends CSVImporter $primary_key = $this->getPrimaryKey(); $id_azienda = setting('Azienda predefinita'); + // Compilo la ragione sociale se sono valorizzati cognome e nome + if (!$record['ragione_sociale'] && ($record['cognome'] && $record['nome'])) { + $record['ragione_sociale'] = $record['cognome'] . ' ' . $record['nome']; + } + unset($record['cognome']); + unset($record['nome']); + // Individuazione del tipo dell'anagrafica $tipologie = []; if (!empty($record['idtipoanagrafica'])) { @@ -297,7 +296,6 @@ class CSV extends CSVImporter // Separazione dei campi relativi alla sede legale $campi_sede = [ 'indirizzo', - 'indirizzo2', 'citta', 'cap', 'provincia', @@ -337,11 +335,11 @@ class CSV extends CSVImporter if ($anagrafica->id == $id_azienda) { return; } + unset($record['ragione_sociale']); $anagrafica->fill($record); $anagrafica->tipologie = $tipologie; $anagrafica->tipo = $tipi_selezionati; - $anagrafica->id_settore = $id_settore; $anagrafica->save(); $sede = $anagrafica->sedeLegale; @@ -352,8 +350,8 @@ class CSV extends CSVImporter public static function getExample() { return [ - ['Codice', 'Ragione sociale', 'Nome', 'Cognome', 'Tipologia', 'Partita IVA', 'Codice destinatario', 'Nazione', 'Indirizzo', 'CAP', 'Città', 'Provincia', 'Telefono', 'Fax', 'Cellulare', 'Email', 'PEC', 'Sito Web', 'IBAN', 'Note', 'Tipo'], - ['00001', 'Mia anagrafica', '', '', 'Azienda', '12345678910', '1234567', 'ITALIA', 'Via Giuseppe Mazzini, 123', '12345', 'Este', 'PD', '+39 0429 60 25 12', '+39 0429 456 781', '+39 321 12 34 567', 'email@anagrafica.it', 'pec@anagrafica.it', 'www.sito.it', 'IT60 X054 2811 1010 0000 0123 456', 'Note dell\'anagrafica di esempio', 'Cliente,Fornitore'], + ['Codice', 'Ragione sociale', 'Nome', 'Cognome', 'Codice destinatario', 'Provincia', 'Città', 'Telefono', 'Indirizzo', 'CAP', 'Cellulare', 'Fax','Email', 'PEC', 'Sito Web', 'Codice fiscale', 'Data di nascita', 'Luogo di nascita', 'Sesso', 'Partita IVA', 'IBAN', 'Note', 'Nazione', 'ID Agente', 'ID pagamento', 'Tipo', 'Tipologia', 'Split Payment', 'Settore merceologico'], + ['001', 'Rossi Mario', '', '', '12345', 'PD', 'Este', '+39 0429 60 25 12', 'Via Rovigo, 51', '35042', '+39 321 12 34 567', '', 'email@anagrafica.it', 'email@pec.it', 'www.sito.it', '', '', '', '', '123456789', 'IT60 X054 2811 1010 0000 0123 456', 'Note dell\'anagrafica di esempio', 'Italia', '', '', 'Cliente', 'Privato', '0', 'Tessile'], ]; } } diff --git a/modules/articoli/plugins/articoli.lotti.php b/modules/articoli/plugins/articoli.lotti.php index 2292b4138..3a311104a 100755 --- a/modules/articoli/plugins/articoli.lotti.php +++ b/modules/articoli/plugins/articoli.lotti.php @@ -289,8 +289,8 @@ if (empty(get('modal'))) { $id = $data[0]['idcontratto']; } - // Inserito su vendita banco - elseif (!empty($vendita['id_riga_venditabanco'])) { + // Inserito su vendita banco + elseif (!empty($vendita['id_riga_venditabanco'])) { $module_id = Modules::get('Vendita al banco')['id']; // Ricerca vendite su contratti diff --git a/modules/contratti/row-list.php b/modules/contratti/row-list.php index eca7e14d7..b48760a2c 100755 --- a/modules/contratti/row-list.php +++ b/modules/contratti/row-list.php @@ -201,13 +201,13 @@ foreach ($righe as $riga) { if (empty($record['is_completato'])) { echo '
'; - if ($riga->isArticolo() && !empty($riga->abilita_serial)) { - echo ' + if ($riga->isArticolo() && !empty($riga->abilita_serial)) { + echo ' '; - } - echo ' + } + echo ' diff --git a/modules/fatture/row-list.php b/modules/fatture/row-list.php index cf28b2c49..e9b6588b3 100755 --- a/modules/fatture/row-list.php +++ b/modules/fatture/row-list.php @@ -39,7 +39,7 @@ echo ' echo ' '.tr('#').' - '.tr('Descrizione').' + '.tr('Descrizione').' '.tr('Q.tà').''; if ($dir == 'entrata') { echo ''.tr('Costo unitario').''; diff --git a/modules/impianti/actions.php b/modules/impianti/actions.php index 942f4eb47..44a77dd17 100644 --- a/modules/impianti/actions.php +++ b/modules/impianti/actions.php @@ -37,7 +37,7 @@ switch ($op) { 'nome' => post('nome'), 'matricola' => $matricola, 'id_categoria' => post('id_categoria') ?: null, - 'id_sottocategoria' => post('subcategoria') ?: null, + 'id_sottocategoria' => post('id_sottocategoria') ?: null, 'descrizione' => post('descrizione'), 'idsede' => post('idsede'), 'data' => post('data') ?: null, @@ -101,6 +101,7 @@ switch ($op) { $idtecnico = post('idtecnico'); $idsede = post('idsede'); $id_categoria = post('id_categoria'); + $id_sottocategoria = post('id_sottocategoria'); if (!empty($matricola)) { $dbo->insert('my_impianti', [ @@ -111,6 +112,7 @@ switch ($op) { 'idtecnico' => $idtecnico ?: 0, 'idsede' => $idsede ?: 0, 'id_categoria' => $id_categoria ?: null, + 'id_sottocategoria' => $id_sottocategoria ?: null, ]); $id_record = $dbo->lastInsertedID(); diff --git a/modules/impianti/add.php b/modules/impianti/add.php index b03b7ebd9..43979cbfc 100644 --- a/modules/impianti/add.php +++ b/modules/impianti/add.php @@ -36,22 +36,25 @@ $id_anagrafica = filter('id_anagrafica');
-
+
{[ "type": "select", "label": "", "name": "idanagrafica", "id": "idanagrafica_impianto", "required": 1, "value": "", "ajax-source": "clienti", "icon-after": "add||tipoanagrafica=Cliente&readonly_tipo=1||", "readonly": "" ]}
-
+
{[ "type": "select", "label": "", "name": "idsede", "value": "$idsede$", "ajax-source": "sedi", "select-options": $id_anagrafica]); ?>, "placeholder": "Sede legale" ]}
+
+ {[ "type": "select", "label": "", "name": "idtecnico", "ajax-source": "tecnici", "icon-after": "add||tipoanagrafica=Tecnico&readonly_tipo=1" ]} +
- {[ "type": "select", "label": "", "name": "idtecnico", "ajax-source": "tecnici", "icon-after": "add||tipoanagrafica=Tecnico&readonly_tipo=1" ]} + {[ "type": "select", "label": "", "name": "id_categoria", "required": 0, "ajax-source": "categorie_imp", "icon-after": "add|" ]}
- {[ "type": "select", "label": "", "name": "id_categoria", "required": 0, "value": "$id_categoria$", "values": "query=SELECT id, nome AS descrizione FROM my_impianti_categorie", "icon-after": "add|" ]} + {[ "type": "select", "label": "", "name": "id_sottocategoria", "id": "sottocategoria_add", "ajax-source": "sottocategorie_imp", "icon-after": "add|||hide" ]}
@@ -64,7 +67,25 @@ $id_anagrafica = filter('id_anagrafica'); + \ No newline at end of file diff --git a/modules/impianti/ajax/select.php b/modules/impianti/ajax/select.php index 733fd15ce..ec1e826bc 100755 --- a/modules/impianti/ajax/select.php +++ b/modules/impianti/ajax/select.php @@ -108,4 +108,39 @@ switch ($resource) { } break; + + case 'categorie_imp': + $query = 'SELECT `id`, `nome` AS descrizione FROM `my_impianti_categorie` |where| ORDER BY `nome`'; + + foreach ($elements as $element) { + $filter[] = '`id`='.prepare($element); + } + + $where[] = '`parent` IS NULL'; + + if (!empty($search)) { + $search_fields[] = '`nome` LIKE '.prepare('%'.$search.'%'); + } + + break; + + /* + * Opzioni utilizzate: + * - id_categoria + */ + case 'sottocategorie_imp': + if (isset($superselect['id_categoria'])) { + $query = 'SELECT `id`, `nome` AS descrizione FROM `my_impianti_categorie` |where| ORDER BY `nome`'; + + foreach ($elements as $element) { + $filter[] = '`id`='.prepare($element); + } + + $where[] = '`parent`='.prepare($superselect['id_categoria']); + + if (!empty($search)) { + $search_fields[] = '`nome` LIKE '.prepare('%'.$search.'%'); + } + } + break; } diff --git a/modules/impianti/edit.php b/modules/impianti/edit.php index b56381579..cf74584e1 100644 --- a/modules/impianti/edit.php +++ b/modules/impianti/edit.php @@ -67,19 +67,20 @@ if (!empty($record['immagine'])) {
-
- {[ "type": "select", "label": "", "name": "id_categoria", "required": 0, "value": "$id_categoria$", "values": "query=SELECT id, nome AS descrizione FROM my_impianti_categorie", "icon-after": "add|" ]} -
- {[ "type": "select", "label": "", "name": "subcategoria", "value": "$id_sottocategoria$", "values": "query=SELECT id, nome AS descrizione FROM my_impianti_categorie WHERE parent = $id_categoria$", "select-options": $record['id_categoria']]); ?>, "icon-after": "add||id_original=" ]} -
+ + {[ "type": "select", "label": "", "name": "id_categoria", "required": 0, "value": "$id_categoria$", "ajax-source": "categorie_imp", "icon-after": "add|" ]} +
+ +
+ {[ "type": "select", "label": "", "name": "id_sottocategoria", "value": "$id_sottocategoria$", "ajax-source": "sottocategorie_imp", "select-options": $record['id_categoria']]); ?>, "icon-after": "add||id_original=" ]} +
- -
{[ "type": "date", "label": "", "name": "data", "value": "$data$" ]}
@@ -90,6 +91,9 @@ if (!empty($record['immagine'])) { {[ "type": "select", "label": "'.tr('Sede').'", "name": "idsede", "value": "$idsede$", "required": "1", "ajax-source": "sedi", "select-options": '.json_encode(['idanagrafica' => $record['idanagrafica']]).', "placeholder": "'.tr('Sede legale').'" ]}
'; ?> +
+ {[ "type": "text", "label": "", "name": "proprietario", "value": "$proprietario$" ]} +
@@ -98,13 +102,6 @@ if (!empty($record['immagine'])) {
-
-
- {[ "type": "text", "label": "", "name": "proprietario", "value": "$proprietario$" ]} -
- -
-
{[ "type": "text", "label": "", "name": "ubicazione", "value": "$ubicazione$" ]} @@ -201,5 +198,12 @@ $(document).ready(function() { $("#idsede").prop("disabled", value) .selectReset(); }); + + $("#id_categoria").change(function() { + updateSelectOption("id_categoria", $(this).val()); + + $("#id_sottocategoria").val(null).trigger("change"); + }); + }); diff --git a/plugins/importFE/src/FatturaOrdinaria.php b/plugins/importFE/src/FatturaOrdinaria.php index 309c9b303..6e0f25229 100755 --- a/plugins/importFE/src/FatturaOrdinaria.php +++ b/plugins/importFE/src/FatturaOrdinaria.php @@ -106,7 +106,20 @@ class FatturaOrdinaria extends FatturaElettronica $riepiloghi = $this->getBody()['DatiBeniServizi']['DatiRiepilogo']; $riepiloghi = $this->forceArray($riepiloghi); + $riepiloghi_raggruppati = []; + foreach ($riepiloghi as $riepilogo) { + $aliquota_iva = $riepilogo['AliquotaIVA']; + + if (array_key_exists($aliquota_iva, $riepiloghi_raggruppati)) { + $riepiloghi_raggruppati[$aliquota_iva]['ImponibileImporto'] += $riepilogo['ImponibileImporto']; + $riepiloghi_raggruppati[$aliquota_iva]['Imposta'] += $riepilogo['Imposta']; + } else { + $riepiloghi_raggruppati[$aliquota_iva] = $riepilogo; + } + } + + foreach ($riepiloghi_raggruppati as $riepilogo) { $valore = 0; if (isset($riepilogo['Arrotondamento']) && $riepilogo['Arrotondamento'] != 0 && round($totale_imposta[$riepilogo['AliquotaIVA']], 2) != (float) $riepilogo['Imposta']) { $valore = $riepilogo['Arrotondamento']; @@ -238,14 +251,13 @@ class FatturaOrdinaria extends FatturaElettronica $conto_arrotondamenti = $conto[$key]; } - $obj->id_rivalsa_inps = $id_rivalsa; - $obj->ritenuta_contributi = $ritenuta_contributi; // Inserisco la ritenuta se è specificata nella riga o se non è specificata nella riga ma è presente in Dati ritenuta (quindi comprende tutte le righe) if (!empty($riga['Ritenuta']) || $info['ritenuta_norighe'] == true) { $obj->id_ritenuta_acconto = $id_ritenuta_acconto; $obj->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto; + $obj->id_rivalsa_inps = $id_rivalsa; } // Totale documento @@ -474,7 +486,9 @@ class FatturaOrdinaria extends FatturaElettronica if (!empty($casse)) { $totale = 0; foreach ($righe as $riga) { - $totale += $riga['PrezzoTotale']; + if ($riga['Ritenuta']) { + $totale += $riga['PrezzoTotale']; + } } $casse = isset($casse[0]) ? $casse : [$casse]; @@ -502,6 +516,8 @@ class FatturaOrdinaria extends FatturaElettronica $id_rivalsa = $rivalsa['id']; } + $percentuale = 0; + $importo = 0; // Ritenuta d'Acconto $ritenuta = $dati_generali['DatiRitenuta']; if (!empty($ritenuta)) { diff --git a/templates/ordini_cons/top.php b/templates/ordini_cons/top.php index 7fddcdcdf..7019305e1 100644 --- a/templates/ordini_cons/top.php +++ b/templates/ordini_cons/top.php @@ -74,6 +74,7 @@ echo ' '.tr('Documento', [], ['upper' => true]).' + '.tr('KM', [], ['upper' => true]).' '.tr('Ore', [], ['upper' => true]).' '.tr('Imponibile', [], ['upper' => true]).' '.tr('Sconto', [], ['upper' => true]).' diff --git a/templates/preventivi/body.php b/templates/preventivi/body.php index 0fe593f80..6b7c4f5d0 100755 --- a/templates/preventivi/body.php +++ b/templates/preventivi/body.php @@ -58,7 +58,7 @@ $has_image = $righe->search(function ($item) { return !empty($item->articolo->immagine); }) !== false && $options['images'] == true; -$columns = 6; +$columns = $options['no-iva'] ? 5 : 6; $columns = $options['pricing'] ? $columns : 3; if ($has_image) { @@ -170,8 +170,12 @@ echo " if ($options['pricing']) { echo " - ".tr('Prezzo unitario', [], ['upper' => true])." - ".tr('IVA', [], ['upper' => true])." (%) + ".tr('Prezzo unitario', [], ['upper' => true]).''; + if (!$options['no-iva']) { + echo " + ".tr('IVA', [], ['upper' => true]).' (%)'; + } + echo " ".($options['hide-total'] ? tr('Importo ivato', [], ['upper' => true]) : tr('Importo', [], ['upper' => true])).''; } @@ -273,13 +277,13 @@ foreach ($righe as $key => $riga) { echo ' '; - - // Iva - echo ' - - '.Translator::numberToLocale($riga->aliquota->percentuale, 2).' - '; - + if (!$options['no-iva']) { + // Iva + echo ' + + '.Translator::numberToLocale($riga->aliquota->percentuale, 2).' + '; + } // Imponibile echo ' @@ -293,8 +297,11 @@ foreach ($righe as $key => $riga) { if ($options['pricing']) { echo ' - '; + if (!$options['no-iva']) { + echo ' + '; + } } } } @@ -314,8 +321,9 @@ foreach ($righe as $key => $riga) { '.moneyFormat($subtotale_gruppo, 2).' - - + '; + if (!$options['no-iva']) { + echo ' '.tr('Iva', [], ['upper' => true]).': @@ -324,16 +332,15 @@ foreach ($righe as $key => $riga) { '.moneyFormat($iva_gruppo, 2).' - - + '.tr('Subtotale ivato', [], ['upper' => true]).': '.moneyFormat($subtotale_gruppo + $iva_gruppo, 2).' '; - + } $autofill->next(); $autofill->next(); $autofill->next(); @@ -360,11 +367,11 @@ if (($options['pricing'] && !isset($options['hide-total'])) || $options['show-on // Totale imponibile echo ' - + '.tr('Imponibile', [], ['upper' => true]).': - + '.moneyFormat($show_sconto ? $imponibile : $totale_imponibile, 2).' '; @@ -396,56 +403,66 @@ if (($options['pricing'] && !isset($options['hide-total'])) || $options['show-on } // IVA - echo ' - - - '.tr('Totale IVA', [], ['upper' => true]).': - - - - '.moneyFormat($totale_iva, 2).' - - '; - - // TOTALE - echo ' - - - '.tr('Totale documento', [], ['upper' => true]).': - - - '.moneyFormat($totale, 2).' - - '; - - if ($sconto_finale) { - // SCONTO IN FATTURA + if (!$options['no-iva']) { echo ' - '.tr('Sconto in fattura', [], ['upper' => true]).': + '.tr('Totale IVA', [], ['upper' => true]).': + - '.moneyFormat($sconto_finale, 2).' + '.moneyFormat($totale_iva, 2).' '; - // NETTO A PAGARE + // TOTALE echo ' - '.tr('Netto a pagare', [], ['upper' => true]).': + '.tr('Totale documento', [], ['upper' => true]).': - '.moneyFormat($netto_a_pagare, 2).' + '.moneyFormat($totale, 2).' '; + + if ($sconto_finale) { + // SCONTO IN FATTURA + echo ' + + + '.tr('Sconto in fattura', [], ['upper' => true]).': + + + '.moneyFormat($sconto_finale, 2).' + + '; + + // NETTO A PAGARE + echo ' + + + '.tr('Netto a pagare', [], ['upper' => true]).': + + + '.moneyFormat($netto_a_pagare, 2).' + + '; + } } } echo ' '; +if ($options['no-iva']) { + echo ' +

+ Importo IVA esclusa +

+'; +} + // CONDIZIONI GENERALI DI FORNITURA echo ' diff --git a/templates/scadenzario/init.php b/templates/scadenzario/init.php index 68ed0976e..578a72ea9 100755 --- a/templates/scadenzario/init.php +++ b/templates/scadenzario/init.php @@ -41,7 +41,7 @@ if (!empty(get('date_end'))) { $date_end = get('date_end'); } -if (get('id_anagrafica') != 'null') { +if (get('id_anagrafica') && get('id_anagrafica') != 'null') { $module_query = str_replace('1=1', '1=1 AND co_scadenziario.idanagrafica="'.get('id_anagrafica').'"', $module_query); $id_anagrafica = get('id_anagrafica'); } diff --git a/update/2_4_52.sql b/update/2_4_52.sql index a11f12f9d..4010c384b 100644 --- a/update/2_4_52.sql +++ b/update/2_4_52.sql @@ -29,4 +29,7 @@ ORDER BY -- Serial in Contratti ALTER TABLE `mg_prodotti` ADD `id_riga_contratto` INT NULL AFTER `id_riga_intervento`; -ALTER TABLE `mg_prodotti` ADD FOREIGN KEY (`id_riga_contratto`) REFERENCES `co_righe_contratti`(`id`) ON DELETE CASCADE; \ No newline at end of file +ALTER TABLE `mg_prodotti` ADD FOREIGN KEY (`id_riga_contratto`) REFERENCES `co_righe_contratti`(`id`) ON DELETE CASCADE; + +-- Aggiunta stampa preventivo (solo totale imponibile) +INSERT INTO `zz_prints` (`id_module`, `is_record`, `name`, `title`, `filename`, `directory`, `previous`, `options`, `icon`, `version`, `compatibility`, `order`, `predefined`, `default`, `enabled`, `available_options`) VALUES ((SELECT `id` FROM `zz_modules` WHERE `name` = 'Preventivi'), '1', 'Preventivo(solo totale imponibile)', 'Preventivo (solo totale imponibile)', 'Preventivo num. {numero} del {data} rev {revisione}', 'preventivi', 'idpreventivo', '{\"pricing\": false, \"last-page-footer\": true, \"images\": true, \"no-iva\":true, \"show-only-total\":true }', 'fa fa-print', '', '', '0', '0', '1', '1', '{\"pricing\":\"Visualizzare i prezzi\", \"hide-total\": \"Nascondere i totali delle righe\", \"show-only-total\": \"Visualizzare solo i totali del documento\", \"hide-header\": \"Nascondere intestazione\", \"hide-footer\": \"Nascondere footer\", \"last-page-footer\": \"Visualizzare footer solo su ultima pagina\", \"hide-item-number\": \"Nascondere i codici degli articoli\"}'); \ No newline at end of file