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();