subtotaltitle/ajax/move_section.php

232 lines
8 KiB
PHP
Executable file

<?php
define('NOTOKENRENEWAL', 1);
require '../../../main.inc.php';
require_once __DIR__.'/../class/DocumentTypeHelper.class.php';
$section_id = GETPOST('section_id', 'int');
$direction = GETPOST('direction', 'alpha');
$docType = GETPOST('document_type', 'alpha');
if (!$section_id || !$direction) {
echo json_encode(array('success' => false, 'error' => 'Missing parameters'));
exit;
}
// Wenn kein docType übergeben, versuche ihn aus der Section zu ermitteln
if (!$docType) {
$sql = "SELECT document_type FROM ".MAIN_DB_PREFIX."facture_lines_manager WHERE rowid = ".(int)$section_id;
$res = $db->query($sql);
if ($res && $obj = $db->fetch_object($res)) {
$docType = $obj->document_type;
}
}
if (!$docType) {
$docType = 'invoice'; // Fallback
}
$tables = DocumentTypeHelper::getTableNames($docType);
if (!$tables) {
echo json_encode(array('success' => false, 'error' => 'Invalid document type'));
exit;
}
// Hole Section-Info
$sql = "SELECT ".$tables['fk_parent']." as doc_id FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE rowid = ".(int)$section_id;
$sql .= " AND line_type = 'section'";
$sql .= " AND document_type = '".$db->escape($docType)."'";
$resql = $db->query($sql);
if (!$resql || $db->num_rows($resql) == 0) {
echo json_encode(array('success' => false, 'error' => 'Section not found'));
exit;
}
$section = $db->fetch_object($resql);
$doc_id = $section->doc_id;
$db->begin();
// 1. Hole alle Sections (sortiert)
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " AND line_type = 'section'";
$sql .= " ORDER BY line_order";
$resql = $db->query($sql);
$sections = array();
while ($obj = $db->fetch_object($resql)) {
$sections[] = $obj->rowid;
}
// 2. Finde Index und tausche
$current_index = array_search($section_id, $sections);
if ($current_index === false) {
$db->rollback();
echo json_encode(array('success' => false, 'error' => 'Section not in list'));
exit;
}
if ($direction == 'up') {
if ($current_index == 0) {
$db->rollback();
echo json_encode(array('success' => false, 'error' => 'Already at top'));
exit;
}
$swap_index = $current_index - 1;
} else {
if ($current_index == count($sections) - 1) {
$db->rollback();
echo json_encode(array('success' => false, 'error' => 'Already at bottom'));
exit;
}
$swap_index = $current_index + 1;
}
// Tausche
$temp = $sections[$current_index];
$sections[$current_index] = $sections[$swap_index];
$sections[$swap_index] = $temp;
// 3. Baue komplette neue Reihenfolge auf
// Strategie: Freie Zeilen behalten ihre Position relativ zu Sections
$new_order = 1;
$updates = array();
$processed = array();
// Hole die aktuelle line_order der ersten Section (VOR dem Swap)
$sql = "SELECT MIN(line_order) as min_section_order FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " AND line_type = 'section'";
$resql = $db->query($sql);
$obj = $db->fetch_object($resql);
$first_section_order = $obj ? $obj->min_section_order : 9999;
// 1. FREIE ZEILEN VOR allen Sections (line_order < erste Section)
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " AND (parent_section IS NULL OR parent_section = 0)";
$sql .= " AND line_type != 'section'";
$sql .= " AND line_order < ".(int)$first_section_order;
$sql .= " ORDER BY line_order";
$resql = $db->query($sql);
while ($obj = $db->fetch_object($resql)) {
$updates[$obj->rowid] = $new_order;
$processed[$obj->rowid] = true;
dol_syslog('[SubtotalTitle] move_section: Freie Zeile VOR Sections #'.$obj->rowid.' → line_order='.$new_order, LOG_INFO);
$new_order++;
}
// 2. SECTIONS in neuer Reihenfolge (nach dem Swap)
foreach ($sections as $sec_id) {
// Section-Header
$updates[$sec_id] = $new_order;
$processed[$sec_id] = true;
dol_syslog('[SubtotalTitle] move_section: Section #'.$sec_id.' → line_order='.$new_order, LOG_INFO);
$new_order++;
// Produkte dieser Section
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " AND line_type = 'product'";
$sql .= " AND parent_section = ".(int)$sec_id;
$sql .= " ORDER BY line_order";
$resql = $db->query($sql);
while ($obj = $db->fetch_object($resql)) {
$updates[$obj->rowid] = $new_order;
$processed[$obj->rowid] = true;
$new_order++;
}
// Textzeilen dieser Section
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " AND line_type = 'text'";
$sql .= " AND parent_section = ".(int)$sec_id;
$sql .= " ORDER BY line_order";
$resql = $db->query($sql);
while ($obj = $db->fetch_object($resql)) {
$updates[$obj->rowid] = $new_order;
$processed[$obj->rowid] = true;
$new_order++;
}
// Subtotal dieser Section
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " AND line_type = 'subtotal'";
$sql .= " AND parent_section = ".(int)$sec_id;
$resql = $db->query($sql);
while ($obj = $db->fetch_object($resql)) {
$updates[$obj->rowid] = $new_order;
$processed[$obj->rowid] = true;
$new_order++;
}
}
// 3. FREIE ZEILEN NACH allen Sections (die noch nicht processed wurden)
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " AND (parent_section IS NULL OR parent_section = 0)";
$sql .= " AND line_type != 'section'";
$sql .= " ORDER BY line_order";
$resql = $db->query($sql);
while ($obj = $db->fetch_object($resql)) {
if (!isset($processed[$obj->rowid])) {
$updates[$obj->rowid] = $new_order;
$processed[$obj->rowid] = true;
dol_syslog('[SubtotalTitle] move_section: Freie Zeile NACH Sections #'.$obj->rowid.' → line_order='.$new_order, LOG_INFO);
$new_order++;
}
}
// 4. Führe alle Updates aus
foreach ($updates as $rowid => $order) {
$sql = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " SET line_order = ".(int)$order;
$sql .= " WHERE rowid = ".(int)$rowid;
$db->query($sql);
}
// 5. Sync rang in Detail-Tabelle
dol_syslog('[SubtotalTitle] move_section: Starte rang-Synchronisation für docType='.$docType.' doc_id='.$doc_id, LOG_INFO);
$sql = "SELECT rowid, line_type, ".$tables['fk_line']." as detail_id FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$doc_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);
dol_syslog('[SubtotalTitle] Sync rang: '.$obj->line_type.' manager#'.$obj->rowid.' detail#'.$detail_id.' → rang='.$rang, LOG_INFO);
$rang++;
}
}
dol_syslog('[SubtotalTitle] move_section: rang-Synchronisation abgeschlossen, '.$rang.' Zeilen synchronisiert', LOG_INFO);
$db->commit();
echo json_encode(array('success' => true));