false, 'error' => 'Missing parameters']); exit; } // Hole die richtigen Tabellennamen für diesen Dokumenttyp $tables = DocumentTypeHelper::getTableNames($docType); if (!$tables) { echo json_encode(['success' => false, 'error' => 'Invalid document type']); exit; } $new_order = json_decode($new_order_json, true); if (!$new_order) { echo json_encode(['success' => false, 'error' => 'Invalid JSON']); exit; } $db->begin(); // Für jede Zeile: line_order und parent_section updaten foreach ($new_order as $item) { if ($item['type'] == 'section') { $sql = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager"; $sql .= " SET line_order = ".(int)$item['order']; $sql .= " WHERE rowid = ".(int)$item['id']; $db->query($sql); subtotaltitle_debug_log(' Section #'.$item['id'].' → order='.$item['order']); } else if ($item['type'] == 'product') { $sql = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager"; $sql .= " SET line_order = ".(int)$item['order']; $sql .= ", parent_section = ".($item['parent_section'] ? (int)$item['parent_section'] : "NULL"); $sql .= " WHERE ".$tables['fk_line']." = ".(int)$item['id']; $db->query($sql); subtotaltitle_debug_log(' Produkt #'.$item['id'].' → order='.$item['order'].', section='.($item['parent_section'] ?: 'FREI')); } else if ($item['type'] == 'text') { $sql = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager"; $sql .= " SET line_order = ".(int)$item['order']; $sql .= ", parent_section = ".($item['parent_section'] ? (int)$item['parent_section'] : "NULL"); $sql .= " WHERE rowid = ".(int)$item['id']; $sql .= " AND line_type = 'text'"; $db->query($sql); subtotaltitle_debug_log(' Text #'.$item['id'].' → order='.$item['order'].', section='.($item['parent_section'] ?: 'FREI')); } } // ========== SUBTOTALS NEU POSITIONIEREN ========== subtotaltitle_debug_log('🔢 Repositioniere Subtotals...'); // Hole alle Subtotals für dieses Dokument $sql = "SELECT rowid, parent_section FROM ".MAIN_DB_PREFIX."facture_lines_manager WHERE ".$tables['fk_parent']." = ".(int)$facture_id." AND document_type = '".$db->escape($docType)."' AND line_type = 'subtotal'"; $resql = $db->query($sql); $subtotals_to_update = array(); while ($subtotal = $db->fetch_object($resql)) { $subtotals_to_update[] = $subtotal; } foreach ($subtotals_to_update as $subtotal) { // Finde höchste line_order der Produkte dieser Section $sql_max = "SELECT MAX(line_order) as max_order FROM ".MAIN_DB_PREFIX."facture_lines_manager WHERE parent_section = ".(int)$subtotal->parent_section." AND line_type = 'product' AND document_type = '".$db->escape($docType)."'"; $res_max = $db->query($sql_max); $obj_max = $db->fetch_object($res_max); if ($obj_max && $obj_max->max_order) { // Subtotal kommt direkt nach dem letzten Produkt: max_order + 0.5 $temp_order = (float)$obj_max->max_order + 0.5; $sql_upd = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager SET line_order = ".$temp_order." WHERE rowid = ".(int)$subtotal->rowid; $db->query($sql_upd); subtotaltitle_debug_log(' Subtotal #'.$subtotal->rowid.' (Section '.$subtotal->parent_section.') → temp_order='.$temp_order); } else { subtotaltitle_debug_log(' ⚠️ Subtotal #'.$subtotal->rowid.' hat keine Produkte in Section '.$subtotal->parent_section); } } // ========== SECTIONS VOR IHREN PRODUKTEN SICHERSTELLEN ========== subtotaltitle_debug_log('🔧 Stelle sicher dass Sections vor ihren Produkten stehen...'); // Für jede Section: Wenn ein Produkt dieser Section VOR der Section steht, // verschiebe die Section vor das erste Produkt $sql_sections = "SELECT rowid, line_order FROM ".MAIN_DB_PREFIX."facture_lines_manager WHERE ".$tables['fk_parent']." = ".(int)$facture_id." AND document_type = '".$db->escape($docType)."' AND line_type = 'section'"; $res_sections = $db->query($sql_sections); while ($section = $db->fetch_object($res_sections)) { // Finde das Produkt dieser Section mit der kleinsten line_order $sql_first_prod = "SELECT MIN(line_order) as min_order FROM ".MAIN_DB_PREFIX."facture_lines_manager WHERE parent_section = ".(int)$section->rowid." AND document_type = '".$db->escape($docType)."' AND line_type = 'product'"; $res_first = $db->query($sql_first_prod); $first_prod = $db->fetch_object($res_first); if ($first_prod && $first_prod->min_order && $first_prod->min_order < $section->line_order) { // Section steht NACH ihrem ersten Produkt - verschiebe sie davor $new_section_order = (float)$first_prod->min_order - 0.5; $sql_move = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager SET line_order = ".$new_section_order." WHERE rowid = ".(int)$section->rowid; $db->query($sql_move); subtotaltitle_debug_log(' Section #'.$section->rowid.' verschoben: '.$section->line_order.' → '.$new_section_order.' (vor Produkt mit order='.$first_prod->min_order.')'); } } // ========== ALLES NEU DURCHNUMMERIEREN ========== subtotaltitle_debug_log('🔢 Normalisiere line_order...'); $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager WHERE ".$tables['fk_parent']." = ".(int)$facture_id." AND document_type = '".$db->escape($docType)."' ORDER BY line_order"; $resql = $db->query($sql); $new_order_num = 1; while ($obj = $db->fetch_object($resql)) { $sql_upd = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager SET line_order = ".$new_order_num." WHERE rowid = ".(int)$obj->rowid; $db->query($sql_upd); $new_order_num++; } // ========== SYNC RANG IN DETAIL-TABELLE ========== // Synchronisiere ALLE Zeilen die in der Detail-Tabelle sind (nicht nur Produkte!) $sql = "SELECT ".$tables['fk_line'].", line_type FROM ".MAIN_DB_PREFIX."facture_lines_manager"; $sql .= " WHERE ".$tables['fk_parent']." = ".(int)$facture_id; $sql .= " AND document_type = '".$db->escape($docType)."'"; $sql .= " AND ".$tables['fk_line']." IS NOT NULL"; // Alle die in Detail-Tabelle sind $sql .= " ORDER BY line_order"; $resql = $db->query($sql); $rang = 1; while ($obj = $db->fetch_object($resql)) { $fk_line_value = $obj->{$tables['fk_line']}; $sql_upd = "UPDATE ".MAIN_DB_PREFIX.$tables['lines_table']; $sql_upd .= " SET rang = ".$rang; $sql_upd .= " WHERE rowid = ".(int)$fk_line_value; $db->query($sql_upd); subtotaltitle_debug_log(' Sync rang: '.$obj->line_type.' #'.$fk_line_value.' → rang='.$rang); $rang++; } $db->commit(); echo json_encode(['success' => true, 'updated' => count($new_order)]);