attribute_17 != '') { $sql = "SELECT * FROM import_geraetezuordnung WHERE anr='".$obj->attribute_17."'"; $result = $this->db->query($sql); } else { $sql = "SELECT * FROM import_geraetezuordnung WHERE anr='".$obj->number."'"; $result = $this->db->query($sql); }*/ $result = null; // COMMENTED OUT - Wrong mapping logic /*if (strlen($obj->number) == 8) { $sql = "SELECT g.* FROM krempl_geraete_22 g INNER JOIN krempl_artikelgeraet_22 ag ON g.id = ag.geraet INNER JOIN krempl_passendwie pw ON ag.ersatzteil = pw.id INNER JOIN items i ON pw.navisionid = i.krempl_id WHERE i.number = ".$this->db->real_escape_string($obj->number).";"; $result = $this->db->query($sql); }*/ // ORIGINAL MONSTER-SQL (PERFORMANCE-KILLER!) // 4-fach JOIN über 1.3M Zeilen krempl_artikelgeraet_22 = HORROR! /* ORIGINAL MONSTER-QUERY - AUSKOMMENTIERT FÜR STEP-BY-STEP ZERLEGUNG: SELECT g.* FROM krempl_geraete_22 g -- Gerätedaten (Ziel) INNER JOIN krempl_artikelgeraet_22 ag ON g.id = ag.geraet -- 1.3M ROWS N:M Mapping! INNER JOIN krempl_passendwie pw ON ag.ersatzteil = pw.id -- Ersatzteil-Mapping INNER JOIN items i ON ( -- Item-Verknüpfung pw.navisionid = i.attribute_7 -- Legacy Items OR (LENGTH(i.number) >= 8 AND pw.navisionid = i.number) -- Moderne Items ) WHERE i.number = obj->number LOGIK: 1. Items (i) → finde Ersatzteile über attribute_7 oder number 2. Ersatzteile (pw) → finde krempl_artikelgeraet_22 Mappings 3. Mappings (ag) → finde passende Geräte 4. Geräte (g) → liefere Gerätedaten */ // STEP-BY-STEP ZERLEGUNG (Performance-Optimiert): // FIX: Läuft für number >= 8 ODER wenn attribute_7 vorhanden (Legacy-Artikel) if (strlen($obj->number) >= 8 || !empty($obj->attribute_7)) { // STEP 1: Finde Ersatzteil-IDs für dieses Item $ersatzteil_ids = array(); // Query 1A: Legacy Items (über attribute_7) // 27.09.2026: navisionid ist bigint -- nur eine echte Ziffernfolge in die SQL. Artikel 832247 // hatte ein einzelnes Leerzeichen in attribute_7 (truthy, aber "navisionid = " => SQL-Fehler, // Artikelseite HTTP 500, 14x im fatal.log seit 22.09.). $attr7 = trim((string)$obj->attribute_7); if ($attr7 !== '' && ctype_digit($attr7)) { $sql1a = "SELECT id FROM krempl_passendwie WHERE navisionid = ".$attr7; $result1a = $this->db->query($sql1a); if ($result1a) { while ($row = $result1a->fetch_assoc()) { $ersatzteil_ids[] = $row['id']; } } } // Query 1B: Moderne Items (über number, wenn >= 8 Zeichen) $sql1b = "SELECT id FROM krempl_passendwie WHERE navisionid = ".$this->db->real_escape_string($obj->number); $result1b = $this->db->query($sql1b); if ($result1b) { while ($row = $result1b->fetch_assoc()) { $ersatzteil_ids[] = $row['id']; } } // STEP 2: Finde Geräte-IDs für diese Ersatzteile $geraet_ids = array(); if (!empty($ersatzteil_ids)) { $ersatzteil_list = implode(',', array_map('intval', $ersatzteil_ids)); $sql2 = "SELECT DISTINCT geraet FROM krempl_artikelgeraet_22 WHERE ersatzteil IN ($ersatzteil_list)"; $result2 = $this->db->query($sql2); if ($result2) { while ($row = $result2->fetch_assoc()) { $geraet_ids[] = $row['geraet']; } } } // STEP 3: Hole finale Gerätedaten $result = false; if (!empty($geraet_ids)) { $geraet_list = implode(',', array_map('intval', $geraet_ids)); $sql3 = "SELECT * FROM krempl_geraete_22 WHERE id IN ($geraet_list)"; $result = $this->db->query($sql3); if (!$result) { $result = false; // Explizit setzen für Fallback } } else { $result = false; // Explizit setzen für Fallback } } if (!empty($obj->krempl_id) && (!isset($result) || !$result || $result->num_rows < 1)) { $sql = "SELECT * FROM krempl_artikelgeraet_22 ka left join krempl_geraete_22 kg on kg.id=ka.geraet WHERE ka.ersatzteil=".$this->db->real_escape_string($obj->krempl_id)." AND not isnull(nr)"; $result = $this->db->query($sql); } $obj->geraetezuordnung = array(); if ($result) { while ($obj1 = $result->fetch_object()) { $obj->geraetezuordnung[] = $obj1; } } // get parent warengruppe $sql = "select i.name, s.name, s2.name as wg from items i left join item_structure_assign isa on isa.item_id=i.id left join structure s on s.id=isa.structure_id left join structure s2 on s2.id=s.parent_id where i.id=".$obj->id.' AND s.active=1 LIMIT 1'; $result = $this->db->query($sql); $parent_warengruppe = ''; if ($result) { while ($obj1 = $result->fetch_object()) { $parent_warengruppe = $obj1->wg; } } $table_data = array(); foreach ($obj->geraetezuordnung as $geraet) { $nr1 = str_replace('#', '', $geraet->nr); $nr1 = str_replace('_', ' ', $nr1); $nr2 = str_replace('#', '', $geraet->produktionsstart); $nr2 = str_replace('_', ' ', $nr2); $nr3 = str_replace('#', '', $geraet->produktionsende); $nr3 = str_replace('_', ' ', $nr3); $nr3 = empty($nr3) ? "" : " - ".$nr3; $nr2 = $nr2.$nr3; $bezeichnungoriginal = str_replace('#', '', $geraet->bezeichnungoriginal); $bezeichnungoriginal = str_replace('_', ' ', $bezeichnungoriginal); $bezeichnungoriginal = preg_replace('/\r\n|\n|\r/', '', $bezeichnungoriginal); // Überprüfe, ob $bezeichnungoriginal leer ist, und verwende $geraet->modellBezeichnung falls ja if (empty($bezeichnungoriginal) && !empty($geraet->modellBezeichnung)) { $bezeichnungoriginal = str_replace('#', '', $geraet->modellBezeichnung); $bezeichnungoriginal = str_replace('_', ' ', $bezeichnungoriginal);// Ersetze durch modellBezeichnung } elseif (empty($bezeichnungoriginal)) { $bezeichnungoriginal = "-"; // Oder einen Platzhalter, wenn auch modellBezeichnung leer ist } $einkaufsmoeglichkeitencached = $nr1." ".$nr2; $table_data[$einkaufsmoeglichkeitencached][$bezeichnungoriginal][] = array($nr1, $nr2); } /* $html = ''; foreach ($table_data as $key => $marken) { $y = 0; $html .= ''; $html .= ''; foreach ($marken as $geraet => $nummern) { $color = 'intelectra_table_row1'; if ($y % 2 == 1) { $color = 'intelectra_table_row2'; } $z = 0; foreach ($nummern as $nummer) { if ($z == 0) { $html .= ''; } else { $html .= ''; } $z++; } $y++; } } $html .= '

