- 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>
368 lines
10 KiB
PHP
Executable file
368 lines
10 KiB
PHP
Executable file
<?php
|
|
/* Copyright (C) 2026 Alles Watt lauft
|
|
*
|
|
* Building Type class (Gebäudetypen)
|
|
* Global structure elements for all systems
|
|
*/
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
|
|
|
|
class BuildingType extends CommonObject
|
|
{
|
|
public $element = 'buildingtype';
|
|
public $table_element = 'kundenkarte_building_type';
|
|
|
|
// Level type constants
|
|
const LEVEL_BUILDING = 'building';
|
|
const LEVEL_FLOOR = 'floor';
|
|
const LEVEL_WING = 'wing';
|
|
const LEVEL_CORRIDOR = 'corridor';
|
|
const LEVEL_ROOM = 'room';
|
|
const LEVEL_AREA = 'area';
|
|
|
|
public $id;
|
|
public $entity;
|
|
public $ref;
|
|
public $label;
|
|
public $label_short;
|
|
public $description;
|
|
public $fk_parent;
|
|
public $level_type;
|
|
public $icon;
|
|
public $color;
|
|
public $picto;
|
|
public $is_system;
|
|
public $can_have_children;
|
|
public $has_product;
|
|
public $position;
|
|
public $active;
|
|
public $date_creation;
|
|
public $tms;
|
|
public $fk_user_creat;
|
|
public $fk_user_modif;
|
|
|
|
// Loaded parent info
|
|
public $parent_label;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param DoliDB $db Database handler
|
|
*/
|
|
public function __construct($db)
|
|
{
|
|
$this->db = $db;
|
|
}
|
|
|
|
/**
|
|
* Create building type
|
|
*
|
|
* @param User $user User object
|
|
* @return int >0 if OK, <0 if KO
|
|
*/
|
|
public function create($user)
|
|
{
|
|
global $conf;
|
|
|
|
$now = dol_now();
|
|
$this->ref = trim($this->ref);
|
|
$this->label = trim($this->label);
|
|
|
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
|
|
$sql .= "entity, ref, label, label_short, description, fk_parent, level_type,";
|
|
$sql .= "icon, color, picto, is_system, can_have_children, has_product, position, active,";
|
|
$sql .= "date_creation, fk_user_creat";
|
|
$sql .= ") VALUES (";
|
|
$sql .= (int)$conf->entity;
|
|
$sql .= ", '".$this->db->escape($this->ref)."'";
|
|
$sql .= ", '".$this->db->escape($this->label)."'";
|
|
$sql .= ", ".($this->label_short ? "'".$this->db->escape($this->label_short)."'" : "NULL");
|
|
$sql .= ", ".($this->description ? "'".$this->db->escape($this->description)."'" : "NULL");
|
|
$sql .= ", ".(int)($this->fk_parent ?: 0);
|
|
$sql .= ", ".($this->level_type ? "'".$this->db->escape($this->level_type)."'" : "NULL");
|
|
$sql .= ", ".($this->icon ? "'".$this->db->escape($this->icon)."'" : "NULL");
|
|
$sql .= ", ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
|
|
$sql .= ", ".($this->picto ? "'".$this->db->escape($this->picto)."'" : "NULL");
|
|
$sql .= ", ".(int)($this->is_system ?: 0);
|
|
$sql .= ", ".(int)($this->can_have_children !== null ? $this->can_have_children : 1);
|
|
$sql .= ", ".(int)($this->has_product ?: 0);
|
|
$sql .= ", ".(int)($this->position ?: 0);
|
|
$sql .= ", ".(int)($this->active !== null ? $this->active : 1);
|
|
$sql .= ", '".$this->db->idate($now)."'";
|
|
$sql .= ", ".(int)$user->id;
|
|
$sql .= ")";
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
|
|
return $this->id;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch building type
|
|
*
|
|
* @param int $id ID
|
|
* @param string $ref Reference
|
|
* @return int >0 if OK, <0 if KO
|
|
*/
|
|
public function fetch($id, $ref = '')
|
|
{
|
|
$sql = "SELECT t.*, p.label as parent_label";
|
|
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
|
|
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$this->table_element." as p ON t.fk_parent = p.rowid";
|
|
$sql .= " WHERE ";
|
|
if ($id > 0) {
|
|
$sql .= "t.rowid = ".(int)$id;
|
|
} else {
|
|
$sql .= "t.ref = '".$this->db->escape($ref)."'";
|
|
}
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
if ($obj = $this->db->fetch_object($resql)) {
|
|
$this->id = $obj->rowid;
|
|
$this->entity = $obj->entity;
|
|
$this->ref = $obj->ref;
|
|
$this->label = $obj->label;
|
|
$this->label_short = $obj->label_short;
|
|
$this->description = $obj->description;
|
|
$this->fk_parent = $obj->fk_parent;
|
|
$this->level_type = $obj->level_type;
|
|
$this->icon = $obj->icon;
|
|
$this->color = $obj->color;
|
|
$this->picto = $obj->picto;
|
|
$this->is_system = $obj->is_system;
|
|
$this->can_have_children = $obj->can_have_children;
|
|
$this->has_product = $obj->has_product ?? 0;
|
|
$this->position = $obj->position;
|
|
$this->active = $obj->active;
|
|
$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->parent_label = $obj->parent_label;
|
|
|
|
$this->db->free($resql);
|
|
return 1;
|
|
}
|
|
$this->db->free($resql);
|
|
return 0;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update building type
|
|
*
|
|
* @param User $user User object
|
|
* @return int >0 if OK, <0 if KO
|
|
*/
|
|
public function update($user)
|
|
{
|
|
$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
|
|
$sql .= " ref = '".$this->db->escape($this->ref)."'";
|
|
$sql .= ", label = '".$this->db->escape($this->label)."'";
|
|
$sql .= ", label_short = ".($this->label_short ? "'".$this->db->escape($this->label_short)."'" : "NULL");
|
|
$sql .= ", description = ".($this->description ? "'".$this->db->escape($this->description)."'" : "NULL");
|
|
$sql .= ", fk_parent = ".(int)($this->fk_parent ?: 0);
|
|
$sql .= ", level_type = ".($this->level_type ? "'".$this->db->escape($this->level_type)."'" : "NULL");
|
|
$sql .= ", icon = ".($this->icon ? "'".$this->db->escape($this->icon)."'" : "NULL");
|
|
$sql .= ", color = ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
|
|
$sql .= ", can_have_children = ".(int)$this->can_have_children;
|
|
$sql .= ", has_product = ".(int)($this->has_product ?: 0);
|
|
$sql .= ", position = ".(int)$this->position;
|
|
$sql .= ", active = ".(int)$this->active;
|
|
$sql .= ", fk_user_modif = ".(int)$user->id;
|
|
$sql .= " WHERE rowid = ".(int)$this->id;
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
return 1;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete building type
|
|
*
|
|
* @param User $user User object
|
|
* @return int >0 if OK, <0 if KO
|
|
*/
|
|
public function delete($user)
|
|
{
|
|
// Don't allow deleting system types
|
|
if ($this->is_system) {
|
|
$this->error = 'CannotDeleteSystemType';
|
|
return -1;
|
|
}
|
|
|
|
// Check if type is used as parent
|
|
$sql = "SELECT COUNT(*) as cnt FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sql .= " WHERE fk_parent = ".(int)$this->id;
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
$obj = $this->db->fetch_object($resql);
|
|
if ($obj->cnt > 0) {
|
|
$this->error = 'CannotDeleteTypeWithChildren';
|
|
return -2;
|
|
}
|
|
}
|
|
|
|
$sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
$sql .= " WHERE rowid = ".(int)$this->id;
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
return 1;
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch all building types
|
|
*
|
|
* @param int $activeOnly Only active types
|
|
* @param string $levelType Filter by level type
|
|
* @return array Array of BuildingType objects
|
|
*/
|
|
public function fetchAll($activeOnly = 1, $levelType = '')
|
|
{
|
|
global $conf;
|
|
|
|
$result = array();
|
|
|
|
$sql = "SELECT t.*, p.label as parent_label";
|
|
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
|
|
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$this->table_element." as p ON t.fk_parent = p.rowid";
|
|
$sql .= " WHERE (t.entity = ".(int)$conf->entity." OR t.entity = 0)";
|
|
if ($activeOnly) {
|
|
$sql .= " AND t.active = 1";
|
|
}
|
|
if ($levelType) {
|
|
$sql .= " AND t.level_type = '".$this->db->escape($levelType)."'";
|
|
}
|
|
$sql .= " ORDER BY t.level_type, t.position, t.label";
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
while ($obj = $this->db->fetch_object($resql)) {
|
|
$type = new BuildingType($this->db);
|
|
$type->id = $obj->rowid;
|
|
$type->entity = $obj->entity;
|
|
$type->ref = $obj->ref;
|
|
$type->label = $obj->label;
|
|
$type->label_short = $obj->label_short;
|
|
$type->description = $obj->description;
|
|
$type->fk_parent = $obj->fk_parent;
|
|
$type->level_type = $obj->level_type;
|
|
$type->icon = $obj->icon;
|
|
$type->color = $obj->color;
|
|
$type->picto = $obj->picto;
|
|
$type->is_system = $obj->is_system;
|
|
$type->can_have_children = $obj->can_have_children;
|
|
$type->has_product = $obj->has_product ?? 0;
|
|
$type->position = $obj->position;
|
|
$type->active = $obj->active;
|
|
$type->parent_label = $obj->parent_label;
|
|
$result[] = $type;
|
|
}
|
|
$this->db->free($resql);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Fetch types grouped by level type
|
|
*
|
|
* @param int $activeOnly Only active types
|
|
* @return array Array grouped by level_type
|
|
*/
|
|
public function fetchGroupedByLevel($activeOnly = 1)
|
|
{
|
|
$all = $this->fetchAll($activeOnly);
|
|
$grouped = array();
|
|
|
|
foreach ($all as $type) {
|
|
$level = $type->level_type ?: 'other';
|
|
if (!isset($grouped[$level])) {
|
|
$grouped[$level] = array();
|
|
}
|
|
$grouped[$level][] = $type;
|
|
}
|
|
|
|
return $grouped;
|
|
}
|
|
|
|
/**
|
|
* Get level type label
|
|
*
|
|
* @return string Translated label
|
|
*/
|
|
public function getLevelTypeLabel()
|
|
{
|
|
global $langs;
|
|
$langs->load('kundenkarte@kundenkarte');
|
|
|
|
$labels = array(
|
|
self::LEVEL_BUILDING => $langs->trans('BuildingLevelBuilding'),
|
|
self::LEVEL_FLOOR => $langs->trans('BuildingLevelFloor'),
|
|
self::LEVEL_WING => $langs->trans('BuildingLevelWing'),
|
|
self::LEVEL_CORRIDOR => $langs->trans('BuildingLevelCorridor'),
|
|
self::LEVEL_ROOM => $langs->trans('BuildingLevelRoom'),
|
|
self::LEVEL_AREA => $langs->trans('BuildingLevelArea'),
|
|
);
|
|
|
|
return isset($labels[$this->level_type]) ? $labels[$this->level_type] : $this->level_type;
|
|
}
|
|
|
|
/**
|
|
* Get all level types with labels
|
|
*
|
|
* @return array Array of level_type => label
|
|
*/
|
|
public static function getLevelTypes()
|
|
{
|
|
global $langs;
|
|
$langs->load('kundenkarte@kundenkarte');
|
|
|
|
return array(
|
|
self::LEVEL_BUILDING => $langs->trans('BuildingLevelBuilding'),
|
|
self::LEVEL_FLOOR => $langs->trans('BuildingLevelFloor'),
|
|
self::LEVEL_WING => $langs->trans('BuildingLevelWing'),
|
|
self::LEVEL_CORRIDOR => $langs->trans('BuildingLevelCorridor'),
|
|
self::LEVEL_ROOM => $langs->trans('BuildingLevelRoom'),
|
|
self::LEVEL_AREA => $langs->trans('BuildingLevelArea'),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get next available position
|
|
*
|
|
* @param string $levelType Level type
|
|
* @return int Next position
|
|
*/
|
|
public function getNextPosition($levelType = '')
|
|
{
|
|
$sql = "SELECT MAX(position) as maxpos FROM ".MAIN_DB_PREFIX.$this->table_element;
|
|
if ($levelType) {
|
|
$sql .= " WHERE level_type = '".$this->db->escape($levelType)."'";
|
|
}
|
|
|
|
$resql = $this->db->query($sql);
|
|
if ($resql) {
|
|
$obj = $this->db->fetch_object($resql);
|
|
return ($obj->maxpos ?: 0) + 10;
|
|
}
|
|
return 10;
|
|
}
|
|
}
|