kundenkarte/anlage_connection.php
data 71272fa425 fix(schematic): Terminal-Farbpropagierung, Auto-Naming, PWA-Abgänge
- buildTerminalPhaseMap: Schritt 1b - Leitungen mit expliziter Farbe als
  Startpunkte (nur Gerät→Gerät, keine Abgänge)
- buildTerminalPhaseMap: Block-Durchreichung (Top↔Bottom) entfernt
- buildTerminalPhaseMap: Junction-Verbindungen (Terminal→Leitung)
  bidirektional verarbeitet via _connectionById Index
- PWA: Abgangs-Rendering mit Index-Fallback wenn source_terminal_id fehlt
- PWA: Abgangs-Labels max-height 130px, min-height 30px
- Auto-Naming: EquipmentCarrier create/update → 'R' + count
- Auto-Naming: EquipmentPanel update → 'Feld ' + count
- pwa_api.php: Hardcoded Fallbacks 'Feld'/'Hutschiene' entfernt
- pwa.js: Hutschiene Auto-Naming dynamisch aus Panel-Carrier-Anzahl
- kundenkarte.js: Carrier-Dialog Placeholder 'z.B. R1 (automatisch)'
- SW Cache auf v12.5 hochgezählt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 09:57:58 +01:00

306 lines
12 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* Edit page for Anlage Connection (cable/wire between elements)
*/
$res = 0;
if (!$res && file_exists("../main.inc.php")) $res = @include "../main.inc.php";
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
if (!$res) die("Include of main fails");
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
dol_include_once('/kundenkarte/class/anlageconnection.class.php');
dol_include_once('/kundenkarte/class/anlage.class.php');
dol_include_once('/kundenkarte/class/mediumtype.class.php');
$langs->loadLangs(array('kundenkarte@kundenkarte'));
$id = GETPOSTINT('id');
$socId = GETPOSTINT('socid');
$contactId = GETPOSTINT('contactid');
$systemId = GETPOSTINT('system_id');
$sourceId = GETPOSTINT('source_id');
$action = GETPOST('action', 'aZ09');
// Security check
if (!$user->hasRight('kundenkarte', 'read')) {
accessforbidden();
}
$connection = new AnlageConnection($db);
$anlage = new Anlage($db);
$form = new Form($db);
// Load existing connection
if ($id > 0) {
$result = $connection->fetch($id);
if ($result <= 0) {
setEventMessages($langs->trans('ErrorRecordNotFound'), null, 'errors');
header('Location: '.DOL_URL_ROOT.'/societe/card.php?socid='.$socId);
exit;
}
// Get socId from source anlage if not provided
if (empty($socId)) {
$tmpAnlage = new Anlage($db);
if ($tmpAnlage->fetch($connection->fk_source) > 0) {
$socId = $tmpAnlage->fk_soc;
$systemId = $tmpAnlage->fk_system;
}
}
}
// Redirect-URL: zurück zur Kontakt- oder Kunden-Anlagenansicht
if ($contactId > 0) {
$backUrl = dol_buildpath('/kundenkarte/tabs/contact_anlagen.php', 1).'?id='.$contactId.'&system='.$systemId;
} else {
$backUrl = dol_buildpath('/kundenkarte/tabs/anlagen.php', 1).'?id='.$socId.'&system='.$systemId;
}
/*
* Actions
*/
if ($action == 'update' && $user->hasRight('kundenkarte', 'write')) {
$connection->fk_source = GETPOSTINT('fk_source');
$connection->fk_target = GETPOSTINT('fk_target');
$connection->label = GETPOST('label', 'alphanohtml');
$connection->fk_medium_type = GETPOSTINT('fk_medium_type');
$connection->medium_type_text = GETPOST('medium_type_text', 'alphanohtml');
$connection->medium_spec = GETPOST('medium_spec', 'alphanohtml');
$connection->medium_length = GETPOST('medium_length', 'alphanohtml');
$connection->medium_color = GETPOST('medium_color', 'alphanohtml');
$connection->route_description = GETPOST('route_description', 'restricthtml');
$connection->installation_date = GETPOST('installation_date', 'alpha');
if (empty($connection->fk_source) || empty($connection->fk_target)) {
setEventMessages($langs->trans('ErrorFieldRequired', 'Quelle/Ziel'), null, 'errors');
} else {
$result = $connection->update($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
header('Location: '.$backUrl);
exit;
} else {
setEventMessages($connection->error, null, 'errors');
}
}
}
if ($action == 'add' && $user->hasRight('kundenkarte', 'write')) {
$connection->fk_source = GETPOSTINT('fk_source');
$connection->fk_target = GETPOSTINT('fk_target');
$connection->label = GETPOST('label', 'alphanohtml');
$connection->fk_medium_type = GETPOSTINT('fk_medium_type');
$connection->medium_type_text = GETPOST('medium_type_text', 'alphanohtml');
$connection->medium_spec = GETPOST('medium_spec', 'alphanohtml');
$connection->medium_length = GETPOST('medium_length', 'alphanohtml');
$connection->medium_color = GETPOST('medium_color', 'alphanohtml');
$connection->route_description = GETPOST('route_description', 'restricthtml');
$connection->installation_date = GETPOST('installation_date', 'alpha');
$connection->status = 1;
if (empty($connection->fk_source) || empty($connection->fk_target)) {
setEventMessages($langs->trans('ErrorFieldRequired', 'Quelle/Ziel'), null, 'errors');
} else {
$result = $connection->create($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
header('Location: '.$backUrl);
exit;
} else {
setEventMessages($connection->error, null, 'errors');
}
}
}
if ($action == 'delete' && $user->hasRight('kundenkarte', 'write')) {
$result = $connection->delete($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
header('Location: '.$backUrl);
exit;
} else {
setEventMessages($connection->error, null, 'errors');
}
}
/*
* View
*/
$title = $id > 0 ? 'Verbindung bearbeiten' : 'Neue Verbindung';
llxHeader('', $title);
// Gebäude-Typ-IDs ermitteln (Verbindungen nur zwischen Geräten, nicht Gebäuden)
$buildingTypeIds = array();
$sqlBt = "SELECT t.rowid FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_type t";
$sqlBt .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system ts ON t.fk_system = ts.rowid";
$sqlBt .= " WHERE ts.code = 'GLOBAL'";
$resBt = $db->query($sqlBt);
if ($resBt) {
while ($btObj = $db->fetch_object($resBt)) {
$buildingTypeIds[] = (int) $btObj->rowid;
}
}
// Alle Elemente für Dropdowns laden (OHNE System-Filter, da Kabel systemübergreifend sein können)
$anlagenList = array();
if ($socId > 0) {
if ($contactId > 0) {
$tree = $anlage->fetchTreeByContact($socId, $contactId, 0);
} else {
$tree = $anlage->fetchTree($socId, 0);
}
// Baum flach machen - nur Geräte, Gebäude als Pfad-Kontext
$flattenTree = function($nodes, $path = '') use (&$flattenTree, &$anlagenList, &$buildingTypeIds) {
foreach ($nodes as $node) {
$isBuilding = in_array((int) $node->fk_anlage_type, $buildingTypeIds);
if ($isBuilding) {
// Gebäude/Raum: nicht wählbar, aber Pfad als Kontext weitergeben
$newPath = $path ? $path.' > '.$node->label : $node->label;
if (!empty($node->children)) {
$flattenTree($node->children, $newPath);
}
} else {
// Gerät: in Liste aufnehmen mit Gebäude-Pfad als Kontext
$typeInfo = !empty($node->type_short) ? $node->type_short : (!empty($node->type_label) ? $node->type_label : '');
$label = '';
if (!empty($path)) {
$label = $path.' > ';
}
$label .= $node->label;
if (!empty($typeInfo)) {
$label .= ' ['.$typeInfo.']';
}
$anlagenList[$node->id] = array(
'label' => $label,
'picto' => !empty($node->type_picto) ? $node->type_picto : 'fa-cube',
);
// Rekursion in Geräte-Kinder
if (!empty($node->children)) {
$flattenTree($node->children, $path);
}
}
}
};
$flattenTree($tree);
}
// Load medium types
$mediumTypes = array();
$sql = "SELECT rowid, label, category FROM ".MAIN_DB_PREFIX."kundenkarte_medium_type WHERE active = 1 ORDER BY category, label";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$mediumTypes[$obj->rowid] = $obj->label;
}
}
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="id" value="'.$id.'">';
print '<input type="hidden" name="socid" value="'.$socId.'">';
print '<input type="hidden" name="contactid" value="'.$contactId.'">';
print '<input type="hidden" name="system_id" value="'.$systemId.'">';
print '<input type="hidden" name="action" value="'.($id > 0 ? 'update' : 'add').'">';
print load_fiche_titre($title, '', 'object_kundenkarte@kundenkarte');
print '<table class="border centpercent">';
// Source
print '<tr><td class="titlefield fieldrequired">'.$langs->trans('Von (Quelle)').'</td>';
print '<td><select name="fk_source" id="fk_source" class="flat minwidth300">';
print '<option value="">-- Quelle wählen --</option>';
foreach ($anlagenList as $aid => $ainfo) {
$selected = ($connection->fk_source == $aid || $sourceId == $aid) ? ' selected' : '';
print '<option value="'.$aid.'" data-picto="'.dol_escape_htmltag($ainfo['picto']).'"'.$selected.'>'.dol_escape_htmltag($ainfo['label']).'</option>';
}
print '</select></td></tr>';
// Target
print '<tr><td class="fieldrequired">'.$langs->trans('Nach (Ziel)').'</td>';
print '<td><select name="fk_target" id="fk_target" class="flat minwidth300">';
print '<option value="">-- Ziel wählen --</option>';
foreach ($anlagenList as $aid => $ainfo) {
$selected = ($connection->fk_target == $aid) ? ' selected' : '';
print '<option value="'.$aid.'" data-picto="'.dol_escape_htmltag($ainfo['picto']).'"'.$selected.'>'.dol_escape_htmltag($ainfo['label']).'</option>';
}
print '</select></td></tr>';
// Medium type
print '<tr><td>'.$langs->trans('Kabeltyp').'</td>';
print '<td><select name="fk_medium_type" class="flat minwidth200">';
print '<option value="">-- oder Freitext unten --</option>';
foreach ($mediumTypes as $mid => $mlabel) {
$selected = ($connection->fk_medium_type == $mid) ? ' selected' : '';
print '<option value="'.$mid.'"'.$selected.'>'.dol_escape_htmltag($mlabel).'</option>';
}
print '</select></td></tr>';
// Medium type text (free text)
print '<tr><td>'.$langs->trans('Kabeltyp (Freitext)').'</td>';
print '<td><input type="text" name="medium_type_text" class="flat minwidth300" value="'.dol_escape_htmltag($connection->medium_type_text).'" placeholder="z.B. NYM-J"></td></tr>';
// Medium spec
print '<tr><td>'.$langs->trans('Querschnitt/Typ').'</td>';
print '<td><input type="text" name="medium_spec" class="flat minwidth200" value="'.dol_escape_htmltag($connection->medium_spec).'" placeholder="z.B. 5x2,5mm²"></td></tr>';
// Length
print '<tr><td>'.$langs->trans('Länge').'</td>';
print '<td><input type="text" name="medium_length" class="flat minwidth150" value="'.dol_escape_htmltag($connection->medium_length).'" placeholder="z.B. 15m"></td></tr>';
// Color
print '<tr><td>'.$langs->trans('Farbe').'</td>';
print '<td><input type="text" name="medium_color" class="flat minwidth150" value="'.dol_escape_htmltag($connection->medium_color).'" placeholder="z.B. grau"></td></tr>';
// Label
print '<tr><td>'.$langs->trans('Bezeichnung').'</td>';
print '<td><input type="text" name="label" class="flat minwidth300" value="'.dol_escape_htmltag($connection->label).'" placeholder="z.B. Zuleitung HAK"></td></tr>';
// Route description
print '<tr><td>'.$langs->trans('Verlegungsweg').'</td>';
print '<td><textarea name="route_description" class="flat" rows="3" style="width:90%;">'.dol_escape_htmltag($connection->route_description).'</textarea></td></tr>';
// Installation date
print '<tr><td>'.$langs->trans('Installationsdatum').'</td>';
print '<td><input type="date" name="installation_date" class="flat" value="'.dol_escape_htmltag($connection->installation_date).'"></td></tr>';
print '</table>';
print '<div class="center" style="margin-top:20px;">';
print '<button type="submit" class="button button-save">'.$langs->trans('Save').'</button>';
print ' <a class="button button-cancel" href="'.$backUrl.'">'.$langs->trans('Cancel').'</a>';
if ($id > 0 && $user->hasRight('kundenkarte', 'write')) {
print ' <a class="button button-delete" style="margin-left:20px;" href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&socid='.$socId.'&contactid='.$contactId.'&system_id='.$systemId.'&action=delete&token='.newToken().'" onclick="return confirm(\'Verbindung wirklich löschen?\');">'.$langs->trans('Delete').'</a>';
}
print '</div>';
print '</form>';
// Select2 mit Icons für Quelle/Ziel-Dropdowns
print '<script>
$(document).ready(function() {
function formatAnlageOption(option) {
if (!option.id) return option.text;
var picto = $(option.element).data("picto");
if (picto) {
return $("<span><i class=\"fa " + picto + "\" style=\"width:20px;margin-right:8px;text-align:center;color:#666;\"></i>" + $("<span>").text(option.text).html() + "</span>");
}
return option.text;
}
$("#fk_source, #fk_target").select2({
templateResult: formatAnlageOption,
templateSelection: formatAnlageOption,
width: "100%",
placeholder: "-- Gerät wählen --",
allowClear: true
});
});
</script>';
llxFooter();
$db->close();