Version 3.5.0 - Drag & Drop Sortierung, Duplicate-Key-Fix
- Drag & Drop Sortierung im Anlagenbaum (Geschwister-Ebene) - UNIQUE KEY uk_kundenkarte_societe_system um fk_contact erweitert - Automatische DB-Migration beim Modul-Aktivieren - Visueller Abstand zwischen Root-Elementen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f2f3393b12
commit
06f8bc8fde
72 changed files with 281 additions and 5 deletions
0
CLAUDE.md
Normal file → Executable file
0
CLAUDE.md
Normal file → Executable file
20
ChangeLog.md
20
ChangeLog.md
|
|
@ -1,5 +1,25 @@
|
||||||
# CHANGELOG MODULE KUNDENKARTE FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
|
# CHANGELOG MODULE KUNDENKARTE FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
|
||||||
|
|
||||||
|
## 3.5.0 (2026-02)
|
||||||
|
|
||||||
|
### Neue Features
|
||||||
|
- **Drag & Drop Sortierung**: Elemente im Anlagenbaum per Drag & Drop umsortieren
|
||||||
|
- Geschwister-Elemente auf gleicher Ebene verschieben
|
||||||
|
- Visuelle Drop-Indikatoren (blaue Linie)
|
||||||
|
- Reihenfolge wird sofort per AJAX gespeichert (kein Seitenreload)
|
||||||
|
- Funktioniert in Kunden- und Kontakt-Anlagen
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- **Duplicate-Key-Fehler behoben**: UNIQUE KEY `uk_kundenkarte_societe_system` um `fk_contact` erweitert
|
||||||
|
- Systeme koennen nun gleichzeitig auf Kunden- und Kontaktebene existieren
|
||||||
|
- Migration wird automatisch beim Modul-Aktivieren ausgefuehrt
|
||||||
|
|
||||||
|
### Verbesserungen
|
||||||
|
- Visueller Abstand zwischen Root-Elementen im Anlagenbaum
|
||||||
|
- INSERT fuer Kunden-Systeme setzt explizit `fk_contact = 0`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2.0 (2026-01)
|
## 2.0 (2026-01)
|
||||||
|
|
||||||
### Neue Features
|
### Neue Features
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Das KundenKarte-Modul erweitert Dolibarr um zwei wichtige Funktionen fuer Kunden
|
||||||
|
|
||||||
### Technische Anlagen (Anlagen)
|
### Technische Anlagen (Anlagen)
|
||||||
- Hierarchische Baumstruktur fuer technische Installationen
|
- Hierarchische Baumstruktur fuer technische Installationen
|
||||||
|
- Drag & Drop Sortierung der Elemente innerhalb einer Ebene
|
||||||
- Flexible Systemkategorien (z.B. Strom, Internet, Kabel, Sat)
|
- Flexible Systemkategorien (z.B. Strom, Internet, Kabel, Sat)
|
||||||
- Kategorie-Auswahl beim Erstellen: Gebaeude/Standort oder Element/Geraet
|
- Kategorie-Auswahl beim Erstellen: Gebaeude/Standort oder Element/Geraet
|
||||||
- Typ-Select mit FontAwesome-Icons und Farbkodierung (Select2)
|
- Typ-Select mit FontAwesome-Icons und Farbkodierung (Select2)
|
||||||
|
|
|
||||||
0
admin/building_types.php
Normal file → Executable file
0
admin/building_types.php
Normal file → Executable file
0
admin/busbar_types.php
Normal file → Executable file
0
admin/busbar_types.php
Normal file → Executable file
0
admin/equipment_types.php
Normal file → Executable file
0
admin/equipment_types.php
Normal file → Executable file
0
admin/medium_types.php
Normal file → Executable file
0
admin/medium_types.php
Normal file → Executable file
21
ajax/anlage.php
Normal file → Executable file
21
ajax/anlage.php
Normal file → Executable file
|
|
@ -130,6 +130,27 @@ switch ($action) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'reorder':
|
||||||
|
// Reihenfolge der Elemente aktualisieren
|
||||||
|
if (!$user->hasRight('kundenkarte', 'write')) {
|
||||||
|
$response['error'] = $langs->trans('ErrorPermissionDenied');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$idsRaw = GETPOST('ids', 'array');
|
||||||
|
if (!empty($idsRaw) && is_array($idsRaw)) {
|
||||||
|
$ids = array_map('intval', $idsRaw);
|
||||||
|
$result = $anlage->updateRangs($ids);
|
||||||
|
if ($result > 0) {
|
||||||
|
$response['success'] = true;
|
||||||
|
} else {
|
||||||
|
$response['error'] = 'Fehler beim Speichern der Reihenfolge';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$response['error'] = 'Keine IDs übergeben';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$response['error'] = 'Unknown action';
|
$response['error'] = 'Unknown action';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
0
ajax/anlage_connection.php
Normal file → Executable file
0
ajax/anlage_connection.php
Normal file → Executable file
0
ajax/audit_log.php
Normal file → Executable file
0
ajax/audit_log.php
Normal file → Executable file
0
ajax/bom_generator.php
Normal file → Executable file
0
ajax/bom_generator.php
Normal file → Executable file
0
ajax/building_types.php
Normal file → Executable file
0
ajax/building_types.php
Normal file → Executable file
0
ajax/equipment.php
Normal file → Executable file
0
ajax/equipment.php
Normal file → Executable file
0
ajax/equipment_carrier.php
Normal file → Executable file
0
ajax/equipment_carrier.php
Normal file → Executable file
0
ajax/equipment_connection.php
Normal file → Executable file
0
ajax/equipment_connection.php
Normal file → Executable file
0
ajax/equipment_panel.php
Normal file → Executable file
0
ajax/equipment_panel.php
Normal file → Executable file
0
ajax/equipment_type_fields.php
Normal file → Executable file
0
ajax/equipment_type_fields.php
Normal file → Executable file
0
ajax/equipment_type_icon.php
Normal file → Executable file
0
ajax/equipment_type_icon.php
Normal file → Executable file
0
ajax/export_schematic_pdf.php
Normal file → Executable file
0
ajax/export_schematic_pdf.php
Normal file → Executable file
0
ajax/medium_types.php
Normal file → Executable file
0
ajax/medium_types.php
Normal file → Executable file
0
ajax/tree_config.php
Normal file → Executable file
0
ajax/tree_config.php
Normal file → Executable file
0
anlage_connection.php
Normal file → Executable file
0
anlage_connection.php
Normal file → Executable file
|
|
@ -301,6 +301,36 @@ class Anlage extends CommonObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reihenfolge (rang) für mehrere Elemente aktualisieren
|
||||||
|
*
|
||||||
|
* @param array $ids Array von Anlage-IDs in gewünschter Reihenfolge
|
||||||
|
* @return int 1 bei Erfolg, <0 bei Fehler
|
||||||
|
*/
|
||||||
|
public function updateRangs($ids)
|
||||||
|
{
|
||||||
|
$this->db->begin();
|
||||||
|
$error = 0;
|
||||||
|
|
||||||
|
foreach ($ids as $rang => $id) {
|
||||||
|
$sql = "UPDATE ".MAIN_DB_PREFIX."kundenkarte_anlage";
|
||||||
|
$sql .= " SET rang = ".((int) $rang);
|
||||||
|
$sql .= " WHERE rowid = ".((int) $id);
|
||||||
|
if (!$this->db->query($sql)) {
|
||||||
|
$error++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
$this->db->rollback();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->commit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete object in database
|
* Delete object in database
|
||||||
*
|
*
|
||||||
|
|
|
||||||
0
class/auditlog.class.php
Normal file → Executable file
0
class/auditlog.class.php
Normal file → Executable file
0
class/busbartype.class.php
Normal file → Executable file
0
class/busbartype.class.php
Normal file → Executable file
0
class/equipment.class.php
Normal file → Executable file
0
class/equipment.class.php
Normal file → Executable file
0
class/equipmentcarrier.class.php
Normal file → Executable file
0
class/equipmentcarrier.class.php
Normal file → Executable file
0
class/equipmentconnection.class.php
Normal file → Executable file
0
class/equipmentconnection.class.php
Normal file → Executable file
0
class/equipmentpanel.class.php
Normal file → Executable file
0
class/equipmentpanel.class.php
Normal file → Executable file
0
class/equipmenttype.class.php
Normal file → Executable file
0
class/equipmenttype.class.php
Normal file → Executable file
0
class/mediumtype.class.php
Normal file → Executable file
0
class/mediumtype.class.php
Normal file → Executable file
|
|
@ -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'
|
$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'
|
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
|
||||||
$this->version = '3.4.0';
|
$this->version = '3.5.0';
|
||||||
// Url to the file with your last numberversion of this module
|
// Url to the file with your last numberversion of this module
|
||||||
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
|
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
|
||||||
|
|
||||||
|
|
@ -512,6 +512,9 @@ class modKundenKarte extends DolibarrModules
|
||||||
//$result4=$extrafields->addExtraField('kundenkarte_myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', -1, 0, '', '', 'kundenkarte@kundenkarte', 'isModEnabled("kundenkarte")');
|
//$result4=$extrafields->addExtraField('kundenkarte_myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', -1, 0, '', '', 'kundenkarte@kundenkarte', 'isModEnabled("kundenkarte")');
|
||||||
//$result5=$extrafields->addExtraField('kundenkarte_myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', -1, 0, '', '', 'kundenkarte@kundenkarte', 'isModEnabled("kundenkarte")');
|
//$result5=$extrafields->addExtraField('kundenkarte_myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', -1, 0, '', '', 'kundenkarte@kundenkarte', 'isModEnabled("kundenkarte")');
|
||||||
|
|
||||||
|
// Migrationen: UNIQUE KEY uk_kundenkarte_societe_system um fk_contact erweitern
|
||||||
|
$this->_migrateSocieteSystemUniqueKey();
|
||||||
|
|
||||||
// Permissions
|
// Permissions
|
||||||
$this->remove($options);
|
$this->remove($options);
|
||||||
|
|
||||||
|
|
@ -551,6 +554,41 @@ class modKundenKarte extends DolibarrModules
|
||||||
return $this->_init($sql, $options);
|
return $this->_init($sql, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migration: UNIQUE KEY uk_kundenkarte_societe_system um fk_contact erweitern.
|
||||||
|
* Idempotent - kann mehrfach ausgeführt werden.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function _migrateSocieteSystemUniqueKey()
|
||||||
|
{
|
||||||
|
$table = MAIN_DB_PREFIX.'kundenkarte_societe_system';
|
||||||
|
|
||||||
|
// Prüfen ob Tabelle existiert
|
||||||
|
$resql = $this->db->query("SHOW TABLES LIKE '".$this->db->escape($table)."'");
|
||||||
|
if (!$resql || $this->db->num_rows($resql) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NULL-Werte in fk_contact auf 0 normalisieren
|
||||||
|
$this->db->query("UPDATE ".$table." SET fk_contact = 0 WHERE fk_contact IS NULL");
|
||||||
|
|
||||||
|
// Spalte NOT NULL mit Default 0 setzen
|
||||||
|
$this->db->query("ALTER TABLE ".$table." MODIFY COLUMN fk_contact integer DEFAULT 0 NOT NULL");
|
||||||
|
|
||||||
|
// Prüfen ob der UNIQUE KEY fk_contact enthält
|
||||||
|
$resql = $this->db->query("SHOW INDEX FROM ".$table." WHERE Key_name = 'uk_kundenkarte_societe_system' AND Column_name = 'fk_contact'");
|
||||||
|
if ($resql && $this->db->num_rows($resql) > 0) {
|
||||||
|
return; // Bereits migriert
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alten UNIQUE KEY entfernen (falls vorhanden)
|
||||||
|
$this->db->query("ALTER TABLE ".$table." DROP INDEX uk_kundenkarte_societe_system");
|
||||||
|
|
||||||
|
// Neuen UNIQUE KEY mit fk_contact anlegen
|
||||||
|
$this->db->query("ALTER TABLE ".$table." ADD UNIQUE INDEX uk_kundenkarte_societe_system (fk_soc, fk_contact, fk_system)");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when module is disabled.
|
* Function called when module is disabled.
|
||||||
* Remove from database constants, boxes and permissions from Dolibarr database.
|
* Remove from database constants, boxes and permissions from Dolibarr database.
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,11 @@
|
||||||
padding-left: 0 !important;
|
padding-left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Abstand zwischen Root-Elementen (nicht beim ersten) */
|
||||||
|
.kundenkarte-tree > .kundenkarte-tree-node + .kundenkarte-tree-node {
|
||||||
|
margin-top: 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Tree-row at root level - no lines */
|
/* Tree-row at root level - no lines */
|
||||||
.kundenkarte-tree > .kundenkarte-tree-row .cable-line {
|
.kundenkarte-tree > .kundenkarte-tree-row .cable-line {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
|
@ -254,6 +259,32 @@
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Drag & Drop Sortierung */
|
||||||
|
.kundenkarte-dragging {
|
||||||
|
opacity: 0.4 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kundenkarte-dragging > .kundenkarte-tree-item {
|
||||||
|
border: 1px dashed #666 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.kundenkarte-drag-active {
|
||||||
|
cursor: grabbing !important;
|
||||||
|
user-select: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.kundenkarte-drag-active * {
|
||||||
|
cursor: grabbing !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kundenkarte-drag-above > .kundenkarte-tree-item {
|
||||||
|
border-top: 3px solid #4a9eff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kundenkarte-drag-below > .kundenkarte-tree-item {
|
||||||
|
border-bottom: 3px solid #4a9eff !important;
|
||||||
|
}
|
||||||
|
|
||||||
.kundenkarte-tree-type {
|
.kundenkarte-tree-type {
|
||||||
font-size: 0.75em !important;
|
font-size: 0.75em !important;
|
||||||
padding: 2px 8px !important;
|
padding: 2px 8px !important;
|
||||||
|
|
|
||||||
|
|
@ -171,9 +171,13 @@
|
||||||
hideTimeout: null,
|
hideTimeout: null,
|
||||||
currentTooltip: null,
|
currentTooltip: null,
|
||||||
currentItem: null,
|
currentItem: null,
|
||||||
|
draggedNode: null,
|
||||||
|
isDragging: false,
|
||||||
|
dropTarget: null,
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
|
this.initDragDrop();
|
||||||
},
|
},
|
||||||
|
|
||||||
bindEvents: function() {
|
bindEvents: function() {
|
||||||
|
|
@ -580,6 +584,118 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Drag & Drop Sortierung initialisieren
|
||||||
|
initDragDrop: function() {
|
||||||
|
var self = this;
|
||||||
|
this.draggedNode = null;
|
||||||
|
|
||||||
|
$(document).on('mousedown', '.kundenkarte-tree-item', function(e) {
|
||||||
|
// Nicht bei Klick auf Links, Buttons oder Toggle
|
||||||
|
if ($(e.target).closest('a, button, .kundenkarte-tree-toggle').length) return;
|
||||||
|
|
||||||
|
var $item = $(this);
|
||||||
|
var $node = $item.closest('.kundenkarte-tree-node');
|
||||||
|
|
||||||
|
// Nur wenn Schreibberechtigung (Actions vorhanden)
|
||||||
|
if (!$item.find('.kundenkarte-tree-actions').length) return;
|
||||||
|
|
||||||
|
self.draggedNode = $node;
|
||||||
|
self.dragStartY = e.pageY;
|
||||||
|
self.isDragging = false;
|
||||||
|
|
||||||
|
$(document).on('mousemove.treeDrag', function(e) {
|
||||||
|
// Erst ab 5px Bewegung als Drag werten
|
||||||
|
if (!self.isDragging && Math.abs(e.pageY - self.dragStartY) > 5) {
|
||||||
|
self.isDragging = true;
|
||||||
|
self.draggedNode.addClass('kundenkarte-dragging');
|
||||||
|
$('body').addClass('kundenkarte-drag-active');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.isDragging) {
|
||||||
|
self.handleDragOver(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('mouseup.treeDrag', function(e) {
|
||||||
|
$(document).off('mousemove.treeDrag mouseup.treeDrag');
|
||||||
|
|
||||||
|
if (self.isDragging) {
|
||||||
|
self.handleDrop();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.draggedNode.removeClass('kundenkarte-dragging');
|
||||||
|
$('body').removeClass('kundenkarte-drag-active');
|
||||||
|
$('.kundenkarte-drag-above, .kundenkarte-drag-below').removeClass('kundenkarte-drag-above kundenkarte-drag-below');
|
||||||
|
self.draggedNode = null;
|
||||||
|
self.isDragging = false;
|
||||||
|
self.dropTarget = null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDragOver: function(e) {
|
||||||
|
var self = this;
|
||||||
|
// Alle Markierungen entfernen
|
||||||
|
$('.kundenkarte-drag-above, .kundenkarte-drag-below').removeClass('kundenkarte-drag-above kundenkarte-drag-below');
|
||||||
|
|
||||||
|
// Element unter dem Mauszeiger finden
|
||||||
|
var $target = $(e.target).closest('.kundenkarte-tree-node');
|
||||||
|
if (!$target.length || $target.is(self.draggedNode)) return;
|
||||||
|
|
||||||
|
// Nur Geschwister erlauben (gleicher Parent-Container)
|
||||||
|
var $dragParent = self.draggedNode.parent();
|
||||||
|
var $targetParent = $target.parent();
|
||||||
|
if (!$dragParent.is($targetParent)) return;
|
||||||
|
|
||||||
|
// Position bestimmen: obere oder untere Hälfte des Ziels
|
||||||
|
var targetRect = $target.children('.kundenkarte-tree-item')[0].getBoundingClientRect();
|
||||||
|
var midY = targetRect.top + targetRect.height / 2;
|
||||||
|
|
||||||
|
if (e.clientY < midY) {
|
||||||
|
$target.addClass('kundenkarte-drag-above');
|
||||||
|
self.dropTarget = { node: $target, position: 'before' };
|
||||||
|
} else {
|
||||||
|
$target.addClass('kundenkarte-drag-below');
|
||||||
|
self.dropTarget = { node: $target, position: 'after' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDrop: function() {
|
||||||
|
var self = this;
|
||||||
|
if (!self.dropTarget) return;
|
||||||
|
|
||||||
|
var $target = self.dropTarget.node;
|
||||||
|
var position = self.dropTarget.position;
|
||||||
|
|
||||||
|
// DOM-Reihenfolge aktualisieren
|
||||||
|
if (position === 'before') {
|
||||||
|
self.draggedNode.insertBefore($target);
|
||||||
|
} else {
|
||||||
|
self.draggedNode.insertAfter($target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neue Reihenfolge der Geschwister sammeln
|
||||||
|
var $parent = self.draggedNode.parent();
|
||||||
|
var ids = [];
|
||||||
|
$parent.children('.kundenkarte-tree-node').each(function() {
|
||||||
|
var id = $(this).children('.kundenkarte-tree-item').data('anlage-id');
|
||||||
|
if (id) ids.push(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Per AJAX speichern
|
||||||
|
var baseUrl = $('meta[name="dolibarr-baseurl"]').attr('content') || '';
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: baseUrl + '/custom/kundenkarte/ajax/anlage.php',
|
||||||
|
data: {
|
||||||
|
action: 'reorder',
|
||||||
|
token: $('input[name="token"]').val() || '',
|
||||||
|
'ids[]': ids
|
||||||
|
},
|
||||||
|
dataType: 'json'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
expandAll: function() {
|
expandAll: function() {
|
||||||
$('.kundenkarte-tree-toggle').removeClass('collapsed');
|
$('.kundenkarte-tree-toggle').removeClass('collapsed');
|
||||||
$('.kundenkarte-tree-children').removeClass('collapsed');
|
$('.kundenkarte-tree-children').removeClass('collapsed');
|
||||||
|
|
|
||||||
0
js/pathfinding.min.js
vendored
Normal file → Executable file
0
js/pathfinding.min.js
vendored
Normal file → Executable file
0
sql/data_building_types.sql
Normal file → Executable file
0
sql/data_building_types.sql
Normal file → Executable file
0
sql/data_busbar_types.sql
Normal file → Executable file
0
sql/data_busbar_types.sql
Normal file → Executable file
0
sql/data_medium_types.sql
Normal file → Executable file
0
sql/data_medium_types.sql
Normal file → Executable file
0
sql/data_terminal_types.sql
Normal file → Executable file
0
sql/data_terminal_types.sql
Normal file → Executable file
0
sql/llx_kundenkarte_anlage_connection.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_anlage_connection.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_anlage_connection.sql
Normal file → Executable file
0
sql/llx_kundenkarte_anlage_connection.sql
Normal file → Executable file
0
sql/llx_kundenkarte_audit_log.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_audit_log.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_audit_log.sql
Normal file → Executable file
0
sql/llx_kundenkarte_audit_log.sql
Normal file → Executable file
0
sql/llx_kundenkarte_building_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_building_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_building_type.sql
Normal file → Executable file
0
sql/llx_kundenkarte_building_type.sql
Normal file → Executable file
0
sql/llx_kundenkarte_busbar_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_busbar_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_busbar_type.sql
Normal file → Executable file
0
sql/llx_kundenkarte_busbar_type.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_carrier.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_carrier.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_carrier.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_carrier.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_connection.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_connection.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_connection.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_connection.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_panel.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_panel.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type_field.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type_field.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type_field.sql
Normal file → Executable file
0
sql/llx_kundenkarte_equipment_type_field.sql
Normal file → Executable file
0
sql/llx_kundenkarte_medium_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_medium_type.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_medium_type.sql
Normal file → Executable file
0
sql/llx_kundenkarte_medium_type.sql
Normal file → Executable file
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
ALTER TABLE llx_kundenkarte_societe_system ADD INDEX idx_kundenkarte_societe_system_fk_soc (fk_soc);
|
ALTER TABLE llx_kundenkarte_societe_system ADD INDEX idx_kundenkarte_societe_system_fk_soc (fk_soc);
|
||||||
ALTER TABLE llx_kundenkarte_societe_system ADD INDEX idx_kundenkarte_societe_system_fk_system (fk_system);
|
ALTER TABLE llx_kundenkarte_societe_system ADD INDEX idx_kundenkarte_societe_system_fk_system (fk_system);
|
||||||
ALTER TABLE llx_kundenkarte_societe_system ADD UNIQUE INDEX uk_kundenkarte_societe_system (fk_soc, fk_system);
|
ALTER TABLE llx_kundenkarte_societe_system ADD UNIQUE INDEX uk_kundenkarte_societe_system (fk_soc, fk_contact, fk_system);
|
||||||
|
|
||||||
ALTER TABLE llx_kundenkarte_societe_system ADD CONSTRAINT fk_kundenkarte_societe_system_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe(rowid);
|
ALTER TABLE llx_kundenkarte_societe_system ADD CONSTRAINT fk_kundenkarte_societe_system_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe(rowid);
|
||||||
ALTER TABLE llx_kundenkarte_societe_system ADD CONSTRAINT fk_kundenkarte_societe_system_system FOREIGN KEY (fk_system) REFERENCES llx_c_kundenkarte_anlage_system(rowid);
|
ALTER TABLE llx_kundenkarte_societe_system ADD CONSTRAINT fk_kundenkarte_societe_system_system FOREIGN KEY (fk_system) REFERENCES llx_c_kundenkarte_anlage_system(rowid);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ CREATE TABLE llx_kundenkarte_societe_system (
|
||||||
rowid integer AUTO_INCREMENT PRIMARY KEY,
|
rowid integer AUTO_INCREMENT PRIMARY KEY,
|
||||||
entity integer DEFAULT 1 NOT NULL,
|
entity integer DEFAULT 1 NOT NULL,
|
||||||
fk_soc integer NOT NULL, -- Customer (llx_societe)
|
fk_soc integer NOT NULL, -- Customer (llx_societe)
|
||||||
|
fk_contact integer DEFAULT 0 NOT NULL, -- Contact/Address (0 = thirdparty-level)
|
||||||
fk_system integer NOT NULL, -- System category (llx_c_kundenkarte_anlage_system)
|
fk_system integer NOT NULL, -- System category (llx_c_kundenkarte_anlage_system)
|
||||||
note text, -- Optional notes
|
note text, -- Optional notes
|
||||||
date_creation datetime NOT NULL,
|
date_creation datetime NOT NULL,
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@
|
||||||
-- Add fk_contact column for contact/address specific system assignments
|
-- Add fk_contact column for contact/address specific system assignments
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
|
|
||||||
ALTER TABLE llx_kundenkarte_societe_system ADD COLUMN fk_contact integer DEFAULT NULL AFTER fk_soc;
|
ALTER TABLE llx_kundenkarte_societe_system ADD COLUMN fk_contact integer DEFAULT 0 NOT NULL AFTER fk_soc;
|
||||||
ALTER TABLE llx_kundenkarte_societe_system ADD INDEX idx_kundenkarte_societe_system_fk_contact (fk_contact);
|
ALTER TABLE llx_kundenkarte_societe_system ADD INDEX idx_kundenkarte_societe_system_fk_contact (fk_contact);
|
||||||
|
|
|
||||||
0
sql/llx_kundenkarte_terminal_bridge.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_terminal_bridge.key.sql
Normal file → Executable file
0
sql/llx_kundenkarte_terminal_bridge.sql
Normal file → Executable file
0
sql/llx_kundenkarte_terminal_bridge.sql
Normal file → Executable file
0
sql/update_3.0.0.sql
Normal file → Executable file
0
sql/update_3.0.0.sql
Normal file → Executable file
0
sql/update_3.1.0.sql
Normal file → Executable file
0
sql/update_3.1.0.sql
Normal file → Executable file
0
sql/update_3.2.0.sql
Normal file → Executable file
0
sql/update_3.2.0.sql
Normal file → Executable file
0
sql/update_3.3.0.sql
Normal file → Executable file
0
sql/update_3.3.0.sql
Normal file → Executable file
0
sql/update_3.3.2.sql
Normal file → Executable file
0
sql/update_3.3.2.sql
Normal file → Executable file
18
sql/update_3.4.1.sql
Normal file
18
sql/update_3.4.1.sql
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
-- ============================================================================
|
||||||
|
-- KundenKarte Module Update 3.4.1
|
||||||
|
-- Fix: UNIQUE KEY uk_kundenkarte_societe_system um fk_contact erweitern
|
||||||
|
-- Ohne den Fix kann ein System nicht gleichzeitig auf Kunden- und Kontaktebene
|
||||||
|
-- existieren (Duplicate entry Fehler).
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- 1. NULL-Werte in fk_contact auf 0 normalisieren (Kunden-Ebene)
|
||||||
|
UPDATE llx_kundenkarte_societe_system SET fk_contact = 0 WHERE fk_contact IS NULL;
|
||||||
|
|
||||||
|
-- 2. Spalte NOT NULL mit Default 0 setzen
|
||||||
|
ALTER TABLE llx_kundenkarte_societe_system MODIFY COLUMN fk_contact integer DEFAULT 0 NOT NULL;
|
||||||
|
|
||||||
|
-- 3. Alten UNIQUE KEY entfernen
|
||||||
|
ALTER TABLE llx_kundenkarte_societe_system DROP INDEX uk_kundenkarte_societe_system;
|
||||||
|
|
||||||
|
-- 4. Neuen UNIQUE KEY mit fk_contact anlegen
|
||||||
|
ALTER TABLE llx_kundenkarte_societe_system ADD UNIQUE INDEX uk_kundenkarte_societe_system (fk_soc, fk_contact, fk_system);
|
||||||
|
|
@ -104,8 +104,8 @@ if ($action == 'add_system' && $permissiontoadd) {
|
||||||
$newSystemId = GETPOSTINT('new_system_id');
|
$newSystemId = GETPOSTINT('new_system_id');
|
||||||
if ($newSystemId > 0 && !isset($customerSystems[$newSystemId])) {
|
if ($newSystemId > 0 && !isset($customerSystems[$newSystemId])) {
|
||||||
$sql = "INSERT INTO ".MAIN_DB_PREFIX."kundenkarte_societe_system";
|
$sql = "INSERT INTO ".MAIN_DB_PREFIX."kundenkarte_societe_system";
|
||||||
$sql .= " (entity, fk_soc, fk_system, date_creation, fk_user_creat, active)";
|
$sql .= " (entity, fk_soc, fk_contact, fk_system, date_creation, fk_user_creat, active)";
|
||||||
$sql .= " VALUES (".$conf->entity.", ".((int) $id).", ".((int) $newSystemId).", NOW(), ".((int) $user->id).", 1)";
|
$sql .= " VALUES (".$conf->entity.", ".((int) $id).", 0, ".((int) $newSystemId).", NOW(), ".((int) $user->id).", 1)";
|
||||||
$result = $db->query($sql);
|
$result = $db->query($sql);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
setEventMessages($langs->trans('SystemAdded'), null, 'mesgs');
|
setEventMessages($langs->trans('SystemAdded'), null, 'mesgs');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue