diff --git a/admin/anlage_types.php b/admin/anlage_types.php
old mode 100755
new mode 100644
index 10e727f..42bfccc
--- a/admin/anlage_types.php
+++ b/admin/anlage_types.php
@@ -63,6 +63,7 @@ if ($action == 'add') {
$anlageType->can_be_nested = GETPOSTINT('can_be_nested');
$anlageType->allowed_parent_types = preg_replace('/[^A-Z0-9_,]/i', '', GETPOST('allowed_parent_types', 'nohtml'));
$anlageType->can_have_equipment = GETPOSTINT('can_have_equipment');
+ $anlageType->has_accessories = GETPOSTINT('has_accessories');
$anlageType->picto = GETPOST('picto', 'alphanohtml');
$anlageType->color = GETPOST('color', 'alphanohtml');
$anlageType->position = GETPOSTINT('position');
@@ -113,6 +114,7 @@ if ($action == 'update') {
$anlageType->can_be_nested = GETPOSTINT('can_be_nested');
$anlageType->allowed_parent_types = preg_replace('/[^A-Z0-9_,]/i', '', GETPOST('allowed_parent_types', 'nohtml'));
$anlageType->can_have_equipment = GETPOSTINT('can_have_equipment');
+ $anlageType->has_accessories = GETPOSTINT('has_accessories');
$anlageType->picto = GETPOST('picto', 'alphanohtml');
$anlageType->color = GETPOST('color', 'alphanohtml');
$anlageType->position = GETPOSTINT('position');
@@ -166,6 +168,7 @@ if ($action == 'copy' && $typeId > 0) {
$newType->can_be_nested = $sourceType->can_be_nested;
$newType->allowed_parent_types = $sourceType->allowed_parent_types;
$newType->can_have_equipment = $sourceType->can_have_equipment;
+ $newType->has_accessories = $sourceType->has_accessories;
$newType->picto = $sourceType->picto;
$newType->color = $sourceType->color;
$newType->position = $sourceType->position + 1;
@@ -402,6 +405,11 @@ if (in_array($action, array('create', 'edit'))) {
print '
| '.$langs->trans('AllowedParentTypes').' | ';
print '';
diff --git a/ajax/anlage_accessory.php b/ajax/anlage_accessory.php
new file mode 100644
index 0000000..a30459d
--- /dev/null
+++ b/ajax/anlage_accessory.php
@@ -0,0 +1,154 @@
+loadLangs(array('kundenkarte@kundenkarte'));
+
+$action = GETPOST('action', 'aZ09');
+
+$response = array('success' => false, 'error' => '');
+
+// Berechtigungsprüfung
+if (!$user->hasRight('kundenkarte', 'read')) {
+ $response['error'] = $langs->trans('ErrorPermissionDenied');
+ echo json_encode($response);
+ exit;
+}
+
+$accessory = new AnlageAccessory($db);
+
+switch ($action) {
+ case 'list':
+ // Alle Zubehörteile einer Anlage laden
+ $anlageId = GETPOSTINT('fk_anlage');
+ if ($anlageId > 0) {
+ $accessories = $accessory->fetchAllByAnlage($anlageId);
+ $result = array();
+ foreach ($accessories as $acc) {
+ $result[] = array(
+ 'id' => $acc->id,
+ 'fk_product' => $acc->fk_product,
+ 'product_ref' => $acc->product_ref,
+ 'product_label' => $acc->product_label,
+ 'product_price' => $acc->product_price,
+ 'qty' => $acc->qty,
+ 'note' => $acc->note,
+ );
+ }
+ $response['success'] = true;
+ $response['accessories'] = $result;
+ } else {
+ $response['error'] = 'Missing fk_anlage';
+ }
+ break;
+
+ case 'add':
+ // Zubehör hinzufügen
+ if (!$user->hasRight('kundenkarte', 'write')) {
+ $response['error'] = $langs->trans('ErrorPermissionDenied');
+ break;
+ }
+
+ $accessory->fk_anlage = GETPOSTINT('fk_anlage');
+ $accessory->fk_product = GETPOSTINT('fk_product');
+ $accessory->qty = GETPOSTINT('qty') > 0 ? GETPOSTINT('qty') : 1;
+ $accessory->note = GETPOST('note', 'alphanohtml');
+
+ $result = $accessory->create($user);
+ if ($result > 0) {
+ $response['success'] = true;
+ $response['id'] = $result;
+ } else {
+ $response['error'] = $accessory->error ?: 'Fehler beim Speichern';
+ }
+ break;
+
+ case 'update':
+ // Zubehör aktualisieren (Menge, Notiz)
+ if (!$user->hasRight('kundenkarte', 'write')) {
+ $response['error'] = $langs->trans('ErrorPermissionDenied');
+ break;
+ }
+
+ $id = GETPOSTINT('id');
+ if ($id > 0 && $accessory->fetch($id) > 0) {
+ $accessory->qty = GETPOSTINT('qty') > 0 ? GETPOSTINT('qty') : $accessory->qty;
+ $accessory->note = GETPOST('note', 'alphanohtml');
+
+ $result = $accessory->update($user);
+ if ($result > 0) {
+ $response['success'] = true;
+ } else {
+ $response['error'] = 'Fehler beim Speichern';
+ }
+ } else {
+ $response['error'] = $langs->trans('ErrorRecordNotFound');
+ }
+ break;
+
+ case 'delete':
+ // Zubehör löschen
+ if (!$user->hasRight('kundenkarte', 'delete')) {
+ $response['error'] = $langs->trans('ErrorPermissionDenied');
+ break;
+ }
+
+ $id = GETPOSTINT('id');
+ if ($id > 0 && $accessory->fetch($id) > 0) {
+ $result = $accessory->delete($user);
+ if ($result > 0) {
+ $response['success'] = true;
+ } else {
+ $response['error'] = 'Fehler beim Löschen';
+ }
+ } else {
+ $response['error'] = $langs->trans('ErrorRecordNotFound');
+ }
+ break;
+
+ case 'order':
+ // Lieferantenbestellung aus Zubehör erstellen
+ if (!$user->hasRight('kundenkarte', 'write')) {
+ $response['error'] = $langs->trans('ErrorPermissionDenied');
+ break;
+ }
+
+ $anlageId = GETPOSTINT('fk_anlage');
+ $supplierId = GETPOSTINT('supplier_id');
+ $idsRaw = GETPOST('ids', 'array');
+
+ if ($anlageId > 0 && $supplierId > 0 && !empty($idsRaw)) {
+ $ids = array_map('intval', $idsRaw);
+ $result = $accessory->generateSupplierOrder($user, $supplierId, $anlageId, $ids);
+ if ($result > 0) {
+ $response['success'] = true;
+ $response['order_id'] = $result;
+ } else {
+ $response['error'] = $accessory->error ?: 'Fehler beim Erstellen der Bestellung';
+ }
+ } else {
+ $response['error'] = 'Fehlende Parameter (Anlage, Lieferant, IDs)';
+ }
+ break;
+
+ default:
+ $response['error'] = 'Unknown action';
+}
+
+echo json_encode($response);
diff --git a/class/anlage.class.php b/class/anlage.class.php
index cac7377..f3c409e 100755
--- a/class/anlage.class.php
+++ b/class/anlage.class.php
@@ -24,6 +24,7 @@ class Anlage extends CommonObject
public $fk_parent;
public $fk_system;
public $fk_building_node;
+ public $fk_product;
public $manufacturer;
public $model;
@@ -96,7 +97,7 @@ class Anlage extends CommonObject
$this->db->begin();
$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
- $sql .= "entity, ref, label, fk_soc, fk_contact, fk_anlage_type, fk_parent, fk_system,";
+ $sql .= "entity, ref, label, fk_soc, fk_contact, fk_anlage_type, fk_parent, fk_system, fk_product,";
$sql .= " manufacturer, model, serial_number, power_rating, field_values,";
$sql .= " location, installation_date, warranty_until,";
$sql .= " rang, level, note_private, note_public, status,";
@@ -110,6 +111,7 @@ class Anlage extends CommonObject
$sql .= ", ".((int) $this->fk_anlage_type);
$sql .= ", ".((int) ($this->fk_parent > 0 ? $this->fk_parent : 0));
$sql .= ", ".((int) $this->fk_system);
+ $sql .= ", ".($this->fk_product > 0 ? (int) $this->fk_product : "NULL");
$sql .= ", ".($this->manufacturer ? "'".$this->db->escape($this->manufacturer)."'" : "NULL");
$sql .= ", ".($this->model ? "'".$this->db->escape($this->model)."'" : "NULL");
$sql .= ", ".($this->serial_number ? "'".$this->db->escape($this->serial_number)."'" : "NULL");
@@ -203,6 +205,7 @@ class Anlage extends CommonObject
$this->fk_parent = $obj->fk_parent;
$this->fk_system = $obj->fk_system;
$this->fk_building_node = isset($obj->fk_building_node) ? (int) $obj->fk_building_node : 0;
+ $this->fk_product = isset($obj->fk_product) ? (int) $obj->fk_product : null;
$this->manufacturer = $obj->manufacturer;
$this->model = $obj->model;
@@ -231,8 +234,14 @@ class Anlage extends CommonObject
$this->type_label = $obj->type_label;
$this->type_short = $obj->type_short;
$this->type_picto = $obj->type_picto;
+ $this->type_color = isset($obj->type_color) ? $obj->type_color : '';
$this->type_can_have_children = isset($obj->type_can_have_children) ? (int) $obj->type_can_have_children : 0;
$this->type_can_have_equipment = isset($obj->type_can_have_equipment) ? (int) $obj->type_can_have_equipment : 0;
+ $this->type_has_accessories = isset($obj->type_has_accessories) ? (int) $obj->type_has_accessories : 0;
+
+ // Produkt-Info (aus JOIN)
+ $this->product_ref = isset($obj->product_ref) ? $obj->product_ref : '';
+ $this->product_label = isset($obj->product_label) ? $obj->product_label : '';
// System info
$this->system_label = $obj->system_label;
@@ -291,6 +300,7 @@ class Anlage extends CommonObject
$sql .= ", note_private = ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL");
$sql .= ", note_public = ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "NULL");
$sql .= ", status = ".((int) $this->status);
+ $sql .= ", fk_product = ".($this->fk_product > 0 ? (int) $this->fk_product : "NULL");
$sql .= ", decommissioned = ".((int) $this->decommissioned);
$sql .= ", date_decommissioned = ".($this->date_decommissioned ? "'".$this->db->escape($this->date_decommissioned)."'" : "NULL");
$sql .= ", fk_user_modif = ".((int) $user->id);
@@ -407,9 +417,11 @@ class Anlage extends CommonObject
$results = array();
- $sql = "SELECT a.*, t.label as type_label, t.label_short as type_short, t.picto as type_picto,";
+ $sql = "SELECT a.*, t.label as type_label, t.label_short as type_short, t.picto as type_picto, t.color as type_color,";
$sql .= " t.can_have_children as type_can_have_children, t.can_have_equipment as type_can_have_equipment,";
+ $sql .= " t.has_accessories as type_has_accessories,";
$sql .= " s.label as system_label, s.code as system_code,";
+ $sql .= " p.ref as product_ref, p.label as product_label,";
// Count images
$sql .= " (SELECT COUNT(*) FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_files f WHERE f.fk_anlage = a.rowid AND f.file_type = 'image') as image_count,";
// Count documents (pdf + document)
@@ -417,6 +429,7 @@ class Anlage extends CommonObject
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as a";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_anlage_type as t ON a.fk_anlage_type = t.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON a.fk_system = s.rowid";
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON a.fk_product = p.rowid";
$sql .= " WHERE a.fk_parent = ".((int) $parentId);
$sql .= " AND a.entity = ".((int) $conf->entity);
$sql .= " AND a.status = 1";
@@ -717,9 +730,11 @@ class Anlage extends CommonObject
$results = array();
- $sql = "SELECT a.*, t.label as type_label, t.label_short as type_short, t.picto as type_picto,";
+ $sql = "SELECT a.*, t.label as type_label, t.label_short as type_short, t.picto as type_picto, t.color as type_color,";
$sql .= " t.can_have_children as type_can_have_children, t.can_have_equipment as type_can_have_equipment,";
+ $sql .= " t.has_accessories as type_has_accessories,";
$sql .= " s.label as system_label, s.code as system_code,";
+ $sql .= " p.ref as product_ref, p.label as product_label,";
// Count images
$sql .= " (SELECT COUNT(*) FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_files f WHERE f.fk_anlage = a.rowid AND f.file_type = 'image') as image_count,";
// Count documents (pdf + document)
@@ -727,6 +742,7 @@ class Anlage extends CommonObject
$sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as a";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."kundenkarte_anlage_type as t ON a.fk_anlage_type = t.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system as s ON a.fk_system = s.rowid";
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON a.fk_product = p.rowid";
$sql .= " WHERE a.fk_parent = ".((int) $parentId);
$sql .= " AND a.entity = ".((int) $conf->entity);
$sql .= " AND a.status = 1";
diff --git a/class/anlageaccessory.class.php b/class/anlageaccessory.class.php
new file mode 100644
index 0000000..9b2f0da
--- /dev/null
+++ b/class/anlageaccessory.class.php
@@ -0,0 +1,391 @@
+db = $db;
+ }
+
+ /**
+ * Zubehör erstellen
+ *
+ * @param User $user Benutzer
+ * @return int <0 bei Fehler, ID bei Erfolg
+ */
+ public function create($user)
+ {
+ $error = 0;
+ $now = dol_now();
+
+ if (empty($this->fk_anlage) || empty($this->fk_product)) {
+ $this->error = 'ErrorMissingParameters';
+ return -1;
+ }
+
+ // Prüfen ob bereits vorhanden
+ if ($this->alreadyExists($this->fk_anlage, $this->fk_product)) {
+ $this->error = 'ErrorAccessoryAlreadyExists';
+ return -2;
+ }
+
+ $this->db->begin();
+
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
+ $sql .= "fk_anlage, fk_product, qty, rang, note,";
+ $sql .= " date_creation, fk_user_creat";
+ $sql .= ") VALUES (";
+ $sql .= ((int) $this->fk_anlage);
+ $sql .= ", ".((int) $this->fk_product);
+ $sql .= ", ".((float) ($this->qty > 0 ? $this->qty : 1));
+ $sql .= ", ".((int) $this->rang);
+ $sql .= ", ".($this->note ? "'".$this->db->escape($this->note)."'" : "NULL");
+ $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;
+ }
+ }
+
+ /**
+ * Zubehör laden
+ *
+ * @param int $id ID
+ * @return int <0 bei Fehler, 0 nicht gefunden, >0 OK
+ */
+ public function fetch($id)
+ {
+ $sql = "SELECT a.*, p.ref as product_ref, p.label as product_label, p.price as product_price, p.fk_unit as product_fk_unit";
+ $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as a";
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON a.fk_product = p.rowid";
+ $sql .= " WHERE a.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->fk_anlage = $obj->fk_anlage;
+ $this->fk_product = $obj->fk_product;
+ $this->qty = $obj->qty;
+ $this->rang = $obj->rang;
+ $this->note = $obj->note;
+ $this->date_creation = $this->db->jdate($obj->date_creation);
+ $this->fk_user_creat = $obj->fk_user_creat;
+ $this->product_ref = $obj->product_ref;
+ $this->product_label = $obj->product_label;
+ $this->product_price = $obj->product_price;
+ $this->product_fk_unit = $obj->product_fk_unit;
+ $this->db->free($resql);
+ return 1;
+ } else {
+ $this->db->free($resql);
+ return 0;
+ }
+ } else {
+ $this->error = $this->db->lasterror();
+ return -1;
+ }
+ }
+
+ /**
+ * Zubehör aktualisieren
+ *
+ * @param User $user Benutzer
+ * @return int <0 bei Fehler, >0 OK
+ */
+ public function update($user)
+ {
+ $error = 0;
+
+ $this->db->begin();
+
+ $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
+ $sql .= " qty = ".((float) $this->qty);
+ $sql .= ", rang = ".((int) $this->rang);
+ $sql .= ", note = ".($this->note ? "'".$this->db->escape($this->note)."'" : "NULL");
+ $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;
+ }
+ }
+
+ /**
+ * Zubehör löschen
+ *
+ * @param User $user Benutzer
+ * @return int <0 bei Fehler, >0 OK
+ */
+ public function delete($user)
+ {
+ $this->db->begin();
+
+ $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element;
+ $sql .= " WHERE rowid = ".((int) $this->id);
+
+ $resql = $this->db->query($sql);
+ if (!$resql) {
+ $this->db->rollback();
+ $this->error = $this->db->lasterror();
+ return -1;
+ }
+
+ $this->db->commit();
+ return 1;
+ }
+
+ /**
+ * Alle Zubehörteile einer Anlage laden
+ *
+ * @param int $anlageId Anlage-ID
+ * @return array Array von AnlageAccessory-Objekten
+ */
+ public function fetchAllByAnlage($anlageId)
+ {
+ $results = array();
+
+ $sql = "SELECT a.*, p.ref as product_ref, p.label as product_label, p.price as product_price, p.fk_unit as product_fk_unit";
+ $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as a";
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON a.fk_product = p.rowid";
+ $sql .= " WHERE a.fk_anlage = ".((int) $anlageId);
+ $sql .= " ORDER BY a.rang ASC, a.rowid ASC";
+
+ $resql = $this->db->query($sql);
+ if ($resql) {
+ while ($obj = $this->db->fetch_object($resql)) {
+ $acc = new AnlageAccessory($this->db);
+ $acc->id = $obj->rowid;
+ $acc->fk_anlage = $obj->fk_anlage;
+ $acc->fk_product = $obj->fk_product;
+ $acc->qty = $obj->qty;
+ $acc->rang = $obj->rang;
+ $acc->note = $obj->note;
+ $acc->date_creation = $this->db->jdate($obj->date_creation);
+ $acc->fk_user_creat = $obj->fk_user_creat;
+ $acc->product_ref = $obj->product_ref;
+ $acc->product_label = $obj->product_label;
+ $acc->product_price = $obj->product_price;
+ $acc->product_fk_unit = $obj->product_fk_unit;
+ $results[] = $acc;
+ }
+ $this->db->free($resql);
+ }
+
+ return $results;
+ }
+
+ /**
+ * Prüfen ob Produkt bereits als Zubehör zugeordnet ist
+ *
+ * @param int $anlageId Anlage-ID
+ * @param int $productId Produkt-ID
+ * @return bool true wenn bereits vorhanden
+ */
+ public function alreadyExists($anlageId, $productId)
+ {
+ $sql = "SELECT COUNT(*) as cnt FROM ".MAIN_DB_PREFIX.$this->table_element;
+ $sql .= " WHERE fk_anlage = ".((int) $anlageId);
+ $sql .= " AND fk_product = ".((int) $productId);
+
+ $resql = $this->db->query($sql);
+ if ($resql) {
+ $obj = $this->db->fetch_object($resql);
+ return ($obj->cnt > 0);
+ }
+ return false;
+ }
+
+ /**
+ * Lieferantenbestellung aus ausgewählten Zubehörteilen erstellen
+ *
+ * @param User $user Benutzer
+ * @param int $supplierId Lieferanten-ID (fournisseur)
+ * @param int $anlageId Anlage-ID
+ * @param array $selectedIds Array von Accessory-IDs
+ * @param array $quantities Optional: ID => Menge
+ * @return int Bestell-ID bei Erfolg, <0 bei Fehler
+ */
+ public function generateSupplierOrder($user, $supplierId, $anlageId, $selectedIds, $quantities = array())
+ {
+ global $conf, $langs, $mysoc;
+
+ require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
+ require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
+ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
+
+ if (empty($selectedIds)) {
+ $this->error = 'NoProductsSelected';
+ return -1;
+ }
+
+ // Lieferant laden
+ $supplier = new Societe($this->db);
+ if ($supplier->fetch($supplierId) <= 0) {
+ $this->error = 'ErrorLoadingSupplier';
+ return -1;
+ }
+
+ // Zubehör der Anlage laden
+ $accessories = $this->fetchAllByAnlage($anlageId);
+ if (!is_array($accessories) || empty($accessories)) {
+ $this->error = 'NoAccessoriesFound';
+ return -2;
+ }
+
+ // Ausgewählte filtern
+ $toAdd = array();
+ foreach ($accessories as $acc) {
+ if (in_array($acc->id, $selectedIds)) {
+ $qty = isset($quantities[$acc->id]) ? (float) $quantities[$acc->id] : $acc->qty;
+ if ($qty > 0) {
+ $toAdd[] = array(
+ 'product_id' => $acc->fk_product,
+ 'qty' => $qty
+ );
+ }
+ }
+ }
+
+ if (empty($toAdd)) {
+ $this->error = 'NoValidProductsToAdd';
+ return -2;
+ }
+
+ // Lieferantenbestellung erstellen
+ $order = new CommandeFournisseur($this->db);
+ $order->socid = $supplierId;
+ $order->date = dol_now();
+ $order->note_private = $langs->trans('OrderGeneratedFromAccessories');
+
+ $this->db->begin();
+
+ $result = $order->create($user);
+ if ($result <= 0) {
+ $this->error = $order->error;
+ $this->errors = $order->errors;
+ $this->db->rollback();
+ return -3;
+ }
+
+ // Produkte hinzufügen
+ foreach ($toAdd as $item) {
+ $product = new Product($this->db);
+ $product->fetch($item['product_id']);
+
+ // MwSt-Satz ermitteln (Lieferant = Verkäufer, eigene Firma = Käufer)
+ $tva_tx = get_default_tva($supplier, $mysoc, $product->id);
+ $localtax1_tx = get_default_localtax($supplier, $mysoc, 1, $product->id);
+ $localtax2_tx = get_default_localtax($supplier, $mysoc, 2, $product->id);
+
+ // Lieferantenpreis ermitteln
+ $fournPrice = $product->price;
+ $fournPriceId = 0;
+ $fournRef = '';
+ $sqlFourn = "SELECT rowid, price as fourn_price, ref_fourn";
+ $sqlFourn .= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price";
+ $sqlFourn .= " WHERE fk_product = ".((int) $product->id);
+ $sqlFourn .= " AND fk_soc = ".((int) $supplierId);
+ $sqlFourn .= " ORDER BY price ASC LIMIT 1";
+ $resFourn = $this->db->query($sqlFourn);
+ if ($resFourn && $this->db->num_rows($resFourn) > 0) {
+ $objFourn = $this->db->fetch_object($resFourn);
+ $fournPrice = $objFourn->fourn_price;
+ $fournPriceId = $objFourn->rowid;
+ $fournRef = $objFourn->ref_fourn;
+ }
+
+ $lineResult = $order->addline(
+ $product->label, // Beschreibung
+ $fournPrice, // Preis HT
+ $item['qty'], // Menge
+ $tva_tx, // MwSt
+ $localtax1_tx, // Lokale Steuer 1
+ $localtax2_tx, // Lokale Steuer 2
+ $product->id, // Produkt-ID
+ $fournPriceId, // Lieferantenpreis-ID
+ $fournRef, // Lieferanten-Referenz
+ 0, // Rabatt
+ 'HT', // Preis-Basis
+ 0, // Preis TTC
+ 0, // Typ (0=Produkt)
+ 0, // Info bits
+ false, // notrigger
+ null, // Startdatum
+ null, // Enddatum
+ array(), // Optionen
+ $product->fk_unit // Einheit
+ );
+
+ if ($lineResult < 0) {
+ $this->error = $order->error;
+ $this->errors = $order->errors;
+ $this->db->rollback();
+ return -4;
+ }
+ }
+
+ $this->db->commit();
+ return $order->id;
+ }
+}
diff --git a/class/anlagetype.class.php b/class/anlagetype.class.php
old mode 100755
new mode 100644
index 07f743e..fd167a2
--- a/class/anlagetype.class.php
+++ b/class/anlagetype.class.php
@@ -26,6 +26,7 @@ class AnlageType extends CommonObject
public $can_be_nested;
public $allowed_parent_types;
public $can_have_equipment;
+ public $has_accessories;
public $picto;
public $color;
@@ -73,7 +74,7 @@ class AnlageType extends CommonObject
$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
$sql .= "entity, ref, label, label_short, description, fk_system,";
- $sql .= " can_have_children, can_be_nested, allowed_parent_types, can_have_equipment,";
+ $sql .= " can_have_children, can_be_nested, allowed_parent_types, can_have_equipment, has_accessories,";
$sql .= " picto, color, is_system, position, active,";
$sql .= " date_creation, fk_user_creat";
$sql .= ") VALUES (";
@@ -87,6 +88,7 @@ class AnlageType extends CommonObject
$sql .= ", ".((int) $this->can_be_nested);
$sql .= ", ".($this->allowed_parent_types ? "'".$this->db->escape($this->allowed_parent_types)."'" : "NULL");
$sql .= ", ".((int) $this->can_have_equipment);
+ $sql .= ", ".((int) $this->has_accessories);
$sql .= ", ".($this->picto ? "'".$this->db->escape($this->picto)."'" : "NULL");
$sql .= ", ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
$sql .= ", 0"; // is_system = 0 for user-created
@@ -144,6 +146,7 @@ class AnlageType extends CommonObject
$this->can_be_nested = $obj->can_be_nested;
$this->allowed_parent_types = $obj->allowed_parent_types;
$this->can_have_equipment = $obj->can_have_equipment ?? 0;
+ $this->has_accessories = $obj->has_accessories ?? 0;
$this->picto = $obj->picto;
$this->color = $obj->color;
$this->is_system = $obj->is_system;
@@ -190,6 +193,7 @@ class AnlageType extends CommonObject
$sql .= ", can_be_nested = ".((int) $this->can_be_nested);
$sql .= ", allowed_parent_types = ".($this->allowed_parent_types ? "'".$this->db->escape($this->allowed_parent_types)."'" : "NULL");
$sql .= ", can_have_equipment = ".((int) $this->can_have_equipment);
+ $sql .= ", has_accessories = ".((int) $this->has_accessories);
$sql .= ", picto = ".($this->picto ? "'".$this->db->escape($this->picto)."'" : "NULL");
$sql .= ", color = ".($this->color ? "'".$this->db->escape($this->color)."'" : "NULL");
$sql .= ", position = ".((int) $this->position);
@@ -312,6 +316,7 @@ class AnlageType extends CommonObject
$type->can_be_nested = $obj->can_be_nested;
$type->allowed_parent_types = $obj->allowed_parent_types;
$type->can_have_equipment = $obj->can_have_equipment ?? 0;
+ $type->has_accessories = $obj->has_accessories ?? 0;
$type->picto = $obj->picto;
$type->is_system = $obj->is_system;
$type->position = $obj->position;
diff --git a/core/modules/modKundenKarte.class.php b/core/modules/modKundenKarte.class.php
index afce6f9..1810463 100755
--- a/core/modules/modKundenKarte.class.php
+++ b/core/modules/modKundenKarte.class.php
@@ -76,7 +76,7 @@ class modKundenKarte extends DolibarrModules
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@kundenkarte'
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
- $this->version = '8.4';
+ $this->version = '8.5';
// Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
@@ -412,6 +412,23 @@ class modKundenKarte extends DolibarrModules
'target' => '',
'user' => 0,
);
+ // Werkzeuge-Seite unter Start-Menü
+ $this->menu[$r++] = array(
+ 'fk_menu' => 'fk_mainmenu=home',
+ 'type' => 'left',
+ 'titre' => 'CompanyTools',
+ 'prefix' => img_picto('', 'fa-wrench', 'class="pictofixedwidth valignmiddle paddingright"'),
+ 'mainmenu' => 'home',
+ 'leftmenu' => 'kundenkarte_werkzeuge',
+ 'url' => '/kundenkarte/werkzeuge.php',
+ 'langs' => 'kundenkarte@kundenkarte',
+ 'position' => 100,
+ 'enabled' => 'isModEnabled("kundenkarte")',
+ 'perms' => '$user->hasRight("kundenkarte", "read")',
+ 'target' => '',
+ 'user' => 0,
+ );
+
/* END MODULEBUILDER LEFTMENU */
@@ -636,6 +653,9 @@ class modKundenKarte extends DolibarrModules
// v8.0.0: Ausgebaut-Status für Anlagen
$this->migrate_v800_decommissioned();
+
+ // v8.1.0: Werkzeuge & Zubehör
+ $this->migrate_v810_werkzeuge();
}
/**
@@ -950,6 +970,58 @@ class modKundenKarte extends DolibarrModules
}
}
+ /**
+ * Migration v8.1.0: Werkzeuge & Zubehör
+ * - fk_product auf Anlage (Produkt-Zuordnung)
+ * - has_accessories auf Anlage-Typ
+ * - Zubehör-Tabelle
+ * - WERKZEUG System-Kategorie
+ */
+ private function migrate_v810_werkzeuge()
+ {
+ // 1. fk_product auf Anlage
+ $table = MAIN_DB_PREFIX."kundenkarte_anlage";
+ $resql = $this->db->query("SHOW COLUMNS FROM ".$table." LIKE 'fk_product'");
+ if (!$resql || $this->db->num_rows($resql) == 0) {
+ $this->db->query("ALTER TABLE ".$table." ADD COLUMN fk_product integer NULL AFTER fk_building_node");
+ $this->db->query("ALTER TABLE ".$table." ADD INDEX idx_anlage_fk_product (fk_product)");
+ }
+
+ // 2. has_accessories auf Anlage-Typ
+ $table = MAIN_DB_PREFIX."kundenkarte_anlage_type";
+ $resql = $this->db->query("SHOW COLUMNS FROM ".$table." LIKE 'has_accessories'");
+ if (!$resql || $this->db->num_rows($resql) == 0) {
+ $this->db->query("ALTER TABLE ".$table." ADD COLUMN has_accessories tinyint DEFAULT 0 NOT NULL AFTER can_have_equipment");
+ }
+
+ // 3. Zubehör-Tabelle
+ $table = MAIN_DB_PREFIX."kundenkarte_anlage_accessory";
+ $resql = $this->db->query("SHOW TABLES LIKE '".$this->db->escape($table)."'");
+ if (!$resql || $this->db->num_rows($resql) == 0) {
+ $sql = "CREATE TABLE ".$table." (";
+ $sql .= " rowid integer AUTO_INCREMENT PRIMARY KEY,";
+ $sql .= " fk_anlage integer NOT NULL,";
+ $sql .= " fk_product integer NOT NULL,";
+ $sql .= " qty double DEFAULT 1,";
+ $sql .= " rang integer DEFAULT 0,";
+ $sql .= " note varchar(255),";
+ $sql .= " date_creation datetime,";
+ $sql .= " fk_user_creat integer,";
+ $sql .= " UNIQUE KEY uk_anlage_accessory (fk_anlage, fk_product),";
+ $sql .= " INDEX idx_accessory_anlage (fk_anlage),";
+ $sql .= " CONSTRAINT fk_accessory_anlage FOREIGN KEY (fk_anlage) REFERENCES ".MAIN_DB_PREFIX."kundenkarte_anlage(rowid) ON DELETE CASCADE";
+ $sql .= ") ENGINE=InnoDB";
+ $this->db->query($sql);
+ }
+
+ // 4. WERKZEUG System-Kategorie (falls nicht vorhanden)
+ $sysTable = MAIN_DB_PREFIX."c_kundenkarte_anlage_system";
+ $resql = $this->db->query("SELECT rowid FROM ".$sysTable." WHERE code = 'WERKZEUG'");
+ if (!$resql || $this->db->num_rows($resql) == 0) {
+ $this->db->query("INSERT INTO ".$sysTable." (code, label, active, position) VALUES ('WERKZEUG', 'Werkzeuge & Maschinen', 1, 90)");
+ }
+ }
+
/**
* Function called when module is disabled.
* Remove from database constants, boxes and permissions from Dolibarr database.
diff --git a/langs/de_DE/kundenkarte.lang b/langs/de_DE/kundenkarte.lang
index 1505a42..1e2d564 100755
--- a/langs/de_DE/kundenkarte.lang
+++ b/langs/de_DE/kundenkarte.lang
@@ -561,3 +561,19 @@ Decommissioned = Ausgebaut
Decommission = Ausbauen
Recommission = Wieder einbauen
ShowDecommissioned = Ausgebaute Elemente anzeigen
+
+# Werkzeuge & Zubehör
+CompanyTools = Firmen-Werkzeuge
+HasAccessories = Hat Zubehör
+HasAccessoriesHelp = Ermöglicht die Zuordnung von Zubehör und Ersatzteilen
+Accessories = Zubehör / Ersatzteile
+NoAccessories = Kein Zubehör zugeordnet
+SearchProduct = Produkt suchen
+SelectSupplier = Lieferant auswählen
+CreateSupplierOrder = Lieferantenbestellung erstellen
+OrderAccessories = Zubehör bestellen
+OrderGeneratedFromAccessories = Bestellung aus Anlagen-Zubehör generiert
+ConfirmDeleteAccessory = Dieses Zubehör wirklich entfernen?
+NoToolsYet = Noch keine Werkzeuge erfasst
+AddFirstTool = Erstes Werkzeug hinzufügen
+GoToTypeAdmin = Zur Typverwaltung
diff --git a/langs/en_US/kundenkarte.lang b/langs/en_US/kundenkarte.lang
index eaa1329..cb7baa3 100755
--- a/langs/en_US/kundenkarte.lang
+++ b/langs/en_US/kundenkarte.lang
@@ -309,3 +309,19 @@ Decommissioned = Decommissioned
Decommission = Decommission
Recommission = Recommission
ShowDecommissioned = Show decommissioned elements
+
+# Tools & Accessories
+CompanyTools = Company Tools
+HasAccessories = Has Accessories
+HasAccessoriesHelp = Allows assigning accessories and spare parts
+Accessories = Accessories / Spare Parts
+NoAccessories = No accessories assigned
+SearchProduct = Search product
+SelectSupplier = Select supplier
+CreateSupplierOrder = Create supplier order
+OrderAccessories = Order accessories
+OrderGeneratedFromAccessories = Order generated from installation accessories
+ConfirmDeleteAccessory = Really remove this accessory?
+NoToolsYet = No tools registered yet
+AddFirstTool = Add first tool
+GoToTypeAdmin = Go to type administration
diff --git a/werkzeuge.php b/werkzeuge.php
new file mode 100644
index 0000000..08779e0
--- /dev/null
+++ b/werkzeuge.php
@@ -0,0 +1,837 @@
+loadLangs(array('companies', 'kundenkarte@kundenkarte'));
+
+// Berechtigungen
+if (!$user->hasRight('kundenkarte', 'read')) {
+ accessforbidden();
+}
+
+$permissiontoread = $user->hasRight('kundenkarte', 'read');
+$permissiontoadd = $user->hasRight('kundenkarte', 'write');
+$permissiontodelete = $user->hasRight('kundenkarte', 'delete');
+
+$action = GETPOST('action', 'aZ09');
+$confirm = GETPOST('confirm', 'alpha');
+$anlageId = GETPOSTINT('anlage_id');
+$parentId = GETPOSTINT('parent_id');
+
+// Eigene Firma als Kontext
+$socId = $mysoc->id;
+if ($socId <= 0) {
+ setEventMessages('Eigene Firma nicht konfiguriert. Bitte unter Einrichtung → Firma konfigurieren.', null, 'errors');
+ llxHeader('', 'Firmen-Werkzeuge');
+ llxFooter();
+ exit;
+}
+
+// WERKZEUG-System ermitteln
+$werkzeugSystemId = 0;
+$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system WHERE code = 'WERKZEUG' AND active = 1";
+$resql = $db->query($sql);
+if ($resql && $db->num_rows($resql) > 0) {
+ $obj = $db->fetch_object($resql);
+ $werkzeugSystemId = $obj->rowid;
+}
+
+if ($werkzeugSystemId <= 0) {
+ setEventMessages('System WERKZEUG nicht gefunden. Bitte Modul deaktivieren und wieder aktivieren.', null, 'errors');
+ llxHeader('', 'Firmen-Werkzeuge');
+ llxFooter();
+ exit;
+}
+
+$systemId = $werkzeugSystemId;
+
+// Sicherstellen dass WERKZEUG für eigene Firma aktiviert ist
+$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."kundenkarte_societe_system";
+$sql .= " WHERE fk_soc = ".((int) $socId)." AND fk_system = ".((int) $systemId);
+$sql .= " AND (fk_contact IS NULL OR fk_contact = 0) AND active = 1";
+$resql = $db->query($sql);
+if (!$resql || $db->num_rows($resql) == 0) {
+ // Automatisch aktivieren
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."kundenkarte_societe_system";
+ $sql .= " (entity, fk_soc, fk_contact, fk_system, date_creation, fk_user_creat, active)";
+ $sql .= " VALUES (".$conf->entity.", ".((int) $socId).", 0, ".((int) $systemId).", NOW(), ".((int) $user->id).", 1)";
+ $db->query($sql);
+}
+
+// Objekte initialisieren
+$form = new Form($db);
+$anlage = new Anlage($db);
+$anlageType = new AnlageType($db);
+
+/*
+ * Actions
+ */
+
+if ($action == 'add' && $permissiontoadd) {
+ $anlage->label = GETPOST('label', 'alphanohtml');
+ $anlage->fk_soc = $socId;
+ $anlage->fk_anlage_type = GETPOSTINT('fk_anlage_type');
+ $anlage->fk_parent = GETPOSTINT('fk_parent');
+ $anlage->fk_system = $systemId;
+ $anlage->fk_product = GETPOSTINT('fk_product') > 0 ? GETPOSTINT('fk_product') : null;
+ $anlage->note_private = isset($_POST['note_private']) ? $_POST['note_private'] : '';
+ $anlage->status = 1;
+
+ // Dynamische Felder
+ $type = new AnlageType($db);
+ if ($type->fetch($anlage->fk_anlage_type) > 0) {
+ $fieldValues = array();
+ $fields = $type->fetchFields();
+ foreach ($fields as $field) {
+ if ($field->field_type === 'header') continue;
+ $value = GETPOST('field_'.$field->field_code, 'alphanohtml');
+ if ($value !== '') {
+ $fieldValues[$field->field_code] = $value;
+ }
+ }
+ $anlage->setFieldValues($fieldValues);
+ }
+
+ $result = $anlage->create($user);
+ if ($result > 0) {
+ setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
+ header('Location: '.$_SERVER['PHP_SELF']);
+ exit;
+ } else {
+ setEventMessages($anlage->error, $anlage->errors, 'errors');
+ $action = 'create';
+ }
+}
+
+if ($action == 'update' && $permissiontoadd) {
+ $anlage->fetch($anlageId);
+ $anlage->label = GETPOST('label', 'alphanohtml');
+ $anlage->fk_anlage_type = GETPOSTINT('fk_anlage_type');
+ $anlage->fk_parent = GETPOSTINT('fk_parent');
+ $anlage->fk_product = GETPOSTINT('fk_product') > 0 ? GETPOSTINT('fk_product') : null;
+ $anlage->note_private = isset($_POST['note_private']) ? $_POST['note_private'] : '';
+
+ // Dynamische Felder
+ $type = new AnlageType($db);
+ if ($type->fetch($anlage->fk_anlage_type) > 0) {
+ $fieldValues = array();
+ $fields = $type->fetchFields();
+ foreach ($fields as $field) {
+ if ($field->field_type === 'header') continue;
+ $value = GETPOST('field_'.$field->field_code, 'alphanohtml');
+ if ($value !== '') {
+ $fieldValues[$field->field_code] = $value;
+ }
+ }
+ $anlage->setFieldValues($fieldValues);
+ }
+
+ $result = $anlage->update($user);
+ if ($result > 0) {
+ setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
+ header('Location: '.$_SERVER['PHP_SELF']);
+ exit;
+ } else {
+ setEventMessages($anlage->error, $anlage->errors, 'errors');
+ $action = 'edit';
+ }
+}
+
+if ($action == 'confirm_delete' && $confirm == 'yes' && $permissiontodelete) {
+ $anlage->fetch($anlageId);
+ $result = $anlage->delete($user);
+ if ($result > 0) {
+ setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
+ } else {
+ setEventMessages($anlage->error, $anlage->errors, 'errors');
+ }
+ header('Location: '.$_SERVER['PHP_SELF']);
+ exit;
+}
+
+/*
+ * View
+ */
+
+$title = $langs->trans('CompanyTools');
+$jsFiles = array('/kundenkarte/js/kundenkarte.js?v='.time());
+$cssFiles = array('/kundenkarte/css/kundenkarte.css?v='.time());
+
+llxHeader('', $title, '', '', 0, 0, $jsFiles, $cssFiles);
+
+print load_fiche_titre($title, '', 'fa-wrench');
+
+print '';
+
+// Bestätigungsdialog
+if ($action == 'delete') {
+ print $form->formconfirm(
+ $_SERVER['PHP_SELF'].'?anlage_id='.$anlageId,
+ $langs->trans('DeleteElement'),
+ $langs->trans('ConfirmDeleteElement'),
+ 'confirm_delete',
+ '',
+ 'yes',
+ 1
+ );
+}
+
+// Typen für WERKZEUG-System laden
+$types = $anlageType->fetchAllBySystem($systemId, 1, 1); // excludeGlobal=1, nur WERKZEUG-Typen
+
+if (in_array($action, array('create', 'edit', 'view'))) {
+ // Formular oder Detail-Ansicht
+
+ if ($action != 'create' && $anlageId > 0) {
+ $anlage->fetch($anlageId);
+ $type = new AnlageType($db);
+ $type->fetch($anlage->fk_anlage_type);
+ $type->fetchFields();
+ }
+
+ print ' ';
+
+} else {
+ // Baumansicht
+
+ if ($permissiontoadd) {
+ print ' ';
+ }
+
+ // Steuerungs-Buttons
+ print ' ';
+ print '';
+ print '';
+ print '';
+ print '';
+ print ' ';
+
+ // Baum laden
+ $tree = $anlage->fetchTree($socId, $systemId);
+
+ // Feld-Metadaten laden
+ $typeFieldsMap = array();
+ $sql = "SELECT f.*, f.fk_anlage_type FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_type_field f WHERE f.active = 1 ORDER BY f.position ASC";
+ $resql = $db->query($sql);
+ if ($resql) {
+ while ($obj = $db->fetch_object($resql)) {
+ if (!isset($typeFieldsMap[$obj->fk_anlage_type])) {
+ $typeFieldsMap[$obj->fk_anlage_type] = array();
+ }
+ $typeFieldsMap[$obj->fk_anlage_type][] = $obj;
+ }
+ $db->free($resql);
+ }
+
+ if (!empty($tree)) {
+ print ' ';
+ werkzeuge_printTree($tree, $socId, $systemId, $permissiontoadd, $permissiontodelete, $langs, 0, $typeFieldsMap);
+ print ' ';
+ } else {
+ print ' ';
+ }
+}
+
+print ' '; // fichecenter
+
+// Tooltip Container
+print '';
+
+// JavaScript: Produkt-Autocomplete + Zubehör-AJAX
+print '';
+
+// CSS für Autocomplete
+print '';
+
+llxFooter();
+$db->close();
+
+
+/**
+ * Baum rekursiv ausgeben (vereinfachte Version für Werkzeuge-Seite)
+ */
+function werkzeuge_printTree($nodes, $socid, $systemId, $canEdit, $canDelete, $langs, $level = 0, $typeFieldsMap = array())
+{
+ foreach ($nodes as $node) {
+ $hasChildren = !empty($node->children);
+ $fieldValues = $node->getFieldValues();
+
+ // Badges sammeln
+ $treeInfoBadges = array();
+ $treeInfoParentheses = array();
+
+ if (!empty($typeFieldsMap[$node->fk_anlage_type])) {
+ foreach ($typeFieldsMap[$node->fk_anlage_type] as $fieldDef) {
+ if ($fieldDef->field_type === 'header') continue;
+ $value = isset($fieldValues[$fieldDef->field_code]) ? $fieldValues[$fieldDef->field_code] : '';
+ if ($fieldDef->show_in_tree && $value !== '') {
+ $displayVal = $value;
+ if ($fieldDef->field_type === 'date' && $value) {
+ $displayVal = dol_print_date(strtotime($value), 'day');
+ }
+ $fieldInfo = array(
+ 'label' => $fieldDef->field_label,
+ 'value' => $displayVal,
+ 'code' => $fieldDef->field_code,
+ 'type' => $fieldDef->field_type,
+ 'color' => $fieldDef->badge_color ?? ''
+ );
+ $displayMode = $fieldDef->tree_display_mode ?? 'badge';
+ if ($displayMode === 'parentheses') {
+ $treeInfoParentheses[] = $fieldInfo;
+ } else {
+ $treeInfoBadges[] = $fieldInfo;
+ }
+ }
+ }
+ }
+
+ $nodeClass = 'kundenkarte-tree-node';
+ if (!empty($node->decommissioned)) {
+ $nodeClass .= ' decommissioned';
+ }
+ if ($node->type_can_have_children) {
+ $nodeClass .= ' node-structure';
+ } else {
+ $nodeClass .= ' node-leaf';
+ }
+
+ print '';
+ print ' ';
+
+ // Toggle
+ if ($hasChildren) {
+ print ' ';
+ } else {
+ print ' ';
+ }
+
+ // Icon
+ $picto = $node->type_picto ? $node->type_picto : 'fa-wrench';
+ print ' '.kundenkarte_render_icon($picto).'';
+
+ // Label
+ $viewUrl = $_SERVER['PHP_SELF'].'?action=view&anlage_id='.$node->id;
+ print ' '.dol_escape_htmltag($node->label);
+ if (!empty($treeInfoParentheses)) {
+ $infoValues = array();
+ foreach ($treeInfoParentheses as $info) {
+ $infoValues[] = dol_escape_htmltag($info['value']);
+ }
+ print ' ('.implode(', ', $infoValues).')';
+ }
+ print '';
+
+ // Ausgebaut-Badge
+ if (!empty($node->decommissioned)) {
+ $decommDate = !empty($node->date_decommissioned) ? dol_print_date(strtotime($node->date_decommissioned), 'day') : '';
+ $decommText = $langs->trans('Decommissioned');
+ if ($decommDate) $decommText .= ' '.$decommDate;
+ print ' '.$decommText.'';
+ }
+
+ // Produkt-Badge
+ if (!empty($node->fk_product) && !empty($node->product_ref)) {
+ print ' '.dol_escape_htmltag($node->product_ref).'';
+ }
+
+ // Spacer
+ print ' ';
+
+ // Badges
+ $defaultBadgeColor = getDolGlobalString('KUNDENKARTE_TREE_BADGE_COLOR', '#2a4a5e');
+ if (!empty($treeInfoBadges)) {
+ print ' ';
+ foreach ($treeInfoBadges as $info) {
+ $badgeIcon = kundenkarte_get_field_icon($info['code'], $info['type']);
+ $fieldBadgeColor = !empty($info['color']) ? $info['color'] : $defaultBadgeColor;
+ print '';
+ print ' '.dol_escape_htmltag($info['value']);
+ print '';
+ }
+ print '';
+ }
+
+ // Typ-Badge
+ if ($node->type_short || $node->type_label) {
+ $typeDisplay = $node->type_short ? $node->type_short : $node->type_label;
+ print ' '.dol_escape_htmltag($typeDisplay).'';
+ }
+
+ // Aktionen
+ print ' ';
+ print '';
+ if ($canEdit) {
+ print '';
+ print '';
+ $decommLabel = $node->decommissioned ? $langs->trans('Recommission') : $langs->trans('Decommission');
+ $decommIcon = $node->decommissioned ? 'fa-plug' : 'fa-power-off';
+ print '';
+ }
+ if ($canDelete) {
+ print '';
+ }
+ print '';
+
+ print ' ';
+
+ // Kinder
+ if ($hasChildren) {
+ print ' ';
+ werkzeuge_printTree($node->children, $socid, $systemId, $canEdit, $canDelete, $langs, $level + 1, $typeFieldsMap);
+ print ' ';
+ }
+
+ print ' ';
+ }
+}
+
+/**
+ * Baum-Options für Select (vereinfacht)
+ */
+function werkzeuge_printTreeOptions($nodes, $selected = 0, $excludeId = 0, $prefix = '', $level = 0)
+{
+ foreach ($nodes as $node) {
+ if ($node->id == $excludeId) continue;
+ $sel = ($node->id == $selected) ? ' selected' : '';
+ print '';
+ if (!empty($node->children)) {
+ werkzeuge_printTreeOptions($node->children, $selected, $excludeId, $prefix.'── ', $level + 1);
+ }
+ }
+}
|