kundenkarte/admin/busbar_types.php
2026-03-04 15:35:25 +01:00

488 lines
20 KiB
PHP

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* Admin page to manage busbar types (Sammelschienen-Typen)
*/
$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';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
dol_include_once('/kundenkarte/lib/kundenkarte.lib.php');
dol_include_once('/kundenkarte/class/busbartype.class.php');
$langs->loadLangs(array('admin', 'kundenkarte@kundenkarte', 'products'));
// Security check
if (!$user->admin && !$user->hasRight('kundenkarte', 'admin')) {
accessforbidden();
}
$action = GETPOST('action', 'aZ09');
$confirm = GETPOST('confirm', 'alpha');
$typeId = GETPOSTINT('typeid');
// 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);
// Load systems
$systems = array();
$sql = "SELECT rowid, code, label FROM ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system WHERE active = 1 ORDER BY position ASC";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$systems[$obj->rowid] = $obj;
}
}
// Load products for dropdown
$products = array();
$sql = "SELECT rowid, ref, label FROM ".MAIN_DB_PREFIX."product WHERE tosell = 1 ORDER BY ref ASC";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$products[$obj->rowid] = $obj;
}
}
// 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'),
);
/*
* Actions
*/
if ($action == 'add') {
$busbarType->ref = GETPOST('ref', 'aZ09');
$busbarType->label = GETPOST('label', 'alphanohtml');
$busbarType->label_short = GETPOST('label_short', 'alphanohtml');
$busbarType->description = GETPOST('description', 'restricthtml');
$busbarType->fk_system = GETPOSTINT('fk_system');
$busbarType->phases = GETPOST('phases', 'alphanohtml');
// Convert comma-separated phases_config to JSON array
$phasesConfigInput = GETPOST('phases_config', 'alphanohtml');
if (!empty($phasesConfigInput)) {
$arr = array_map('trim', explode(',', $phasesConfigInput));
$busbarType->phases_config = json_encode($arr);
}
$busbarType->num_lines = GETPOSTINT('num_lines');
$busbarType->color = GETPOST('color', 'alphanohtml');
$busbarType->default_color = GETPOST('default_color', 'alphanohtml');
$busbarType->line_height = GETPOSTINT('line_height') ?: 3;
$busbarType->line_spacing = GETPOSTINT('line_spacing') ?: 4;
$busbarType->position_default = GETPOST('position_default', 'alphanohtml') ?: 'below';
$busbarType->fk_product = GETPOSTINT('fk_product');
$busbarType->picto = GETPOST('picto', 'alphanohtml');
$busbarType->position = GETPOSTINT('position');
$busbarType->active = 1;
if (empty($busbarType->ref) || empty($busbarType->label) || empty($busbarType->phases)) {
setEventMessages($langs->trans('ErrorFieldRequired'), null, 'errors');
$action = 'create';
} else {
$result = $busbarType->create($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
header('Location: '.$_SERVER['PHP_SELF'].'?system='.$busbarType->fk_system);
exit;
} else {
setEventMessages($busbarType->error, $busbarType->errors, 'errors');
$action = 'create';
}
}
}
if ($action == 'update') {
$busbarType->fetch($typeId);
$busbarType->ref = GETPOST('ref', 'aZ09');
$busbarType->label = GETPOST('label', 'alphanohtml');
$busbarType->label_short = GETPOST('label_short', 'alphanohtml');
$busbarType->description = GETPOST('description', 'restricthtml');
$busbarType->fk_system = GETPOSTINT('fk_system');
$busbarType->phases = GETPOST('phases', 'alphanohtml');
// Convert comma-separated phases_config to JSON array
$phasesConfigInput = GETPOST('phases_config', 'alphanohtml');
if (!empty($phasesConfigInput)) {
$arr = array_map('trim', explode(',', $phasesConfigInput));
$busbarType->phases_config = json_encode($arr);
} else {
$busbarType->phases_config = null;
}
$busbarType->num_lines = GETPOSTINT('num_lines');
$busbarType->color = GETPOST('color', 'alphanohtml');
$busbarType->default_color = GETPOST('default_color', 'alphanohtml');
$busbarType->line_height = GETPOSTINT('line_height') ?: 3;
$busbarType->line_spacing = GETPOSTINT('line_spacing') ?: 4;
$busbarType->position_default = GETPOST('position_default', 'alphanohtml') ?: 'below';
$busbarType->fk_product = GETPOSTINT('fk_product');
$busbarType->picto = GETPOST('picto', 'alphanohtml');
$busbarType->position = GETPOSTINT('position');
$result = $busbarType->update($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
header('Location: '.$_SERVER['PHP_SELF'].'?system='.$busbarType->fk_system);
exit;
} else {
setEventMessages($busbarType->error, $busbarType->errors, 'errors');
$action = 'edit';
}
}
if ($action == 'confirm_delete' && $confirm == 'yes') {
$busbarType->fetch($typeId);
$result = $busbarType->delete($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
} else {
setEventMessages($busbarType->error, $busbarType->errors, 'errors');
}
$action = '';
}
if ($action == 'activate') {
$sql = "UPDATE ".MAIN_DB_PREFIX."kundenkarte_busbar_type SET active = 1 WHERE rowid = ".((int) $typeId);
$db->query($sql);
$action = '';
}
if ($action == 'deactivate') {
$sql = "UPDATE ".MAIN_DB_PREFIX."kundenkarte_busbar_type SET active = 0 WHERE rowid = ".((int) $typeId);
$db->query($sql);
$action = '';
}
/*
* View
*/
llxHeader('', $langs->trans('BusbarTypes'));
$head = kundenkarteAdminPrepareHead();
print dol_get_fiche_head($head, 'busbar_types', $langs->trans('KundenkarteSetup'), -1, 'kundenkarte@kundenkarte');
// System filter
print '<div class="tabBar" style="margin-bottom:15px;">';
print '<form method="get" action="'.$_SERVER['PHP_SELF'].'">';
print $langs->trans('System').': ';
print '<select name="system" class="flat" onchange="this.form.submit()">';
print '<option value="0">'.$langs->trans('All').'</option>';
foreach ($systems as $sys) {
$selected = ($systemFilter == $sys->rowid) ? ' selected' : '';
print '<option value="'.$sys->rowid.'"'.$selected.'>'.dol_escape_htmltag($sys->label).'</option>';
}
print '</select>';
print ' <button type="submit" class="button">'.$langs->trans('Filter').'</button>';
print ' <a class="button" href="'.$_SERVER['PHP_SELF'].'?action=create&system='.$systemFilter.'">'.$langs->trans('NewBusbarType').'</a>';
print '</form>';
print '</div>';
// Delete confirmation
if ($action == 'delete') {
$busbarType->fetch($typeId);
print $form->formconfirm(
$_SERVER['PHP_SELF'].'?typeid='.$typeId.'&system='.$systemFilter,
$langs->trans('DeleteBusbarType'),
$langs->trans('ConfirmDeleteBusbarType', $busbarType->label),
'confirm_delete',
'',
0,
1
);
}
// Create/Edit form
if ($action == 'create' || $action == 'edit') {
if ($action == 'edit') {
$busbarType->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="'.$busbarType->id.'">';
}
print '<table class="border centpercent">';
// Ref
print '<tr><td class="fieldrequired">'.$langs->trans('Ref').'</td>';
print '<td><input type="text" name="ref" class="flat minwidth200" value="'.dol_escape_htmltag($busbarType->ref).'" required></td></tr>';
// Label
print '<tr><td class="fieldrequired">'.$langs->trans('Label').'</td>';
print '<td><input type="text" name="label" class="flat minwidth300" value="'.dol_escape_htmltag($busbarType->label).'" required></td></tr>';
// Label Short
print '<tr><td>'.$langs->trans('LabelShort').'</td>';
print '<td><input type="text" name="label_short" class="flat minwidth100" value="'.dol_escape_htmltag($busbarType->label_short).'" maxlength="32"></td></tr>';
// Description
print '<tr><td>'.$langs->trans('Description').'</td>';
print '<td><textarea name="description" class="flat" rows="3" cols="60">'.dol_escape_htmltag($busbarType->description).'</textarea></td></tr>';
// System
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 && $systemFilter > 0)) ? ' selected' : '';
print '<option value="'.$sys->rowid.'"'.$selected.'>'.dol_escape_htmltag($sys->label).'</option>';
}
print '</select>';
print '<div class="opacitymedium small">'.$langs->trans('AllSystemsHint').'</div>';
print '</td></tr>';
// Channel configuration
print '<tr><td class="fieldrequired">'.$langs->trans('Channels').'</td>';
print '<td>';
print '<div style="margin-bottom:10px;">';
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="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="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
print '<tr><td>'.$langs->trans('NumLines').'</td>';
print '<td><input type="number" name="num_lines" id="numlines-input" class="flat" value="'.($busbarType->num_lines ?: 1).'" min="1" max="10"></td></tr>';
// Phase labels per line (phases_config)
$phasesConfigVal = '';
if (!empty($busbarType->phases_config)) {
$arr = json_decode($busbarType->phases_config, true);
if (is_array($arr)) {
$phasesConfigVal = implode(',', $arr);
}
}
print '<tr><td>'.$langs->trans('PhaseLabels').'</td>';
print '<td>';
print '<input type="text" name="phases_config" id="phases-config-input" class="flat minwidth200" value="'.dol_escape_htmltag($phasesConfigVal).'" placeholder="L1,L2,L3">';
print '<div class="opacitymedium small">Kommagetrennte Bezeichnungen pro Linie, wiederholen sich (z.B. L1,L2,L3 oder L1,N)</div>';
print '</td></tr>';
// Colors
print '<tr><td>'.$langs->trans('Colors').'</td>';
print '<td>';
print '<input type="text" name="color" id="colors-input" class="flat minwidth300" value="'.dol_escape_htmltag($busbarType->color).'" placeholder="Kommagetrennt: #e74c3c,#3498db">';
print '<div class="opacitymedium small">Kommagetrennte Farbcodes fuer jede Linie (z.B. #e74c3c,#2ecc71,#9b59b6)</div>';
print '</td></tr>';
// Default color
print '<tr><td>'.$langs->trans('DefaultColor').'</td>';
print '<td><input type="color" name="default_color" class="flat" value="'.($busbarType->default_color ?: '#e74c3c').'" style="width:60px;height:30px;"></td></tr>';
// Line height
print '<tr><td>'.$langs->trans('LineHeight').'</td>';
print '<td><input type="number" name="line_height" class="flat" value="'.($busbarType->line_height ?: 3).'" min="1" max="10"> px</td></tr>';
// Line spacing
print '<tr><td>'.$langs->trans('LineSpacing').'</td>';
print '<td><input type="number" name="line_spacing" class="flat" value="'.($busbarType->line_spacing ?: 4).'" min="1" max="20"> px</td></tr>';
// Default position
print '<tr><td>'.$langs->trans('DefaultPosition').'</td>';
print '<td><select name="position_default" class="flat">';
print '<option value="below"'.($busbarType->position_default == 'below' ? ' selected' : '').'>Unterhalb (below)</option>';
print '<option value="above"'.($busbarType->position_default == 'above' ? ' selected' : '').'>Oberhalb (above)</option>';
print '</select></td></tr>';
// Product link
print '<tr><td>'.$langs->trans('LinkedProduct').'</td>';
print '<td><select name="fk_product" class="flat minwidth300">';
print '<option value="0">-- '.$langs->trans('None').' --</option>';
foreach ($products as $prod) {
$selected = ($busbarType->fk_product == $prod->rowid) ? ' selected' : '';
print '<option value="'.$prod->rowid.'"'.$selected.'>'.dol_escape_htmltag($prod->ref.' - '.$prod->label).'</option>';
}
print '</select></td></tr>';
// Position
print '<tr><td>'.$langs->trans('Position').'</td>';
print '<td><input type="number" name="position" class="flat" value="'.($busbarType->position ?: 0).'" min="0"></td></tr>';
// Preview
print '<tr><td>'.$langs->trans('Preview').'</td>';
print '<td>';
print '<div id="busbar-preview" style="background:#1a1a2e;padding:20px;border-radius:8px;min-height:80px;">';
print '<svg id="preview-svg" width="200" height="60"></svg>';
print '</div>';
print '</td></tr>';
print '</table>';
print '<div class="center" style="margin-top:20px;">';
print '<button type="submit" class="button">'.$langs->trans('Save').'</button>';
print ' <a class="button button-cancel" href="'.$_SERVER['PHP_SELF'].'?system='.$systemFilter.'">'.$langs->trans('Cancel').'</a>';
print '</div>';
print '</form>';
// JavaScript for preset selection and preview
print '<script>
document.querySelectorAll(".channel-preset").forEach(function(el) {
el.addEventListener("click", function() {
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();
});
});
function updatePreview() {
var numLines = parseInt(document.getElementById("numlines-input").value) || 1;
var colorsStr = document.getElementById("colors-input").value;
var colors = colorsStr ? colorsStr.split(",") : ["#e74c3c"];
var lineHeight = parseInt(document.querySelector("input[name=line_height]").value) || 3;
var lineSpacing = parseInt(document.querySelector("input[name=line_spacing]").value) || 4;
var svg = document.getElementById("preview-svg");
var html = "";
var y = 10;
for (var i = 0; i < numLines; i++) {
var color = colors[i % colors.length] || "#e74c3c";
html += "<rect x=\"10\" y=\"" + y + "\" width=\"180\" height=\"" + lineHeight + "\" fill=\"" + color + "\" rx=\"1\"/>";
y += lineHeight + lineSpacing;
}
svg.innerHTML = html;
svg.setAttribute("height", y + 10);
}
// Update preview on input change
document.getElementById("numlines-input").addEventListener("change", updatePreview);
document.getElementById("colors-input").addEventListener("input", updatePreview);
document.querySelector("input[name=line_height]").addEventListener("change", updatePreview);
document.querySelector("input[name=line_spacing]").addEventListener("change", updatePreview);
// Initial preview
updatePreview();
</script>';
} else {
// List of busbar types
$types = $busbarType->fetchAllBySystem($systemFilter, 0);
print '<div class="div-table-responsive">';
print '<table class="tagtable nobordernopadding liste centpercent">';
print '<tr class="liste_titre">';
print '<th>'.$langs->trans('Ref').'</th>';
print '<th>'.$langs->trans('Label').'</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>';
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($types)) {
print '<tr><td colspan="9" class="opacitymedium">'.$langs->trans('NoRecordFound').'</td></tr>';
} else {
foreach ($types as $type) {
print '<tr class="oddeven">';
print '<td><a href="'.$_SERVER['PHP_SELF'].'?action=edit&typeid='.$type->id.'&system='.$systemFilter.'">'.dol_escape_htmltag($type->ref).'</a></td>';
print '<td>'.dol_escape_htmltag($type->label);
if ($type->label_short) {
print ' <span class="opacitymedium">('.dol_escape_htmltag($type->label_short).')</span>';
}
print '</td>';
print '<td>'.dol_escape_htmltag($type->phases).'</td>';
print '<td class="center">'.$type->num_lines.'</td>';
// Color preview
print '<td>';
$colors = $type->color ? explode(',', $type->color) : array($type->default_color ?: '#e74c3c');
foreach ($colors as $c) {
print '<span style="display:inline-block;width:16px;height:16px;background:'.trim($c).';border-radius:2px;margin-right:2px;border:1px solid #555;"></span>';
}
print '</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
print '<td class="center">';
if ($type->active) {
print '<span class="badge badge-status4">'.$langs->trans('Enabled').'</span>';
} else {
print '<span class="badge badge-status5">'.$langs->trans('Disabled').'</span>';
}
print '</td>';
// Actions
print '<td class="center nowraponall">';
print '<a href="'.$_SERVER['PHP_SELF'].'?action=edit&typeid='.$type->id.'&system='.$systemFilter.'" title="'.$langs->trans('Edit').'">';
print img_edit();
print '</a> ';
if ($type->active) {
print '<a href="'.$_SERVER['PHP_SELF'].'?action=deactivate&typeid='.$type->id.'&system='.$systemFilter.'&token='.newToken().'" title="'.$langs->trans('Disable').'">';
print img_picto($langs->trans('Disable'), 'switch_on');
print '</a> ';
} else {
print '<a href="'.$_SERVER['PHP_SELF'].'?action=activate&typeid='.$type->id.'&system='.$systemFilter.'&token='.newToken().'" title="'.$langs->trans('Enable').'">';
print img_picto($langs->trans('Enable'), 'switch_off');
print '</a> ';
}
if (!$type->is_system) {
print '<a href="'.$_SERVER['PHP_SELF'].'?action=delete&typeid='.$type->id.'&system='.$systemFilter.'" title="'.$langs->trans('Delete').'">';
print img_delete();
print '</a>';
}
print '</td>';
print '</tr>';
}
}
print '</table>';
print '</div>';
}
print dol_get_fiche_end();
llxFooter();
$db->close();