PWA (neue Dateien): - Vollständige Progressive Web App mit Token-basierter Auth - 4 Swipe-Panels: Alle STZ, Stundenzettel, Produktliste, Lieferauflistung - Kundensuche, Leistungen-Accordion, Mehraufwand-Sektion - Produkt-Übernahme aus Auftrag + Mehraufwand in STZ - Service Worker, Manifest, App-Icons für Installation Desktop-Änderungen: - Produktliste: Checkboxen immer sichtbar (außer bereits auf STZ) - Lieferauflistung: Vereinfachte Ansicht (nur Verbaut-Spalte) - Admin: PWA-Link in Einstellungen - Sprachdatei: PWA-Übersetzungen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
147 lines
6.4 KiB
PHP
Executable file
147 lines
6.4 KiB
PHP
Executable file
<?php
|
|
/**
|
|
* Debug-Script für Netto STZ Berechnung
|
|
* Aufruf: debug_netto.php?order_id=21
|
|
*/
|
|
|
|
// Load Dolibarr environment
|
|
$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");
|
|
|
|
dol_include_once('/stundenzettel/lib/stundenzettel.lib.php');
|
|
|
|
$order_id = GETPOST('order_id', 'int');
|
|
if (empty($order_id)) {
|
|
die("Bitte order_id angeben: debug_netto.php?order_id=XXX");
|
|
}
|
|
|
|
echo "<h2>Debug Netto STZ für Auftrag #".$order_id."</h2>";
|
|
|
|
// 1. Auftrag und Kunde prüfen
|
|
$sqlOrder = "SELECT c.rowid, c.ref, c.fk_soc, s.nom as customer_name FROM ".MAIN_DB_PREFIX."commande c";
|
|
$sqlOrder .= " LEFT JOIN ".MAIN_DB_PREFIX."societe s ON s.rowid = c.fk_soc";
|
|
$sqlOrder .= " WHERE c.rowid = ".((int)$order_id);
|
|
$resqlOrder = $db->query($sqlOrder);
|
|
$order = $db->fetch_object($resqlOrder);
|
|
|
|
echo "<h3>Auftrag</h3>";
|
|
echo "<pre>Ref: ".$order->ref."\nKunde: ".$order->customer_name." (ID: ".$order->fk_soc.")</pre>";
|
|
|
|
// 2. Standard-Leistung des Kunden
|
|
$sqlService = "SELECT stundenzettel_default_service FROM ".MAIN_DB_PREFIX."societe_extrafields WHERE fk_object = ".((int)$order->fk_soc);
|
|
$resqlService = $db->query($sqlService);
|
|
$serviceObj = $db->fetch_object($resqlService);
|
|
$defaultServiceId = $serviceObj ? (int)$serviceObj->stundenzettel_default_service : 0;
|
|
|
|
echo "<h3>Standard-Leistung beim Kunden</h3>";
|
|
if ($defaultServiceId > 0) {
|
|
$sqlProd = "SELECT rowid, ref, label, price FROM ".MAIN_DB_PREFIX."product WHERE rowid = ".((int)$defaultServiceId);
|
|
$resqlProd = $db->query($sqlProd);
|
|
$prod = $db->fetch_object($resqlProd);
|
|
echo "<pre>Service ID: ".$defaultServiceId."\nRef: ".$prod->ref."\nLabel: ".$prod->label."\nPreis: ".price($prod->price)." EUR</pre>";
|
|
|
|
// Kundenspezifischer Preis?
|
|
$priceInfo = getCustomerPrice($db, $defaultServiceId, $order->fk_soc);
|
|
echo "<pre>Effektiver Preis (mit Kundenpreis): ".price($priceInfo['price'])." EUR";
|
|
echo " (".($priceInfo['is_customer_price'] ? "Kundenpreis" : "Standardpreis").")</pre>";
|
|
} else {
|
|
echo "<pre style='color:red'>KEINE Standard-Leistung beim Kunden hinterlegt!</pre>";
|
|
}
|
|
|
|
// 3. Stundenzettel des Auftrags
|
|
echo "<h3>Stundenzettel des Auftrags</h3>";
|
|
$sqlStz = "SELECT s.rowid, s.ref, s.status, s.hourly_rate, s.hourly_rate_is_custom,";
|
|
$sqlStz .= " (SELECT SUM(duration) FROM ".MAIN_DB_PREFIX."stundenzettel_leistung WHERE fk_stundenzettel = s.rowid) as total_minutes";
|
|
$sqlStz .= " FROM ".MAIN_DB_PREFIX."stundenzettel s";
|
|
$sqlStz .= " WHERE s.fk_commande = ".((int)$order_id);
|
|
$resqlStz = $db->query($sqlStz);
|
|
|
|
echo "<table border='1' cellpadding='5'>";
|
|
echo "<tr><th>ID</th><th>Ref</th><th>Status</th><th>Leistungen</th></tr>";
|
|
|
|
$totalNetto = 0;
|
|
while ($stz = $db->fetch_object($resqlStz)) {
|
|
$statusText = ($stz->status == 0) ? '<span style="color:orange">Entwurf</span>' : '<span style="color:green">Freigegeben</span>';
|
|
|
|
// Leistungen dieses Stundenzettels laden
|
|
$sqlLeist = "SELECT l.duration, l.fk_product, l.description, p.ref as product_ref, p.label as product_label, p.price as product_price";
|
|
$sqlLeist .= " FROM ".MAIN_DB_PREFIX."stundenzettel_leistung l";
|
|
$sqlLeist .= " LEFT JOIN ".MAIN_DB_PREFIX."product p ON p.rowid = l.fk_product";
|
|
$sqlLeist .= " WHERE l.fk_stundenzettel = ".((int)$stz->rowid);
|
|
$resqlLeist = $db->query($sqlLeist);
|
|
|
|
$leistungenHtml = "<table border='1' style='font-size:12px'>";
|
|
$leistungenHtml .= "<tr><th>Dauer</th><th>Leistung</th><th>Preis</th><th>Berechnung</th></tr>";
|
|
|
|
$stzSubtotal = 0;
|
|
while ($leist = $db->fetch_object($resqlLeist)) {
|
|
$hours = $leist->duration / 60;
|
|
$hourlyRate = 0;
|
|
$rateSource = "<span style='color:red'>KEINER!</span>";
|
|
|
|
if ($leist->fk_product > 0) {
|
|
$priceInfo = getCustomerPrice($db, $leist->fk_product, $order->fk_soc);
|
|
$hourlyRate = $priceInfo['price'];
|
|
$rateSource = $leist->product_ref." - ".$leist->product_label;
|
|
if ($priceInfo['is_customer_price']) {
|
|
$rateSource .= " <span style='color:green'>(Kundenpreis)</span>";
|
|
}
|
|
} elseif ($stz->hourly_rate > 0) {
|
|
$hourlyRate = (float)$stz->hourly_rate;
|
|
$rateSource = "Stundenzettel-Rate";
|
|
} elseif ($defaultServiceId > 0) {
|
|
$priceInfo = getCustomerPrice($db, $defaultServiceId, $order->fk_soc);
|
|
$hourlyRate = $priceInfo['price'];
|
|
$rateSource = "Kunden-Standard";
|
|
}
|
|
|
|
$subtotal = ($stz->status >= 1) ? ($hourlyRate * $hours) : 0;
|
|
if ($stz->status >= 1) {
|
|
$stzSubtotal += $subtotal;
|
|
}
|
|
|
|
$calcText = ($stz->status >= 1)
|
|
? price($hourlyRate)." x ".$hours."h = <b>".price($subtotal)."</b>"
|
|
: "<i>Nicht freigegeben</i>";
|
|
|
|
$leistungenHtml .= "<tr>";
|
|
$leistungenHtml .= "<td>".$hours."h</td>";
|
|
$leistungenHtml .= "<td>".$rateSource."</td>";
|
|
$leistungenHtml .= "<td>".price($hourlyRate)." EUR</td>";
|
|
$leistungenHtml .= "<td>".$calcText."</td>";
|
|
$leistungenHtml .= "</tr>";
|
|
}
|
|
$leistungenHtml .= "<tr><td colspan='3'><b>Summe:</b></td><td><b>".price($stzSubtotal)." EUR</b></td></tr>";
|
|
$leistungenHtml .= "</table>";
|
|
|
|
$totalNetto += $stzSubtotal;
|
|
|
|
echo "<tr>";
|
|
echo "<td>".$stz->rowid."</td>";
|
|
echo "<td>".$stz->ref."</td>";
|
|
echo "<td>".$statusText."</td>";
|
|
echo "<td>".$leistungenHtml."</td>";
|
|
echo "</tr>";
|
|
}
|
|
echo "</table>";
|
|
|
|
echo "<h3>Ergebnis</h3>";
|
|
echo "<pre style='font-size:18px; color:blue'>Berechneter Netto STZ: <b>".price($totalNetto)." EUR</b></pre>";
|
|
|
|
// 4. Aktueller Wert in der Datenbank
|
|
$sqlCurrent = "SELECT stundenzettel_netto FROM ".MAIN_DB_PREFIX."commande_extrafields WHERE fk_object = ".((int)$order_id);
|
|
$resqlCurrent = $db->query($sqlCurrent);
|
|
$current = $db->fetch_object($resqlCurrent);
|
|
$currentValue = $current ? $current->stundenzettel_netto : "NICHT GESETZT";
|
|
|
|
echo "<pre>Aktueller Wert in DB: ".($currentValue !== "NICHT GESETZT" ? price($currentValue)." EUR" : $currentValue)."</pre>";
|
|
|
|
echo "<hr><p><a href='debug_netto.php?order_id=".$order_id."&update=1'>Jetzt neu berechnen und speichern</a></p>";
|
|
|
|
if (GETPOST('update', 'int')) {
|
|
$result = updateOrderNettoSTZ($db, $order_id);
|
|
echo "<p style='color:green; font-weight:bold'>Berechnung durchgeführt! Ergebnis: ".price($result)." EUR</p>";
|
|
echo "<p><a href='debug_netto.php?order_id=".$order_id."'>Seite neu laden</a></p>";
|
|
}
|