add aha blatt parsing

This commit is contained in:
Luca Haid
2026-01-20 13:27:35 +01:00
parent b79be61ca9
commit d6d213a8d3
9 changed files with 412 additions and 140 deletions

View File

@@ -1,5 +1,7 @@
<?php
use Smalot\PdfParser\Parser;
class RimoWorkorder extends mfBaseModel {
private $adb_wohneinheit;
private $termination;
@@ -56,6 +58,98 @@ class RimoWorkorder extends mfBaseModel {
return $ah;
}
public function parseAha(): array {
if (!$this->id || !$this->adb_wohneinheit_id) return ['success' => false, 'message' => 'Missing ID'];
$preorder = PreorderModel::getFirstActive(["adb_wohneinheit_id" => $this->adb_wohneinheit_id]);
if (!$preorder?->id) return ['success' => false, 'message' => 'No active Preorder'];
$workorder = WorkorderModel::getFirst(['preorderId' => $preorder->id]);
if (!$workorder || !($pdf = $this->getAha())) return ['success' => false, 'message' => 'No Workorder or PDF'];
try {
$dropkabel = $this->parseDropkabelFromPdf($pdf);
$map = $this->extractMapFromPdf($pdf);
$meta = json_decode($workorder->metadata ?: '{}', true) ?: [];
$mapFileId = null;
if ($map) {
if ($oldId = ($meta['dropcable']['map_file_id'] ?? null)) {
$old = new File($oldId); if ($old->id) try { $old->delete(); } catch (Exception $e) {}
}
$fn = 'aha_lageplan_' . $this->id . '_' . time() . '.png';
$file = FileModel::create(['name' => 'AHA Lageplan ' . $this->rimo_name, 'filename' => $fn,
'store_filename' => $fn, 'orig_filename' => 'AHA_Lageplan_' . $this->rimo_name . '.png',
'mimetype' => 'image/png', 'subfolder' => 'aha_maps']);
if ($file->save()) {
$dir = MFUPLOAD_FILE_SAVE_PATH . '/aha_maps';
if (!is_dir($dir)) mkdir($dir, 0755, true);
if (file_put_contents("$dir/$fn", $map)) $mapFileId = $file->id;
}
}
$meta['dropcable'] = ['rimo_workorder_id' => $this->id, 'rimo_name' => $this->rimo_name,
'parsed_at' => time(), 'entries' => $dropkabel, 'map_file_id' => $mapFileId];
$workorder->metadata = json_encode($meta);
WorkorderModel::update((array)$workorder);
return ['success' => true, 'dropkabel_count' => count($dropkabel), 'has_map' => (bool)$mapFileId];
} catch (Exception $e) {
$this->log->error(__METHOD__ . ": " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
public static function autoParseForWorkorder(int $workorderId): void {
$wo = WorkorderModel::get($workorderId);
if (!$wo) return;
$meta = json_decode($wo->metadata ?? '{}', true);
if (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();
}
}
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;
$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)) {
$rest = $p[2]; $status = '';
foreach (['Planfreigabe', 'Plan released', 'Grobplanung', 'Executed', 'Ausgeführt'] 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;
}
$lp = $li = '';
if (preg_match_all('/(\d+)\s*m\b/', $rest, $lens, PREG_SET_ORDER)) {
$lp = ($lens[0][1] ?? '') . ' m'; $li = ($lens[1][1] ?? '') . ' m';
$rest = preg_replace('/\d+\s*m\b/', '', $rest);
}
$result[] = ['cable_id' => trim($p[1]), 'type' => trim(preg_replace('/\s+/', ' ', $rest)),
'laenge_plan' => $lp, 'laenge_ist' => $li, 'status' => $status];
}
}
return $result;
}
private function extractMapFromPdf(string $pdf): ?string {
$tmp = tempnam(sys_get_temp_dir(), 'aha_'); file_put_contents($tmp, $pdf);
$out = tempnam(sys_get_temp_dir(), 'aha_img_'); unlink($out);
exec(sprintf('pdftoppm -png -f 1 -l 1 -r 150 %s %s 2>&1', escapeshellarg($tmp), escapeshellarg($out)), $_, $ret);
@unlink($tmp);
$outFile = file_exists("$out-1.png") ? "$out-1.png" : "$out.png";
if ($ret !== 0 || !file_exists($outFile)) return null;
$img = @imagecreatefromstring(file_get_contents($outFile)); @unlink($outFile);
if (!$img) return null;
$h = imagesy($img); $cropY = (int)($h * 0.42); $cropH = (int)($h * 0.84) - $cropY;
$cropped = imagecrop($img, ['x' => 60, 'y' => $cropY, 'width' => imagesx($img) - 90, 'height' => $cropH]);
imagedestroy($img); if (!$cropped) return null;
ob_start(); imagepng($cropped, null, 6); $content = ob_get_clean(); imagedestroy($cropped);
return $content;
}
public function getProperty($name) {
if($this->$name == null) {