false, 'error' => 'Missing parameters']); exit; } $tables = DocumentTypeHelper::getTableNames($docType); if (!$tables) { echo json_encode(['success' => false, 'error' => 'Invalid document type']); exit; } $db->begin(); // 1. Hole die Manager-Zeile des Produkts $sql = "SELECT rowid, line_order FROM ".MAIN_DB_PREFIX."facture_lines_manager"; $sql .= " WHERE ".$tables['fk_line']." = ".(int)$line_id; $sql .= " AND ".$tables['fk_parent']." = ".(int)$document_id; $sql .= " AND document_type = '".$db->escape($docType)."'"; $sql .= " AND line_type = 'product'"; $resql = $db->query($sql); if (!$resql || $db->num_rows($resql) == 0) { $db->rollback(); echo json_encode(['success' => false, 'error' => 'Product not found in manager table']); exit; } $product = $db->fetch_object($resql); $manager_id = $product->rowid; $current_line_order = $product->line_order; // 2. Hole die line_order der Section $sql_section = "SELECT line_order FROM ".MAIN_DB_PREFIX."facture_lines_manager"; $sql_section .= " WHERE rowid = ".(int)$section_id; $sql_section .= " AND line_type = 'section'"; $sql_section .= " AND document_type = '".$db->escape($docType)."'"; $resql_section = $db->query($sql_section); if (!$resql_section || $db->num_rows($resql_section) == 0) { $db->rollback(); echo json_encode(['success' => false, 'error' => 'Section not found']); exit; } $section = $db->fetch_object($resql_section); $section_line_order = $section->line_order; // 3. Finde die neue line_order für das Produkt (nach der Section, vor anderen Produkten der Section) $sql_next = "SELECT MIN(line_order) as next_order FROM ".MAIN_DB_PREFIX."facture_lines_manager"; $sql_next .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; $sql_next .= " AND document_type = '".$db->escape($docType)."'"; $sql_next .= " AND parent_section = ".(int)$section_id; $sql_next .= " AND line_type IN ('product', 'text')"; $resql_next = $db->query($sql_next); $obj_next = $db->fetch_object($resql_next); if ($obj_next && $obj_next->next_order) { // Es gibt bereits Produkte in dieser Section → füge VOR dem ersten ein $new_line_order = $obj_next->next_order; } else { // Keine Produkte in der Section → füge direkt nach der Section ein $new_line_order = $section_line_order + 1; } subtotaltitle_debug_log(' current_line_order='.$current_line_order.', section_line_order='.$section_line_order.', new_line_order='.$new_line_order); // 4. Verschiebe Zeilen je nach Richtung if ($current_line_order > $new_line_order) { // Nach vorne: Verschiebe Zeilen von new_line_order bis BEFORE current um +1 $sql_shift = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager"; $sql_shift .= " SET line_order = line_order + 1"; $sql_shift .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; $sql_shift .= " AND document_type = '".$db->escape($docType)."'"; $sql_shift .= " AND line_order >= ".(int)$new_line_order; $sql_shift .= " AND line_order < ".(int)$current_line_order; $db->query($sql_shift); subtotaltitle_debug_log(' Nach vorne verschoben: Zeilen '.$new_line_order.'-'.($current_line_order-1).' um +1'); } elseif ($current_line_order < $new_line_order) { // Nach hinten: Verschiebe Zeilen von current+1 bis new um -1 $sql_shift = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager"; $sql_shift .= " SET line_order = line_order - 1"; $sql_shift .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; $sql_shift .= " AND document_type = '".$db->escape($docType)."'"; $sql_shift .= " AND line_order > ".(int)$current_line_order; $sql_shift .= " AND line_order <= ".(int)$new_line_order; $db->query($sql_shift); subtotaltitle_debug_log(' Nach hinten verschoben: Zeilen '.($current_line_order+1).'-'.$new_line_order.' um -1'); } // Wenn current == new, keine Verschiebung nötig // 5. Update das Produkt: setze parent_section und neue line_order $sql_update = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager"; $sql_update .= " SET parent_section = ".(int)$section_id; $sql_update .= ", line_order = ".(int)$new_line_order; $sql_update .= " WHERE rowid = ".(int)$manager_id; $db->query($sql_update); subtotaltitle_debug_log('✅ Produkt #'.$line_id.' zu Section #'.$section_id.' hinzugefügt'); // 6. Sync rang in Detail-Tabelle subtotaltitle_debug_log(' Starte rang-Synchronisation für docType='.$docType.' doc_id='.$document_id); $sql = "SELECT rowid, line_type, ".$tables['fk_line']." as detail_id FROM ".MAIN_DB_PREFIX."facture_lines_manager"; $sql .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id; $sql .= " AND document_type = '".$db->escape($docType)."'"; $sql .= " AND ".$tables['fk_line']." IS NOT NULL"; $sql .= " ORDER BY line_order"; $resql = $db->query($sql); $rang = 1; while ($obj = $db->fetch_object($resql)) { $detail_id = $obj->detail_id; if ($detail_id) { $sql_upd = "UPDATE ".MAIN_DB_PREFIX.$tables['lines_table']; $sql_upd .= " SET rang = ".$rang; $sql_upd .= " WHERE rowid = ".(int)$detail_id; $db->query($sql_upd); subtotaltitle_debug_log(' Sync rang: '.$obj->line_type.' manager#'.$obj->rowid.' detail#'.$detail_id.' → rang='.$rang); $rang++; } } subtotaltitle_debug_log(' rang-Synchronisation abgeschlossen, '.$rang.' Zeilen synchronisiert'); $db->commit(); echo json_encode(['success' => true]);