'.$obj->name.' passend zu '.$key.' '.$parent_warengruppe.'

Geräte-/ModellbezeichnungE-, Service-, Produktions- oder HauptnummerZusatz-, F- oder Seriennummer oder Fertigungsdatum
'.$geraet.''.$nummer[0].''.$nummer[1].'
 '.$nummer[0].''.$nummer[1].'
'; */ $html = '
'; foreach ($table_data as $key => $marken) { $y = 0; // Eine einzige Überschrift pro Artikel if ($y == 0) { $html .= '
'; $html .= '

'.$obj->name.' passend zu '.$key.' '.$parent_warengruppe.'

'; $html .= '
'; $html .= '
Geräte-/Modellbezeichnung
'; $html .= '
E-, Service-, Produktions- oder Hauptnummer
'; $html .= '
Zusatz-, F- oder Seriennummer oder Fertigungsdatum
'; $html .= '
'; // Header-Ende } foreach ($marken as $geraet => $nummern) { $colorClass = ($y % 2 == 1) ? 'tba_row_odd' : 'tba_row_even'; $z = 0; foreach ($nummern as $nummer) { $html .= '
'; if ($z == 0) { $html .= '
'.$geraet.'
'; } else { $html .= '
 
'; } $html .= ''; $html .= '
'.$nummer[1].'
'; $html .= '
'; // Zeile Ende $z++; } $y++; } $html .= '
'; // Section Ende } $html .= '
'; // Container Ende $shopArticle->geraetezuordnung = $html; $int = $this->createIntWithTableData($html); // base price calc // // 25.08.2026 gehaertet. Vorher wurde nur auf "truthy" geprueft -- und zwei Sorten // gepflegter Werte sind truthy, ohne rechenbar zu sein: // // " " (Artikel 831966, beide Felder ein Leerzeichen) // PHP 8: float / " " => TypeError => Artikelseite mit HTTP 500 tot. // Unter PHP 7 lief das als Warnung durch -- ein Migrationsueberbleibsel. // // "2,5" (24 aktive Artikel, Komma statt Punkt) // PHP 8 nimmt den fuehrenden Teil und rechnet mit 2 statt 2,5. Kein Fehler, // aber ein um 25 % zu hoher Grundpreis -- und wegen error_reporting(0) in // index.php sieht das niemand. // // Deshalb: Komma normalisieren, numerisch pruefen, und erst dann rechnen. Ist der // Teiler unbrauchbar, bleibt sample_price schlicht ungesetzt -- besser kein Grundpreis // als ein falscher (Preisangabenverordnung). $grundpreis_teiler = str_replace(',', '.', trim((string)$obj->attribute_11)); $grundpreis_einheit = trim((string)$obj->attribute_15); if (is_numeric($grundpreis_teiler) && (float)$grundpreis_teiler > 0 && $grundpreis_einheit !== '') { $grundpreis_teiler = (float)$grundpreis_teiler; $obj->sample_unit = $obj->attribute_15; if (strstr($grundpreis_einheit, '100')) { $obj->sample_price = $obj->shop_price_1 / ($grundpreis_teiler * 10); } else { $obj->sample_price = $obj->shop_price_1 / $grundpreis_teiler; } }