Skip to content

Commit 411e9d5

Browse files
committed
fix: ricerca articoli nei documenti
1 parent d6bb6db commit 411e9d5

8 files changed

Lines changed: 463 additions & 16 deletions

File tree

assets/src/css/style.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ input[type=file] {
295295
align-items: flex-start;
296296
color: var(--text-light) !important;
297297
transition: all 0.2s ease;
298+
min-height: auto;
299+
white-space: normal;
298300
}
299301

300302
.search-result-item:hover {
@@ -313,7 +315,9 @@ input[type=file] {
313315

314316
.search-result-text {
315317
flex: 1;
316-
overflow: hidden;
318+
overflow: visible;
319+
word-wrap: break-word;
320+
white-space: normal;
317321
}
318322

319323
.search-result-text > div {
@@ -327,6 +331,9 @@ input[type=file] {
327331
color: rgba(255, 255, 255, 0.6);
328332
display: block;
329333
word-wrap: break-word;
334+
white-space: normal;
335+
line-height: 1.3;
336+
overflow-wrap: break-word;
330337
}
331338

332339
#clear-search {

assets/src/js/base/supersearch.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ $(document).ready(function () {
260260

261261
results.forEach(result => {
262262
const title = result.title;
263-
const labels = result.labels ? result.labels.join('').split('<br/>,').join(' • ') : '';
263+
// Preserva i <br/> per permettere il wrapping del testo
264+
const labels = result.labels ? result.labels.join('') : '';
264265

265266
// Preserva l'evidenziazione esistente e applica quella per search-highlight
266267
let processedLabels = labels;

modules/contratti/ajax/search.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
/*
3+
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
4+
* Copyright (C) DevCode s.r.l.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
include_once __DIR__.'/../../../core.php';
21+
use Models\Module;
22+
23+
$link_id = Module::where('name', 'Contratti')->first()->id;
24+
25+
$results = [];
26+
27+
$fields = [
28+
'Numero' => 'co_contratti.numero',
29+
'Nome' => 'co_contratti.nome',
30+
'Descrizione' => 'co_contratti.descrizione',
31+
'Data accettazione' => 'co_contratti.data_accettazione',
32+
'Righe' => 'righe.descrizione',
33+
];
34+
35+
$query = 'SELECT co_contratti.*';
36+
37+
foreach ($fields as $name => $value) {
38+
$query .= ', '.$value." AS '".str_replace("'", "\'", $name)."'";
39+
}
40+
41+
$query .= ' FROM co_contratti LEFT JOIN (SELECT GROUP_CONCAT(`descrizione` SEPARATOR " -- ") AS "descrizione", `idcontratto`, SUM(`qta`) AS "totale_quantita", SUM(`subtotale`) AS "totale_vendita" FROM co_righe_contratti GROUP BY `idcontratto`) righe ON `righe`.`idcontratto`=`co_contratti`.`id` WHERE 1=0 ';
42+
43+
foreach ($fields as $name => $value) {
44+
$query .= ' OR '.$value.' LIKE '.prepare('%'.$term.'%');
45+
}
46+
47+
// Ricerca anche per anagrafica se il termine corrisponde a una ragione sociale
48+
$query .= ' OR co_contratti.idanagrafica IN (SELECT idanagrafica FROM an_anagrafiche WHERE ragione_sociale LIKE '.prepare('%'.$term.'%').')';
49+
50+
// Ricerca anche negli articoli associati al contratto
51+
$query .= ' OR co_contratti.id IN (
52+
SELECT DISTINCT co_righe_contratti.idcontratto
53+
FROM co_righe_contratti
54+
LEFT JOIN mg_articoli ON co_righe_contratti.idarticolo = mg_articoli.id
55+
LEFT JOIN mg_articoli_lang ON (mg_articoli.id = mg_articoli_lang.id_record AND mg_articoli_lang.id_lang = '.prepare(Models\Locale::getDefault()->id).')
56+
WHERE mg_articoli.codice LIKE '.prepare('%'.$term.'%').'
57+
OR mg_articoli_lang.title LIKE '.prepare('%'.$term.'%').'
58+
)';
59+
60+
$query .= Modules::getAdditionalsQuery(Module::where('name', 'Contratti')->first()->id);
61+
62+
$rs = $dbo->fetchArray($query);
63+
64+
foreach ($rs as $r) {
65+
$result = [];
66+
67+
$result['link'] = base_path().'/editor.php?id_module='.$link_id.'&id_record='.$r['id'];
68+
$result['title'] = 'Contratto '.$r['numero'];
69+
70+
if ($r['data_accettazione'] && $r['data_accettazione'] != '0000-00-00') {
71+
$result['title'] .= ' del '.Translator::dateToLocale($r['data_accettazione']);
72+
}
73+
74+
$result['category'] = 'Contratti';
75+
76+
// Campi da evidenziare
77+
$result['labels'] = [];
78+
foreach ($fields as $name => $value) {
79+
if (string_contains($r[$name], $term)) {
80+
$text = $r[$name];
81+
82+
// Formattazione speciale per la data di accettazione
83+
if ($name == 'Data accettazione' && $text != '0000-00-00' && !empty($text)) {
84+
$text = Translator::dateToLocale($text);
85+
}
86+
87+
$text = str_replace($term, "<span class='highlight'>".$term.'</span>', $text);
88+
$result['labels'][] = $name.': '.$text.'<br/>';
89+
}
90+
}
91+
92+
// Aggiunta nome anagrafica
93+
$anagrafica_query = 'SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica = '.prepare($r['idanagrafica']);
94+
$anagrafica_rs = $dbo->fetchOne($anagrafica_query);
95+
if (!empty($anagrafica_rs['ragione_sociale'])) {
96+
$result['labels'][] = 'Anagrafica: '.$anagrafica_rs['ragione_sociale'].'<br/>';
97+
}
98+
99+
// Recupero solo gli articoli che corrispondono al termine di ricerca con quantità e valori
100+
$articoli_query = 'SELECT CONCAT(COALESCE(`mg_articoli`.`codice`, ""), IF(`mg_articoli`.`codice` IS NOT NULL AND `mg_articoli_lang`.`title` IS NOT NULL, " - ", ""), COALESCE(`mg_articoli_lang`.`title`, "")) AS articolo, `co_righe_contratti`.`qta`, `co_righe_contratti`.`prezzo_unitario`, `co_righe_contratti`.`sconto`, `co_righe_contratti`.`subtotale` FROM co_righe_contratti LEFT JOIN `mg_articoli` ON `co_righe_contratti`.`idarticolo` = `mg_articoli`.`id` LEFT JOIN `mg_articoli_lang` ON (`mg_articoli`.`id` = `mg_articoli_lang`.`id_record` AND `mg_articoli_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `co_righe_contratti`.`idcontratto` = '.prepare($r['id']).' AND `mg_articoli`.`id` IS NOT NULL AND (CONCAT(COALESCE(`mg_articoli`.`codice`, ""), " - ", COALESCE(`mg_articoli_lang`.`title`, "")) LIKE "%'.$term.'%" OR `mg_articoli`.`codice` LIKE "%'.$term.'%" OR `mg_articoli_lang`.`title` LIKE "%'.$term.'%")';
101+
$articoli_rs = $dbo->fetchArray($articoli_query);
102+
103+
$articoli = [];
104+
$quantita_totale = 0;
105+
$valore_totale = 0;
106+
107+
foreach ($articoli_rs as $articolo) {
108+
if (!empty(trim($articolo['articolo']))) {
109+
$articoli[] = $articolo['articolo'];
110+
$quantita_totale += $articolo['qta'];
111+
112+
// Calcolo del valore per contratti (sempre vendita)
113+
$valore_totale += $articolo['prezzo_unitario'] * $articolo['qta'] - $articolo['sconto'];
114+
}
115+
}
116+
117+
// Aggiunta solo degli articoli che corrispondono alla ricerca
118+
if (!empty($articoli)) {
119+
$result['labels'][] = implode(', ', $articoli).'<br/>';
120+
121+
// Aggiunta quantità dell'articolo cercato
122+
if ($quantita_totale > 0) {
123+
$result['labels'][] = 'Quantità: '.numberFormat($quantita_totale, setting('Cifre decimali per quantità')).'<br/>';
124+
}
125+
126+
// Aggiunta valore dell'articolo cercato
127+
if ($valore_totale > 0) {
128+
$result['labels'][] = 'Valore: '.moneyFormat($valore_totale).'<br/>';
129+
}
130+
}
131+
132+
$results[] = $result;
133+
}

modules/ddt/ajax/search.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
'Numero secondario' => 'numero_esterno',
2929
'Data' => 'data',
3030
'Note' => 'note',
31-
'Righe' => '(SELECT GROUP_CONCAT(descrizione SEPARATOR \' -- \') FROM dt_righe_ddt WHERE dt_righe_ddt.idddt = dt_ddt.id)',
31+
'Righe' => 'righe.descrizione',
3232
];
3333

3434
$query = 'SELECT *, `dt_ddt`.`id`, `dt_tipiddt_lang`.`title` AS tipologia';
@@ -37,12 +37,15 @@
3737
$query .= ', '.$value." AS '".str_replace("'", "\'", $name)."'";
3838
}
3939

40-
$query .= ' FROM `dt_ddt` INNER JOIN `dt_tipiddt` ON `dt_ddt`.`idtipoddt`=`dt_tipiddt`.`id` LEFT JOIN `dt_tipiddt_lang` ON (`dt_tipiddt`.`id`= `dt_tipiddt_lang`.`id_record` AND `dt_tipiddt_lang`.`id_lang`='.prepare(Models\Locale::getDefault()->id).') WHERE `idanagrafica` IN('.implode(',', $idanagrafiche).') ';
40+
$query .= ' FROM `dt_ddt` INNER JOIN `dt_tipiddt` ON `dt_ddt`.`idtipoddt`=`dt_tipiddt`.`id` LEFT JOIN `dt_tipiddt_lang` ON (`dt_tipiddt`.`id`= `dt_tipiddt_lang`.`id_record` AND `dt_tipiddt_lang`.`id_lang`='.prepare(Models\Locale::getDefault()->id).') LEFT JOIN (SELECT GROUP_CONCAT(`descrizione` SEPARATOR " -- ") AS "descrizione", `idddt`, SUM(`qta`) AS "totale_quantita", SUM(`costo_unitario` * `qta`) AS "totale_acquisto", SUM(`prezzo_unitario` * `qta` - `sconto`) AS "totale_vendita" FROM dt_righe_ddt GROUP BY `idddt`) righe ON `righe`.`idddt`=`dt_ddt`.`id` WHERE `idanagrafica` IN('.implode(',', $idanagrafiche).') ';
4141

4242
foreach ($fields as $name => $value) {
4343
$query .= ' OR '.$value.' LIKE "%'.$term.'%"';
4444
}
4545

46+
// Aggiunta ricerca diretta negli articoli
47+
$query .= ' OR `dt_ddt`.`id` IN (SELECT DISTINCT `dt_righe_ddt`.`idddt` FROM `dt_righe_ddt` LEFT JOIN `mg_articoli` ON `dt_righe_ddt`.`idarticolo` = `mg_articoli`.`id` LEFT JOIN `mg_articoli_lang` ON (`mg_articoli`.`id` = `mg_articoli_lang`.`id_record` AND `mg_articoli_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `mg_articoli`.`codice` LIKE "%'.$term.'%" OR `mg_articoli_lang`.`title` LIKE "%'.$term.'%")';
48+
4649
$rs = $dbo->fetchArray($query);
4750

4851
foreach ($rs as $r) {
@@ -76,5 +79,48 @@
7679
$result['labels'][] = 'Anagrafica: '.$ragioni_sociali[$r['idanagrafica']].'<br/>';
7780
}
7881

82+
// Recupero solo gli articoli che corrispondono al termine di ricerca con quantità e valori
83+
$articoli_query = 'SELECT CONCAT(COALESCE(`mg_articoli`.`codice`, ""), IF(`mg_articoli`.`codice` IS NOT NULL AND `mg_articoli_lang`.`title` IS NOT NULL, " - ", ""), COALESCE(`mg_articoli_lang`.`title`, "")) AS articolo, `dt_righe_ddt`.`qta`, `dt_righe_ddt`.`prezzo_unitario`, `dt_righe_ddt`.`costo_unitario`, `dt_righe_ddt`.`sconto`, `dt_righe_ddt`.`subtotale` FROM dt_righe_ddt LEFT JOIN `mg_articoli` ON `dt_righe_ddt`.`idarticolo` = `mg_articoli`.`id` LEFT JOIN `mg_articoli_lang` ON (`mg_articoli`.`id` = `mg_articoli_lang`.`id_record` AND `mg_articoli_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `dt_righe_ddt`.`idddt` = '.prepare($r['id']).' AND `mg_articoli`.`id` IS NOT NULL AND (CONCAT(COALESCE(`mg_articoli`.`codice`, ""), " - ", COALESCE(`mg_articoli_lang`.`title`, "")) LIKE "%'.$term.'%" OR `mg_articoli`.`codice` LIKE "%'.$term.'%" OR `mg_articoli_lang`.`title` LIKE "%'.$term.'%")';
84+
$articoli_rs = $dbo->fetchArray($articoli_query);
85+
86+
$articoli = [];
87+
$quantita_totale = 0;
88+
$valore_totale = 0;
89+
90+
foreach ($articoli_rs as $articolo) {
91+
if (!empty(trim($articolo['articolo']))) {
92+
$articoli[] = $articolo['articolo'];
93+
$quantita_totale += $articolo['qta'];
94+
95+
// Calcolo del valore in base al tipo di DDT
96+
if ($r['dir'] == 'entrata') {
97+
// DDT in entrata - usa costo unitario
98+
$valore_totale += $articolo['costo_unitario'] * $articolo['qta'];
99+
} else {
100+
// DDT in uscita - usa prezzo unitario meno sconto
101+
$valore_totale += $articolo['prezzo_unitario'] * $articolo['qta'] - $articolo['sconto'];
102+
}
103+
}
104+
}
105+
106+
// Aggiunta solo degli articoli che corrispondono alla ricerca
107+
if (!empty($articoli)) {
108+
$result['labels'][] = implode(', ', $articoli).'<br/>';
109+
110+
// Aggiunta quantità dell'articolo cercato
111+
if ($quantita_totale > 0) {
112+
$result['labels'][] = 'Quantità: '.numberFormat($quantita_totale, setting('Cifre decimali per quantità')).'<br/>';
113+
}
114+
115+
// Aggiunta valore dell'articolo cercato
116+
if ($valore_totale > 0) {
117+
if ($r['dir'] == 'entrata') {
118+
$result['labels'][] = 'Valore acquisto: '.moneyFormat($valore_totale).'<br/>';
119+
} else {
120+
$result['labels'][] = 'Valore vendita: '.moneyFormat($valore_totale).'<br/>';
121+
}
122+
}
123+
}
124+
79125
$results[] = $result;
80126
}

modules/fatture/ajax/search.php

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@
3939
$query .= ', '.$value." AS '".str_replace("'", "\'", $name)."'";
4040
}
4141

42-
$query .= ' FROM `co_documenti` INNER JOIN `co_tipidocumento` ON `co_documenti`.`idtipodocumento`=`co_tipidocumento`.`id` LEFT JOIN `co_tipidocumento_lang` ON (`co_tipidocumento_lang`.`id_record` = `co_tipidocumento`.`id` AND `co_tipidocumento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') LEFT JOIN (SELECT GROUP_CONCAT(`descrizione` SEPARATOR " -- ") AS "descrizione", `iddocumento` FROM co_righe_documenti GROUP BY `iddocumento`) righe ON `righe`.`iddocumento`=`co_documenti`.`id` WHERE `idanagrafica` IN('.implode(',', $idanagrafiche).') ';
42+
$query .= ' FROM `co_documenti` INNER JOIN `co_tipidocumento` ON `co_documenti`.`idtipodocumento`=`co_tipidocumento`.`id` LEFT JOIN `co_tipidocumento_lang` ON (`co_tipidocumento_lang`.`id_record` = `co_tipidocumento`.`id` AND `co_tipidocumento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') LEFT JOIN (SELECT GROUP_CONCAT(`descrizione` SEPARATOR " -- ") AS "descrizione", `iddocumento`, SUM(`qta`) AS "totale_quantita", SUM(`costo_unitario` * `qta`) AS "totale_acquisto", SUM(`prezzo_unitario` * `qta` - `sconto`) AS "totale_vendita" FROM co_righe_documenti GROUP BY `iddocumento`) righe ON `righe`.`iddocumento`=`co_documenti`.`id` WHERE `idanagrafica` IN('.implode(',', $idanagrafiche).') ';
4343

4444
foreach ($fields as $name => $value) {
4545
$query .= ' OR '.$value.' LIKE "%'.$term.'%"';
4646
}
4747

48-
// $query .= Modules::getAdditionalsQuery(Module::where('name', 'Interventi')->first()->id)
48+
// Aggiunta ricerca diretta negli articoli
49+
$query .= ' OR `co_documenti`.`id` IN (SELECT DISTINCT `co_righe_documenti`.`iddocumento` FROM `co_righe_documenti` LEFT JOIN `mg_articoli` ON `co_righe_documenti`.`idarticolo` = `mg_articoli`.`id` LEFT JOIN `mg_articoli_lang` ON (`mg_articoli`.`id` = `mg_articoli_lang`.`id_record` AND `mg_articoli_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `mg_articoli`.`codice` LIKE "%'.$term.'%" OR `mg_articoli_lang`.`title` LIKE "%'.$term.'%")';
50+
4951

5052
$rs = $dbo->fetchArray($query);
5153

@@ -80,5 +82,48 @@
8082
$result['labels'][] = 'Anagrafica: '.$ragioni_sociali[$r['idanagrafica']].'<br/>';
8183
}
8284

85+
// Recupero solo gli articoli che corrispondono al termine di ricerca con quantità e valori
86+
$articoli_query = 'SELECT CONCAT(COALESCE(`mg_articoli`.`codice`, ""), IF(`mg_articoli`.`codice` IS NOT NULL AND `mg_articoli_lang`.`title` IS NOT NULL, " - ", ""), COALESCE(`mg_articoli_lang`.`title`, "")) AS articolo, `co_righe_documenti`.`qta`, `co_righe_documenti`.`prezzo_unitario`, `co_righe_documenti`.`costo_unitario`, `co_righe_documenti`.`sconto`, `co_righe_documenti`.`subtotale` FROM co_righe_documenti LEFT JOIN `mg_articoli` ON `co_righe_documenti`.`idarticolo` = `mg_articoli`.`id` LEFT JOIN `mg_articoli_lang` ON (`mg_articoli`.`id` = `mg_articoli_lang`.`id_record` AND `mg_articoli_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `co_righe_documenti`.`iddocumento` = '.prepare($r['id']).' AND `mg_articoli`.`id` IS NOT NULL AND (CONCAT(COALESCE(`mg_articoli`.`codice`, ""), " - ", COALESCE(`mg_articoli_lang`.`title`, "")) LIKE "%'.$term.'%" OR `mg_articoli`.`codice` LIKE "%'.$term.'%" OR `mg_articoli_lang`.`title` LIKE "%'.$term.'%")';
87+
$articoli_rs = $dbo->fetchArray($articoli_query);
88+
89+
$articoli = [];
90+
$quantita_totale = 0;
91+
$valore_totale = 0;
92+
93+
foreach ($articoli_rs as $articolo) {
94+
if (!empty(trim($articolo['articolo']))) {
95+
$articoli[] = $articolo['articolo'];
96+
$quantita_totale += $articolo['qta'];
97+
98+
// Calcolo del valore in base al tipo di documento
99+
if ($r['dir'] == 'uscita') {
100+
// Fattura di acquisto - usa costo unitario
101+
$valore_totale += $articolo['costo_unitario'] * $articolo['qta'];
102+
} else {
103+
// Fattura di vendita - usa prezzo unitario meno sconto
104+
$valore_totale += $articolo['prezzo_unitario'] * $articolo['qta'] - $articolo['sconto'];
105+
}
106+
}
107+
}
108+
109+
// Aggiunta solo degli articoli che corrispondono alla ricerca
110+
if (!empty($articoli)) {
111+
$result['labels'][] = implode(', ', $articoli).'<br/>';
112+
113+
// Aggiunta quantità dell'articolo cercato
114+
if ($quantita_totale > 0) {
115+
$result['labels'][] = 'Quantità: '.numberFormat($quantita_totale, setting('Cifre decimali per quantità')).'<br/>';
116+
}
117+
118+
// Aggiunta valore dell'articolo cercato
119+
if ($valore_totale > 0) {
120+
if ($r['dir'] == 'uscita') {
121+
$result['labels'][] = 'Valore acquisto: '.moneyFormat($valore_totale).'<br/>';
122+
} else {
123+
$result['labels'][] = 'Valore vendita: '.moneyFormat($valore_totale).'<br/>';
124+
}
125+
}
126+
}
127+
83128
$results[] = $result;
84129
}

0 commit comments

Comments
 (0)