kundenkarte/admin/medium_types.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

332 lines
12 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* Admin page for managing Medium Types (Kabeltypen)
*/
// Load Dolibarr environment
$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/lib/admin.lib.php';
dol_include_once('/kundenkarte/class/mediumtype.class.php');
dol_include_once('/kundenkarte/lib/kundenkarte.lib.php');
$langs->loadLangs(array("admin", "kundenkarte@kundenkarte"));
// Security check
if (!$user->admin) {
accessforbidden();
}
$action = GETPOST('action', 'aZ09');
$typeId = GETPOSTINT('typeid');
$mediumType = new MediumType($db);
// Load systems for dropdown
$systems = array();
$sql = "SELECT rowid, code, label FROM ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system WHERE active = 1 ORDER BY position, label";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$systems[$obj->rowid] = $obj;
}
}
$error = 0;
$message = '';
// Actions
if ($action == 'add' && $user->admin) {
$mediumType->ref = GETPOST('ref', 'alphanohtml');
$mediumType->label = GETPOST('label', 'alphanohtml');
$mediumType->label_short = GETPOST('label_short', 'alphanohtml');
$mediumType->description = GETPOST('description', 'restricthtml');
$mediumType->fk_system = GETPOSTINT('fk_system');
$mediumType->category = GETPOST('category', 'alphanohtml');
$mediumType->default_spec = GETPOST('default_spec', 'alphanohtml');
$mediumType->color = GETPOST('color', 'alphanohtml');
$mediumType->position = GETPOSTINT('position');
$mediumType->active = GETPOSTINT('active');
// Available specs as JSON array
$specsText = GETPOST('available_specs', 'nohtml');
if ($specsText) {
$specsArray = array_map('trim', explode(',', $specsText));
$mediumType->available_specs = json_encode($specsArray);
}
$result = $mediumType->create($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
header('Location: '.$_SERVER['PHP_SELF']);
exit;
} else {
setEventMessages($mediumType->error, $mediumType->errors, 'errors');
$action = 'create';
}
}
if ($action == 'update' && $user->admin) {
if ($mediumType->fetch($typeId) > 0) {
$mediumType->ref = GETPOST('ref', 'alphanohtml');
$mediumType->label = GETPOST('label', 'alphanohtml');
$mediumType->label_short = GETPOST('label_short', 'alphanohtml');
$mediumType->description = GETPOST('description', 'restricthtml');
$mediumType->fk_system = GETPOSTINT('fk_system');
$mediumType->category = GETPOST('category', 'alphanohtml');
$mediumType->default_spec = GETPOST('default_spec', 'alphanohtml');
$mediumType->color = GETPOST('color', 'alphanohtml');
$mediumType->position = GETPOSTINT('position');
$mediumType->active = GETPOSTINT('active');
$specsText = GETPOST('available_specs', 'nohtml');
if ($specsText) {
$specsArray = array_map('trim', explode(',', $specsText));
$mediumType->available_specs = json_encode($specsArray);
} else {
$mediumType->available_specs = '';
}
$result = $mediumType->update($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
header('Location: '.$_SERVER['PHP_SELF']);
exit;
} else {
setEventMessages($mediumType->error, $mediumType->errors, 'errors');
$action = 'edit';
}
}
}
if ($action == 'confirm_delete' && GETPOST('confirm') == 'yes' && $user->admin) {
if ($mediumType->fetch($typeId) > 0) {
$result = $mediumType->delete($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
} else {
setEventMessages($mediumType->error, $mediumType->errors, 'errors');
}
}
header('Location: '.$_SERVER['PHP_SELF']);
exit;
}
/*
* View
*/
$title = $langs->trans('MediumTypes');
llxHeader('', $title);
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($title, $linkback, 'title_setup');
// Admin tabs
$head = kundenkarteAdminPrepareHead();
print dol_get_fiche_head($head, 'medium_types', $langs->trans('KundenKarte'), -1, 'kundenkarte@kundenkarte');
// Delete confirmation
if ($action == 'delete') {
if ($mediumType->fetch($typeId) > 0) {
print $form->formconfirm(
$_SERVER['PHP_SELF'].'?typeid='.$typeId,
$langs->trans('DeleteMediumType'),
$langs->trans('ConfirmDeleteMediumType', $mediumType->label),
'confirm_delete',
'',
0,
1
);
}
}
// Add/Edit form
if (in_array($action, array('create', 'edit'))) {
if ($action == 'edit' && $typeId > 0) {
$mediumType->fetch($typeId);
}
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="'.($action == 'edit' ? 'update' : 'add').'">';
if ($action == 'edit') {
print '<input type="hidden" name="typeid" value="'.$typeId.'">';
}
print '<table class="border centpercent">';
// Ref
print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td>';
print '<td><input type="text" name="ref" value="'.dol_escape_htmltag($mediumType->ref ?: GETPOST('ref')).'" size="20" maxlength="50" required></td></tr>';
// Label
print '<tr><td class="fieldrequired">'.$langs->trans('Label').'</td>';
print '<td><input type="text" name="label" value="'.dol_escape_htmltag($mediumType->label ?: GETPOST('label')).'" size="40" maxlength="128" required></td></tr>';
// Label short
print '<tr><td>'.$langs->trans('LabelShort').'</td>';
print '<td><input type="text" name="label_short" value="'.dol_escape_htmltag($mediumType->label_short ?: GETPOST('label_short')).'" size="20" maxlength="32"></td></tr>';
// System
print '<tr><td>'.$langs->trans('System').'</td>';
print '<td><select name="fk_system" class="flat">';
print '<option value="0">'.$langs->trans('AllSystems').'</option>';
foreach ($systems as $sys) {
$selected = ($mediumType->fk_system == $sys->rowid) ? ' selected' : '';
print '<option value="'.$sys->rowid.'"'.$selected.'>'.dol_escape_htmltag($sys->label).'</option>';
}
print '</select></td></tr>';
// Category
print '<tr><td>'.$langs->trans('Category').'</td>';
print '<td><select name="category" class="flat">';
$categories = MediumType::getCategoryOptions();
foreach ($categories as $code => $label) {
$selected = ($mediumType->category == $code) ? ' selected' : '';
print '<option value="'.$code.'"'.$selected.'>'.dol_escape_htmltag($label).'</option>';
}
print '</select></td></tr>';
// Default spec
print '<tr><td>'.$langs->trans('DefaultSpec').'</td>';
print '<td><input type="text" name="default_spec" value="'.dol_escape_htmltag($mediumType->default_spec ?: GETPOST('default_spec')).'" size="20" maxlength="100">';
print '<br><span class="opacitymedium">'.$langs->trans('DefaultSpecHelp').'</span></td></tr>';
// Available specs
$specsText = '';
if ($mediumType->available_specs) {
$specsArray = json_decode($mediumType->available_specs, true);
if (is_array($specsArray)) {
$specsText = implode(', ', $specsArray);
}
}
print '<tr><td>'.$langs->trans('AvailableSpecs').'</td>';
print '<td><input type="text" name="available_specs" value="'.dol_escape_htmltag($specsText ?: GETPOST('available_specs')).'" size="60">';
print '<br><span class="opacitymedium">'.$langs->trans('AvailableSpecsHelp').'</span></td></tr>';
// Color
print '<tr><td>'.$langs->trans('Color').'</td>';
print '<td><input type="color" name="color" value="'.dol_escape_htmltag($mediumType->color ?: '#666666').'" style="width:50px;height:30px;">';
print ' <input type="text" name="color_text" value="'.dol_escape_htmltag($mediumType->color ?: '#666666').'" size="10" onchange="this.form.color.value=this.value" placeholder="#RRGGBB"></td></tr>';
// Position
print '<tr><td>'.$langs->trans('Position').'</td>';
print '<td><input type="number" name="position" value="'.((int) ($mediumType->position ?: GETPOSTINT('position'))).'" min="0" max="999"></td></tr>';
// Status
print '<tr><td>'.$langs->trans('Status').'</td>';
print '<td><select name="active" class="flat">';
$activeValue = ($action == 'edit') ? $mediumType->active : 1;
print '<option value="1"'.($activeValue == 1 ? ' selected' : '').'>'.$langs->trans('Enabled').'</option>';
print '<option value="0"'.($activeValue == 0 ? ' selected' : '').'>'.$langs->trans('Disabled').'</option>';
print '</select></td></tr>';
// Description
print '<tr><td>'.$langs->trans('Description').'</td>';
print '<td><textarea name="description" rows="3" cols="60">'.dol_escape_htmltag($mediumType->description ?: GETPOST('description')).'</textarea></td></tr>';
print '</table>';
print '<div class="center" style="margin-top:15px;">';
print '<input type="submit" class="button button-save" value="'.$langs->trans('Save').'">';
print ' <a class="button button-cancel" href="'.$_SERVER['PHP_SELF'].'">'.$langs->trans('Cancel').'</a>';
print '</div>';
print '</form>';
} else {
// List view
// Button to add
print '<div class="tabsAction">';
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?action=create">'.$langs->trans('AddMediumType').'</a>';
print '</div>';
// Filter by category
$filterCategory = GETPOST('filter_category', 'alphanohtml');
print '<form method="GET" action="'.$_SERVER['PHP_SELF'].'" style="margin-bottom:15px;">';
print '<label>'.$langs->trans('FilterByCategory').': </label>';
print '<select name="filter_category" class="flat" onchange="this.form.submit()">';
print '<option value="">'.$langs->trans('All').'</option>';
$categories = MediumType::getCategoryOptions();
foreach ($categories as $code => $label) {
$selected = ($filterCategory == $code) ? ' selected' : '';
print '<option value="'.$code.'"'.$selected.'>'.dol_escape_htmltag($label).'</option>';
}
print '</select>';
print '</form>';
// List
$allTypes = $mediumType->fetchAllBySystem(0, 0);
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th>'.$langs->trans('Ref').'</th>';
print '<th>'.$langs->trans('Label').'</th>';
print '<th>'.$langs->trans('Category').'</th>';
print '<th>'.$langs->trans('System').'</th>';
print '<th>'.$langs->trans('DefaultSpec').'</th>';
print '<th class="center">'.$langs->trans('Color').'</th>';
print '<th class="center">'.$langs->trans('Position').'</th>';
print '<th class="center">'.$langs->trans('Status').'</th>';
print '<th class="center">'.$langs->trans('Actions').'</th>';
print '</tr>';
if (empty($allTypes)) {
print '<tr><td colspan="9" class="opacitymedium">'.$langs->trans('NoRecords').'</td></tr>';
} else {
$i = 0;
foreach ($allTypes as $t) {
// Filter
if ($filterCategory && $t->category != $filterCategory) continue;
print '<tr class="oddeven">';
print '<td><strong>'.dol_escape_htmltag($t->ref).'</strong></td>';
print '<td>'.dol_escape_htmltag($t->label);
if ($t->label_short) print ' <span class="opacitymedium">('.dol_escape_htmltag($t->label_short).')</span>';
print '</td>';
print '<td>'.dol_escape_htmltag($t->getCategoryLabel()).'</td>';
print '<td>';
if ($t->fk_system > 0 && $t->system_label) {
print dol_escape_htmltag($t->system_label);
} else {
print '<em>'.$langs->trans('AllSystems').'</em>';
}
print '</td>';
print '<td>'.dol_escape_htmltag($t->default_spec).'</td>';
print '<td class="center"><span style="display:inline-block;width:20px;height:20px;background:'.dol_escape_htmltag($t->color ?: '#ccc').';border:1px solid #999;border-radius:3px;"></span></td>';
print '<td class="center">'.$t->position.'</td>';
print '<td class="center">';
print $t->active ? '<span class="badge badge-status4">'.$langs->trans('Enabled').'</span>' : '<span class="badge badge-status5">'.$langs->trans('Disabled').'</span>';
print '</td>';
print '<td class="center nowraponall">';
print '<a href="'.$_SERVER['PHP_SELF'].'?action=edit&typeid='.$t->id.'"><i class="fa fa-edit" title="'.$langs->trans('Edit').'"></i></a>';
if (!$t->is_system) {
print ' <a href="'.$_SERVER['PHP_SELF'].'?action=delete&typeid='.$t->id.'"><i class="fa fa-trash" style="color:#c00;" title="'.$langs->trans('Delete').'"></i></a>';
}
print '</td>';
print '</tr>';
$i++;
}
}
print '</table>';
}
print dol_get_fiche_end();
// JavaScript for color picker sync
print '<script>
document.querySelector("input[name=color]").addEventListener("input", function() {
document.querySelector("input[name=color_text]").value = this.value;
});
</script>';
llxFooter();
$db->close();