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)
|
||||
|
||||
## 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)
|
||||
|
||||
### Neue Features
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ Das KundenKarte-Modul erweitert Dolibarr um zwei wichtige Funktionen fuer Kunden
|
|||
|
||||
### Technische Anlagen (Anlagen)
|
||||
- Hierarchische Baumstruktur fuer technische Installationen
|
||||
- Drag & Drop Sortierung der Elemente innerhalb einer Ebene
|
||||
- Flexible Systemkategorien (z.B. Strom, Internet, Kabel, Sat)
|
||||
- Kategorie-Auswahl beim Erstellen: Gebaeude/Standort oder Element/Geraet
|
||||
- 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;
|
||||
|
||||
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:
|
||||
$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
|
||||
*
|
||||
|
|
|
|||
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'
|
||||
|
||||
// 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
|
||||
//$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")');
|
||||
//$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
|
||||
$this->remove($options);
|
||||
|
||||
|
|
@ -551,6 +554,41 @@ class modKundenKarte extends DolibarrModules
|
|||
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.
|
||||
* Remove from database constants, boxes and permissions from Dolibarr database.
|
||||
|
|
|
|||
|
|
@ -146,6 +146,11 @@
|
|||
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 */
|
||||
.kundenkarte-tree > .kundenkarte-tree-row .cable-line {
|
||||
display: none !important;
|
||||
|
|
@ -254,6 +259,32 @@
|
|||
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 {
|
||||
font-size: 0.75em !important;
|
||||
padding: 2px 8px !important;
|
||||
|
|
|
|||
|
|
@ -171,9 +171,13 @@
|
|||
hideTimeout: null,
|
||||
currentTooltip: null,
|
||||
currentItem: null,
|
||||
draggedNode: null,
|
||||
isDragging: false,
|
||||
dropTarget: null,
|
||||
|
||||
init: function() {
|
||||
this.bindEvents();
|
||||
this.initDragDrop();
|
||||
},
|
||||
|
||||
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() {
|
||||
$('.kundenkarte-tree-toggle').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_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_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,
|
||||
entity integer DEFAULT 1 NOT NULL,
|
||||
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)
|
||||
note text, -- Optional notes
|
||||
date_creation datetime NOT NULL,
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
-- 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);
|
||||
|
|
|
|||
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');
|
||||
if ($newSystemId > 0 && !isset($customerSystems[$newSystemId])) {
|
||||
$sql = "INSERT INTO ".MAIN_DB_PREFIX."kundenkarte_societe_system";
|
||||
$sql .= " (entity, fk_soc, fk_system, date_creation, fk_user_creat, active)";
|
||||
$sql .= " VALUES (".$conf->entity.", ".((int) $id).", ".((int) $newSystemId).", NOW(), ".((int) $user->id).", 1)";
|
||||
$sql .= " (entity, fk_soc, fk_contact, fk_system, date_creation, fk_user_creat, active)";
|
||||
$sql .= " VALUES (".$conf->entity.", ".((int) $id).", 0, ".((int) $newSystemId).", NOW(), ".((int) $user->id).", 1)";
|
||||
$result = $db->query($sql);
|
||||
if ($result) {
|
||||
setEventMessages($langs->trans('SystemAdded'), null, 'mesgs');
|
||||
|
|
|
|||
Loading…
Reference in a new issue