Kein Stunden-Dummy mehr beim Direkt-Freigeben (1.4.0)

api/orders.php?action=create gibt den Auftrag mit validate=true jetzt ohne
jede Position frei. Bisher hing das Backend vorher eine Std-Lohn-Zeile mit
Menge 1 an (Kundenkarten-Default, sonst Fallback-Produkt).

Die Annahme, Commande::valid() scheitere an einem leeren Auftrag, ist falsch -
weder valid() noch confirm_validate pruefen auf Zeilen, gesperrt ist nur die
Button-Darstellung in commande/card.php (KB #355/#989, gegen Dolibarr 22.0.2
verifiziert). Die Alibi-Zeile verfaelschte total_ht, tauchte als offene Rest-
menge in der Lieferauflistung auf, stand im Kunden-PDF und liess sich nach der
Freigabe nicht mehr per deleteLine() entfernen. Die Leistungen kommen aus dem
Stundenzettel.

- Antwortfeld added_line entfaellt (die Baustelle-PWA hat es nie ausgewertet)
- Konstante BERICHT_ORDER_DEFAULT_SERVICE_REF wird nicht mehr verwendet
- Gleiche Umstellung in der Stunden-App (Stundenzettel 2.17.0), die mit der
  neuen Aktion create_order jetzt ebenfalls Auftraege anlegen kann

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-08-15 16:25:59 +02:00
parent 52810b2b91
commit 3ab13e2e23
4 changed files with 25 additions and 59 deletions

View file

