Version 3.2.1 - System-agnostische Begriffe & Globale Typen

Änderungen:
- Sammelschienen-Typen: Elektrische Begriffe durch system-agnostische ersetzt
  - "Phasenschienen" -> "Sammelschienen"
  - "Phasen" -> "Kanäle" (Channels)
  - Presets: L1/L2/L3/N/PE -> A/B/C/AB/ABC (+ Rückwärtskompatibilität)
- Alle Admin-Seiten: Session-basierte Filter-Persistenz hinzugefügt
- Element-Typen & Sammelschienen-Typen: "Alle Systeme" Option für globale Typen
- fetchAllBySystem() Methoden: Globale Typen (fk_system=0/NULL) einbezogen
- Sprachdatei: Neue Übersetzungen (AllSystems, AllSystemsHint, Channels, etc.)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-02-16 11:22:58 +01:00
parent 5d05ac9f68
commit 1360b061b7
7 changed files with 105 additions and 49 deletions

View file

@ -24,7 +24,17 @@ if (!$user->admin && !$user->hasRight('kundenkarte', 'admin')) {
$action = GETPOST('action', 'aZ09');
$confirm = GETPOST('confirm', 'alpha');
$typeId = GETPOSTINT('typeid');
$systemFilter = GETPOSTINT('system');
// System filter - save in session for persistence
$sessionKey = 'kundenkarte_anlage_types_system_filter';
if (GETPOSTISSET('system')) {
$systemFilter = GETPOSTINT('system');
$_SESSION[$sessionKey] = $systemFilter;
} elseif (isset($_SESSION[$sessionKey])) {
$systemFilter = $_SESSION[$sessionKey];
} else {
$systemFilter = 0;
}
$form = new Form($db);
$anlageType = new AnlageType($db);
@ -58,7 +68,7 @@ if ($action == 'add') {
$anlageType->position = GETPOSTINT('position');
$anlageType->active = 1;
if (empty($anlageType->ref) || empty($anlageType->label) || empty($anlageType->fk_system)) {
if (empty($anlageType->ref) || empty($anlageType->label)) {
setEventMessages($langs->trans('ErrorFieldRequired'), null, 'errors');
$action = 'create';
} else {
@ -329,14 +339,17 @@ if (in_array($action, array('create', 'edit'))) {
print '<table class="border centpercent">';
// System
print '<tr><td class="titlefield fieldrequired">'.$langs->trans('System').'</td>';
print '<td><select name="fk_system" class="flat minwidth200" required>';
print '<option value="">'.$langs->trans('SelectSystem').'</option>';
print '<tr><td class="titlefield">'.$langs->trans('System').'</td>';
print '<td><select name="fk_system" class="flat minwidth200">';
$selAll = (empty($anlageType->fk_system)) ? ' selected' : '';
print '<option value="0"'.$selAll.'>'.$langs->trans('AllSystems').'</option>';
foreach ($systems as $sys) {
$sel = ($anlageType->fk_system == $sys->rowid) ? ' selected' : '';
print '<option value="'.$sys->rowid.'"'.$sel.'>'.dol_escape_htmltag($sys->label).'</option>';
}
print '</select></td></tr>';
print '</select>';
print ' <span class="opacitymedium">('.$langs->trans('AllSystemsHint').')</span>';
print '</td></tr>';
// Reference
print '<tr><td class="fieldrequired">'.$langs->trans('TypeRef').'</td>';
@ -632,7 +645,11 @@ if (in_array($action, array('create', 'edit'))) {
}
print '</td>';
print '<td>'.dol_escape_htmltag($type->system_label).'</td>';
if (empty($type->fk_system)) {
print '<td><span class="badge badge-info">'.$langs->trans('AllSystems').'</span></td>';
} else {
print '<td>'.dol_escape_htmltag($type->system_label).'</td>';
}
print '<td class="center">'.($type->can_have_children ? img_picto('', 'tick') : '').'</td>';
print '<td class="center">'.$type->position.'</td>';

View file

@ -1,7 +1,7 @@
<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* Admin page to manage busbar/phase rail types (Phasenschienen-Typen)
* Admin page to manage busbar types (Sammelschienen-Typen)
*/
$res = 0;
@ -24,7 +24,17 @@ if (!$user->admin && !$user->hasRight('kundenkarte', 'admin')) {
$action = GETPOST('action', 'aZ09');
$confirm = GETPOST('confirm', 'alpha');
$typeId = GETPOSTINT('typeid');
$systemFilter = GETPOSTINT('system');
// System filter - save in session for persistence
$sessionKey = 'kundenkarte_busbar_types_system_filter';
if (GETPOSTISSET('system')) {
$systemFilter = GETPOSTINT('system');
$_SESSION[$sessionKey] = $systemFilter;
} elseif (isset($_SESSION[$sessionKey])) {
$systemFilter = $_SESSION[$sessionKey];
} else {
$systemFilter = 0;
}
$form = new Form($db);
$busbarType = new BusbarType($db);
@ -49,17 +59,19 @@ if ($resql) {
}
}
// Predefined phase configurations
$phasePresets = array(
'L1' => array('label' => 'L1 (Phase 1)', 'num_lines' => 1, 'colors' => '#e74c3c'),
'L2' => array('label' => 'L2 (Phase 2)', 'num_lines' => 1, 'colors' => '#2ecc71'),
'L3' => array('label' => 'L3 (Phase 3)', 'num_lines' => 1, 'colors' => '#9b59b6'),
'N' => array('label' => 'N (Neutralleiter)', 'num_lines' => 1, 'colors' => '#3498db'),
'PE' => array('label' => 'PE (Schutzleiter)', 'num_lines' => 1, 'colors' => '#f1c40f'),
'L1N' => array('label' => 'L1+N (Wechselstrom)', 'num_lines' => 2, 'colors' => '#e74c3c,#3498db'),
'3P' => array('label' => '3P (Drehstrom)', 'num_lines' => 3, 'colors' => '#e74c3c,#2ecc71,#9b59b6'),
'3P+N' => array('label' => '3P+N (Drehstrom+N)', 'num_lines' => 4, 'colors' => '#e74c3c,#2ecc71,#9b59b6,#3498db'),
'3P+N+PE' => array('label' => '3P+N+PE (Vollausstattung)', 'num_lines' => 5, 'colors' => '#e74c3c,#2ecc71,#9b59b6,#3498db,#f1c40f'),
// Predefined channel configurations (system-independent)
$channelPresets = array(
// General presets
'A' => array('label' => 'Kanal A (1 Linie)', 'num_lines' => 1, 'colors' => '#e74c3c'),
'B' => array('label' => 'Kanal B (1 Linie)', 'num_lines' => 1, 'colors' => '#2ecc71'),
'C' => array('label' => 'Kanal C (1 Linie)', 'num_lines' => 1, 'colors' => '#9b59b6'),
'AB' => array('label' => 'Kanal A+B (2 Linien)', 'num_lines' => 2, 'colors' => '#e74c3c,#2ecc71'),
'ABC' => array('label' => 'Kanal A+B+C (3 Linien)', 'num_lines' => 3, 'colors' => '#e74c3c,#2ecc71,#9b59b6'),
'4CH' => array('label' => '4 Kanaele', 'num_lines' => 4, 'colors' => '#e74c3c,#2ecc71,#9b59b6,#3498db'),
'5CH' => array('label' => '5 Kanaele', 'num_lines' => 5, 'colors' => '#e74c3c,#2ecc71,#9b59b6,#3498db,#f1c40f'),
// Electrical presets (for backward compatibility)
'L1' => array('label' => 'L1 (Strom)', 'num_lines' => 1, 'colors' => '#e74c3c'),
'3P+N' => array('label' => '3P+N (Strom)', 'num_lines' => 4, 'colors' => '#e74c3c,#2ecc71,#9b59b6,#3498db'),
);
/*
@ -84,7 +96,7 @@ if ($action == 'add') {
$busbarType->position = GETPOSTINT('position');
$busbarType->active = 1;
if (empty($busbarType->ref) || empty($busbarType->label) || empty($busbarType->fk_system) || empty($busbarType->phases)) {
if (empty($busbarType->ref) || empty($busbarType->label) || empty($busbarType->phases)) {
setEventMessages($langs->trans('ErrorFieldRequired'), null, 'errors');
$action = 'create';
} else {
@ -223,28 +235,32 @@ if ($action == 'create' || $action == 'edit') {
print '<td><textarea name="description" class="flat" rows="3" cols="60">'.dol_escape_htmltag($busbarType->description).'</textarea></td></tr>';
// System
print '<tr><td class="fieldrequired">'.$langs->trans('System').'</td>';
print '<td><select name="fk_system" class="flat" required>';
print '<tr><td>'.$langs->trans('System').'</td>';
print '<td><select name="fk_system" class="flat">';
$selectedAll = (empty($busbarType->fk_system) && $action == 'edit') || ($action == 'create' && $systemFilter == 0) ? ' selected' : '';
print '<option value="0"'.$selectedAll.'>'.$langs->trans('AllSystems').'</option>';
foreach ($systems as $sys) {
$selected = ($busbarType->fk_system == $sys->rowid || ($action == 'create' && $systemFilter == $sys->rowid)) ? ' selected' : '';
$selected = ($busbarType->fk_system == $sys->rowid || ($action == 'create' && $systemFilter == $sys->rowid && $systemFilter > 0)) ? ' selected' : '';
print '<option value="'.$sys->rowid.'"'.$selected.'>'.dol_escape_htmltag($sys->label).'</option>';
}
print '</select></td></tr>';
print '</select>';
print '<div class="opacitymedium small">'.$langs->trans('AllSystemsHint').'</div>';
print '</td></tr>';
// Phase configuration
print '<tr><td class="fieldrequired">'.$langs->trans('Phases').'</td>';
// Channel configuration
print '<tr><td class="fieldrequired">'.$langs->trans('Channels').'</td>';
print '<td>';
print '<div style="margin-bottom:10px;">';
print '<strong>Schnellauswahl:</strong><br>';
foreach ($phasePresets as $code => $preset) {
print '<strong>'.$langs->trans('QuickSelect').':</strong><br>';
foreach ($channelPresets as $code => $preset) {
$style = 'display:inline-block;margin:3px;padding:5px 10px;border:1px solid #ccc;border-radius:4px;cursor:pointer;background:#f8f8f8;';
print '<span class="phase-preset" data-phases="'.$code.'" data-numlines="'.$preset['num_lines'].'" data-colors="'.$preset['colors'].'" style="'.$style.'">';
print '<span class="channel-preset" data-channels="'.$code.'" data-numlines="'.$preset['num_lines'].'" data-colors="'.$preset['colors'].'" style="'.$style.'">';
print dol_escape_htmltag($preset['label']);
print '</span>';
}
print '</div>';
print '<input type="text" name="phases" id="phases-input" class="flat minwidth150" value="'.dol_escape_htmltag($busbarType->phases).'" placeholder="z.B. L1N, 3P, 3P+N" required>';
print '<div class="opacitymedium small">Phasen-Konfiguration: L1, L2, L3, N, PE oder Kombinationen wie L1N, 3P, 3P+N, 3P+N+PE</div>';
print '<input type="text" name="phases" id="channels-input" class="flat minwidth150" value="'.dol_escape_htmltag($busbarType->phases).'" placeholder="z.B. A, AB, ABC" required>';
print '<div class="opacitymedium small">'.$langs->trans('ChannelsHint').'</div>';
print '</td></tr>';
// Number of lines
@ -310,9 +326,9 @@ if ($action == 'create' || $action == 'edit') {
// JavaScript for preset selection and preview
print '<script>
document.querySelectorAll(".phase-preset").forEach(function(el) {
document.querySelectorAll(".channel-preset").forEach(function(el) {
el.addEventListener("click", function() {
document.getElementById("phases-input").value = this.dataset.phases;
document.getElementById("channels-input").value = this.dataset.channels;
document.getElementById("numlines-input").value = this.dataset.numlines;
document.getElementById("colors-input").value = this.dataset.colors;
updatePreview();
@ -359,7 +375,7 @@ if ($action == 'create' || $action == 'edit') {
print '<tr class="liste_titre">';
print '<th>'.$langs->trans('Ref').'</th>';
print '<th>'.$langs->trans('Label').'</th>';
print '<th>'.$langs->trans('Phases').'</th>';
print '<th>'.$langs->trans('Channels').'</th>';
print '<th class="center">'.$langs->trans('Lines').'</th>';
print '<th>'.$langs->trans('Colors').'</th>';
print '<th>'.$langs->trans('System').'</th>';
@ -390,7 +406,13 @@ if ($action == 'create' || $action == 'edit') {
}
print '</td>';
print '<td>'.dol_escape_htmltag($type->system_label).'</td>';
print '<td>';
if (empty($type->fk_system)) {
print '<span class="badge badge-secondary">'.$langs->trans('AllSystems').'</span>';
} else {
print dol_escape_htmltag($type->system_label);
}
print '</td>';
print '<td class="center">'.$type->position.'</td>';
// Status

View file

@ -24,7 +24,17 @@ if (!$user->admin && !$user->hasRight('kundenkarte', 'admin')) {
$action = GETPOST('action', 'aZ09');
$confirm = GETPOST('confirm', 'alpha');
$typeId = GETPOSTINT('typeid');
$systemFilter = GETPOSTINT('system');
// System filter - save in session for persistence
$sessionKey = 'kundenkarte_equipment_types_system_filter';
if (GETPOSTISSET('system')) {
$systemFilter = GETPOSTINT('system');
$_SESSION[$sessionKey] = $systemFilter;
} elseif (isset($_SESSION[$sessionKey])) {
$systemFilter = $_SESSION[$sessionKey];
} else {
$systemFilter = 0;
}
$form = new Form($db);
$equipmentType = new EquipmentType($db);

View file

@ -280,7 +280,8 @@ class AnlageType extends CommonObject
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON t.fk_system = s.rowid";
$sql .= " WHERE 1 = 1";
if ($systemId > 0) {
$sql .= " AND t.fk_system = ".((int) $systemId);
// Show types for this system AND global types (fk_system = 0 or NULL)
$sql .= " AND (t.fk_system = ".((int) $systemId)." OR t.fk_system = 0 OR t.fk_system IS NULL)";
}
if ($activeOnly) {
$sql .= " AND t.active = 1";

View file

@ -9,7 +9,7 @@
/**
* Class BusbarType
* Manages busbar/phase rail type templates (Phasenschienen-Typen)
* Manages busbar type templates (Sammelschienen-Typen)
*/
class BusbarType extends CommonObject
{
@ -23,7 +23,7 @@ class BusbarType extends CommonObject
public $fk_system;
// Busbar-spezifische Felder
public $phases; // L1, L2, L3, N, PE, L1N, 3P, 3P+N, etc.
public $phases; // Channel configuration (A, B, AB, ABC, or legacy L1, L2, L3, N, PE, etc.)
public $num_lines = 1; // Anzahl der Linien
public $color; // Kommagetrennte Farben
public $default_color; // Standard-Einzelfarbe
@ -71,7 +71,7 @@ class BusbarType extends CommonObject
$error = 0;
$now = dol_now();
if (empty($this->ref) || empty($this->label) || empty($this->fk_system) || empty($this->phases)) {
if (empty($this->ref) || empty($this->label) || empty($this->phases)) {
$this->error = 'ErrorMissingParameters';
return -1;
}
@ -298,7 +298,8 @@ class BusbarType extends CommonObject
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON t.fk_system = s.rowid";
$sql .= " WHERE 1 = 1";
if ($systemId > 0) {
$sql .= " AND t.fk_system = ".((int) $systemId);
// Show types for this system AND global types (fk_system = 0 or NULL)
$sql .= " AND (t.fk_system = ".((int) $systemId)." OR t.fk_system = 0 OR t.fk_system IS NULL)";
}
if ($activeOnly) {
$sql .= " AND t.active = 1";

View file

@ -76,7 +76,7 @@ class modKundenKarte extends DolibarrModules
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@kundenkarte'
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
$this->version = '3.1';
$this->version = '3.2.1';
// Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
@ -114,8 +114,10 @@ class modKundenKarte extends DolibarrModules
'/kundenkarte/css/kundenkarte.css',
),
// Set this to relative path of js file if module must load a js on all pages
// DISABLED: Loading 438KB JS globally causes conflicts with Dolibarr file upload
// The JS is now loaded only on kundenkarte pages via explicit include
'js' => array(
'/kundenkarte/js/kundenkarte.js',
// '/kundenkarte/js/kundenkarte.js',
),
// Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context to 'all'
/* BEGIN MODULEBUILDER HOOKSCONTEXTS */

View file

@ -44,6 +44,8 @@ EditElement = Element bearbeiten
DeleteElement = Element loeschen
NoInstallations = Keine Installationen vorhanden
SelectSystem = System auswaehlen
AllSystems = Alle Systeme
AllSystemsHint = Leer lassen fuer alle Systeme
SelectType = Typ auswaehlen
SelectParent = Uebergeordnetes Element
Root = Stamm
@ -230,11 +232,12 @@ AddOutput = Abgang hinzufuegen
AddRail = Sammelschiene hinzufuegen
AddBusbar = Sammelschiene hinzufuegen
Busbar = Sammelschiene
BusbarTypes = Phasenschienen-Typen
NewBusbarType = Neuer Phasenschienen-Typ
DeleteBusbarType = Phasenschienen-Typ loeschen
ConfirmDeleteBusbarType = Moechten Sie den Phasenschienen-Typ "%s" wirklich loeschen?
Phases = Phasen
BusbarTypes = Sammelschienen-Typen
NewBusbarType = Neuer Sammelschienen-Typ
DeleteBusbarType = Sammelschienen-Typ loeschen
ConfirmDeleteBusbarType = Moechten Sie den Sammelschienen-Typ "%s" wirklich loeschen?
Channels = Kanaele
ChannelsHint = Konfigurations-ID (z.B. A, B, AB, 1-2-3)
NumLines = Anzahl Linien
Colors = Farben
DefaultColor = Standardfarbe