kundenkarte/class/equipment.class.php
2026-02-11 15:41:33 +01:00

500 lines
15 KiB
PHP

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*/
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmenttype.class.php';
/**
* Class Equipment
* Manages equipment instances (Sicherungsautomaten, FI-Schalter, etc.)
*/
class Equipment extends CommonObject
{
public $element = 'equipment';
public $table_element = 'kundenkarte_equipment';
public $fk_carrier;
public $fk_equipment_type;
public $label;
public $position_te;
public $width_te;
public $field_values;
public $fk_product;
public $fk_protection; // FK to protection device (FI/RCD)
public $protection_label; // Label shown above equipment when in protection group
public $note_private;
public $status;
public $date_creation;
public $fk_user_creat;
public $fk_user_modif;
// Loaded objects
public $type; // EquipmentType object
public $type_label;
public $type_label_short;
public $type_color;
public $type_picto;
public $type_icon_file; // SVG/PNG schematic symbol
public $product_ref;
public $product_label;
public $protection_device_label; // Label of the protection device
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
$this->db = $db;
}
/**
* Create object in database
*
* @param User $user User that creates
* @return int Return integer <0 if KO, Id of created object if OK
*/
public function create($user)
{
global $conf;
$error = 0;
$now = dol_now();
if (empty($this->fk_carrier) || empty($this->fk_equipment_type)) {
$this->error = 'ErrorMissingParameters';
return -1;
}
// Get default width from type if not set
if (empty($this->width_te)) {
$type = new EquipmentType($this->db);
if ($type->fetch($this->fk_equipment_type) > 0) {
$this->width_te = $type->width_te;
} else {
$this->width_te = 1;
}
}
$this->db->begin();
$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
$sql .= "entity, fk_carrier, fk_equipment_type, label,";
$sql .= " position_te, width_te, field_values, fk_product,";
$sql .= " fk_protection, protection_label,";
$sql .= " note_private, status,";
$sql .= " date_creation, fk_user_creat";
$sql .= ") VALUES (";
$sql .= ((int) $conf->entity);
$sql .= ", ".((int) $this->fk_carrier);
$sql .= ", ".((int) $this->fk_equipment_type);
$sql .= ", ".($this->label ? "'".$this->db->escape($this->label)."'" : "NULL");
$sql .= ", ".((int) $this->position_te);
$sql .= ", ".((int) $this->width_te);
$sql .= ", ".($this->field_values ? "'".$this->db->escape($this->field_values)."'" : "NULL");
$sql .= ", ".($this->fk_product > 0 ? ((int) $this->fk_product) : "NULL");
$sql .= ", ".($this->fk_protection > 0 ? ((int) $this->fk_protection) : "NULL");
$sql .= ", ".($this->protection_label ? "'".$this->db->escape($this->protection_label)."'" : "NULL");
$sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL");
$sql .= ", ".((int) ($this->status !== null ? $this->status : 1));
$sql .= ", '".$this->db->idate($now)."'";
$sql .= ", ".((int) $user->id);
$sql .= ")";
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if (!$error) {
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
}
if ($error) {
$this->db->rollback();
return -1 * $error;
} else {
$this->db->commit();
return $this->id;
}
}
/**
* Load object from database
*
* @param int $id ID of record
* @return int Return integer <0 if KO, 0 if not found, >0 if OK
*/
public function fetch($id)
{
$sql = "SELECT e.*, t.label as type_label, t.label_short as type_label_short,";
$sql .= " t.ref as type_ref, t.color as type_color, t.picto as type_picto, t.icon_file as type_icon_file,";
$sql .= " t.terminals_config as terminals_config,";
$sql .= " p.ref as product_ref, p.label as product_label,";
$sql .= " prot.label as protection_device_label";
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as e";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_equipment_type as t ON e.fk_equipment_type = t.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON e.fk_product = p.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_equipment as prot ON e.fk_protection = prot.rowid";
$sql .= " WHERE e.rowid = ".((int) $id);
$resql = $this->db->query($sql);
if ($resql) {
if ($this->db->num_rows($resql)) {
$obj = $this->db->fetch_object($resql);
$this->id = $obj->rowid;
$this->entity = $obj->entity;
$this->fk_carrier = $obj->fk_carrier;
$this->fk_equipment_type = $obj->fk_equipment_type;
$this->label = $obj->label;
$this->position_te = $obj->position_te;
$this->width_te = $obj->width_te;
$this->field_values = $obj->field_values;
$this->fk_product = $obj->fk_product;
$this->fk_protection = $obj->fk_protection;
$this->protection_label = $obj->protection_label;
$this->note_private = $obj->note_private;
$this->status = $obj->status;
$this->date_creation = $this->db->jdate($obj->date_creation);
$this->fk_user_creat = $obj->fk_user_creat;
$this->fk_user_modif = $obj->fk_user_modif;
$this->type_label = $obj->type_label;
$this->type_label_short = $obj->type_label_short;
$this->type_ref = $obj->type_ref;
$this->type_color = $obj->type_color;
$this->type_picto = $obj->type_picto;
$this->type_icon_file = $obj->type_icon_file;
$this->terminals_config = $obj->terminals_config;
$this->product_ref = $obj->product_ref;
$this->product_label = $obj->product_label;
$this->protection_device_label = $obj->protection_device_label;
$this->db->free($resql);
return 1;
} else {
$this->db->free($resql);
return 0;
}
} else {
$this->error = $this->db->lasterror();
return -1;
}
}
/**
* Update object in database
*
* @param User $user User that modifies
* @return int Return integer <0 if KO, >0 if OK
*/
public function update($user)
{
$error = 0;
$this->db->begin();
$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
$sql .= " fk_equipment_type = ".((int) $this->fk_equipment_type);
$sql .= ", label = ".($this->label ? "'".$this->db->escape($this->label)."'" : "NULL");
$sql .= ", position_te = ".((int) $this->position_te);
$sql .= ", width_te = ".((int) $this->width_te);
$sql .= ", field_values = ".($this->field_values ? "'".$this->db->escape($this->field_values)."'" : "NULL");
$sql .= ", fk_product = ".($this->fk_product > 0 ? ((int) $this->fk_product) : "NULL");
$sql .= ", fk_protection = ".($this->fk_protection > 0 ? ((int) $this->fk_protection) : "NULL");
$sql .= ", protection_label = ".($this->protection_label ? "'".$this->db->escape($this->protection_label)."'" : "NULL");
$sql .= ", note_private = ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL");
$sql .= ", status = ".((int) $this->status);
$sql .= ", fk_user_modif = ".((int) $user->id);
$sql .= " WHERE rowid = ".((int) $this->id);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if ($error) {
$this->db->rollback();
return -1 * $error;
} else {
$this->db->commit();
return 1;
}
}
/**
* Delete object in database
*
* @param User $user User that deletes
* @return int Return integer <0 if KO, >0 if OK
*/
public function delete($user)
{
$error = 0;
$this->db->begin();
$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if ($error) {
$this->db->rollback();
return -1 * $error;
} else {
$this->db->commit();
return 1;
}
}
/**
* Fetch all equipment on a carrier
*
* @param int $carrierId Carrier ID
* @param int $activeOnly Only active equipment
* @return array Array of Equipment objects
*/
public function fetchByCarrier($carrierId, $activeOnly = 1)
{
$results = array();
$sql = "SELECT e.*, t.label as type_label, t.label_short as type_label_short,";
$sql .= " t.ref as type_ref, t.color as type_color, t.picto as type_picto, t.icon_file as type_icon_file,";
$sql .= " t.terminals_config as terminals_config,";
$sql .= " prot.label as protection_device_label";
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as e";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_equipment_type as t ON e.fk_equipment_type = t.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_equipment as prot ON e.fk_protection = prot.rowid";
$sql .= " WHERE e.fk_carrier = ".((int) $carrierId);
if ($activeOnly) {
$sql .= " AND e.status = 1";
}
$sql .= " ORDER BY e.position_te ASC";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$eq = new Equipment($this->db);
$eq->id = $obj->rowid;
$eq->entity = $obj->entity;
$eq->fk_carrier = $obj->fk_carrier;
$eq->fk_equipment_type = $obj->fk_equipment_type;
$eq->label = $obj->label;
$eq->position_te = $obj->position_te;
$eq->width_te = $obj->width_te;
$eq->field_values = $obj->field_values;
$eq->fk_product = $obj->fk_product;
$eq->fk_protection = $obj->fk_protection;
$eq->protection_label = $obj->protection_label;
$eq->note_private = $obj->note_private;
$eq->status = $obj->status;
$eq->type_label = $obj->type_label;
$eq->type_label_short = $obj->type_label_short;
$eq->type_ref = $obj->type_ref;
$eq->type_color = $obj->type_color;
$eq->type_picto = $obj->type_picto;
$eq->type_icon_file = $obj->type_icon_file;
$eq->terminals_config = $obj->terminals_config;
$eq->protection_device_label = $obj->protection_device_label;
$results[] = $eq;
}
$this->db->free($resql);
}
return $results;
}
/**
* Fetch protection devices (FI/RCD) for an Anlage
* Protection devices are equipment types that can protect other equipment
*
* @param int $anlageId Anlage ID
* @return array Array of Equipment objects that are protection devices
*/
public function fetchProtectionDevices($anlageId)
{
$results = array();
// Get all equipment for this anlage that have type with is_protection = 1
// Or equipment types that are typically protection devices (FI, RCD, etc.)
$sql = "SELECT e.*, t.label as type_label, t.label_short as type_label_short,";
$sql .= " t.color as type_color, t.ref as type_ref, c.fk_anlage";
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as e";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_equipment_type as t ON e.fk_equipment_type = t.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_equipment_carrier as c ON e.fk_carrier = c.rowid";
$sql .= " WHERE c.fk_anlage = ".((int) $anlageId);
$sql .= " AND e.status = 1";
// Filter for protection device types (FI, RCD, FI_LS, etc.)
$sql .= " AND (t.ref LIKE '%FI%' OR t.ref LIKE '%RCD%' OR t.ref LIKE 'RCBO%')";
$sql .= " ORDER BY c.position ASC, e.position_te ASC";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$eq = new Equipment($this->db);
$eq->id = $obj->rowid;
$eq->fk_carrier = $obj->fk_carrier;
$eq->fk_equipment_type = $obj->fk_equipment_type;
$eq->label = $obj->label;
$eq->position_te = $obj->position_te;
$eq->width_te = $obj->width_te;
$eq->type_label = $obj->type_label;
$eq->type_label_short = $obj->type_label_short;
$eq->type_color = $obj->type_color;
$results[] = $eq;
}
$this->db->free($resql);
}
return $results;
}
/**
* Duplicate this equipment (for "+" button)
*
* @param User $user User that creates
* @param int $carrierId Target carrier (0 = same carrier)
* @param int $position Target position (-1 = auto)
* @return int Return integer <0 if KO, Id of new object if OK
*/
public function duplicate($user, $carrierId = 0, $position = -1)
{
require_once DOL_DOCUMENT_ROOT.'/custom/kundenkarte/class/equipmentcarrier.class.php';
$newEquipment = new Equipment($this->db);
$newEquipment->fk_carrier = $carrierId > 0 ? $carrierId : $this->fk_carrier;
$newEquipment->fk_equipment_type = $this->fk_equipment_type;
$newEquipment->label = $this->label;
$newEquipment->width_te = $this->width_te;
$newEquipment->field_values = $this->field_values;
$newEquipment->fk_product = $this->fk_product;
$newEquipment->note_private = $this->note_private;
$newEquipment->status = 1;
// Find position
if ($position >= 0) {
$newEquipment->position_te = $position;
} else {
// Auto-find next position after this equipment
$carrier = new EquipmentCarrier($this->db);
$carrier->fetch($newEquipment->fk_carrier);
$carrier->fetchEquipment();
// Try position right after this element
$tryPos = $this->position_te + $this->width_te;
if ($carrier->isPositionAvailable($tryPos, $this->width_te)) {
$newEquipment->position_te = $tryPos;
} else {
// Find any free position
$newEquipment->position_te = $carrier->getNextFreePosition($this->width_te);
if ($newEquipment->position_te < 0) {
$this->error = 'ErrorNoSpaceOnCarrier';
return -1;
}
}
}
return $newEquipment->create($user);
}
/**
* Get field values as array
*
* @return array
*/
public function getFieldValues()
{
if (empty($this->field_values)) {
return array();
}
$values = json_decode($this->field_values, true);
return is_array($values) ? $values : array();
}
/**
* Set field values from array
*
* @param array $values Key-value pairs
* @return void
*/
public function setFieldValues($values)
{
$this->field_values = json_encode($values);
}
/**
* Get single field value
*
* @param string $fieldCode Field code
* @return mixed|null
*/
public function getFieldValue($fieldCode)
{
$values = $this->getFieldValues();
return isset($values[$fieldCode]) ? $values[$fieldCode] : null;
}
/**
* Get label for SVG block display
* Combines fields with show_on_block = 1
*
* @return string Label to display on block (e.g. "B16")
*/
public function getBlockLabel()
{
$type = new EquipmentType($this->db);
if ($type->fetch($this->fk_equipment_type) <= 0) {
return $this->type_label_short ?: '';
}
$blockFields = $type->getBlockFields();
if (empty($blockFields)) {
return $this->type_label_short ?: '';
}
$values = $this->getFieldValues();
$parts = array();
foreach ($blockFields as $field) {
if (isset($values[$field->field_code]) && $values[$field->field_code] !== '') {
$parts[] = $values[$field->field_code];
}
}
if (empty($parts)) {
return $this->type_label_short ?: '';
}
return implode('', $parts);
}
/**
* Get color for SVG block
*
* @return string Hex color code
*/
public function getBlockColor()
{
if (!empty($this->type_color)) {
return $this->type_color;
}
// Default color
return '#3498db';
}
}