diff --git a/composer.json b/composer.json index 7344a4577..77a08b9fe 100755 --- a/composer.json +++ b/composer.json @@ -70,7 +70,9 @@ "Update\\": "update/", "Modules\\Aggiornamenti\\": ["modules/aggiornamenti/custom/src/", "modules/aggiornamenti/src/"], "Modules\\Anagrafiche\\": ["modules/anagrafiche/custom/src/", "modules/anagrafiche/src/"], + "Modules\\AttributiCombinazioni\\": ["modules/attributi_combinazioni/custom/src/", "modules/attributi_combinazioni/src/"], "Modules\\Backups\\": ["modules/backups/custom/src/", "modules/backups/src/"], + "Modules\\CombinazioniArticoli\\": ["modules/combinazioni_articoli/custom/src/", "modules/combinazioni_articoli/src/"], "Modules\\Emails\\": ["modules/emails/custom/src/", "modules/emails/src/"], "Modules\\Articoli\\": ["modules/articoli/custom/src/", "modules/articoli/src/"], "Modules\\Checklists\\": ["modules/checklists/custom/src/", "modules/checklists/src/"], diff --git a/modules/articoli/actions.php b/modules/articoli/actions.php index 8830d8b36..0d6605d4f 100755 --- a/modules/articoli/actions.php +++ b/modules/articoli/actions.php @@ -20,6 +20,7 @@ use Carbon\Carbon; use Modules\Articoli\Articolo; use Modules\Articoli\Categoria; +use Modules\CombinazioniArticoli\Combinazione; use Util\Ini; include_once __DIR__.'/../../core.php'; @@ -61,6 +62,9 @@ switch (post('op')) { $articolo->setPrezzoVendita(post('prezzo_vendita'), post('idiva_vendita')); $articolo->save(); + // Aggiornamento delle varianti per i campi comuni + Combinazione::sincronizzaVarianti($articolo); + if (!empty(post('qta'))) { $data_movimento = new Carbon(); $articolo->movimenta(post('qta'), tr('Carico manuale'), $data_movimento->format('Y-m-d'), true); @@ -132,6 +136,9 @@ switch (post('op')) { $articolo->save(); + // Aggiornamento delle varianti per i campi comuni + Combinazione::sincronizzaVarianti($articolo); + // Leggo la quantità attuale per capire se l'ho modificata $old_qta = $record['qta']; $movimento = $qta - $old_qta; diff --git a/modules/articoli/buttons.php b/modules/articoli/buttons.php index e3fb67160..85ef38b52 100755 --- a/modules/articoli/buttons.php +++ b/modules/articoli/buttons.php @@ -19,6 +19,14 @@ include_once __DIR__.'/../../core.php'; +// Messaggio informativo per variante +if ($articolo->isVariante()) { + echo ' +
'.tr('Variante: _NAME_', [ + '_NAME_' => $articolo->nome_variante, +]).'
'; +} + echo ' + + +'; diff --git a/modules/attributi_combinazioni/edit.php b/modules/attributi_combinazioni/edit.php new file mode 100644 index 000000000..83f0970ed --- /dev/null +++ b/modules/attributi_combinazioni/edit.php @@ -0,0 +1,105 @@ + + + + +
+
+

'.tr('Dati').'

+
+ +
+
+
+ {[ "type": "span", "label": "'.tr('Nome').'", "name": "nome", "value": "'.$attributo->nome.'", "help": "'.tr("Nome univoco dell'attributo").'" ]} +
+ +
+ {[ "type": "text", "label": "'.tr('Titolo').'", "name": "titolo", "value": "'.$attributo->titolo.'", "required": 1, "help": "'.tr("Nome visibile dell'attributo").'" ]} +
+
+
+
+ + +
+
+

'.tr('Valori attributo').'

+
+ +
+ + + + + + + + + + + '; + +$valori = $attributo->valori; +foreach ($valori as $valore) { + echo ' + + + + '; +} + +echo ' + +
'.tr('Valore').'#
'.$valore->nome.' + + + +
+
+
+ + + '.tr('Elimina').' + + +'; diff --git a/modules/attributi_combinazioni/gestione-valore.php b/modules/attributi_combinazioni/gestione-valore.php new file mode 100644 index 000000000..e7d33c73d --- /dev/null +++ b/modules/attributi_combinazioni/gestione-valore.php @@ -0,0 +1,34 @@ +nome; +} + +echo ' +
+ + + + +
+
+ {[ "type": "text", "label": "'.tr('Valore').'", "name": "nome", "value": "'.$testo_valore.'", "required": 1 ]} +
+
+ + +
+
+ +
+
+
'; diff --git a/modules/attributi_combinazioni/init.php b/modules/attributi_combinazioni/init.php new file mode 100644 index 000000000..e93d7b607 --- /dev/null +++ b/modules/attributi_combinazioni/init.php @@ -0,0 +1,11 @@ +toArray(); +} diff --git a/modules/attributi_combinazioni/src/Attributo.php b/modules/attributi_combinazioni/src/Attributo.php new file mode 100644 index 000000000..53618083f --- /dev/null +++ b/modules/attributi_combinazioni/src/Attributo.php @@ -0,0 +1,21 @@ +hasMany(ValoreAttributo::class, 'id_attributo'); + } +} diff --git a/modules/attributi_combinazioni/src/ValoreAttributo.php b/modules/attributi_combinazioni/src/ValoreAttributo.php new file mode 100644 index 000000000..005680273 --- /dev/null +++ b/modules/attributi_combinazioni/src/ValoreAttributo.php @@ -0,0 +1,33 @@ +attributo()->associate($attributo); + $model->nome = $valore; + + $model->save(); + + return $model; + } + + /* Relazioni Eloquent */ + public function attributo() + { + return $this->belongsTo(Attributo::class, 'id_attributo'); + } +} diff --git a/modules/combinazioni_articoli/actions.php b/modules/combinazioni_articoli/actions.php new file mode 100644 index 000000000..c69bf1e36 --- /dev/null +++ b/modules/combinazioni_articoli/actions.php @@ -0,0 +1,61 @@ +where('id', '!=', $combinazione->id); + } + $esistente = $esistente->count() !== 0; + + if (!$esistente) { + $combinazione = $combinazione ?: Combinazione::build(); + $combinazione->nome = $nome; + $combinazione->codice = post('codice'); + $combinazione->id_categoria = post('id_categoria'); + $combinazione->id_sottocategoria = post('id_sottocategoria'); + $combinazione->save(); + + $id_record = $combinazione->id; + + // Selezione attributi per la combinazione + if ($combinazione->articoli()->count() == 0) { + $combinazione->attributi()->sync((array) post('attributi')); + } + + flash()->info(tr('Combinazione aggiornata correttamente!')); + } else { + flash()->error(tr('Combinazione esistente con lo stesso nome!')); + } + + break; + + case 'delete': + $combinazione->delete(); + + flash()->info(tr('Combinazione rimossa correttamente!')); + + break; + + case 'gestione-variante': + $combinazione->generaVariante((array) filter('attributo')); + + flash()->info(tr('Variante aggiunta correttamente!')); + + break; + + case 'genera-varianti': + $combinazione->generaTutto(); + + flash()->info(tr('Varianti generate correttamente!')); + + break; +} diff --git a/modules/combinazioni_articoli/add.php b/modules/combinazioni_articoli/add.php new file mode 100644 index 000000000..acc97ebd1 --- /dev/null +++ b/modules/combinazioni_articoli/add.php @@ -0,0 +1,45 @@ + + + + +
+
+ {[ "type": "text", "label": "'.tr('Codice').'", "name": "codice", "required": 1, "help": "'.tr('Codice di base per la combinazione: alla generazione variante vengono aggiunti i valore degli Attributi relativi').'" ]} +
+ +
+ {[ "type": "text", "label": "'.tr('Nome').'", "name": "nome", "required": 1, "help": "'.tr('Nome univoco della combinazione').'" ]} +
+
+ +
+
+ '.Modules::link('Categorie articoli', $record['id_categoria'], null, null, 'class="pull-right"').' + {[ "type": "select", "label": "'.tr('Categoria').'", "name": "id_categoria", "required": 0, "value": "$id_categoria$", "ajax-source": "categorie", "icon-after": "add|'.Modules::get('Categorie articoli')['id'].'" ]} +
+ +
+ {[ "type": "select", "label": "'.tr('Sottocategoria').'", "name": "id_sottocategoria", "value": "$id_sottocategoria$", "ajax-source": "sottocategorie", "select-options": '.json_encode(['id_categoria' => $record['id_categoria']]).' ]} +
+
+ +
+
+ {[ "type": "select", "label": "'.tr('Attributi').'", "name": "attributi[]", "values": "query=SELECT id, nome AS descrizione FROM mg_attributi WHERE deleted_at IS NULL", "required": 1, "multiple": 1, "help": "'.tr('Attributi abilitati per la combinazione corrente').'" ]} +
+
+ + +
+
+ +
+
+'; diff --git a/modules/combinazioni_articoli/edit.php b/modules/combinazioni_articoli/edit.php new file mode 100644 index 000000000..6ba036485 --- /dev/null +++ b/modules/combinazioni_articoli/edit.php @@ -0,0 +1,110 @@ +articoli()->count(); + +echo ' +
+ + + +
+
+

'.tr('Dati').'

+
+ +
+
+
+ {[ "type": "text", "label": "'.tr('Codice').'", "name": "codice", "value": "'.$combinazione->codice.'", "required": 1, "help": "'.tr('Codice di base per la combinazione: alla generazione variante vengono aggiunti i valore degli Attributi relativi').'" ]} +
+ +
+ {[ "type": "text", "label": "'.tr('Nome').'", "name": "nome", "value": "'.$combinazione->nome.'", "required": 1, "help": "'.tr('Nome univoco della combinazione').'" ]} +
+
+ +
+
+ '.Modules::link('Categorie articoli', $record['id_categoria'], null, null, 'class="pull-right"').' + {[ "type": "select", "label": "'.tr('Categoria').'", "name": "id_categoria", "required": 0, "value": "$id_categoria$", "ajax-source": "categorie", "icon-after": "add|'.Modules::get('Categorie articoli')['id'].'" ]} +
+ +
+ {[ "type": "select", "label": "'.tr('Sottocategoria').'", "name": "id_sottocategoria", "value": "$id_sottocategoria$", "ajax-source": "sottocategorie", "select-options": '.json_encode(['id_categoria' => $record['id_categoria']]).' ]} +
+
+ +
+
+ {[ "type": "select", "label": "'.tr('Attributi').'", "name": "attributi[]", "value": "'.implode(',', $combinazione->attributi->pluck('id')->all()).'", "values": "query=SELECT id, nome AS descrizione FROM mg_attributi WHERE deleted_at IS NULL", "required": 1, "multiple": 1, "help": "'.tr('Attributi abilitati per la combinazione corrente').'", "disabled": "'.($numero_varianti !== 0).'" ]} +
+
+
+
+
+ +
+
+

'.tr('Varianti disponibili (Articoli)').'

+
+ +
+ + +
+ +
+ + + + + + + + + + + '; + +$articoli = $combinazione->articoli; +foreach ($articoli as $articolo) { + echo ' + + + + + '; +} + +echo ' + +
'.tr('Foto').''.tr('Variante').''.tr('Articolo').'
'.$articolo->nome_variante.''.Modules::link('Articoli', $articolo->id, $articolo->codice.' - '.$articolo->descrizione).'
+
+
+ + + '.tr('Elimina').' + + +'; diff --git a/modules/combinazioni_articoli/gestione-variante.php b/modules/combinazioni_articoli/gestione-variante.php new file mode 100644 index 000000000..14c8324cd --- /dev/null +++ b/modules/combinazioni_articoli/gestione-variante.php @@ -0,0 +1,93 @@ +fetchArray('SELECT GROUP_CONCAT(`variazioni`.`id_valore`) AS variante +FROM (SELECT `mg_articolo_attributo`.`id_valore`, `mg_articolo_attributo`.`id_articolo` + FROM `mg_articolo_attributo` + INNER JOIN `mg_valori_attributi` ON `mg_valori_attributi`.`id` = `mg_articolo_attributo`.`id_valore` + INNER JOIN `mg_attributi` ON `mg_attributi`.`id` = `mg_valori_attributi`.`id_attributo` + + INNER JOIN `mg_articoli` ON `mg_articoli`.`id` = `mg_articolo_attributo`.`id_articolo` + INNER JOIN `mg_combinazioni` ON `mg_combinazioni`.`id` = `mg_articoli`.`id_combinazione` + INNER JOIN `mg_attributo_combinazione` ON `mg_attributo_combinazione`.`id_combinazione` = `mg_combinazioni`.`id` AND `mg_attributo_combinazione`.`id_attributo` = `mg_attributi`.`id` + WHERE `mg_articoli`.`deleted_at` IS NULL AND `mg_articoli`.`id_combinazione` = '.prepare($combinazione->id).' + ORDER BY `mg_attributo_combinazione`.`order` + ) AS variazioni +GROUP BY `variazioni`.`id_articolo`'); +$varianti_esistenti = array_column($varianti_esistenti, 'variante'); + +echo ' +
+ + + +

'.tr('Completa le informazioni dei diversi Attributi per generare una variante della Combinazione').'.

+ +
'; + +$attributi = $combinazione->attributi; +foreach ($attributi as $key => $attributo) { + echo ' +
+ {[ "type": "select", "label": "'.$attributo->nome.'", "name": "attributo['.$key.']", "values": "query=SELECT id, nome AS descrizione FROM mg_valori_attributi WHERE id_attributo = '.prepare($attributo->id).' AND deleted_at IS NULL", "required": 1 ]} +
'; +} + +echo ' +
+ + + + +
+
+ +
+
+
+ +'; diff --git a/modules/combinazioni_articoli/init.php b/modules/combinazioni_articoli/init.php new file mode 100644 index 000000000..e37110ace --- /dev/null +++ b/modules/combinazioni_articoli/init.php @@ -0,0 +1,11 @@ +find($id_record); + + $record = $combinazione->toArray(); +} diff --git a/modules/combinazioni_articoli/modutil.php b/modules/combinazioni_articoli/modutil.php new file mode 100644 index 000000000..cb060ff91 --- /dev/null +++ b/modules/combinazioni_articoli/modutil.php @@ -0,0 +1,28 @@ + $values) { + $append = []; + + foreach ($result as $product) { + foreach ($values as $item) { + $product[$key] = $item; + $append[] = $product; + } + } + + $result = $append; + } + + return $result; +} diff --git a/modules/combinazioni_articoli/src/Combinazione.php b/modules/combinazioni_articoli/src/Combinazione.php new file mode 100644 index 000000000..3624610ba --- /dev/null +++ b/modules/combinazioni_articoli/src/Combinazione.php @@ -0,0 +1,179 @@ +articoli; + foreach ($articoli as $articolo) { + $articolo->delete(); + } + + return parent::delete(); + } + + public function save(array $options = []) + { + $result = parent::save($options); + + // Sincronizzazione dei campi condivisi con la Combinazione + $sincro = collect($this->toArray())->filter(function ($value, $key) { + return in_array($key, self::$campi_combinazione); + }); + $this->sincronizzaCampi($sincro->toArray()); + + return $result; + } + + public function getModuleAttribute() + { + return 'Combinazioni'; + } + + /** + * Metodo per generare dinamicamente una variante dell'articolo per la combinazione corrente. + * + * @param $valori_attributi + */ + public function generaVariante($valori_attributi) + { + $database = database(); + + // Generazione nome variante + $variante = ValoreAttributo::findMany($valori_attributi)->pluck('nome')->all(); + + // Generazione Articolo di base + $articoli = $this->articoli; + if ($articoli->isEmpty()) { + $articolo = Articolo::build($this->nome, $this->nome); + $articolo->id_combinazione = $this->id; + } else { + $articolo = $articoli->first()->replicate(); + } + $articolo->descrizione = $this->nome.' ['.implode(', ', $variante).']'; + $articolo->codice = $this->codice.'-'.implode('|', $variante); + $articolo->save(); + + // Associazione valori della variante + foreach ($valori_attributi as $id => $id_valore) { + $database->insert('mg_articolo_attributo', [ + 'id_articolo' => $articolo->id, + 'id_valore' => $id_valore, + ]); + } + } + + /** + * Metodo per la generazione di tutte le varianti disponibili per la combinazione corrente. + */ + public function generaTutto() + { + if ($this->articoli()->count() !== 0) { + return; + } + + // Individuazione valori disponibili per gli attributi + $valori = []; + $attributi = $this->attributi; + foreach ($attributi as $attributo) { + $valori[] = $attributo->valori->pluck('id')->all(); + } + + // Generazione di tutte le combinazioni + $varianti = cartesian($valori); + + // Generazione delle singole varianti + foreach ($varianti as $variante) { + $this->generaVariante($variante); + } + } + + /** + * Funzione dedicata a mantenere sincronizzati i campi condivisi delle varianti di uno specifico articolo. + */ + public static function sincronizzaVarianti(Articolo $articolo) + { + $combinazione = $articolo->combinazione; + if (empty($combinazione)) { + return; + } + + $sincro = collect($articolo->toArray())->filter(function ($value, $key) { + return in_array($key, self::$campi_varianti); + }); + + $combinazione->sincronizzaCampi($sincro->toArray()); + } + + /* Relazioni Eloquent */ + + public function attributi() + { + return $this->belongsToMany(Attributo::class, 'mg_attributo_combinazione', 'id_combinazione', 'id_attributo') + ->orderBy('order', 'ASC'); + } + + public function articoli() + { + return $this->hasMany(Articolo::class, 'id_combinazione'); + } + + /** + * Funzione per sincronizzare i campi condivisi dagli Articoli di tipo Variante. + * + * @param $values + */ + protected function sincronizzaCampi($values) + { + $articoli = $this->articoli->pluck('id')->all(); + + database()->table('mg_articoli') + ->whereIn('id', $articoli) + ->update($values); + + database()->table('mg_combinazioni') + ->where('id', $this->id) + ->update($values); + } +} diff --git a/plugins/varianti_articolo/edit.php b/plugins/varianti_articolo/edit.php new file mode 100644 index 000000000..68c06d5aa --- /dev/null +++ b/plugins/varianti_articolo/edit.php @@ -0,0 +1,73 @@ +combinazione; + +if (empty($combinazione)) { + echo ' +'; + + return; +} + +echo ' + + +
+
+ +
+
+

'.tr('Varianti disponibili (Articoli)').'

+
+ +
+ + + + + + + + + + '; + +$articoli = $combinazione->articoli; +foreach ($articoli as $articolo) { + echo ' + + + + + '; +} + +echo ' + +
'.tr('Foto').''.tr('Variante').''.tr('Articolo').'
'.$articolo->nome_variante.' + '.Modules::link('Articoli', $articolo->id, $articolo->codice.' - '.$articolo->descrizione).' + '.($articolo->id == $articolo_originale->id ? ''.tr('Articolo corrente').'' : '').' +
+
+
+ +'; diff --git a/update/2_4_25.sql b/update/2_4_25.sql index db8214850..4eaa5dbc7 100644 --- a/update/2_4_25.sql +++ b/update/2_4_25.sql @@ -66,3 +66,76 @@ INSERT INTO `zz_views` (`id`, `id_module`, `name`, `query`, `order`, `search`, ` -- Miglioramento supporto autenticazione OAuth 2 ALTER TABLE `em_accounts` ADD `oauth2_config` TEXT; + +-- Aggiunto sistema di gestione Combinazioni Articoli +CREATE TABLE IF NOT EXISTS `mg_attributi` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `nome` varchar(255) NOT NULL, + `titolo` varchar(255) NOT NULL, + `ordine` int(11) NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY(`id`) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `mg_valori_attributi` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `id_attributo` int(11) NOT NULL, + `nome` varchar(255) NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY(`id`), + FOREIGN KEY (`id_attributo`) REFERENCES `mg_attributi`(`id`) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `mg_combinazioni` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `codice` varchar(255) NOT NULL, + `nome` varchar(255) NOT NULL, + `id_categoria` int(11), + `id_sottocategoria` int(11), + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY(`id`), + FOREIGN KEY (`id_categoria`) REFERENCES `mg_categorie`(`id`) ON DELETE SET NULL, + FOREIGN KEY (`id_sottocategoria`) REFERENCES `mg_categorie`(`id`) ON DELETE SET NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `mg_attributo_combinazione` ( + `id_combinazione` int(11) NOT NULL, + `id_attributo` int(11) NOT NULL, + `order` int(11) NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY(`id_attributo`, `id_combinazione`), + FOREIGN KEY (`id_attributo`) REFERENCES `mg_attributi`(`id`), + FOREIGN KEY (`id_combinazione`) REFERENCES `mg_combinazioni`(`id`) +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `mg_articolo_attributo` ( + `id_articolo` int(11) NOT NULL, + `id_valore` int(11) NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (`id_articolo`) REFERENCES `mg_articoli`(`id`), + FOREIGN KEY (`id_valore`) REFERENCES `mg_valori_attributi`(`id`) +) ENGINE=InnoDB; + +ALTER TABLE mg_articoli ADD `id_combinazione` int(11), ADD FOREIGN KEY (`id_combinazione`) REFERENCES `mg_combinazioni`(`id`); + +INSERT INTO `zz_modules` (`id`, `name`, `title`, `directory`, `options`, `options2`, `icon`, `version`, `compatibility`, `order`, `parent`, `default`, `enabled`) VALUES + (NULL, 'Attributi Combinazioni', 'Attributi Combinazioni', 'attributi_combinazioni', 'SELECT |select| FROM mg_attributi WHERE mg_attributi.deleted_at IS NULL AND 1=1 HAVING 2=2', NULL, 'fa fa-angle-right', '1.0', '2.*', '100', '20', '1', '1'), + (NULL, 'Combinazioni', 'Combinazioni', 'combinazioni_articoli', 'SELECT |select| FROM mg_combinazioni WHERE mg_combinazioni.deleted_at IS NULL AND 1=1 HAVING 2=2', NULL, 'fa fa-angle-right', '1.0', '2.*', '100', '20', '1', '1'); + +INSERT INTO `zz_plugins` (`id`, `name`, `title`, `idmodule_from`, `idmodule_to`, `position`, `directory`, `options`) VALUES +(NULL, 'Varianti Articolo', 'Varianti Articolo', (SELECT `id` FROM `zz_modules` WHERE `name`='Articoli'), (SELECT `id` FROM `zz_modules` WHERE `name`='Articoli'), 'tab', 'varianti_articolo', 'custom'); + +-- Aggiunta colonne per il nuovo modulo Attributi Combinazioni +INSERT INTO `zz_views` (`id`, `id_module`, `name`, `query`, `order`, `visible`, `format`, `default`) VALUES + (NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Attributi Combinazioni'), 'id', 'mg_attributi.id', 1, 0, 0, 1), + (NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Attributi Combinazioni'), 'Nome', 'mg_attributi.nome', 2, 1, 0, 1), + (NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Combinazioni'), 'id', 'mg_combinazioni.id', 1, 0, 0, 1), + (NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Combinazioni'), 'Nome', 'mg_combinazioni.nome', 2, 1, 0, 1);