fixed import fogli di lavoro and disegni tecnici

This commit is contained in:
2026-10-02 11:24:51 +02:00
parent 63674ea6be
commit c2212f7022
11 changed files with 802 additions and 87 deletions
+70 -29
View File
@@ -237,10 +237,12 @@ function extract_fields($grid)
$out['speed_expected_m_h'] = null;
$rv = row_by_label($grid, 'velocita di produzione');
if ($rv) {
$out['speed_expected_kg_h'] = num_or_null(cell($grid, $rv, 'C'));
$v = num_or_null(cell($grid, $rv, 'C'));
$out['speed_expected_kg_h'] = $v === null ? null : round($v, 2);
for ($i = $rv; $i <= $rv + 2; $i++) {
if (norm(cell($grid, $i, 'B')) === 'm/h') {
$out['speed_expected_m_h'] = num_or_null(cell($grid, $i, 'C'));
$v = num_or_null(cell($grid, $i, 'C'));
$out['speed_expected_m_h'] = $v === null ? null : round($v, 2);
break;
}
}
@@ -267,25 +269,37 @@ function extract_fields($grid)
* 3) MATCHER su DB
* ========================================================================= */
function norm_mesc($s)
function strip_code($s)
{
$s = strtolower((string)$s);
$s = preg_replace('/\s+/', ' ', $s);
return trim($s);
$s = str_replace(['à', 'è', 'é', 'ì', 'ò', 'ù'], ['a', 'e', 'e', 'i', 'o', 'u'], $s);
return preg_replace('/[^a-z0-9]+/', '', $s); // solo lettere + cifre (ignora spazi e punteggiatura)
}
/** porzione iniziale prima del primo separatore descrittivo (es. "ATES 71 - EPDM..." -> "ATES 71") */
function raw_head($s)
{
$parts = preg_split('/\s*[-–—|(:,]\s*/u', (string)$s, 2);
return trim($parts[0] ?? '');
}
function match_mescola($raw, array $mescole)
{
$r = norm_mesc($raw);
if ($r === '') return [null, 'none', null];
foreach ($mescole as $m) if (norm_mesc($m['nome']) === $r) return [(int)$m['id'], 'exact', $m['nome']];
foreach ($mescole as $m) {
foreach (explode('/', $m['nome']) as $part) {
if (norm_mesc($part) === $r) return [(int)$m['id'], 'exact-part', $m['nome']];
}
if (trim((string)$raw) === '') return [null, 'none', null];
$rawStrip = strip_code($raw);
$headStrip = strip_code(raw_head($raw));
// 1) uguaglianza ignorando spazi/punteggiatura, sul nome intero (gestisce "ATES 71" = "ATES71")
foreach ($mescole as $m) if ($rawStrip !== '' && strip_code($m['nome']) === $rawStrip) return [(int)$m['id'], 'exact', $m['nome']];
// 2) parte di nome composito (a / b / c)
foreach ($mescole as $m) foreach (explode('/', $m['nome']) as $p) if ($rawStrip !== '' && strip_code($p) === $rawStrip) return [(int)$m['id'], 'exact-part', $m['nome']];
// 3) nome in uscita
foreach ($mescole as $m) if ($rawStrip !== '' && strip_code($m['nomeuscita'] ?? '') === $rawStrip) return [(int)$m['id'], 'exact-uscita', $m['nome']];
// 4) codice iniziale prima di " - descrizione" (gestisce "ATES 71 - EPDM...")
if ($headStrip !== '' && $headStrip !== $rawStrip) {
foreach ($mescole as $m) if (strip_code($m['nome']) === $headStrip) return [(int)$m['id'], 'code', $m['nome']];
foreach ($mescole as $m) foreach (explode('/', $m['nome']) as $p) if (strip_code($p) === $headStrip) return [(int)$m['id'], 'code-part', $m['nome']];
}
foreach ($mescole as $m) if (norm_mesc($m['nomeuscita'] ?? '') === $r) return [(int)$m['id'], 'exact-uscita', $m['nome']];
foreach ($mescole as $m) if ($r !== '' && strpos(norm_mesc($m['nome']), $r) !== false) return [(int)$m['id'], 'contains', $m['nome']];
return [null, 'none', null];
}
@@ -309,24 +323,51 @@ function dim_tokens($s)
function match_packaging($raw, array $packaging, $preferCat = null)
{
$cands = dim_tokens($raw);
if (!$cands) return [null, 'none', null, null];
$best = null;
$rawStrip = strip_code($raw);
if ($rawStrip === '') return [null, 'none', null, null, true];
// 1) nome/codice ESATTO (categoria solo come spareggio) -> sicuro
$exact = [];
foreach ($packaging as $p) {
$itemForms = array_merge(dim_tokens($p['item_name']), dim_tokens($p['item_code']));
foreach ($cands as $c) {
if (in_array($c, $itemForms, true)) {
if ($preferCat && $p['category'] === $preferCat) {
return [(int)$p['id'], 'dimension', $p['item_name'], $p['category']];
}
if ($best === null) $best = $p;
if (strip_code($p['item_code']) === $rawStrip || strip_code($p['item_name']) === $rawStrip) $exact[] = $p;
}
if ($exact) {
$pick = $exact[0];
foreach ($exact as $p) if ($preferCat && $p['category'] === $preferCat) {
$pick = $p;
break;
}
return [(int)$pick['id'], 'name-code', $pick['item_name'], $pick['category'], false];
}
// 2) DIMENSIONI -> sicuro se unico, proposta se ambiguo
$rd = dim_tokens($raw);
if ($rd) {
$dm = [];
foreach ($packaging as $p) {
$pf = array_merge(dim_tokens($p['item_name']), dim_tokens($p['item_code']));
if (array_intersect($rd, $pf)) $dm[] = $p;
}
if ($dm) {
$pick = $dm[0];
foreach ($dm as $p) if ($preferCat && $p['category'] === $preferCat) {
$pick = $p;
break;
}
$ambiguous = count($dm) > 1;
return [(int)$pick['id'], 'dimension', $pick['item_name'], $pick['category'], $ambiguous];
}
}
if ($best) return [(int)$best['id'], 'dimension', $best['item_name'], $best['category']];
return [null, 'none', null, null];
}
// 3) ABBREVIAZIONE: testo corto, prefisso UNICO di un nome -> solo proposta
if (strlen($rawStrip) <= 4) {
$cand = [];
foreach ($packaging as $p) if (strpos(strip_code($p['item_name']), $rawStrip) === 0) $cand[] = $p;
if (count($cand) === 1) return [(int)$cand[0]['id'], 'abbrev', $cand[0]['item_name'], $cand[0]['category'], true];
}
return [null, 'none', null, null, true];
}
/* ---- match generico su dropdown (ws_lookup_options) ---- */
function lk_norm($s)
@@ -461,7 +502,7 @@ try {
];
foreach ($pkgSpecs as $spec) {
if ($spec['raw'] === '') continue;
[$pid, $pconf, $pname, $pcat] = match_packaging($spec['raw'], $packaging, $spec['cat']);
[$pid, $pconf, $pname, $pcat, $pneeds] = match_packaging($spec['raw'], $packaging, $spec['cat']);
$packagesOut[] = [
'source' => $spec['source'],
'raw' => $spec['raw'],
@@ -469,7 +510,7 @@ try {
'matched_name' => $pname,
'category' => $pcat,
'confidence' => $pconf,
'needs_review' => ($pid === null),
'needs_review' => ($pid === null) ? true : $pneeds,
];
}