Version 1.3.0: Netto STZ Spalte in Auftragsliste

- Neue Spalte "Netto STZ" zeigt Netto-Wert aller freigegebenen Stundenzettel
- Berechnung bei Freigabe/Wiedereröffnung von einzelnen oder allen Stundenzetteln
- Arbeitsstunden verwenden Preis der gewählten Leistungsposition (nicht mehr Kunden-Standard)
- Unterstützt kundenspezifische Preise für Produkte und Leistungen
- Extrafeld stundenzettel_netto wird bei Modulaktivierung erstellt
- Debug-Script debug_netto.php für Fehleranalyse
- Deutsche Übersetzungen für Meldungen ergänzt
- Formular-Verbesserung: Enter-Taste und Save-Button bei Produktmengen

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-02-10 20:18:04 +01:00
parent 192cdad8e0
commit 41973f0231
7 changed files with 385 additions and 4 deletions

View file

@ -1,6 +1,6 @@
# Stundenzettel Modul für Dolibarr
**Version:** 1.2.0
**Version:** 1.3.0
**Autor:** Data IT Solution
**Kompatibilität:** Dolibarr 16.0+
**Lizenz:** GPL v3
@ -76,6 +76,7 @@ Sie können beim Kunden (unter **Kunden > Kundenkarte**) eine Standard-Leistung
|------|---------|--------------|
| `auftragsbeschreibung` | Auftrag | Zusätzliche Beschreibung für den Auftrag |
| `stundenzettel_status` | Auftrag | Status der Stundenzettel (0=Offen, 1=Freigegeben, 2=Abgerechnet) |
| `stundenzettel_netto` | Auftrag | Berechneter Netto-Wert aller freigegebenen Stundenzettel |
| `stundenzettel_default_service` | Kunde | Standard-Dienstleistung für Stundenzettel |
## Berechtigungen
@ -99,6 +100,16 @@ Sie können beim Kunden (unter **Kunden > Kundenkarte**) eine Standard-Leistung
## Changelog
### Version 1.3.0
- **Netto STZ Spalte in Auftragsliste**: Neue Spalte zeigt den Netto-Wert aller freigegebenen Stundenzettel eines Auftrags
- Automatische Berechnung bei Freigabe/Wiedereröffnung von Stundenzetteln
- Berücksichtigt Produkte (mit Auftrags- oder Katalogpreisen)
- Berücksichtigt Arbeitsstunden (mit der gewählten Leistungsposition pro Zeile)
- Unterstützt kundenspezifische Preise
- **Verbesserte Preisberechnung**: Jede Arbeitszeit-Zeile verwendet den Preis ihrer eigenen Leistungsposition (nicht mehr Standard-Leistung des Kunden)
- **Extrafeld `stundenzettel_netto`**: Wird automatisch bei Modulaktivierung erstellt
- **Debug-Script**: `debug_netto.php` für Fehleranalyse der Netto-Berechnung
### Version 1.2.0
- **Leistungsposition pro Arbeitszeit**: Jede Arbeitszeit kann einer eigenen Leistungsposition (Dienstleistung) zugeordnet werden
- **Mobile-optimierte Ansicht**: Responsive CSS für Touch-Geräte (Smartphones/Tablets)

View file

