diff --git a/application/RimoWorkorder/RimoWorkorder.php b/application/RimoWorkorder/RimoWorkorder.php index 5c9eb0767..e08448269 100644 --- a/application/RimoWorkorder/RimoWorkorder.php +++ b/application/RimoWorkorder/RimoWorkorder.php @@ -97,11 +97,11 @@ class RimoWorkorder extends mfBaseModel { } } - public static function autoParseForWorkorder(int $workorderId): void { + public static function autoParseForWorkorder(int $workorderId, bool $force = false): void { $wo = WorkorderModel::get($workorderId); if (!$wo) return; $meta = json_decode($wo->metadata ?? '{}', true); - if (empty($meta['dropcable']['parsed_at']) && $wo->preorderId) { + if (($force || empty($meta['dropcable']['parsed_at'])) && $wo->preorderId) { $pre = new Preorder($wo->preorderId); $rimos = $pre->adb_wohneinheit_id ? RimoWorkorderModel::search(['adb_wohneinheit_id' => $pre->adb_wohneinheit_id]) : []; if (!empty($rimos[0])) (new self($rimos[0]->id))->parseAha(); @@ -111,15 +111,29 @@ class RimoWorkorder extends mfBaseModel { private function parseDropkabelFromPdf(string $pdf): array { $result = []; $text = (new Parser())->parseContent($pdf)->getPages()[0]?->getText() ?? ''; - if (!preg_match('/Dropkabel:\s*\n(.+?)(?:Lage:|$)/s', $text, $m)) return $result; + + if (!preg_match('/Dropkabel:\s*\n(.+?)(?:Lage:|$)/s', $text, $m)) { + // Try alternative pattern without strict newline requirement + if (!preg_match('/Dropkabel[:\s]*(.+?)(?:Lage|Anschluss|$)/si', $text, $m)) { + return $result; + } + } + $started = false; foreach (explode("\n", $m[1]) as $line) { $line = trim($line); if (!$line) continue; - if (stripos($line, 'ID') !== false && stripos($line, 'Type') !== false) { $started = true; continue; } - if ($started && preg_match('/^(F-[A-Z0-9\(\)-]+K\d+)\s+(.+)$/i', $line, $p)) { + + // Check for header line (ID and Type columns) + if (stripos($line, 'ID') !== false && (stripos($line, 'Type') !== false || stripos($line, 'Typ') !== false)) { + $started = true; + continue; + } + + // Flexible cable ID pattern - matches F26-K009, F-ABC123-K01, F-XYZ(1)-K02, etc. + if ($started && preg_match('#^([A-Z][A-Z0-9()/_-]*-K\d+)\s+(.+)$#i', $line, $p)) { $rest = $p[2]; $status = ''; - foreach (['Planfreigabe', 'Plan released', 'Grobplanung', 'Executed', 'Ausgeführt'] as $s) + foreach (['Planfreigabe', 'Plan released', 'Grobplanung', 'Executed', 'Ausgeführt', 'Detailed planning', 'Detailplanung'] as $s) if (preg_match('/\b' . preg_quote($s, '/') . '\s*$/i', $rest)) { $status = $s; $rest = trim(preg_replace('/\b' . preg_quote($s, '/') . '\s*$/i', '', $rest)); break; } @@ -132,6 +146,7 @@ class RimoWorkorder extends mfBaseModel { 'laenge_plan' => $lp, 'laenge_ist' => $li, 'status' => $status]; } } + return $result; } diff --git a/scripts/workorder-reparse-aha.php b/scripts/workorder-reparse-aha.php new file mode 100644 index 000000000..170e104da --- /dev/null +++ b/scripts/workorder-reparse-aha.php @@ -0,0 +1,87 @@ +#!/usr/bin/php + 1]); +$addressIds = array_column($tenantConfigs, 'addressId'); + +if (empty($addressIds)) { + echo "[" . date('Y-m-d H:i:s') . "] No tenant configs with showTechnicalData enabled found\n"; + exit; +} + +echo "[" . date('Y-m-d H:i:s') . "] Found " . count($tenantConfigs) . " tenant configs with technical data enabled\n"; + +// Get all active workorders +$activeStatuses = ['new', 'assigned', 'scheduled', 'in_progress', 'correction_requested', + 'intervention_required', 'civil_engineering_required', 'civil_engineering_completed', + 'problem_solved', 'documented']; + +$workorders = WorkorderModel::getAll(['status' => $activeStatuses]); + +echo "[" . date('Y-m-d H:i:s') . "] Found " . count($workorders) . " active workorders\n"; + +$parsedCount = 0; +$skippedCount = 0; +$errorCount = 0; + +foreach ($workorders as $workorder) { + // Check if workorder belongs to a tenant with technical data enabled + if (!$workorder->preorderId) { + $skippedCount++; + continue; + } + + $preorder = new Preorder($workorder->preorderId); + if (!$preorder->id || !$preorder->adb_wohneinheit_id) { + $skippedCount++; + continue; + } + + // Find RimoWorkorder for this preorder's wohneinheit + $rimoWorkorders = RimoWorkorderModel::search(['adb_wohneinheit_id' => $preorder->adb_wohneinheit_id]); + if (empty($rimoWorkorders)) { + $skippedCount++; + continue; + } + + $rimoWorkorder = new RimoWorkorder($rimoWorkorders[0]->id); + if (!$rimoWorkorder->id) { + $skippedCount++; + continue; + } + + echo "[" . date('Y-m-d H:i:s') . "] Parsing AHA for Workorder #{$workorder->id} (RimoWorkorder #{$rimoWorkorder->id})... "; + + try { + $result = $rimoWorkorder->parseAha(); + if ($result['success']) { + echo "OK - {$result['dropkabel_count']} cables, map: " . ($result['has_map'] ? 'yes' : 'no') . "\n"; + $parsedCount++; + } else { + echo "FAILED - {$result['message']}\n"; + $errorCount++; + } + } catch (Exception $e) { + echo "ERROR - " . $e->getMessage() . "\n"; + $errorCount++; + } + + // Small delay to avoid overloading the Rimo API + usleep(100000); // 100ms +} + +echo "[" . date('Y-m-d H:i:s') . "] Completed: Parsed: $parsedCount, Skipped: $skippedCount, Errors: $errorCount\n";