subtotaltitle/ajax/sync_to_facturedet.php

266 lines
9.7 KiB
PHP

<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* Sync SubtotalTitle lines to/from facturedet
*/
define('NOTOKENRENEWAL', 1);
$res = 0;
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
if (!$res && file_exists("../../../../main.inc.php")) $res = @include "../../../../main.inc.php";
if (!$res) die("Include of main fails");
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
dol_include_once('/subtotaltitle/lib/subtotaltitle.lib.php');
header('Content-Type: application/json');
$action = GETPOST('action', 'alpha');
$line_id = GETPOST('line_id', 'int');
$line_type = GETPOST('line_type', 'alpha');
$facture_id = GETPOST('facture_id', 'int');
subtotaltitle_debug_log('🔄 sync_to_facturedet: action='.$action.', line_id='.$line_id.', type='.$line_type);
if (!$line_id || !$action) {
echo json_encode(array('success' => false, 'error' => 'Missing parameters'));
exit;
}
// Special codes für unsere Zeilentypen
$special_codes = array(
'section' => 100,
'text' => 101,
'subtotal' => 102
);
if ($action == 'add') {
// ========== ZUR RECHNUNG HINZUFÜGEN ==========
// Hole Daten aus unserer Manager-Tabelle
$sql = "SELECT m.*, s.title as section_title, s.rowid as section_rowid";
$sql .= " FROM ".MAIN_DB_PREFIX."facture_lines_manager m";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_lines_manager s ON s.rowid = m.parent_section";
$sql .= " WHERE m.rowid = ".(int)$line_id;
$resql = $db->query($sql);
if (!$resql || $db->num_rows($resql) == 0) {
echo json_encode(array('success' => false, 'error' => 'Line not found'));
exit;
}
$line = $db->fetch_object($resql);
$facture_id = $line->fk_facture;
$line_type = $line->line_type;
// Prüfe ob schon in facturedet (für nicht-Produkte)
if ($line->fk_facturedet > 0 && $line_type != 'product') {
echo json_encode(array('success' => false, 'error' => 'Already in facturedet'));
exit;
}
// Bestimme special_code
$special_code = isset($special_codes[$line_type]) ? $special_codes[$line_type] : 0;
// Bestimme Beschreibung und Betrag
$description = '';
$total_ht = 0;
$qty = 0;
switch ($line_type) {
case 'section':
$description = $line->title;
$qty = 0;
break;
case 'text':
$description = $line->title;
$qty = 0;
break;
case 'subtotal':
// Berechne Summe der Section
$sql_sum = "SELECT SUM(d.total_ht) as total";
$sql_sum .= " FROM ".MAIN_DB_PREFIX."facture_lines_manager m";
$sql_sum .= " INNER JOIN ".MAIN_DB_PREFIX."facturedet d ON d.rowid = m.fk_facturedet";
$sql_sum .= " WHERE m.parent_section = ".(int)$line->parent_section;
$sql_sum .= " AND m.line_type = 'product'";
$res_sum = $db->query($sql_sum);
$obj_sum = $db->fetch_object($res_sum);
$total_ht = $obj_sum->total ? $obj_sum->total : 0;
$description = 'Zwischensumme: '.$line->section_title;
$qty = 1;
break;
}
// Bestimme rang (Position)
$sql_rang = "SELECT MAX(d.rang) as max_rang";
$sql_rang .= " FROM ".MAIN_DB_PREFIX."facture_lines_manager m";
$sql_rang .= " INNER JOIN ".MAIN_DB_PREFIX."facturedet d ON d.rowid = m.fk_facturedet";
$sql_rang .= " WHERE m.fk_facture = ".(int)$facture_id;
$sql_rang .= " AND m.line_order < ".(int)$line->line_order;
$res_rang = $db->query($sql_rang);
$obj_rang = $db->fetch_object($res_rang);
$new_rang = ($obj_rang && $obj_rang->max_rang) ? $obj_rang->max_rang + 1 : 1;
// Verschiebe alle nachfolgenden Zeilen
$sql_shift = "UPDATE ".MAIN_DB_PREFIX."facturedet";
$sql_shift .= " SET rang = rang + 1";
$sql_shift .= " WHERE fk_facture = ".(int)$facture_id;
$sql_shift .= " AND rang >= ".(int)$new_rang;
$db->query($sql_shift);
// Füge neue Zeile in facturedet ein
subtotaltitle_debug_log('📝 INSERT: line_type='.$line_type.', special_code='.$special_code);
$sql_ins = "INSERT INTO ".MAIN_DB_PREFIX."facturedet";
$sql_ins .= " (fk_facture, description, qty, subprice, total_ht, total_tva, total_ttc,";
$sql_ins .= " tva_tx, product_type, special_code, rang, info_bits)";
$sql_ins .= " VALUES (";
$sql_ins .= (int)$facture_id.", ";
$sql_ins .= "'".$db->escape($description)."', ";
$sql_ins .= (float)$qty.", ";
$sql_ins .= ($line_type == 'subtotal') ? (float)$total_ht.", " : "0, ";
$sql_ins .= ($line_type == 'subtotal') ? (float)$total_ht.", " : "0, ";
$sql_ins .= "0, "; // total_tva
$sql_ins .= ($line_type == 'subtotal') ? (float)$total_ht.", " : "0, ";
$sql_ins .= "0, "; // tva_tx
$sql_ins .= "9, "; // product_type = 9 (Titel/Kommentar)
$sql_ins .= (int)$special_code.", ";
$sql_ins .= (int)$new_rang.", ";
$sql_ins .= "0)";
subtotaltitle_debug_log('📝 SQL: '.$sql_ins);
if (!$db->query($sql_ins)) {
echo json_encode(array('success' => false, 'error' => $db->lasterror()));
exit;
}
$new_facturedet_id = $db->last_insert_id(MAIN_DB_PREFIX."facturedet");
// Update unsere Manager-Tabelle
$sql_upd = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager";
$sql_upd .= " SET fk_facturedet = ".(int)$new_facturedet_id;
$sql_upd .= ", in_facturedet = 1";
$sql_upd .= " WHERE rowid = ".(int)$line_id;
$db->query($sql_upd);
subtotaltitle_debug_log('✅ Zeile #'.$line_id.' zu facturedet hinzugefügt als #'.$new_facturedet_id);
echo json_encode(array(
'success' => true,
'facturedet_id' => $new_facturedet_id,
'rang' => $new_rang
));
} elseif ($action == 'remove') {
// ========== AUS RECHNUNG ENTFERNEN ==========
// Hole Daten
$sql = "SELECT fk_facturedet, fk_facture, line_type FROM ".MAIN_DB_PREFIX."facture_lines_manager";
$sql .= " WHERE rowid = ".(int)$line_id;
$resql = $db->query($sql);
if (!$resql || $db->num_rows($resql) == 0) {
echo json_encode(array('success' => false, 'error' => 'Line not found'));
exit;
}
$line = $db->fetch_object($resql);
// Produkte dürfen nicht entfernt werden
if ($line->line_type == 'product') {
echo json_encode(array('success' => false, 'error' => 'Cannot remove products'));
exit;
}
if (!$line->fk_facturedet) {
echo json_encode(array('success' => false, 'error' => 'Not in facturedet'));
exit;
}
// Hole rang bevor wir löschen
$sql_rang = "SELECT rang FROM ".MAIN_DB_PREFIX."facturedet WHERE rowid = ".(int)$line->fk_facturedet;
$res_rang = $db->query($sql_rang);
$obj_rang = $db->fetch_object($res_rang);
$old_rang = $obj_rang ? $obj_rang->rang : 0;
// Lösche aus facturedet
$sql_del = "DELETE FROM ".MAIN_DB_PREFIX."facturedet";
$sql_del .= " WHERE rowid = ".(int)$line->fk_facturedet;
if (!$db->query($sql_del)) {
echo json_encode(array('success' => false, 'error' => $db->lasterror()));
exit;
}
// Schließe Lücke in rang
if ($old_rang > 0) {
$sql_shift = "UPDATE ".MAIN_DB_PREFIX."facturedet";
$sql_shift .= " SET rang = rang - 1";
$sql_shift .= " WHERE fk_facture = ".(int)$line->fk_facture;
$sql_shift .= " AND rang > ".(int)$old_rang;
$db->query($sql_shift);
}
// Update unsere Manager-Tabelle
$sql_upd = "UPDATE ".MAIN_DB_PREFIX."facture_lines_manager";
$sql_upd .= " SET fk_facturedet = NULL";
$sql_upd .= ", in_facturedet = 0";
$sql_upd .= " WHERE rowid = ".(int)$line_id;
$db->query($sql_upd);
subtotaltitle_debug_log('✅ Zeile #'.$line_id.' aus facturedet entfernt');
echo json_encode(array('success' => true));
} elseif ($action == 'update_subtotal') {
// ========== SUBTOTAL-BETRAG AKTUALISIEREN ==========
$sql = "SELECT m.fk_facturedet, m.parent_section, s.title as section_title";
$sql .= " FROM ".MAIN_DB_PREFIX."facture_lines_manager m";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_lines_manager s ON s.rowid = m.parent_section";
$sql .= " WHERE m.rowid = ".(int)$line_id;
$sql .= " AND m.line_type = 'subtotal'";
$resql = $db->query($sql);
if (!$resql || $db->num_rows($resql) == 0) {
echo json_encode(array('success' => false, 'error' => 'Subtotal not found'));
exit;
}
$line = $db->fetch_object($resql);
if (!$line->fk_facturedet) {
echo json_encode(array('success' => false, 'error' => 'Not in facturedet'));
exit;
}
// Berechne neue Summe
$sql_sum = "SELECT SUM(d.total_ht) as total";
$sql_sum .= " FROM ".MAIN_DB_PREFIX."facture_lines_manager m";
$sql_sum .= " INNER JOIN ".MAIN_DB_PREFIX."facturedet d ON d.rowid = m.fk_facturedet";
$sql_sum .= " WHERE m.parent_section = ".(int)$line->parent_section;
$sql_sum .= " AND m.line_type = 'product'";
$res_sum = $db->query($sql_sum);
$obj_sum = $db->fetch_object($res_sum);
$total_ht = $obj_sum->total ? $obj_sum->total : 0;
// Update facturedet
$sql_upd = "UPDATE ".MAIN_DB_PREFIX."facturedet";
$sql_upd .= " SET subprice = ".(float)$total_ht;
$sql_upd .= ", total_ht = ".(float)$total_ht;
$sql_upd .= ", total_ttc = ".(float)$total_ht;
$sql_upd .= " WHERE rowid = ".(int)$line->fk_facturedet;
$db->query($sql_upd);
subtotaltitle_debug_log('✅ Subtotal #'.$line_id.' aktualisiert: '.$total_ht);
echo json_encode(array('success' => true, 'total_ht' => $total_ht));
} else {
echo json_encode(array('success' => false, 'error' => 'Unknown action'));
}