@ -187,6 +187,8 @@ if ($action == 'confirm_validate' && $confirm == 'yes' && $permissiontovalidate)
$result = $object->validate($user);
if ($result > 0) {
setEventMessages($langs->trans('StundenzettelValidated'), null, 'mesgs');
// Netto-Wert aller Stundenzettel des Auftrags neu berechnen
updateOrderNettoSTZ($db, $object->fk_commande);
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
@ -197,6 +199,8 @@ if ($action == 'confirm_setdraft' && $confirm == 'yes' && $permissiontoadd) {
$result = $object->setDraft($user);
if ($result > 0) {
setEventMessages($langs->trans('RecordModified'), null, 'mesgs');
// Netto-Wert neu berechnen (da dieser Stundenzettel nicht mehr freigegeben ist)
updateOrderNettoSTZ($db, $object->fk_commande);
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
@ -208,6 +212,10 @@ if ($action == 'confirm_delete' && $confirm == 'yes' && $permissiontodelete) {
$result = $object->delete($user);
if ($result > 0) {
setEventMessages($langs->trans('StundenzettelDeleted'), null, 'mesgs');
// Netto-Wert neu berechnen
if ($fk_commande > 0) {
updateOrderNettoSTZ($db, $fk_commande);
}
// Weiterleitung zur Stundenzettel-Liste des Auftrags
if ($fk_commande > 0) {
header('Location: '.dol_buildpath('/stundenzettel/stundenzettel_commande.php?id='.$fk_commande.'&tab=stundenzettel&noredirect=1', 1));
@ -1233,7 +1241,7 @@ elseif ($object->id > 0) {
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="update_qty">';
print '<input type="hidden" name="line_id" value="'.$prod->rowid.'">';
print '<input type="number" name="qty_done" id="qty_'.$prod->rowid.'" value="'.$qtyDoneFormatted.'" class="flat" style="width:70px; text-align:center;" min="0" step="1">';
print '<input type="number" name="qty_done" id="qty_'.$prod->rowid.'" value="'.$qtyDoneFormatted.'" class="flat" style="width:70px; text-align:center;" min="0" step="1" onkeypress="if(event.keyCode==13){this.form.submit();return false;}">';
print '</form>';
} else {
print formatQty($prod->qty_done);
@ -1259,7 +1267,7 @@ elseif ($object->id > 0) {
// Save Button
print '<td class="center" style="width:40px;">';
print '<a class="reposition" href="javascript:document.getElementById(\'form_qty_'.$prod->rowid.'\').submit();" title="'.$langs->trans("Save").'">';
print '<a class="reposition" href="#" onclick="document.getElementById(\'form_qty_'.$prod->rowid.'\').submit(); return false;" title="'.$langs->trans("Save").'">';
print '<span class="fas fa-save" style="color: #007bff;"></span>';
print '</a>';
print '</td>';

View file

@ -53,7 +53,7 @@ class modStundenzettel extends DolibarrModules
$this->descriptionlong = "Verwaltet Stundenzettel für Kundenaufträge. Ermöglicht die Dokumentation von Arbeitszeiten, verbrauchten Materialien und Notizen. Integration mit SubtotalTitle für Produktgruppen-Unterstützung.";
// Version
$this->version = '1.2.0';
$this->version = '1.3.0';
// Autor
$this->editor_name = 'Data IT Solution';
@ -323,6 +323,9 @@ class modStundenzettel extends DolibarrModules
// Stundenpreis-Felder hinzufügen (Update 1.2.0)
$this->addHourlyRateFields();
// Extrafeld "Netto Stundenzettel" für Aufträge anlegen
$this->createExtraFieldNettoSTZ();
$sql = array();
return $this->_init($sql, $options);
@ -520,6 +523,60 @@ class modStundenzettel extends DolibarrModules
return 1;
}
/**
* Erstellt das Extrafeld "Netto Stundenzettel" für Aufträge (commande)
* Zeigt den berechneten Netto-Wert aller Stundenzettel eines Auftrags
*
* @return int 1 if created or exists, -1 if error
*/
private function createExtraFieldNettoSTZ()
{
global $langs;
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
$extrafields = new ExtraFields($this->db);
// Prüfen ob Extrafeld bereits existiert
$extrafields->fetch_name_optionals_label('commande');
if (!isset($extrafields->attributes['commande']['label']['stundenzettel_netto'])) {
// Extrafeld anlegen: Double für Netto-Betrag
$result = $extrafields->addExtraField(
'stundenzettel_netto', // attrname - Feldname
'Netto STZ', // label - Anzeigename (kurz für Spalte)
'price', // type - Feldtyp (price = Geldbetrag)
110, // pos - Position (nach Auftragsbeschreibung)
'', // size - Größe
'commande', // elementtype - Objekttyp
0, // unique
0, // required
'', // default_value
array('options' => array()), // param
0, // alwayseditable (nicht editierbar - wird berechnet)
'', // perms
1, // list - In Liste anzeigen
'', // ishidden
0, // computed
'', // entity
'', // langfile
'$conf->stundenzettel->enabled', // enabled - nur wenn Modul aktiv
0, // totalizable
0, // printable
array('css' => '', 'cssview' => '', 'csslist' => 'right nowraponall') // moreparams - rechts ausrichten
);
if ($result < 0) {
dol_syslog("modStundenzettel::createExtraFieldNettoSTZ Error creating extrafield: ".$extrafields->error, LOG_ERR);
return -1;
}
dol_syslog("modStundenzettel::createExtraFieldNettoSTZ Extrafield 'stundenzettel_netto' created successfully", LOG_DEBUG);
}
return 1;
}
/**
* Funktion beim Deaktivieren des Moduls
*

147
debug_netto.php Normal file
View file

@ -0,0 +1,147 @@
<?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>";
}

View file

@ -104,7 +104,13 @@ MarkAsOpen = Wieder öffnen
ConfirmValidate = Stundenzettel wirklich freigeben?
ConfirmDelete = Stundenzettel wirklich löschen?
ConfirmDeleteLeistung = Diese Leistung wirklich löschen?
RecordSaved = Eintrag gespeichert
RecordModified = Eintrag aktualisiert
RecordDeleted = Eintrag gelöscht
SetupSaved = Einstellungen gespeichert
ProductsTransferred = Produkte übernommen
NoProductsSelected = Keine Produkte ausgewählt
ErrorCreatingStundenzettel = Fehler beim Erstellen des Stundenzettels
ConfirmTransfer = Alle Produkte in Rechnung übertragen?
AllProductsDocumented = Alle Produkte dokumentiert
NotAllProductsDocumented = Nicht alle Produkte dokumentiert
@ -249,3 +255,7 @@ SelectInvoiceHoursMode = Wie sollen die Arbeitsstunden übernommen werden?
perStundenzettel = pro Stundenzettel
Entries = Einträge
incl = inkl.
# Extrafields Aufträge
NettoSTZ = Netto STZ
NettoSTZHelp = Netto-Wert aller freigegebenen Stundenzettel (Produkte + Arbeitsstunden)

View file

@ -266,3 +266,143 @@ function getEffectiveHourlyRate($db, $stundenzettel, $defaultServiceId) {
'source' => 'none'
);
}
/**
* Berechnet den Netto-Wert aller Stundenzettel eines Auftrags
* und aktualisiert das Extrafield stundenzettel_netto
*
* @param DoliDB $db Datenbankverbindung
* @param int $fk_commande Auftrags-ID
* @return float Der berechnete Netto-Wert
*/
function updateOrderNettoSTZ($db, $fk_commande) {
global $conf;
if (empty($fk_commande)) {
dol_syslog("updateOrderNettoSTZ: fk_commande is empty", LOG_WARNING);
return 0;
}
$totalNetto = 0;
// Hole Kunden-ID und Standard-Leistung ZUERST (vor der Stundenzettel-Schleife)
$defaultServiceId = 0;
$socid = 0;
// Hole Kunden-ID vom Auftrag
$sqlOrder = "SELECT fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE rowid = ".((int)$fk_commande);
$resqlOrder = $db->query($sqlOrder);
if ($resqlOrder && ($objOrder = $db->fetch_object($resqlOrder))) {
$socid = (int)$objOrder->fk_soc;
// Hole Standard-Leistung vom Kunden (Extrafield)
$sqlService = "SELECT stundenzettel_default_service FROM ".MAIN_DB_PREFIX."societe_extrafields";
$sqlService .= " WHERE fk_object = ".((int)$socid);
$resqlService = $db->query($sqlService);
if ($resqlService && ($objService = $db->fetch_object($resqlService))) {
$defaultServiceId = (int)$objService->stundenzettel_default_service;
}
}
dol_syslog("updateOrderNettoSTZ: commande=".$fk_commande.", socid=".$socid.", defaultServiceId=".$defaultServiceId, LOG_DEBUG);
// 1. Alle freigegebenen Stundenzettel des Auftrags laden (status >= 1 = validiert)
$sqlStz = "SELECT s.rowid, s.fk_soc, s.hourly_rate, s.hourly_rate_is_custom";
$sqlStz .= " FROM ".MAIN_DB_PREFIX."stundenzettel as s";
$sqlStz .= " WHERE s.fk_commande = ".((int)$fk_commande);
$sqlStz .= " AND s.status >= 1"; // Nur validierte/freigegebene Stundenzettel
$resqlStz = $db->query($sqlStz);
if (!$resqlStz) {
dol_syslog("updateOrderNettoSTZ: SQL error: ".$db->lasterror(), LOG_ERR);
return 0;
}
$numStz = $db->num_rows($resqlStz);
dol_syslog("updateOrderNettoSTZ: Found ".$numStz." validated Stundenzettel", LOG_DEBUG);
while ($stz = $db->fetch_object($resqlStz)) {
// 2. Produkte dieses Stundenzettels summieren
$sqlProd = "SELECT sp.fk_product, sp.fk_commandedet, sp.qty_done, sp.origin,";
$sqlProd .= " cd.subprice as order_price, cd.tva_tx";
$sqlProd .= " FROM ".MAIN_DB_PREFIX."stundenzettel_product as sp";
$sqlProd .= " LEFT JOIN ".MAIN_DB_PREFIX."commandedet as cd ON cd.rowid = sp.fk_commandedet";
$sqlProd .= " WHERE sp.fk_stundenzettel = ".((int)$stz->rowid);
$sqlProd .= " AND sp.origin IN ('order', 'added', 'extra')"; // Nicht 'omitted' (entfällt)
$resqlProd = $db->query($sqlProd);
if ($resqlProd) {
while ($prod = $db->fetch_object($resqlProd)) {
$price = 0;
$qty = (float)$prod->qty_done;
if ($prod->fk_commandedet > 0 && $prod->order_price > 0) {
// Preis aus Auftragszeile
$price = (float)$prod->order_price;
} elseif ($prod->fk_product > 0) {
// Kundenspezifischer oder Standard-Preis
$priceInfo = getCustomerPrice($db, $prod->fk_product, $socid);
$price = $priceInfo['price'];
}
$totalNetto += $price * $qty;
}
}
// 3. Leistungen (Arbeitsstunden) - JEDE Zeile einzeln mit ihrer gewählten Leistungsposition
$sqlHours = "SELECT l.duration, l.fk_product FROM ".MAIN_DB_PREFIX."stundenzettel_leistung l";
$sqlHours .= " WHERE l.fk_stundenzettel = ".((int)$stz->rowid);
$resqlHours = $db->query($sqlHours);
if ($resqlHours) {
while ($leistung = $db->fetch_object($resqlHours)) {
$minutes = (float)$leistung->duration;
$hoursWorked = $minutes / 60;
if ($hoursWorked > 0) {
$hourlyRate = 0;
// Priorität: 1. Leistungsposition der Zeile, 2. Stundenzettel-Rate, 3. Kunden-Standard
if ($leistung->fk_product > 0) {
// Preis der gewählten Leistungsposition (mit Kundenpreis falls vorhanden)
$priceInfo = getCustomerPrice($db, $leistung->fk_product, $socid);
$hourlyRate = $priceInfo['price'];
dol_syslog("updateOrderNettoSTZ: Leistung fk_product=".$leistung->fk_product." price=".$hourlyRate, LOG_DEBUG);
} elseif ($stz->hourly_rate > 0) {
// Fallback: Manueller Preis im Stundenzettel
$hourlyRate = (float)$stz->hourly_rate;
dol_syslog("updateOrderNettoSTZ: Using STZ hourly_rate=".$hourlyRate, LOG_DEBUG);
} elseif ($defaultServiceId > 0) {
// Fallback: Standard-Leistung des Kunden
$priceInfo = getCustomerPrice($db, $defaultServiceId, $socid);
$hourlyRate = $priceInfo['price'];
dol_syslog("updateOrderNettoSTZ: Using defaultService price=".$hourlyRate, LOG_DEBUG);
} else {
dol_syslog("updateOrderNettoSTZ: No price for leistung! fk_product=".$leistung->fk_product, LOG_WARNING);
}
$subtotal = $hourlyRate * $hoursWorked;
$totalNetto += $subtotal;
dol_syslog("updateOrderNettoSTZ: subtotal=".$subtotal." (rate=".$hourlyRate." x hours=".$hoursWorked.")", LOG_DEBUG);
}
}
}
}
dol_syslog("updateOrderNettoSTZ: TOTAL=".$totalNetto, LOG_DEBUG);
// 4. Extrafield aktualisieren
$sqlUpdate = "UPDATE ".MAIN_DB_PREFIX."commande_extrafields";
$sqlUpdate .= " SET stundenzettel_netto = ".((float)$totalNetto);
$sqlUpdate .= " WHERE fk_object = ".((int)$fk_commande);
$resqlUpdate = $db->query($sqlUpdate);
if (!$resqlUpdate || $db->affected_rows($resqlUpdate) == 0) {
// Zeile existiert noch nicht - INSERT
$sqlInsert = "INSERT INTO ".MAIN_DB_PREFIX."commande_extrafields (fk_object, stundenzettel_netto)";
$sqlInsert .= " VALUES (".((int)$fk_commande).", ".((float)$totalNetto).")";
$db->query($sqlInsert);
}
return $totalNetto;
}

View file

@ -301,6 +301,10 @@ if ($doRelease) {
$sql2 = "INSERT INTO ".MAIN_DB_PREFIX."commande_extrafields (fk_object, stundenzettel_status) VALUES (".((int)$order->id).", 1)";
$db->query($sql2);
}
// Netto-Wert aller Stundenzettel berechnen und speichern
updateOrderNettoSTZ($db, $order->id);
setEventMessages($langs->trans('StundenzettelReleased'), null, 'mesgs');
} else {
setEventMessages($db->lasterror(), null, 'errors');
@ -322,6 +326,10 @@ if ($action == 'reopen_stundenzettel' && $canReopen) {
$sql2 = "INSERT INTO ".MAIN_DB_PREFIX."commande_extrafields (fk_object, stundenzettel_status) VALUES (".((int)$order->id).", 0)";
$db->query($sql2);
}
// Netto-Wert neu berechnen (wird 0 wenn keine freigegebenen Stundenzettel mehr)
updateOrderNettoSTZ($db, $order->id);
setEventMessages($langs->trans('StundenzettelReopened'), null, 'mesgs');
} else {
setEventMessages($db->lasterror(), null, 'errors');