@ -1,5 +1,15 @@
# Changelog # Changelog
## 1.4.0 — 2026-08-15
### Kein Stunden-Dummy mehr beim Direkt-Freigeben
- **`api/orders.php?action=create`**: Mit `validate=true` wird der Auftrag jetzt **ohne jede Position** freigegeben. Bisher hängte das Backend vorher eine Std-Lohn-Zeile mit Menge 1 an (Kundenkarten-Default `options_stundenzettel_default_service`, sonst Fallback-Produkt).
- **Warum:** Die Annahme, `Commande::valid()` scheitere an einem leeren Auftrag, ist falsch — weder `valid()` noch der Handler `confirm_validate` prüfen auf Zeilen, gesperrt ist nur die Button-Darstellung in `commande/card.php` (verifiziert gegen Dolibarr 22.0.2, KB #355/#989). Die Alibi-Zeile verfälschte `total_ht`, tauchte als offene Restmenge in der Lieferauflistung auf, stand im Kunden-PDF und ließ sich nach der Freigabe nicht mehr per `deleteLine()` entfernen. Die Leistungen kommen aus dem Stundenzettel.
- Das Antwortfeld `added_line` entfällt (wurde von der Baustelle-PWA nie ausgewertet).
- Die Konstante `BERICHT_ORDER_DEFAULT_SERVICE_REF` wird nicht mehr verwendet.
- Gleiche Umstellung in der Stunden-App: `stundenzettel/ajax/pwa_api.php` (Aktion `validate_order`) fügt ebenfalls keine Fallback-Position mehr ein, und legt mit der neuen Aktion `create_order` selbst Aufträge an (Stundenzettel 2.17.0).
## 1.3.1 — 2026-07-18 ## 1.3.1 — 2026-07-18
### Fixes rund um die PWA-Auftragsanlage ### Fixes rund um die PWA-Auftragsanlage

View file

@ -86,9 +86,9 @@ GET /custom/bericht/api/orders.php?id=<id>
GET /custom/bericht/api/orders.php?id=<id>&action=photos GET /custom/bericht/api/orders.php?id=<id>&action=photos
POST /custom/bericht/api/orders.php?action=create POST /custom/bericht/api/orders.php?action=create
Body: { socid, ref_client, title?, note_private?, date?, date_livraison?, validate? } Body: { socid, ref_client, title?, note_private?, date?, date_livraison?, validate? }
ref_client ("Ihr Zeichen") ist PFLICHT. validate=true legt vor der Freigabe automatisch ref_client ("Ihr Zeichen") ist PFLICHT. validate=true gibt den Auftrag direkt frei —
eine Std-Lohn-Zeile an (Kundenkarten-Default options_stundenzettel_default_service, OHNE Position (Commande::valid() verlangt keine, verifiziert gegen Dolibarr 22.0.2).
sonst Fallback BERICHT_ORDER_DEFAULT_SERVICE_REF; Kundenpreis vor Standardpreis). Die Leistungen kommen später aus dem Stundenzettel.
``` ```
### Dateien ### Dateien
@ -145,7 +145,6 @@ Per `admin/setup.php` oder `llx_const`:
| `BERICHT_SIGNATURE_BOX_DEFAULT` | JSON | Default-Geometrie für FPDI-Stempel-Fallback (`{"page":"last","x_mm":120,"y_mm":230,"w_mm":70,"h_mm":35,"label":"Unterschrift Kunde"}`) | | `BERICHT_SIGNATURE_BOX_DEFAULT` | JSON | Default-Geometrie für FPDI-Stempel-Fallback (`{"page":"last","x_mm":120,"y_mm":230,"w_mm":70,"h_mm":35,"label":"Unterschrift Kunde"}`) |
| `BERICHT_BURN_ANNOTATIONS` | 0 | Annotationen ins PDF einbrennen statt als PDF-Annotation einbetten | | `BERICHT_BURN_ANNOTATIONS` | 0 | Annotationen ins PDF einbrennen statt als PDF-Annotation einbetten |
| `BERICHT_LIBREOFFICE_BIN` | `soffice` | Pfad zur LibreOffice-Binary (für ODT→PDF) | | `BERICHT_LIBREOFFICE_BIN` | `soffice` | Pfad zur LibreOffice-Binary (für ODT→PDF) |
| `BERICHT_ORDER_DEFAULT_SERVICE_REF` | `ELEK-STD-M` | Fallback-Produkt-Ref für die Std-Lohn-Zeile beim Direkt-Freigeben (wenn Kunde keinen `stundenzettel_default_service` gesetzt hat) |
## Datenbank ## Datenbank

View file

@ -13,11 +13,10 @@
* - ref_client ("Ihr Zeichen") ist PFLICHT (Geschäftsregel; Dolibarr selbst verlangt es nicht). * - ref_client ("Ihr Zeichen") ist PFLICHT (Geschäftsregel; Dolibarr selbst verlangt es nicht).
* - title (Auftragsbeschreibung) optional -> Extrafield options_auftragsbeschreibung. * - title (Auftragsbeschreibung) optional -> Extrafield options_auftragsbeschreibung.
* - date_livraison (Unix-TS) optional -> geplanter Liefertermin (Spalte date_livraison). * - date_livraison (Unix-TS) optional -> geplanter Liefertermin (Spalte date_livraison).
* - validate (bool) optional -> Auftrag direkt freigeben. Vorher wird automatisch eine * - validate (bool) optional -> Auftrag direkt freigeben. Der Auftrag bleibt dabei LEER:
* Std-Lohn-Zeile ergänzt (Kundenkarten-Default options_stundenzettel_default_service, * Commande::valid() verlangt keine Position (verifiziert gegen Dolibarr 22.0.2,
* sonst Fallback-Produkt BERICHT_ORDER_DEFAULT_SERVICE_REF, Default 'ELEK-STD-M'). * KB #355/#989 - nur der Button in commande/card.php ist bei 0 Zeilen gesperrt).
* Preis = kundenspezifischer Preis (PRODUIT_CUSTOMER_PRICES) falls vorhanden, * Die Leistungen kommen später aus dem Stundenzettel.
* sonst Produkt-Standardpreis.
* Legt einen Draft-Auftrag an und übernimmt Kunden-Defaults (Zahlungsbedingungen, * Legt einen Draft-Auftrag an und übernimmt Kunden-Defaults (Zahlungsbedingungen,
* Zahlart, Bankkonto, Incoterms, Lieferadresse, Default-Ansprechpartner). * Zahlart, Bankkonto, Incoterms, Lieferadresse, Default-Ansprechpartner).
*/ */
@ -89,58 +88,17 @@ if ($action === 'create' && $_SERVER['REQUEST_METHOD'] === 'POST') {
$cmd->add_contact((int) $oc->rowid, 'CUSTOMER', 'external'); $cmd->add_contact((int) $oc->rowid, 'CUSTOMER', 'external');
} }
/* ----- Optional: Std-Lohn-Zeile ergänzen und Auftrag direkt freigeben ----- */ /* ----- Optional: Auftrag direkt freigeben -----
* Ohne Positionen. Früher wurde hier eine Std-Lohn-Zeile mit Menge 1 angehängt, weil
* angenommen wurde, valid() scheitere am leeren Auftrag. Das stimmt nicht (KB #355/#989,
* gegen Dolibarr 22.0.2 verifiziert) und die Zeile hatte nur Nachteile: sie verfälscht
* total_ht, taucht als offene Restmenge in der Lieferauflistung auf, steht im Kunden-PDF
* und ist nach der Freigabe nicht mehr löschbar. Die Leistungen liefert der Stundenzettel.
*/
$validated = false; $validated = false;
$validate_warning = ''; $validate_warning = '';
$added_line = null;
if ($do_validate) { if ($do_validate) {
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
// 1) Leistungs-Produkt bestimmen: Kundenkarten-Default, sonst Fallback über Ref
// (Ref statt rowid, da rowids zwischen Test-/Prod-DB verschieden sind)
if (method_exists($soc, 'fetch_optionals')) $soc->fetch_optionals();
$svc_id = (int) ($soc->array_options['options_stundenzettel_default_service'] ?? 0);
if ($svc_id <= 0) {
$fallback_ref = getDolGlobalString('BERICHT_ORDER_DEFAULT_SERVICE_REF', 'ELEK-STD-M');
$rp = $db->query("SELECT rowid FROM ".$db->prefix()."product"
." WHERE ref = '".$db->escape($fallback_ref)."'"
." AND entity IN (".getEntity('product').") LIMIT 1");
if ($rp && ($op = $db->fetch_object($rp))) $svc_id = (int) $op->rowid;
}
if ($svc_id > 0) {
$prod = new Product($db);
if ($prod->fetch($svc_id) > 0) {
$pu_ht = (float) $prod->price;
$tva = (float) $prod->tva_tx;
// 2) Kundenspezifischer Preis (PRODUIT_CUSTOMER_PRICES) hat Vorrang
if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
$rcp = $db->query("SELECT price, tva_tx FROM ".$db->prefix()."product_customer_price"
." WHERE fk_product = ".((int) $svc_id)." AND fk_soc = ".((int) $socid)
." ORDER BY rowid DESC LIMIT 1");
if ($rcp && ($cp = $db->fetch_object($rcp))) {
$pu_ht = (float) $cp->price;
if ($cp->tva_tx !== null && $cp->tva_tx !== '') $tva = (float) $cp->tva_tx;
}
}
// Menge 1 als Start; Monteur trägt die echten Stunden später ein
$rl = $cmd->addline($prod->label, $pu_ht, 1, $tva, 0, 0, $svc_id, 0, 0, 0, 'HT', 0, '', '', (int) $prod->type);
if ($rl > 0) {
$added_line = array(
'product' => $prod->ref,
'label' => $prod->label,
'pu_ht' => $pu_ht,
'tva_tx' => $tva,
);
}
}
}
// Zeilen neu laden, dann freigeben
$cmd->fetch($newid); $cmd->fetch($newid);
$cmd->fetch_lines();
$vr = $cmd->valid($user); $vr = $cmd->valid($user);
if ($vr > 0) $validated = true; if ($vr > 0) $validated = true;
else $validate_warning = 'Freigabe fehlgeschlagen: '.$cmd->error; else $validate_warning = 'Freigabe fehlgeschlagen: '.$cmd->error;
@ -173,7 +131,6 @@ if ($action === 'create' && $_SERVER['REQUEST_METHOD'] === 'POST') {
'phone' => $cmd->thirdparty->phone ?? '', 'phone' => $cmd->thirdparty->phone ?? '',
'email' => $cmd->thirdparty->email ?? '', 'email' => $cmd->thirdparty->email ?? '',
), ),
'added_line' => $added_line,
'validate_warning' => $validate_warning, 'validate_warning' => $validate_warning,
)); ));
} }

View file

@ -27,7 +27,7 @@ class modBericht extends DolibarrModules
$this->editor_name = 'Alles Watt läuft'; $this->editor_name = 'Alles Watt läuft';
$this->editor_url = ''; $this->editor_url = '';
$this->version = '1.3.1'; $this->version = '1.4.0';
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
$this->picto = 'fa-file-pdf'; $this->picto = 'fa-file-pdf';