kundenkarte/ajax/equipment.php
data 06f8bc8fde Version 3.5.0 - Drag & Drop Sortierung, Duplicate-Key-Fix
- Drag & Drop Sortierung im Anlagenbaum (Geschwister-Ebene)
- UNIQUE KEY uk_kundenkarte_societe_system um fk_contact erweitert
- Automatische DB-Migration beim Modul-Aktivieren
- Visueller Abstand zwischen Root-Elementen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 21:05:13 +01:00

494 lines
16 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* AJAX endpoint for equipment (Sicherungsautomaten, etc.)
*/
if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1');
if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1');
if (!defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1');
if (!defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1');
$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.'/custom/kundenkarte/class/equipment.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmentcarrier.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmenttype.class.php';
dol_include_once('/kundenkarte/class/auditlog.class.php');
header('Content-Type: application/json; charset=UTF-8');
$action = GETPOST('action', 'aZ09');
$equipmentId = GETPOSTINT('equipment_id');
$carrierId = GETPOSTINT('carrier_id');
$equipment = new Equipment($db);
$auditLog = new AuditLog($db);
$response = array('success' => false, 'error' => '');
// Security check
if (!$user->hasRight('kundenkarte', 'read')) {
$response['error'] = 'Permission denied';
echo json_encode($response);
exit;
}
switch ($action) {
case 'get_types':
// Get all equipment types for dropdown
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmenttype.class.php';
$eqType = new EquipmentType($db);
$systemId = GETPOSTINT('system_id');
$types = $eqType->fetchAllBySystem($systemId, 1); // Filter by system if provided, only active
$result = array();
foreach ($types as $t) {
$result[] = array(
'id' => $t->id,
'label' => $t->label,
'label_short' => $t->label_short,
'width_te' => $t->width_te,
'color' => $t->color
);
}
$response['success'] = true;
$response['types'] = $result;
break;
case 'get':
// Get single equipment data
if ($equipmentId > 0 && $equipment->fetch($equipmentId) > 0) {
$response['success'] = true;
$response['equipment'] = array(
'id' => $equipment->id,
'fk_carrier' => $equipment->fk_carrier,
'type_id' => $equipment->fk_equipment_type,
'type_label' => $equipment->type_label,
'type_label_short' => $equipment->type_label_short,
'type_color' => $equipment->type_color,
'type_icon_file' => $equipment->type_icon_file,
'label' => $equipment->label,
'position_te' => $equipment->position_te,
'width_te' => $equipment->width_te,
'field_values' => $equipment->getFieldValues(),
'fk_product' => $equipment->fk_product,
'fk_protection' => $equipment->fk_protection,
'protection_label' => $equipment->protection_label
);
} else {
$response['error'] = 'Equipment not found';
}
break;
case 'get_protection_devices':
// Get all protection devices (FI/RCD) for an Anlage
$anlageId = GETPOSTINT('anlage_id');
if ($anlageId > 0) {
$devices = $equipment->fetchProtectionDevices($anlageId);
$result = array();
foreach ($devices as $d) {
$result[] = array(
'id' => $d->id,
'label' => $d->label ?: $d->type_label,
'type_label' => $d->type_label,
'type_label_short' => $d->type_label_short,
'display_label' => ($d->label ?: $d->type_label_short ?: $d->type_label).' (Pos. '.$d->position_te.')'
);
}
$response['success'] = true;
$response['devices'] = $result;
} else {
$response['error'] = 'Missing anlage_id';
}
break;
case 'list':
// List all equipment on a carrier
if ($carrierId > 0) {
$items = $equipment->fetchByCarrier($carrierId);
$result = array();
foreach ($items as $eq) {
$iconUrl = '';
if (!empty($eq->type_icon_file)) {
$iconUrl = DOL_URL_ROOT.'/document.php?modulepart=kundenkarte&file=equipment_icons/'.urlencode($eq->type_icon_file);
}
$result[] = array(
'id' => $eq->id,
'type_id' => $eq->fk_equipment_type,
'type_label' => $eq->type_label,
'type_label_short' => $eq->type_label_short,
'type_ref' => $eq->type_ref,
'type_color' => $eq->type_color,
'type_icon_file' => $eq->type_icon_file,
'type_icon_url' => $iconUrl,
'type_block_image' => $eq->type_block_image,
'type_block_image_url' => !empty($eq->type_block_image) ? DOL_URL_ROOT.'/document.php?modulepart=kundenkarte&file=block_images/'.urlencode($eq->type_block_image) : '',
'type_flow_direction' => $eq->type_flow_direction,
'type_terminal_position' => $eq->type_terminal_position ?: 'both',
'terminals_config' => $eq->terminals_config,
'label' => $eq->label,
'position_te' => $eq->position_te,
'width_te' => $eq->width_te,
'block_label' => $eq->getBlockLabel(),
'block_color' => $eq->getBlockColor(),
'field_values' => $eq->getFieldValues(),
'fk_product' => $eq->fk_product
);
}
$response['success'] = true;
$response['equipment'] = $result;
} else {
$response['error'] = 'Missing carrier_id';
}
break;
case 'create':
if (!$user->hasRight('kundenkarte', 'write')) {
$response['error'] = 'Permission denied';
break;
}
$equipment->fk_carrier = $carrierId;
$equipment->fk_equipment_type = GETPOSTINT('type_id');
$equipment->label = GETPOST('label', 'alphanohtml');
$equipment->position_te = GETPOSTINT('position_te');
$equipment->width_te = GETPOSTINT('width_te');
$equipment->fk_product = GETPOSTINT('fk_product');
$equipment->fk_protection = GETPOSTINT('fk_protection');
$equipment->protection_label = GETPOST('protection_label', 'alphanohtml');
// Field values
$fieldValues = GETPOST('field_values', 'nohtml');
if ($fieldValues) {
$equipment->field_values = $fieldValues;
}
// If no width specified, get from type
if (empty($equipment->width_te)) {
$type = new EquipmentType($db);
if ($type->fetch($equipment->fk_equipment_type) > 0) {
$equipment->width_te = $type->width_te;
} else {
$equipment->width_te = 1;
}
}
// Check carrier and position
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($carrierId) > 0) {
// If no position specified, find next free position (1-based)
if (empty($equipment->position_te)) {
$equipment->position_te = $carrier->getNextFreePosition($equipment->width_te);
if ($equipment->position_te < 0) {
$response['error'] = 'No free position available on carrier';
break;
}
}
// Check if position is available
if (!$carrier->isPositionAvailable($equipment->position_te, $equipment->width_te)) {
$response['error'] = 'Position not available';
break;
}
}
$result = $equipment->create($user);
if ($result > 0) {
$response['success'] = true;
$response['equipment_id'] = $result;
$response['block_label'] = $equipment->getBlockLabel();
// Audit log
$anlageId = 0;
if ($carrier->fk_panel > 0) {
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmentpanel.class.php';
$panel = new EquipmentPanel($db);
if ($panel->fetch($carrier->fk_panel) > 0) {
$anlageId = $panel->fk_anlage;
}
} else {
$anlageId = $carrier->fk_anlage;
}
$auditLog->logCreate($user, AuditLog::TYPE_EQUIPMENT, $result, $equipment->label ?: $equipment->type_label, 0, $anlageId, array(
'type_id' => $equipment->fk_equipment_type,
'position_te' => $equipment->position_te,
'width_te' => $equipment->width_te
));
} else {
$response['error'] = $equipment->error;
}
break;
case 'update':
if (!$user->hasRight('kundenkarte', 'write')) {
$response['error'] = 'Permission denied';
break;
}
if ($equipment->fetch($equipmentId) > 0) {
$newPosition = GETPOSTINT('position_te');
$newWidth = GETPOSTINT('width_te') ?: $equipment->width_te;
// Check if new position is available (excluding current equipment)
if ($newPosition != $equipment->position_te || $newWidth != $equipment->width_te) {
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($equipment->fk_carrier) > 0) {
if (!$carrier->isPositionAvailable($newPosition, $newWidth, $equipmentId)) {
$response['error'] = 'Position not available';
break;
}
}
}
$equipment->fk_equipment_type = GETPOSTINT('type_id') ?: $equipment->fk_equipment_type;
$equipment->label = GETPOST('label', 'alphanohtml');
$equipment->position_te = $newPosition;
$equipment->width_te = $newWidth;
$equipment->fk_product = GETPOSTINT('fk_product');
$equipment->fk_protection = GETPOSTINT('fk_protection');
$equipment->protection_label = GETPOST('protection_label', 'alphanohtml');
$fieldValues = GETPOST('field_values', 'nohtml');
if ($fieldValues) {
$equipment->field_values = $fieldValues;
}
$oldLabel = isset($oldLabel) ? $oldLabel : $equipment->label;
$oldPosition = isset($oldPosition) ? $oldPosition : $equipment->position_te;
$result = $equipment->update($user);
if ($result > 0) {
$response['success'] = true;
$response['block_label'] = $equipment->getBlockLabel();
// Audit log
$anlageId = 0;
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($equipment->fk_carrier) > 0) {
if ($carrier->fk_panel > 0) {
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmentpanel.class.php';
$panel = new EquipmentPanel($db);
if ($panel->fetch($carrier->fk_panel) > 0) {
$anlageId = $panel->fk_anlage;
}
} else {
$anlageId = $carrier->fk_anlage;
}
}
$auditLog->logUpdate($user, AuditLog::TYPE_EQUIPMENT, $equipment->id, $equipment->label ?: $equipment->type_label, 'properties', null, null, 0, $anlageId);
} else {
$response['error'] = $equipment->error;
}
} else {
$response['error'] = 'Equipment not found';
}
break;
case 'update_position':
// Quick position update for drag-drop
if (!$user->hasRight('kundenkarte', 'write')) {
$response['error'] = 'Permission denied';
break;
}
if ($equipment->fetch($equipmentId) > 0) {
$newPosition = GETPOSTINT('position_te');
// Check if new position is available
if ($newPosition != $equipment->position_te) {
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($equipment->fk_carrier) > 0) {
if (!$carrier->isPositionAvailable($newPosition, $equipment->width_te, $equipmentId)) {
$response['error'] = 'Position not available';
break;
}
}
}
$equipment->position_te = $newPosition;
$result = $equipment->update($user);
if ($result > 0) {
$response['success'] = true;
} else {
$response['error'] = $equipment->error;
}
} else {
$response['error'] = 'Equipment not found';
}
break;
case 'move_to_carrier':
// Move equipment to different carrier (drag-drop between carriers)
if (!$user->hasRight('kundenkarte', 'write')) {
$response['error'] = 'Permission denied';
break;
}
if ($equipment->fetch($equipmentId) > 0) {
$newCarrierId = GETPOSTINT('carrier_id');
$newPosition = GETPOSTINT('position_te') ?: 1;
// Check if target carrier exists
$targetCarrier = new EquipmentCarrier($db);
if ($targetCarrier->fetch($newCarrierId) <= 0) {
$response['error'] = 'Target carrier not found';
break;
}
// Check if position is available on target carrier
if (!$targetCarrier->isPositionAvailable($newPosition, $equipment->width_te, 0)) {
$response['error'] = 'Position auf Ziel-Hutschiene nicht verfügbar';
break;
}
// Update equipment
$equipment->fk_carrier = $newCarrierId;
$equipment->position_te = $newPosition;
$result = $equipment->update($user);
if ($result > 0) {
$response['success'] = true;
$response['message'] = 'Equipment verschoben';
} else {
$response['error'] = $equipment->error;
}
} else {
$response['error'] = 'Equipment not found';
}
break;
case 'delete':
if (!$user->hasRight('kundenkarte', 'delete')) {
$response['error'] = 'Permission denied';
break;
}
if ($equipment->fetch($equipmentId) > 0) {
// Get anlage_id before deletion for audit log
$anlageId = 0;
$deletedLabel = $equipment->label ?: $equipment->type_label;
$deletedData = array(
'type_id' => $equipment->fk_equipment_type,
'type_label' => $equipment->type_label,
'position_te' => $equipment->position_te,
'width_te' => $equipment->width_te,
'carrier_id' => $equipment->fk_carrier
);
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($equipment->fk_carrier) > 0) {
if ($carrier->fk_panel > 0) {
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmentpanel.class.php';
$panel = new EquipmentPanel($db);
if ($panel->fetch($carrier->fk_panel) > 0) {
$anlageId = $panel->fk_anlage;
}
} else {
$anlageId = $carrier->fk_anlage;
}
}
$result = $equipment->delete($user);
if ($result > 0) {
$response['success'] = true;
// Audit log
$auditLog->logDelete($user, AuditLog::TYPE_EQUIPMENT, $equipmentId, $deletedLabel, 0, $anlageId, $deletedData);
} else {
$response['error'] = $equipment->error;
}
} else {
$response['error'] = 'Equipment not found';
}
break;
case 'duplicate':
if (!$user->hasRight('kundenkarte', 'write')) {
$response['error'] = 'Permission denied';
break;
}
if ($equipment->fetch($equipmentId) > 0) {
$sourceId = $equipmentId;
$newId = $equipment->duplicate($user);
if ($newId > 0) {
$response['success'] = true;
$response['equipment_id'] = $newId;
// Fetch the new equipment to return its data
$newEquipment = new Equipment($db);
if ($newEquipment->fetch($newId) > 0) {
$response['equipment'] = array(
'id' => $newEquipment->id,
'fk_carrier' => $newEquipment->fk_carrier,
'type_id' => $newEquipment->fk_equipment_type,
'type_label' => $newEquipment->type_label,
'type_label_short' => $newEquipment->type_label_short,
'type_color' => $newEquipment->type_color,
'type_ref' => $newEquipment->type_ref,
'type_icon_file' => $newEquipment->type_icon_file,
'terminals_config' => $newEquipment->terminals_config,
'label' => $newEquipment->label,
'position_te' => $newEquipment->position_te,
'width_te' => $newEquipment->width_te,
'block_label' => $newEquipment->getBlockLabel(),
'block_color' => $newEquipment->getBlockColor(),
'field_values' => $newEquipment->getFieldValues(),
'fk_product' => $newEquipment->fk_product
);
// Audit log
$anlageId = 0;
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($newEquipment->fk_carrier) > 0) {
if ($carrier->fk_panel > 0) {
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmentpanel.class.php';
$panel = new EquipmentPanel($db);
if ($panel->fetch($carrier->fk_panel) > 0) {
$anlageId = $panel->fk_anlage;
}
} else {
$anlageId = $carrier->fk_anlage;
}
}
$auditLog->logDuplicate($user, AuditLog::TYPE_EQUIPMENT, $newId, $newEquipment->label ?: $newEquipment->type_label, $sourceId, 0, $anlageId);
}
} else {
$response['error'] = $equipment->error ?: 'Duplication failed';
}
} else {
$response['error'] = 'Equipment not found';
}
break;
case 'move':
// Move equipment to new position (for drag & drop)
if (!$user->hasRight('kundenkarte', 'write')) {
$response['error'] = 'Permission denied';
break;
}
if ($equipment->fetch($equipmentId) > 0) {
$newPosition = GETPOSTINT('position_te');
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($equipment->fk_carrier) > 0) {
if ($carrier->isPositionAvailable($newPosition, $equipment->width_te, $equipmentId)) {
$equipment->position_te = $newPosition;
$result = $equipment->update($user);
if ($result > 0) {
$response['success'] = true;
} else {
$response['error'] = $equipment->error;
}
} else {
$response['error'] = 'Position not available';
}
}
} else {
$response['error'] = 'Equipment not found';
}
break;
default:
$response['error'] = 'Unknown action';
}
echo json_encode($response);
$db->close();