diff --git a/ajax_dataload.php b/ajax_dataload.php index b53ae590f..e85d193f3 100644 --- a/ajax_dataload.php +++ b/ajax_dataload.php @@ -2,6 +2,8 @@ include_once __DIR__.'/core.php'; +use Util\Query; + // Informazioni fondamentali $columns = filter('columns'); $order = filter('order')[0]; @@ -32,27 +34,23 @@ $results = [ 'summable' => [], ]; -$query = Util\Query::getQuery($structure); +$query = Query::getQuery($structure); if (!empty($query)) { // CONTEGGIO TOTALE $results['recordsTotal'] = $dbo->fetchNum($query); // RISULTATI VISIBILI - $query = Util\Query::getQuery($structure, $search, $order, $limit); + $query = Query::getQuery($structure, $search, $order, $limit); // Filtri derivanti dai permessi (eventuali) if (empty($id_plugin)) { $query = Modules::replaceAdditionals($id_module, $query); } - $query = str_replace_once('SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $query); - $rows = $dbo->fetchArray($query); - // Conteggio dei record filtrati - $count = $dbo->fetchArray('SELECT FOUND_ROWS()'); - if (!empty($count)) { - $results['recordsFiltered'] = $count[0]['FOUND_ROWS()']; - } + $data = Query::executeAndCount($query); + $rows = $data['results']; + $results['recordsFiltered'] = $data['count']; // SOMME $results['summable'] = Util\Query::getSums($structure, $search); diff --git a/ajax_select.php b/ajax_select.php index 6ef1bf4f5..473f522a4 100644 --- a/ajax_select.php +++ b/ajax_select.php @@ -4,14 +4,16 @@ include_once __DIR__.'/core.php'; if (!isset($resource)) { $op = empty($op) ? filter('op') : $op; - $search = filter('q'); + $search = filter('search'); + $page = filter('page') ?: 0; + $length = filter('length') ?: 100; if (!isset($elements)) { $elements = []; } $elements = (!is_array($elements)) ? explode(',', $elements) : $elements; - $results = AJAX::select($op, $elements, $search); + $results = AJAX::select($op, $elements, $search, $page, $length); echo json_encode($results); } diff --git a/lib/functions.js b/lib/functions.js index bbcc2c911..80f34ad78 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -972,13 +972,23 @@ function start_superselect() { delay: 250, data: function (params) { return { - q: params.term // search term + search: params.term, + page: params.page || 0, + length: params.length || 100, } }, - processResults: function (data) { - return { - results: data - } + processResults: function (data, params) { + params.page = params.page || 0; + params.length = params.length || 100; + + var response = { + results: data.results, + pagination: { + more: (params.page + 1) * params.length < data.recordsFiltered, + } + }; + + return response; }, cache: false }, diff --git a/lib/helpers.php b/lib/helpers.php index d4569f87e..00579de71 100644 --- a/lib/helpers.php +++ b/lib/helpers.php @@ -175,3 +175,60 @@ function logger() { return Monolog\Registry::getInstance('logs'); } + +/** + * Restituisce il numero indicato formattato secondo la configurazione del sistema. + * + * @param float $number + * @param int $decimals + * + * @return string + * + * @since 2.4.8 + */ +function numberFormat($number, $decimals) +{ + return Translator::numberToLocale($number, $decimals); +} + +/** + * Restituisce il timestamp indicato formattato secondo la configurazione del sistema. + * + * @param string $timestamp ++ * + * @return string + * + * @since 2.4.8 + */ +function timestampFormat($timestamp) +{ + return Translator::timestampToLocale($timestamp); +} + +/** + * Restituisce la data indicata formattato secondo la configurazione del sistema. + * + * @param string $date + * + * @return string + * + * @since 2.4.8 + */ +function dateFormat($date) +{ + return Translator::dateToLocale($date); +} + +/** + * Restituisce l'orario indicato formattato secondo la configurazione del sistema. + * + * @param string $time + * + * @return string + * + * @since 2.4.8 + */ +function timeFormat($time) +{ + return Translator::timeToLocale($time); +} diff --git a/lib/util.php b/lib/util.php index 49055a533..74a355441 100644 --- a/lib/util.php +++ b/lib/util.php @@ -77,30 +77,6 @@ if (!function_exists('ends_with')) { } } -if (!function_exists('str_replace_once')) { - /** - * Sostituisce la prima occorenza di una determinata stringa. - * - * @param string $str_pattern - * @param string $str_replacement - * @param string $string - * - * @since 2.3 - * - * @return string - */ - function str_replace_once($str_pattern, $str_replacement, $string) - { - if (strpos($string, $str_pattern) !== false) { - $occurrence = strpos($string, $str_pattern); - - return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern)); - } - - return $string; - } -} - if (!function_exists('str_contains')) { /** * Check if a string contains the given string. diff --git a/modules/anagrafiche/ajax/select.php b/modules/anagrafiche/ajax/select.php index d2b85fd24..a37bee004 100644 --- a/modules/anagrafiche/ajax/select.php +++ b/modules/anagrafiche/ajax/select.php @@ -87,7 +87,7 @@ switch ($resource) { $search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%'); } - $results = AJAX::completeResults($query, $where, $filter, $search, $custom); + $results = AJAX::selectResults($query, $where, $filter, $search, $limit, $custom); // Evidenzia l'agente di default if ($superselect['idanagrafica']) { diff --git a/modules/articoli/ajax/select.php b/modules/articoli/ajax/select.php index adbae2920..e70fa2e9f 100644 --- a/modules/articoli/ajax/select.php +++ b/modules/articoli/ajax/select.php @@ -4,7 +4,62 @@ include_once __DIR__.'/../../../core.php'; switch ($resource) { case 'articoli': - $query = 'SELECT mg_articoli.*, (SELECT CONCAT(co_pianodeiconti2.numero, ".", co_pianodeiconti3.numero, " ", co_pianodeiconti3.descrizione) FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = idconto_vendita) AS idconto_vendita_title, (SELECT CONCAT(co_pianodeiconti2.numero, ".", co_pianodeiconti3.numero, " ", co_pianodeiconti3.descrizione) FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = idconto_acquisto) AS idconto_acquisto_title, co_iva.descrizione AS iva_vendita FROM mg_articoli LEFT OUTER JOIN co_iva ON mg_articoli.idiva_vendita=co_iva.id |where| ORDER BY mg_articoli.id_categoria ASC, mg_articoli.id_sottocategoria ASC'; + $query = 'SELECT + mg_articoli.id, + mg_articoli.codice, + mg_articoli.descrizione, + mg_articoli.um, + mg_articoli.idiva_vendita, + mg_articoli.idconto_vendita, + mg_articoli.idconto_acquisto, + mg_articoli.prezzo_vendita, + mg_articoli.prezzo_acquisto, + categoria.`nome` AS categoria, + sottocategoria.`nome` AS sottocategoria, + co_iva.descrizione AS iva_vendita, + CONCAT(conto_vendita_categoria .numero, ".", conto_vendita_sottocategoria.numero, " ", conto_vendita_sottocategoria.descrizione) AS idconto_vendita_title, + CONCAT(conto_acquisto_categoria .numero, ".", conto_acquisto_sottocategoria.numero, " ", conto_acquisto_sottocategoria.descrizione) AS idconto_acquisto_title + FROM mg_articoli + LEFT JOIN co_iva ON mg_articoli.idiva_vendita = co_iva.id + LEFT JOIN `mg_categorie` AS categoria ON `categoria`.`id` = `mg_articoli`.`id_categoria` + LEFT JOIN `mg_categorie` AS sottocategoria ON `sottocategoria`.`id` = `mg_articoli`.`id_sottocategoria` + LEFT JOIN co_pianodeiconti3 AS conto_vendita_sottocategoria ON conto_vendita_sottocategoria.id=mg_articoli.idconto_vendita + LEFT JOIN co_pianodeiconti2 AS conto_vendita_categoria ON conto_vendita_sottocategoria.idpianodeiconti2=conto_vendita_categoria.id + LEFT JOIN co_pianodeiconti3 AS conto_acquisto_sottocategoria ON conto_acquisto_sottocategoria.id=mg_articoli.idconto_acquisto + LEFT JOIN co_pianodeiconti2 AS conto_acquisto_categoria ON conto_acquisto_sottocategoria.idpianodeiconti2=conto_acquisto_categoria.id + |where| ORDER BY mg_articoli.id_categoria ASC, mg_articoli.id_sottocategoria ASC'; + + foreach ($elements as $element) { + $filter[] = 'mg_articoli.id='.prepare($element); + } + + $where[] = 'attivo = 1'; + if (!empty($superselect['dir']) && $superselect['dir'] == 'entrata') { + //$where[] = '(qta > 0 OR servizio = 1)'; + } + + if (!empty($search)) { + $search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%'); + $search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%'); + } + + $custom = [ + 'id' => 'id', + 'codice' => 'codice', + 'descrizione' => 'descrizione', + 'um' => 'um', + 'idiva_vendita' => 'idiva_vendita', + 'iva_vendita' => 'iva_vendita', + 'idconto_vendita' => 'idconto_vendita', + 'idconto_vendita_title' => 'idconto_vendita_title', + 'idconto_acquisto' => 'idconto_acquisto', + 'idconto_acquisto_title' => 'idconto_acquisto_title', + 'prezzo_acquisto' => 'prezzo_acquisto', + 'prezzo_vendita' => 'prezzo_vendita', + ]; + + $data = AJAX::selectResults($query, $where, $filter, $search_fields, $limit, $custom); + $rs = $data['results']; // Individuazione di eventuali listini if (!empty($superselect['dir']) && !empty($superselect['idanagrafica'])) { @@ -21,45 +76,22 @@ switch ($resource) { $idiva_predefinita = get_var('Iva predefinita'); $iva_predefinita = $dbo->fetchOne('SELECT descrizione FROM co_iva WHERE id='.prepare($idiva_predefinita))['descrizione']; - foreach ($elements as $element) { - $filter[] = 'mg_articoli.id='.prepare($element); - } - - $where[] = 'attivo = 1'; - if (!empty($superselect['dir']) && $superselect['dir'] == 'entrata') { - //$where[] = '(qta > 0 OR servizio = 1)'; - } - - if (!empty($search)) { - $search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%'); - $search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%'); - } - - if (!empty($search_fields)) { - $where[] = '('.implode(' OR ', $search_fields).')'; - } - - if (!empty($filter)) { - $where[] = '('.implode(' OR ', $filter).')'; - } - - $wh = ''; - if (count($where) != 0) { - $wh = 'WHERE '.implode(' AND ', $where); - } - $query = str_replace('|where|', $wh, $query); - - $prev = -1; - $rs = $dbo->fetchArray($query); + $previous_category = -1; + $previous_subcategory = -1; foreach ($rs as $r) { - if ($prev != $r['id_sottocategoria']) { - $categoria = $dbo->fetchOne('SELECT `nome` FROM `mg_categorie` WHERE `id`='.prepare($r['id_categoria']))['nome']; + if ($previous_category != $r['categoria'] || $previous_subcategory != $r['sottocategoria']) { + $previous_category = $r['categoria']; + $previous_subcategory = $r['sottocategoria']; - $sottocategoria = $dbo->fetchOne('SELECT `nome` FROM `mg_categorie` WHERE `id`='.prepare($r['id_sottocategoria'])); - $sottocategoria = isset($sottocategoria['nome']) ? $sottocategoria['nome'] : null; + $text = ''.tr('Nessuna categoria').''; + if (!empty($r['categoria'])) { + $text = $r['categoria'].' ('.(!empty($r['sottocategoria']) ? $r['sottocategoria'] : '-').')'; + } - $prev = $r['id_sottocategoria']; - $results[] = ['text' => $categoria.' ('.(!empty($r['id_sottocategoria']) ? $sottocategoria : '-').')', 'children' => []]; + $results[] = [ + 'text' => $text, + 'children' => [], + ]; } // Iva dell'articolo @@ -101,6 +133,11 @@ switch ($resource) { ]; } + $results = [ + 'results' => $results, + 'recordsFiltered' => $data['recordsFiltered'], + ]; + break; case 'prodotti_lotti': diff --git a/modules/gestione_componenti/ajax/select.php b/modules/gestione_componenti/ajax/select.php index 0a1833c20..483805bd8 100644 --- a/modules/gestione_componenti/ajax/select.php +++ b/modules/gestione_componenti/ajax/select.php @@ -24,7 +24,7 @@ switch ($resource) { $custom['contenuto'] = 'contenuto'; - $results = AJAX::completeResults($query, $where, $filter, $search, $custom); + $results = AJAX::selectResults($query, $where, $filter, $search, $limit, $custom); foreach ($results as $key => $value) { $matricola = \Util\Ini::getValue($r['contenuto'], 'Matricola'); diff --git a/src/AJAX.php b/src/AJAX.php index 4e0aee995..7a0684da5 100644 --- a/src/AJAX.php +++ b/src/AJAX.php @@ -23,10 +23,12 @@ class AJAX * @param string $resource * @param array $elements * @param mixed $search + * @param int $page + * @param int $length * * @return array */ - public static function select($resource, $elements = [], $search = null) + public static function select($resource, $elements = [], $search = null, $page = 0, $length = 100) { if (!isset($elements)) { $elements = []; @@ -39,13 +41,23 @@ class AJAX array_unshift($files, DOCROOT.'/ajax_select.php'); foreach ($files as $file) { - $results = self::getSelectResults($file, $resource, $elements, $search); + $results = self::getSelectResults($file, $resource, $elements, [ + 'offset' => $page * $length, + 'length' => $length, + ], $search); + if (isset($results)) { break; } } - return $results; + $total = $results['recordsFiltered'] ?: count($results); + $list = $results['results'] ? $results['results'] : $results; + + return [ + 'results' => $list, + 'recordsFiltered' => $total, + ]; } /** @@ -55,11 +67,12 @@ class AJAX * @param array $where * @param array $filter * @param array $search + * @param array $limit * @param array $custom * * @return array */ - public static function completeResults($query, $where, $filter = [], $search = [], $custom = []) + public static function selectResults($query, $where, $filter = [], $search = [], $limit = [], $custom = []) { if (str_contains($query, '|filter|')) { $query = str_replace('|filter|', !empty($filter) ? 'WHERE '.implode(' OR ', $filter) : '', $query); @@ -72,21 +85,25 @@ class AJAX } $query = str_replace('|where|', !empty($where) ? 'WHERE '.implode(' AND ', $where) : '', $query); + $query .= ' LIMIT '.$limit['offset'].', '.$limit['length']; - $database = database(); - $rs = $database->fetchArray($query); + $data = \Util\Query::executeAndCount($query); + $rows = $data['results']; $results = []; - foreach ($rs as $r) { + foreach ($rows as $row) { $result = []; foreach ($custom as $key => $value) { - $result[$key] = $r[$value]; + $result[$key] = $row[$value]; } $results[] = $result; } - return $results; + return [ + 'results' => $results, + 'recordsFiltered' => $data['count'], + ]; } /** @@ -196,11 +213,12 @@ class AJAX * @param string $file * @param string $resource * @param array $elements + * @param array $limit * @param mixed $search * * @return array|null */ - protected static function getSelectResults($file, $resource, $elements = [], $search = null) + protected static function getSelectResults($file, $resource, $elements = [], $limit = [], $search = null) { $superselect = self::getSelectInfo(); @@ -219,7 +237,7 @@ class AJAX require $file; if (!isset($results) && !empty($query)) { - $results = self::completeResults($query, $where, $filter, $search_fields, $custom); + $results = self::selectResults($query, $where, $filter, $search_fields, $limit, $custom); } return isset($results) ? $results : null; diff --git a/src/HTMLBuilder/Handler/SelectHandler.php b/src/HTMLBuilder/Handler/SelectHandler.php index feafa081b..66aba5d09 100644 --- a/src/HTMLBuilder/Handler/SelectHandler.php +++ b/src/HTMLBuilder/Handler/SelectHandler.php @@ -98,8 +98,8 @@ class SelectHandler implements HandlerInterface * Gestione dell'input di tipo "select" con richieste AJAX (nome della richiesta indicato tramite attributo "ajax-source"). * Esempio: {[ "type": "select", "label": "Select di test", "name": "test", "ajax-source": "test" ]}. * - * @param array $values - * @param array $extras + * @param string $op + * @param array $elements * * @return string */ @@ -111,10 +111,11 @@ class SelectHandler implements HandlerInterface include DOCROOT.'/ajax_select.php'; $text = ob_get_clean(); - $result = ''; + $html = ''; - $array = (array) json_decode($text, true); - foreach ($array as $element) { + $response = (array) json_decode($text, true); + $results = $response['results']; + foreach ($results as $element) { $element = (array) $element; if (isset($element['children'][0])) { $element = (array) $element['children'][0]; @@ -137,11 +138,11 @@ class SelectHandler implements HandlerInterface } } - $result .= ' + $html .= ' '; } - return $result; + return $html; } /** diff --git a/src/Util/Query.php b/src/Util/Query.php index 8d91148aa..d0d0be8b3 100644 --- a/src/Util/Query.php +++ b/src/Util/Query.php @@ -181,6 +181,23 @@ class Query return $query; } + public static function executeAndCount($query) + { + $database = database(); + + // Esecuzione della query + $query = self::str_replace_once('SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $query); + $results = $database->fetchArray($query); + + // Conteggio dei record filtrati + $count = $database->fetchOne('SELECT FOUND_ROWS() AS count'); + + return [ + 'results' => $results, + 'count' => $count['count'], + ]; + } + /** * Restituisce le somme richieste dalla query prevista dalla struttura. * @@ -202,7 +219,7 @@ class Query $result_query = self::getQuery($structure, $search); - $query = str_replace_once('SELECT', 'SELECT '.implode(', ', $total['summable']).' FROM(SELECT ', $result_query).') AS `z`'; + $query = self::str_replace_once('SELECT', 'SELECT '.implode(', ', $total['summable']).' FROM(SELECT ', $result_query).') AS `z`'; $sums = database()->fetchOne($query); $results = []; @@ -217,6 +234,28 @@ class Query return $results; } + /** + * Sostituisce la prima occorenza di una determinata stringa. + * + * @param string $str_pattern + * @param string $str_replacement + * @param string $string + * + * @since 2.3 + * + * @return string + */ + protected static function str_replace_once($str_pattern, $str_replacement, $string) + { + if (strpos($string, $str_pattern) !== false) { + $occurrence = strpos($string, $str_pattern); + + return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern)); + } + + return $string; + } + /** * Interpreta lo standard modulare per l'individuazione delle query di un modulo/plugin del progetto. *