kundenkarte/ajax/equipment.php
data 16e51a799a feat(v8.6): Räumlichkeit, Verteilungs-Tabellen, Bundled-Terminals, PWA-Updates
- output_location (Räumlichkeit): Neues Textfeld am Abgang für Raum/Ort des
  Verbrauchers. DB-Migration, Backend (AJAX), Frontend (Website + PWA),
  Anzeige im Schaltplan (kursiv) und in PDF-Tabellen.
- Verteilungs-Tabellen: Kundenansicht (A4, Nr/Verbraucher/Räumlichkeit) und
  Technikeransicht (A4, R.Klem/FI/Nr/Verbraucher/Räumlichkeit/Typ) im
  Leitungslaufplan-PDF. Gruppiert nach Feld/Reihe mit automatischem Seitenumbruch.
- Bundled-Terminals Checkbox: Im Website-Abgang-Dialog (war vorher nur PWA).
- PWA: Diverse Verbesserungen, Service Worker v12.4, Connection-Modal erweitert.
- Typ-Flags: has_product auch für Gebäudetypen, Equipment-Typ Erweiterungen.
- CLAUDE.md + Doku aktualisiert.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 01:33:05 +01:00

721 lines
24 KiB
PHP

<?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_products':
// Get products for equipment selection (electrical components)
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
$search = GETPOST('search', 'alphanohtml');
$limit = GETPOSTINT('limit') ?: 50;
$sql = "SELECT p.rowid, p.ref, p.label, p.price, p.fk_product_type";
$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
$sql .= " WHERE p.entity IN (".getEntity('product').")";
$sql .= " AND p.tosell = 1";
if (!empty($search)) {
$sql .= " AND (p.ref LIKE '%".$db->escape($search)."%' OR p.label LIKE '%".$db->escape($search)."%')";
}
$sql .= " ORDER BY p.ref ASC";
$sql .= " LIMIT ".((int) $limit);
$resql = $db->query($sql);
$products = array();
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$products[] = array(
'id' => $obj->rowid,
'ref' => $obj->ref,
'label' => $obj->label,
'price' => $obj->price,
'display' => $obj->ref.' - '.$obj->label
);
}
}
$response['success'] = true;
$response['products'] = $products;
break;
case 'get_product':
// Get single product by ID
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
$productId = GETPOSTINT('product_id');
if ($productId > 0) {
$product = new Product($db);
if ($product->fetch($productId) > 0) {
$response['success'] = true;
$response['product'] = array(
'id' => $product->id,
'ref' => $product->ref,
'label' => $product->label,
'display' => $product->ref.' - '.$product->label
);
} else {
$response['error'] = 'Product not found';
}
} else {
$response['error'] = 'No product_id provided';
}
break;
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,
'ref' => $t->ref,
'label' => $t->label,
'label_short' => $t->label_short,
'category' => $t->category ?: 'steuerung',
'width_te' => $t->width_te,
'color' => $t->color,
'picto' => $t->picto
);
}
$response['success'] = true;
$response['types'] = $result;
break;
case 'get_type_fields':
// Get fields for a specific equipment type
$typeId = GETPOSTINT('type_id');
if ($typeId > 0) {
$sql = "SELECT field_code, field_label, field_type, field_options, required, position, show_on_block, show_in_hover";
$sql .= " FROM ".MAIN_DB_PREFIX."kundenkarte_equipment_type_field";
$sql .= " WHERE fk_equipment_type = ".((int) $typeId);
$sql .= " AND active = 1";
$sql .= " ORDER BY position ASC";
$resql = $db->query($sql);
$fields = array();
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$fields[] = array(
'field_code' => $obj->field_code,
'field_label' => $obj->field_label,
'field_type' => $obj->field_type,
'field_options' => $obj->field_options,
'required' => $obj->required,
'show_on_block' => $obj->show_on_block,
'show_in_hover' => $obj->show_in_hover
);
}
}
$response['success'] = true;
$response['fields'] = $fields;
} else {
$response['error'] = 'No type_id provided';
}
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();
// Cache type fields for performance
$typeFieldsCache = 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);
}
// Load type fields if not cached
$typeId = $eq->fk_equipment_type;
if (!isset($typeFieldsCache[$typeId])) {
$typeFieldsCache[$typeId] = array();
$sql = "SELECT field_code, field_label, show_on_block, show_in_hover";
$sql .= " FROM ".MAIN_DB_PREFIX."kundenkarte_equipment_type_field";
$sql .= " WHERE fk_equipment_type = ".((int) $typeId);
$sql .= " AND active = 1";
$sql .= " ORDER BY position ASC";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$typeFieldsCache[$typeId][] = array(
'field_code' => $obj->field_code,
'field_label' => $obj->field_label,
'show_on_block' => (int) $obj->show_on_block,
'show_in_hover' => (int) $obj->show_in_hover
);
}
}
}
// Load product data if assigned
$productRef = '';
$productLabel = '';
if (!empty($eq->fk_product)) {
$sqlProd = "SELECT ref, label FROM ".MAIN_DB_PREFIX."product WHERE rowid = ".((int) $eq->fk_product);
$resProd = $db->query($sqlProd);
if ($resProd && ($objProd = $db->fetch_object($resProd))) {
$productRef = $objProd->ref;
$productLabel = $objProd->label;
}
}
$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,
'type_fields' => $typeFieldsCache[$typeId],
'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,
'fk_protection' => $eq->fk_protection,
'product_ref' => $productRef,
'product_label' => $productLabel
);
}
$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 = floatval(GETPOST('position_te', 'alpha'));
$equipment->width_te = floatval(GETPOST('width_te', 'alpha'));
$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;
}
// Auto-generate label if empty: R2.1 or R2.1-3 for multi-TE
if (empty($equipment->label)) {
$carrierLabel = $carrier->label ?: ('R'.$carrier->id);
$posStart = $equipment->position_te;
$posEnd = $posStart + $equipment->width_te - 1;
if ($equipment->width_te > 1) {
$equipment->label = $carrierLabel.'.'.$posStart.'-'.$posEnd;
} else {
$equipment->label = $carrierLabel.'.'.$posStart;
}
}
}
$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 = floatval(GETPOST('position_te', 'alpha'));
$newWidth = floatval(GETPOST('width_te', 'alpha')) ?: $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;
}
// Auto-generate label if empty
if (empty(trim($equipment->label))) {
$carrier = new EquipmentCarrier($db);
if ($carrier->fetch($equipment->fk_carrier) > 0) {
$carrierLabel = $carrier->label ?: ('R'.$carrier->id);
$posStart = $equipment->position_te;
$posEnd = $posStart + $equipment->width_te - 1;
if ($equipment->width_te > 1) {
$equipment->label = $carrierLabel.'.'.$posStart.'-'.$posEnd;
} else {
$equipment->label = $carrierLabel.'.'.$posStart;
}
}
}
$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 = floatval(GETPOST('position_te', 'alpha'));
// Check if new position is available
$carrier = new EquipmentCarrier($db);
if ($newPosition != $equipment->position_te) {
if ($carrier->fetch($equipment->fk_carrier) > 0) {
if (!$carrier->isPositionAvailable($newPosition, $equipment->width_te, $equipmentId)) {
$response['error'] = 'Position not available';
break;
}
}
} else {
$carrier->fetch($equipment->fk_carrier);
}
// Update auto-generated label if it matches the pattern Rxx.xx or Rxx.xx-xx
$oldLabel = $equipment->label;
$carrierLabel = $carrier->label ?: ('R'.$carrier->id);
if (preg_match('/^'.preg_quote($carrierLabel, '/').'\.(\d+)(-\d+)?$/', $oldLabel)) {
$posStart = $newPosition;
$posEnd = $posStart + $equipment->width_te - 1;
if ($equipment->width_te > 1) {
$equipment->label = $carrierLabel.'.'.$posStart.'-'.$posEnd;
} else {
$equipment->label = $carrierLabel.'.'.$posStart;
}
}
$equipment->position_te = $newPosition;
$result = $equipment->update($user);
if ($result > 0) {
$response['success'] = true;
$response['new_label'] = $equipment->label;
} 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 = floatval(GETPOST('position_te', 'alpha')) ?: 1;
// Get old carrier for label pattern check
$oldCarrier = new EquipmentCarrier($db);
$oldCarrier->fetch($equipment->fk_carrier);
$oldCarrierLabel = $oldCarrier->label ?: ('R'.$oldCarrier->id);
// 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 auto-generated label if it matches the old carrier pattern
$oldLabel = $equipment->label;
$newCarrierLabel = $targetCarrier->label ?: ('R'.$targetCarrier->id);
if (preg_match('/^'.preg_quote($oldCarrierLabel, '/').'\.(\d+)(-\d+)?$/', $oldLabel)) {
$posStart = $newPosition;
$posEnd = $posStart + $equipment->width_te - 1;
if ($equipment->width_te > 1) {
$equipment->label = $newCarrierLabel.'.'.$posStart.'-'.$posEnd;
} else {
$equipment->label = $newCarrierLabel.'.'.$posStart;
}
}
// Update equipment
$equipment->fk_carrier = $newCarrierId;
$equipment->position_te = $newPosition;
$result = $equipment->update($user);
if ($result > 0) {
$response['success'] = true;
$response['message'] = 'Equipment verschoben';
$response['new_label'] = $equipment->label;
} 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) {
// Icon-URL berechnen
$iconUrl = '';
if (!empty($newEquipment->type_icon_file)) {
$iconUrl = DOL_URL_ROOT.'/document.php?modulepart=kundenkarte&file=equipment_icons/'.urlencode($newEquipment->type_icon_file);
}
// Typ-Felder laden
$typeFields = array();
$sqlTf = "SELECT field_code, field_label, show_on_block, show_in_hover";
$sqlTf .= " FROM ".MAIN_DB_PREFIX."kundenkarte_equipment_type_field";
$sqlTf .= " WHERE fk_equipment_type = ".((int) $newEquipment->fk_equipment_type);
$sqlTf .= " AND active = 1 ORDER BY position ASC";
$resTf = $db->query($sqlTf);
if ($resTf) {
while ($objTf = $db->fetch_object($resTf)) {
$typeFields[] = array(
'field_code' => $objTf->field_code,
'field_label' => $objTf->field_label,
'show_on_block' => (int) $objTf->show_on_block,
'show_in_hover' => (int) $objTf->show_in_hover
);
}
}
$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,
'type_icon_url' => $iconUrl,
'type_block_image' => $newEquipment->type_block_image,
'type_block_image_url' => !empty($newEquipment->type_block_image) ? DOL_URL_ROOT.'/document.php?modulepart=kundenkarte&file=block_images/'.urlencode($newEquipment->type_block_image) : '',
'type_flow_direction' => $newEquipment->type_flow_direction,
'type_terminal_position' => $newEquipment->type_terminal_position ?: 'both',
'terminals_config' => $newEquipment->terminals_config,
'type_fields' => $typeFields,
'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,
'fk_protection' => $newEquipment->fk_protection,
'protection_label' => $newEquipment->protection_label
);
// 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 = floatval(GETPOST('position_te', 'alpha'));
$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();