kundenkarte/class/mediumtype.class.php
data 844e6060c6 feat(pwa): Offline-fähige Progressive Web App für Elektriker
PWA Mobile App für Schaltschrank-Dokumentation vor Ort:
- Token-basierte Authentifizierung (15 Tage gültig)
- Kundensuche mit Offline-Cache
- Anlagen-Auswahl und Offline-Laden
- Felder/Hutschienen/Automaten erfassen
- Automatische Synchronisierung wenn wieder online
- Installierbar auf dem Smartphone Home Screen
- Touch-optimiertes Dark Mode Design
- Quick-Select für Automaten-Werte (B16, C32, etc.)

Schaltplan-Editor Verbesserungen:
- Block Hover-Tooltip mit show_in_hover Feldern
- Produktinfo mit Icon im Tooltip
- Position und Breite in TE

Neue Dateien:
- pwa.php, pwa_auth.php - PWA Einstieg & Auth
- ajax/pwa_api.php - PWA AJAX API
- js/pwa.js, css/pwa.css - PWA App & Styles
- sw.js, manifest.json - Service Worker & Manifest
- img/pwa-icon-192.png, img/pwa-icon-512.png

Version: 5.2.0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 15:27:06 +01:00

383 lines
11 KiB
PHP
Executable file

<?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.
*/
/**
* Class MediumType
* Manages cable/wire types (Kabeltypen) for connections
*/
class MediumType extends CommonObject
{
public $element = 'mediumtype';
public $table_element = 'kundenkarte_medium_type';
public $ref;
public $label;
public $label_short;
public $description;
public $fk_system;
public $category;
public $default_spec;
public $available_specs; // JSON array
public $color;
public $picto;
public $fk_product;
public $is_system;
public $position;
public $active;
public $date_creation;
public $fk_user_creat;
public $fk_user_modif;
// Loaded properties
public $system_label;
public $system_code;
// Category constants
const CAT_STROMKABEL = 'stromkabel';
const CAT_NETZWERKKABEL = 'netzwerkkabel';
const CAT_LWL = 'lwl';
const CAT_KOAX = 'koax';
const CAT_SONSTIGES = 'sonstiges';
/**
* 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->ref) || empty($this->label)) {
$this->error = 'ErrorMissingParameters';
return -1;
}
$this->db->begin();
$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
$sql .= "entity, ref, label, label_short, description, fk_system, category,";
$sql .= " default_spec, available_specs, color, picto, fk_product,";
$sql .= " is_system, position, active, date_creation, fk_user_creat";
$sql .= ") VALUES (";
$sql .= "0"; // entity 0 = global
$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_system);
$sql .= ", ".($this->category ? "'".$this->db->escape($this->category)."'" : "NULL");
$sql .= ", ".($this->default_spec ? "'".$this->db->escape($this->default_spec)."'" : "NULL");
$sql .= ", ".($this->available_specs ? "'".$this->db->escape($this->available_specs)."'" : "NULL");
$sql .= ", ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
$sql .= ", ".($this->picto ? "'".$this->db->escape($this->picto)."'" : "NULL");
$sql .= ", ".($this->fk_product > 0 ? ((int) $this->fk_product) : "NULL");
$sql .= ", 0"; // is_system = 0 for user-created
$sql .= ", ".((int) $this->position);
$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) {
$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 t.*, s.label as system_label, s.code as system_code";
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON t.fk_system = s.rowid";
$sql .= " WHERE t.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->ref = $obj->ref;
$this->label = $obj->label;
$this->label_short = $obj->label_short;
$this->description = $obj->description;
$this->fk_system = $obj->fk_system;
$this->category = $obj->category;
$this->default_spec = $obj->default_spec;
$this->available_specs = $obj->available_specs;
$this->color = $obj->color;
$this->picto = $obj->picto;
$this->fk_product = $obj->fk_product;
$this->is_system = $obj->is_system;
$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->system_label = $obj->system_label;
$this->system_code = $obj->system_code;
$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 .= " 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_system = ".((int) $this->fk_system);
$sql .= ", category = ".($this->category ? "'".$this->db->escape($this->category)."'" : "NULL");
$sql .= ", default_spec = ".($this->default_spec ? "'".$this->db->escape($this->default_spec)."'" : "NULL");
$sql .= ", available_specs = ".($this->available_specs ? "'".$this->db->escape($this->available_specs)."'" : "NULL");
$sql .= ", color = ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
$sql .= ", picto = ".($this->picto ? "'".$this->db->escape($this->picto)."'" : "NULL");
$sql .= ", fk_product = ".($this->fk_product > 0 ? ((int) $this->fk_product) : "NULL");
$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) {
$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)
{
// Cannot delete system types
if ($this->is_system) {
$this->error = 'ErrorCannotDeleteSystemType';
return -2;
}
$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 medium types for a system
*
* @param int $systemId System ID (0 = all)
* @param int $activeOnly Only active types
* @return array Array of MediumType objects
*/
public function fetchAllBySystem($systemId = 0, $activeOnly = 1)
{
$results = array();
$sql = "SELECT t.*, s.label as system_label, s.code as system_code";
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON t.fk_system = s.rowid";
$sql .= " WHERE 1 = 1";
if ($systemId > 0) {
// Show types for this system AND global types (fk_system = 0)
$sql .= " AND (t.fk_system = ".((int) $systemId)." OR t.fk_system = 0)";
}
if ($activeOnly) {
$sql .= " AND t.active = 1";
}
$sql .= " ORDER BY t.category ASC, t.position ASC, t.label ASC";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$type = new MediumType($this->db);
$type->id = $obj->rowid;
$type->ref = $obj->ref;
$type->label = $obj->label;
$type->label_short = $obj->label_short;
$type->description = $obj->description;
$type->fk_system = $obj->fk_system;
$type->category = $obj->category;
$type->default_spec = $obj->default_spec;
$type->available_specs = $obj->available_specs;
$type->color = $obj->color;
$type->picto = $obj->picto;
$type->fk_product = $obj->fk_product;
$type->is_system = $obj->is_system;
$type->position = $obj->position;
$type->active = $obj->active;
$type->system_label = $obj->system_label;
$type->system_code = $obj->system_code;
$results[] = $type;
}
$this->db->free($resql);
}
return $results;
}
/**
* Fetch all types grouped by category
*
* @param int $systemId System ID (0 = all)
* @return array Associative array: category => array of MediumType objects
*/
public function fetchGroupedByCategory($systemId = 0)
{
$all = $this->fetchAllBySystem($systemId, 1);
$grouped = array();
foreach ($all as $type) {
$cat = $type->category ?: 'sonstiges';
if (!isset($grouped[$cat])) {
$grouped[$cat] = array();
}
$grouped[$cat][] = $type;
}
return $grouped;
}
/**
* Get available specs as array
*
* @return array Array of specification strings
*/
public function getAvailableSpecsArray()
{
if (empty($this->available_specs)) {
return array();
}
$specs = json_decode($this->available_specs, true);
return is_array($specs) ? $specs : array();
}
/**
* Get category label
*
* @return string Translated category label
*/
public function getCategoryLabel()
{
global $langs;
switch ($this->category) {
case self::CAT_STROMKABEL:
return $langs->trans('MediumCatStromkabel');
case self::CAT_NETZWERKKABEL:
return $langs->trans('MediumCatNetzwerkkabel');
case self::CAT_LWL:
return $langs->trans('MediumCatLWL');
case self::CAT_KOAX:
return $langs->trans('MediumCatKoax');
case self::CAT_SONSTIGES:
default:
return $langs->trans('MediumCatSonstiges');
}
}
/**
* Get all category options
*
* @return array category_code => translated_label
*/
public static function getCategoryOptions()
{
global $langs;
return array(
self::CAT_STROMKABEL => $langs->trans('MediumCatStromkabel'),
self::CAT_NETZWERKKABEL => $langs->trans('MediumCatNetzwerkkabel'),
self::CAT_LWL => $langs->trans('MediumCatLWL'),
self::CAT_KOAX => $langs->trans('MediumCatKoax'),
self::CAT_SONSTIGES => $langs->trans('MediumCatSonstiges')
);
}
}