table = 'Preorder'; } public function getClusters($frame_referrer): array { $query = " SELECT n.adb_netzgebiet_id as id, ng.name, GROUP_CONCAT(pc.id SEPARATOR ', ') as campaign_ids, GROUP_CONCAT(pc.name SEPARATOR ', ') as campaign_names FROM thetool.Preordercampaign pc JOIN thetool.Network n ON pc.Network_id = n.id JOIN addressdb.Netzgebiet ng ON n.adb_netzgebiet_id = ng.id WHERE JSON_SEARCH(pc.iframe_origins, 'one', '" . $this->db->escape($frame_referrer) . "') IS NOT NULL GROUP BY n.adb_netzgebiet_id, ng.name ORDER BY ng.name ASC "; $res = $this->db->query($query); $clusters = $this->db->fetch_all_assoc($res); if (empty($clusters)) { // Fallback for development or specific cases return [['id' => 98, 'name' => 'Leibnitz', 'campaign_id' => 99, 'campaign_name' => 'X - Leibnitz']]; } return $clusters; } public function findCities(array $params): array { if (empty($params['gemeindeId']) && empty($params['clusterId'])) return []; $sql = "SELECT DISTINCT o.name FROM addressdb.Plz p JOIN addressdb.Ortschaft o ON p.gemeinde_id = o.gemeinde_id JOIN addressdb.Gemeinde g ON o.gemeinde_id = g.id LEFT JOIN addressdb.GemeindeNetzgebiet gn ON g.id = gn.gemeinde_id WHERE p.plzstring = " . $this->db->escape($params['zip']); $cond = !empty($params['gemeindeId']) ? " AND g.id = " . intval($params['gemeindeId']) : " AND gn.netzgebiet_id = " . intval($params['clusterId']); $rows = $this->db->fetch_all_assoc($this->db->query($sql . $cond)); if (empty($rows) && empty($params['gemeindeId'])) $rows = $this->db->fetch_all_assoc($this->db->query($sql)); return array_column($rows, 'name'); } public function findStreets(array $params): array { if (empty($params['gemeindeId']) && empty($params['clusterId'])) return []; $sql = "SELECT DISTINCT s.name FROM addressdb.Strasse s JOIN addressdb.Gemeinde g ON s.gemeinde_id = g.id JOIN addressdb.Ortschaft o ON o.gemeinde_id = g.id LEFT JOIN addressdb.GemeindeNetzgebiet gn ON g.id = gn.gemeinde_id WHERE o.name = '" . $this->db->escape($params['city']) . "' AND EXISTS (SELECT 1 FROM addressdb.Plz p WHERE p.plzstring = " . $this->db->escape($params['zip']) . " AND p.gemeinde_id = o.gemeinde_id)"; $cond = !empty($params['gemeindeId']) ? " AND g.id = " . intval($params['gemeindeId']) : " AND gn.netzgebiet_id = " . intval($params['clusterId']); $rows = $this->db->fetch_all_assoc($this->db->query($sql . $cond)); // Fallback: If empty result and we were using clusterId, run without the specific ID constraint if (empty($rows) && empty($params['gemeindeId'])) $rows = $this->db->fetch_all_assoc($this->db->query($sql)); return array_column($rows, 'name'); } public function findAddresses(array $params): array { $whereClauses = [ "p.plzstring = " . $this->db->escape($params['zip']), "o.name = '" . $this->db->escape($params['city']) . "'", "s.name = '" . $this->db->escape($params['street']) . "'", "h.hausnummer = '" . $this->db->escape($params['housenumber']) . "'", ]; if (!empty($params['gemeinde_id'])) { $whereClauses[] = "h.gemeinde_id = " . intval($params['gemeinde_id']); } elseif (!empty($params['cluster_id'])) { $whereClauses[] = "h.netzgebiet_id = " . intval($params['cluster_id']); } else { return []; } $whereString = implode(" AND ", $whereClauses); $query = " SELECT h.oaid, h.hausnummer, s.name as street, p.plzstring as zip, o.name as city, h.id as hausnummer_id, w.id as wohneinheit_id, h.stiege, h.unit_count as building_unit_count, h.tool_building_type as building_type, w.oaid as unit_oaid, w.stock, w.tuer, w.zusatz FROM addressdb.Hausnummer h JOIN addressdb.Strasse s ON h.strasse_id = s.id JOIN addressdb.Plz p ON h.plz_id = p.id JOIN addressdb.Ortschaft o ON s.gemeinde_id = o.gemeinde_id LEFT JOIN addressdb.Wohneinheit w ON w.hausnummer_id = h.id WHERE $whereString "; $results = $this->db->fetch_all_assoc($this->db->query($query)); if (empty($results)) return []; $orderType = $params['orderType'] ?? 'order'; // For 'interest' order type, return a single entry for the whole building. if ($orderType === 'interest') { $representativeAddress = $this->formatAddressRow($results[0]); $representativeAddress['wohneinheit_id'] = null; // Critical: No specific unit $representativeAddress['oaid'] = $results[0]['oaid']; // Use building OAID $representativeAddress['showText'] = "Gesamtes Gebäude"; $representativeAddress['preorderTypes'] = ['interest']; return [$representativeAddress]; // Return one item, so frontend proceeds directly. } // Original logic for 'order' type $addresses = []; $topCounter = 1; if (count($results) > 1 && $results[0]['wohneinheit_id'] !== null) { foreach ($results as $row) { $address = $this->formatAddressRow($row); $address['showText'] = $this->buildShowText($row, $topCounter++); $address['preorderTypes'] = ['order']; $addresses[] = $address; } } else { // Single unit or building without units $address = $this->formatAddressRow($results[0]); $address['preorderTypes'] = ['order']; $addresses[] = $address; } return $addresses; } private function formatAddressRow(array $row): array { return [ 'oaid' => $row['unit_oaid'] ?? $row['oaid'], 'street' => $row['street'], 'housenumber' => $row['hausnummer'], 'hausnummer_id' => $row['hausnummer_id'], 'wohneinheit_id' => $row['wohneinheit_id'], 'building_type' => intval($row['building_type']), 'zip' => $row['zip'], 'city' => $row['city'], 'stiege' => $row['stiege'], 'stock' => $row['stock'], 'tuer' => $row['tuer'], 'zusatz' => $row['zusatz'], 'building_unit_count' => $row['building_unit_count'], 'showText' => $this->buildShowText($row, 1), ]; } private function buildShowText(array $row, int $counter): string { $parts = array_filter([ $row['stiege'] ? "Stiege {$row['stiege']}" : null, $row['stock'] ? "Stock {$row['stock']}" : null, $row['tuer'] ? "Tür {$row['tuer']}" : null, $row['zusatz'] ?: null ]); return $parts ? implode(', ', $parts) : "Top {$counter}"; } }