Fehler beseitig Verwaiste Zeilen über Button entfernen
This commit is contained in:
parent
458f393612
commit
ea2609c66e
18 changed files with 164 additions and 59 deletions
0
.claude/settings.json
Normal file → Executable file
0
.claude/settings.json
Normal file → Executable file
0
MIGRATION_MULTITYPE.md
Normal file → Executable file
0
MIGRATION_MULTITYPE.md
Normal file → Executable file
0
ajax/add_to_section.php
Normal file → Executable file
0
ajax/add_to_section.php
Normal file → Executable file
0
ajax/check_subtotal.php
Normal file → Executable file
0
ajax/check_subtotal.php
Normal file → Executable file
0
ajax/cleanup_subtotals.php
Normal file → Executable file
0
ajax/cleanup_subtotals.php
Normal file → Executable file
0
ajax/fix_section_hierarchy.php
Normal file → Executable file
0
ajax/fix_section_hierarchy.php
Normal file → Executable file
0
ajax/fix_sections.php
Normal file → Executable file
0
ajax/fix_sections.php
Normal file → Executable file
0
ajax/repair_missing_subtotals.php
Normal file → Executable file
0
ajax/repair_missing_subtotals.php
Normal file → Executable file
|
|
@ -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'));
|
||||
}
|
||||
|
|
|
|||
0
class/DocumentTypeHelper.class.php
Normal file → Executable file
0
class/DocumentTypeHelper.class.php
Normal file → Executable file
|
|
@ -1440,10 +1440,25 @@ class ActionsSubtotalTitle extends CommonHookActions
|
|||
|
||||
$html .= ' $(\'form[name="addproduct"]\').append(\'<input type="hidden" name="section_id" id="section_id" value="">\');';
|
||||
|
||||
// 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 .= '});';
|
||||
|
|
|
|||
0
debug_sections.php
Normal file → Executable file
0
debug_sections.php
Normal file → Executable file
0
img/grip.png
Normal file → Executable file
0
img/grip.png
Normal file → Executable file
|
Before Width: | Height: | Size: 90 B After Width: | Height: | Size: 90 B |
|
|
@ -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);
|
||||
|
|
@ -821,6 +821,33 @@ 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');
|
||||
|
|
@ -828,7 +855,7 @@ function addUnlinkColumn() {
|
|||
}
|
||||
$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() {
|
||||
|
|
|
|||
|
|
@ -144,6 +144,9 @@ function syncAllToFacturedet() {
|
|||
var errors = 0;
|
||||
var docType = getDocumentTypeForSync();
|
||||
|
||||
// Zeige Loading-Hinweis
|
||||
$('body').append('<div id="sync-loading" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.3);z-index:9999;display:flex;align-items:center;justify-content:center;"><div style="background:#fff;padding:20px 40px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,0.2);">Synchronisiere... Bitte warten.</div></div>');
|
||||
|
||||
$unchecked.each(function() {
|
||||
var lineId = $(this).data('line-id');
|
||||
var lineType = $(this).data('line-type');
|
||||
|
|
@ -155,16 +158,16 @@ function syncAllToFacturedet() {
|
|||
document_type: docType
|
||||
}, function(response) {
|
||||
done++;
|
||||
if (response.success) {
|
||||
updateSyncCheckbox(lineId, true);
|
||||
} else {
|
||||
if (!response.success) {
|
||||
errors++;
|
||||
}
|
||||
if (done >= total) {
|
||||
debugLog('✅ Sync abgeschlossen: ' + (total - errors) + ' erfolgreich, ' + errors + ' Fehler');
|
||||
if (errors > 0) {
|
||||
$('#sync-loading').remove();
|
||||
showErrorAlert((total - errors) + ' von ' + total + ' Elementen hinzugefügt. ' + errors + ' Fehler aufgetreten.');
|
||||
} else {
|
||||
// Direkt reloaden ohne UI-Update
|
||||
safeReload();
|
||||
}
|
||||
}
|
||||
|
|
@ -181,56 +184,42 @@ function syncAllToFacturedet() {
|
|||
|
||||
/**
|
||||
* Entfernt ALLE Sections/Textzeilen/Subtotals aus facturedet
|
||||
* Inkl. verwaister Einträge die nicht mehr in der Manager-Tabelle existieren
|
||||
*/
|
||||
function removeAllFromFacturedet() {
|
||||
var lang = (typeof subtotalTitleLang !== 'undefined') ? subtotalTitleLang : {};
|
||||
|
||||
var $checked = $('.sync-checkbox:checked');
|
||||
var total = $checked.length;
|
||||
|
||||
if (total === 0) {
|
||||
showErrorAlert(lang.noElementsInInvoice || 'Keine Elemente in der Rechnung vorhanden.');
|
||||
return;
|
||||
}
|
||||
|
||||
showConfirmDialog(
|
||||
'Alle aus Rechnung entfernen',
|
||||
(lang.confirmRemoveAll || 'ALLE Positionsgruppen-Elemente aus der Rechnung entfernen?') + '<br><br><em>Die Elemente bleiben in der Verwaltung erhalten.</em>',
|
||||
(lang.confirmRemoveAll || 'ALLE Positionsgruppen-Elemente (Sections, Textzeilen, Zwischensummen) aus der Rechnung entfernen?') +
|
||||
'<br><br><em>Inkl. verwaister Einträge. Die Elemente in der Verwaltung bleiben erhalten.</em>',
|
||||
function() {
|
||||
debugLog('📥 Remove ALL from facturedet...');
|
||||
debugLog('📥 Remove ALL from facturedet (server-side)...');
|
||||
|
||||
var done = 0;
|
||||
var errors = 0;
|
||||
var docType = getDocumentTypeForSync();
|
||||
var documentId = getFactureId();
|
||||
|
||||
$checked.each(function() {
|
||||
var lineId = $(this).data('line-id');
|
||||
var lineType = $(this).data('line-type');
|
||||
if (!documentId) {
|
||||
showErrorAlert('Fehler: Keine Dokument-ID gefunden');
|
||||
return;
|
||||
}
|
||||
|
||||
$.post(subtotaltitleAjaxUrl + 'sync_to_facturedet.php', {
|
||||
action: 'remove',
|
||||
line_id: lineId,
|
||||
line_type: lineType,
|
||||
document_type: docType
|
||||
}, function(response) {
|
||||
done++;
|
||||
if (response.success) {
|
||||
updateSyncCheckbox(lineId, false);
|
||||
} else {
|
||||
errors++;
|
||||
}
|
||||
if (done >= total) {
|
||||
debugLog('✅ Remove abgeschlossen: ' + (total - errors) + ' erfolgreich, ' + errors + ' Fehler');
|
||||
if (errors > 0) {
|
||||
showErrorAlert((total - errors) + ' von ' + total + ' Elementen entfernt. ' + errors + ' Fehler aufgetreten.');
|
||||
} else {
|
||||
safeReload();
|
||||
}
|
||||
}
|
||||
}, 'json').fail(function() {
|
||||
done++;
|
||||
errors++;
|
||||
});
|
||||
$.post(subtotaltitleAjaxUrl + 'sync_to_facturedet.php', {
|
||||
action: 'remove_all',
|
||||
line_id: 1, // Dummy, wird benötigt wegen Parameter-Check
|
||||
document_id: documentId,
|
||||
document_type: docType
|
||||
}, function(response) {
|
||||
debugLog('Remove ALL response: ' + JSON.stringify(response));
|
||||
if (response.success) {
|
||||
debugLog('✅ Alle Spezialzeilen entfernt');
|
||||
safeReload();
|
||||
} else {
|
||||
showErrorAlert((lang.errorSyncing || 'Fehler') + ': ' + (response.error || 'Unbekannter Fehler'));
|
||||
}
|
||||
}, 'json').fail(function(xhr, status, error) {
|
||||
debugLog('AJAX Fehler: ' + status + ' ' + error);
|
||||
showErrorAlert((lang.errorSyncing || 'Fehler') + ': ' + error);
|
||||
});
|
||||
},
|
||||
'Ja, alle entfernen',
|
||||
|
|
|
|||
|
|
@ -86,9 +86,9 @@ ButtonCancel = Abbrechen
|
|||
# UI Elements - Section Actions
|
||||
#
|
||||
SectionCreate = Produktgruppe erstellen
|
||||
SectionEdit = Section bearbeiten
|
||||
SectionDelete = Section löschen
|
||||
SectionName = Section-Name
|
||||
SectionEdit = Produktgruppe bearbeiten
|
||||
SectionDelete = Produktgruppe löschen
|
||||
SectionName = Name der Produktgruppe
|
||||
SectionSubtotal = Zwischensumme anzeigen
|
||||
ProductCount = Produkte
|
||||
|
||||
|
|
|
|||
|
|
@ -85,10 +85,10 @@ ButtonCancel = Cancel
|
|||
#
|
||||
# UI Elements - Section Actions
|
||||
#
|
||||
SectionCreate = Create section
|
||||
SectionEdit = Edit section
|
||||
SectionDelete = Delete section
|
||||
SectionName = Section name
|
||||
SectionCreate = Create product group
|
||||
SectionEdit = Edit product group
|
||||
SectionDelete = Delete product group
|
||||
SectionName = Product group name
|
||||
SectionSubtotal = Show subtotal
|
||||
ProductCount = Products
|
||||
|
||||
|
|
|
|||
0
sql/llx_facture_lines_manager.sql
Normal file → Executable file
0
sql/llx_facture_lines_manager.sql
Normal file → Executable file
Loading…
Reference in a new issue