diff --git a/.claude/settings.json b/.claude/settings.json old mode 100644 new mode 100755 diff --git a/MIGRATION_MULTITYPE.md b/MIGRATION_MULTITYPE.md old mode 100644 new mode 100755 diff --git a/ajax/add_to_section.php b/ajax/add_to_section.php old mode 100644 new mode 100755 diff --git a/ajax/check_subtotal.php b/ajax/check_subtotal.php old mode 100644 new mode 100755 diff --git a/ajax/cleanup_subtotals.php b/ajax/cleanup_subtotals.php old mode 100644 new mode 100755 diff --git a/ajax/fix_section_hierarchy.php b/ajax/fix_section_hierarchy.php old mode 100644 new mode 100755 diff --git a/ajax/fix_sections.php b/ajax/fix_sections.php old mode 100644 new mode 100755 diff --git a/ajax/repair_missing_subtotals.php b/ajax/repair_missing_subtotals.php old mode 100644 new mode 100755 diff --git a/ajax/sync_to_facturedet.php b/ajax/sync_to_facturedet.php index 36bba2b..2aae2db 100755 --- a/ajax/sync_to_facturedet.php +++ b/ajax/sync_to_facturedet.php @@ -312,6 +312,80 @@ if ($action == 'add') { echo json_encode(array('success' => true, 'total_ht' => $total_ht)); +} elseif ($action == 'remove_all') { + // ========== ALLE SPEZIALZEILEN UND VERWAISTE EINTRÄGE ENTFERNEN ========== + + // document_id wird benötigt + $document_id = GETPOST('document_id', 'int'); + if (!$document_id) { + echo json_encode(array('success' => false, 'error' => 'Missing document_id')); + exit; + } + + $removed_count = 0; + $orphan_count = 0; + + // 1. Entferne ALLE Einträge mit special_code 100, 101, 102 aus der Detail-Tabelle + // (unabhängig davon ob sie noch in der Manager-Tabelle existieren) + $sql_delete_all = "DELETE FROM ".MAIN_DB_PREFIX.$tables['lines_table']; + $sql_delete_all .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; + $sql_delete_all .= " AND special_code IN (100, 101, 102)"; + + subtotaltitle_debug_log('🗑️ Remove ALL special lines: '.$sql_delete_all); + + if ($db->query($sql_delete_all)) { + $removed_count = $db->affected_rows($db->query("SELECT ROW_COUNT()")); + // Fallback: Zähle manuell wenn affected_rows nicht funktioniert + if ($removed_count === 0) { + // Zähle vorher + $sql_count = "SELECT COUNT(*) as cnt FROM ".MAIN_DB_PREFIX.$tables['lines_table']; + $sql_count .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; + $sql_count .= " AND special_code IN (100, 101, 102)"; + // Da wir schon gelöscht haben, ist es jetzt 0 + $removed_count = -1; // Unbekannt, aber erfolgreich + } + } + + // 2. Setze in_facturedet und fk_*det auf NULL für alle Manager-Einträge dieses Dokuments + $sql_reset = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager"; + $sql_reset .= " SET ".$tables['fk_line']." = NULL, in_facturedet = 0"; + $sql_reset .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; + $sql_reset .= " AND document_type = '".$db->escape($docType)."'"; + $sql_reset .= " AND line_type IN ('section', 'text', 'subtotal')"; + + subtotaltitle_debug_log('🔄 Reset manager entries: '.$sql_reset); + $db->query($sql_reset); + + // 3. Normalisiere die rang-Werte (schließe Lücken) + $sql_reorder = "SET @r = 0; UPDATE ".MAIN_DB_PREFIX.$tables['lines_table']; + $sql_reorder .= " SET rang = (@r := @r + 1)"; + $sql_reorder .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; + $sql_reorder .= " ORDER BY rang"; + + // MySQL erlaubt kein SET in einer Anweisung mit UPDATE, also manuell: + $sql_get_lines = "SELECT rowid FROM ".MAIN_DB_PREFIX.$tables['lines_table']; + $sql_get_lines .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; + $sql_get_lines .= " ORDER BY rang"; + $res_lines = $db->query($sql_get_lines); + + $new_rang = 1; + while ($obj = $db->fetch_object($res_lines)) { + $sql_upd_rang = "UPDATE ".MAIN_DB_PREFIX.$tables['lines_table']; + $sql_upd_rang .= " SET rang = ".(int)$new_rang; + $sql_upd_rang .= " WHERE rowid = ".(int)$obj->rowid; + $db->query($sql_upd_rang); + $new_rang++; + } + + subtotaltitle_debug_log('✅ Remove ALL completed: removed='.$removed_count); + + echo json_encode(array( + 'success' => true, + 'removed' => $removed_count, + 'orphans_cleaned' => $orphan_count, + 'message' => 'Alle Spezialzeilen wurden entfernt' + )); + } else { echo json_encode(array('success' => false, 'error' => 'Unknown action')); } diff --git a/class/DocumentTypeHelper.class.php b/class/DocumentTypeHelper.class.php old mode 100644 new mode 100755 diff --git a/class/actions_subtotaltitle.class.php b/class/actions_subtotaltitle.class.php index dc86d19..c4fa3ce 100755 --- a/class/actions_subtotaltitle.class.php +++ b/class/actions_subtotaltitle.class.php @@ -1437,15 +1437,30 @@ class ActionsSubtotalTitle extends CommonHookActions $html .= ' dropdown += \'\';'; $html .= ' $(\'#addproduct tr:last\').before(dropdown);'; - + $html .= ' $(\'form[name="addproduct"]\').append(\'\');'; - + + // Lade gespeicherte Auswahl aus sessionStorage (dokumentspezifisch) + $html .= ' var storageKey = \'subtotaltitle_section_\' + '.$document_id.';'; + $html .= ' var savedSection = sessionStorage.getItem(storageKey);'; + $html .= ' if (savedSection) {'; + $html .= ' $(\'#section_id_dropdown\').val(savedSection);'; + $html .= ' $(\'#section_id\').val(savedSection);'; + $html .= ' console.log(\'[SubtotalTitle] Gespeicherte Section geladen:\', savedSection);'; + $html .= ' }'; + $html .= ' $(document).on(\'change\', \'#section_id_dropdown\', function() {'; $html .= ' var val = $(this).val();'; $html .= ' console.log(\'Section selected:\', val);'; $html .= ' $(\'#section_id\').val(val);'; + // Speichere Auswahl in sessionStorage (dokumentspezifisch) + $html .= ' if (val) {'; + $html .= ' sessionStorage.setItem(storageKey, val);'; + $html .= ' } else {'; + $html .= ' sessionStorage.removeItem(storageKey);'; + $html .= ' }'; $html .= ' });'; - + $html .= '});'; $html .= ''; diff --git a/debug_sections.php b/debug_sections.php old mode 100644 new mode 100755 diff --git a/img/grip.png b/img/grip.png old mode 100644 new mode 100755 diff --git a/js/subtotaltitle.js b/js/subtotaltitle.js index 23fc84d..efd2d5a 100755 --- a/js/subtotaltitle.js +++ b/js/subtotaltitle.js @@ -345,8 +345,8 @@ function createNewSection() { } showInputDialog( - lang.sectionCreate || 'Positionsgruppe erstellen', - lang.sectionName || 'Name der Positionsgruppe:', + lang.sectionCreate || 'Produktgruppe erstellen', + lang.sectionName || 'Name der Produktgruppe:', '', function(title) { debugLog('Erstelle Section: ' + title + ' für ' + docInfo.type + ' ID ' + docInfo.id); @@ -414,8 +414,8 @@ function renameSection(sectionId, currentTitle) { var lang = (typeof subtotalTitleLang !== 'undefined') ? subtotalTitleLang : {}; showInputDialog( - lang.buttonEdit || 'Positionsgruppe umbenennen', - lang.sectionName || 'Name der Positionsgruppe:', + lang.sectionEdit || 'Produktgruppe umbenennen', + lang.sectionName || 'Name der Produktgruppe:', currentTitle || '', function(newTitle) { debugLog('✏️ Benenne Section ' + sectionId + ' um zu: ' + newTitle); @@ -820,15 +820,42 @@ function moveProductToSection(productId, sectionId, newLineOrder) { function addUnlinkColumn() { var $table = $('#tablelines'); if (!$table.length) return; - + + // NUR auf Dokumentdetailseiten ausführen (card), NICHT auf Listen + // Prüfe ob wir auf einer gültigen Seite sind (invoicecard, propalcard, ordercard) + var url = window.location.href; + var isDocumentCard = (url.indexOf('/facture/card.php') !== -1 || + url.indexOf('/propal/card.php') !== -1 || + url.indexOf('/commande/card.php') !== -1); + + // Zusätzliche Prüfung: Modul muss aktiv sein (subtotalTitleIsDraft wird von PHP gesetzt) + var isModuleActive = (typeof subtotalTitleIsDraft !== 'undefined'); + + if (!isDocumentCard) { + debugLog('🔗 Keine Dokumentdetailseite, Unlink-Spalte wird übersprungen'); + return; + } + + if (!isModuleActive) { + debugLog('🔗 SubtotalTitle Modul nicht aktiv auf dieser Seite, Unlink-Spalte wird übersprungen'); + return; + } + + // Prüfe ob mindestens eine Produktgruppe (Section) vorhanden ist + var hasSections = ($('tr.section-header').length > 0); + if (!hasSections) { + debugLog('🔗 Keine Produktgruppen vorhanden, Unlink-Spalte wird übersprungen'); + return; + } + // Prüfe ob schon ausgeführt if ($table.data('unlink-added')) { debugLog('🔗 Unlink-Spalte bereits vorhanden, überspringe'); return; } $table.data('unlink-added', true); - - debugLog('🔗 Füge Unlink-Spalte hinzu...'); + + debugLog('🔗 Füge Unlink-Spalte hinzu (Sections vorhanden)...'); // THEAD: Leere Spalte hinzufügen $table.find('thead tr').each(function() { diff --git a/js/subtotaltitle_sync.js b/js/subtotaltitle_sync.js index 3e38701..ec4aed7 100755 --- a/js/subtotaltitle_sync.js +++ b/js/subtotaltitle_sync.js @@ -144,6 +144,9 @@ function syncAllToFacturedet() { var errors = 0; var docType = getDocumentTypeForSync(); + // Zeige Loading-Hinweis + $('body').append('