subtotaltitle/ajax/add_to_section.php

171 lines
7.2 KiB
PHP

<?php
define('NOTOKENRENEWAL', 1);
require '../../../main.inc.php';
require_once __DIR__.'/../lib/subtotaltitle.lib.php';
require_once __DIR__.'/../class/DocumentTypeHelper.class.php';
$line_id = GETPOST('line_id', 'int');
$section_id = GETPOST('section_id', 'int');
$document_id = GETPOST('document_id', 'int');
$docType = GETPOST('document_type', 'alpha');
subtotaltitle_debug_log('🔗 add_to_section: line='.$line_id.', section='.$section_id.', doc='.$document_id.', docType='.$docType);
if (!$line_id || !$section_id || !$document_id || !$docType) {
echo json_encode(['success' => 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
// Das Produkt soll IMMER als LETZTES Produkt der Section eingefügt werden
// (nach allen bestehenden Produkten dieser Section, aber vor der nächsten Section oder dem Subtotal)
// Suche das letzte Produkt/Text dieser Section
$sql_last = "SELECT MAX(line_order) as max_order FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql_last .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id;
$sql_last .= " AND document_type = '".$db->escape($docType)."'";
$sql_last .= " AND parent_section = ".(int)$section_id;
$sql_last .= " AND line_type IN ('product', 'text')";
$sql_last .= " AND rowid != ".(int)$manager_id; // Nicht das aktuelle Produkt selbst
$resql_last = $db->query($sql_last);
$obj_last = $db->fetch_object($resql_last);
if ($obj_last && $obj_last->max_order) {
// Es gibt bereits Produkte in dieser Section → füge NACH dem letzten ein
$new_line_order = (int)$obj_last->max_order + 1;
} else {
// Keine anderen 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
// WICHTIG: Zuerst das Produkt "entfernen" (temporär auf -1 setzen), dann verschieben, dann einfügen
$sql_temp = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager";
$sql_temp .= " SET line_order = -1";
$sql_temp .= " WHERE rowid = ".(int)$manager_id;
$db->query($sql_temp);
if ($current_line_order < $new_line_order) {
// Produkt wird nach hinten verschoben
// Schließe die Lücke: alle Zeilen zwischen current+1 und new_line_order um -1 verschieben
$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);
// Korrigiere new_line_order (weil wir verschoben haben)
$new_line_order = $new_line_order - 1;
subtotaltitle_debug_log(' Nach hinten: Lücke geschlossen, new_line_order korrigiert auf '.$new_line_order);
} elseif ($current_line_order > $new_line_order) {
// Produkt wird nach vorne verschoben
// Mache Platz: alle Zeilen ab new_line_order bis current-1 um +1 verschieben
$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: Platz gemacht ab position '.$new_line_order);
}
// 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 mit line_order='.$new_line_order);
// 6. Normalisiere alle line_order (keine Lücken, keine Duplikate)
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE ".$tables['fk_parent']." = ".(int)$document_id;
$sql .= " AND document_type = '".$db->escape($docType)."'";
$sql .= " ORDER BY line_order, rowid"; // Bei Gleichstand nach rowid sortieren
$resql = $db->query($sql);
$new_order = 1;
while ($obj = $db->fetch_object($resql)) {
$sql_upd = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager";
$sql_upd .= " SET line_order = ".$new_order;
$sql_upd .= " WHERE rowid = ".(int)$obj->rowid;
$db->query($sql_upd);
$new_order++;
}
subtotaltitle_debug_log(' line_order normalisiert: '.($new_order-1).' Zeilen');
// 7. 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]);