All checks were successful
Deploy bericht / deploy (push) Successful in 13s
Der Reiter stand auf jeder Kundenkarte; auf Prod gibt es 9 Berichte (ueber Auftraege/Rechnungen/Angebote) bei einem Teil der Kunden. Er erscheint jetzt nur bei Bestand, mit Anzahl — reiner Lesereiter, kein Anlegen-Weg geht verloren. completeTabsHead in der vorhandenen Hook-Klasse ergaenzt (dieselbe UNION-Abfrage wie bericht_thirdparty.php). Uebernimmt einen bereits vorhandenen Eintrag desselben Schluessels statt einen zweiten anzuhaengen — sonst waere der Reiter bis zur Reaktivierung doppelt (live beobachtet und nachgezogen). Lokal verifiziert: Kunde mit Berichten zeigt 'Berichte 1' einmalig. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
363 lines
23 KiB
Markdown
363 lines
23 KiB
Markdown
# Changelog
|
||
|
||
## 1.7.1 — 2026-09-07
|
||
|
||
### Reiter am Kunden nur noch bei vorhandenen Berichten
|
||
Der Reiter „Berichte" stand auf **jeder** Kundenkarte. Die Reiterleiste dort trägt über 20
|
||
Einträge; auf Prod gibt es 9 Berichte (über Aufträge, Rechnungen, Angebote) bei einem Teil der
|
||
Kunden. Er erscheint jetzt nur bei Bestand, mit der Anzahl daneben — reiner Lesereiter, kein
|
||
Anlegen-Weg geht dadurch verloren.
|
||
|
||
Technisch als Hook (`class/actions_bericht.class.php`, `completeTabsHead`, gleiche UNION-
|
||
Abfrage wie `bericht_thirdparty.php`) statt festem Tab. Muster wie bei Mahnung,
|
||
ElektroPlanung, NetDiag, ElektroCheck. **Nach dem Deploy Modul einmal reaktivieren.**
|
||
|
||
## 1.7.0 — 2026-08-28
|
||
|
||
### Fotoqualität ist einstellbar — Vorgabe ist jetzt 1:1
|
||
|
||
Die Baustelle-PWA hat **jedes** Foto fest auf 2000 px heruntergerechnet. Auf Typenschildern,
|
||
Zählerständen und Mängeln war danach beim Hineinzoomen nichts mehr zu erkennen. Das war
|
||
nirgends einstellbar, sondern eine Zahl im JavaScript.
|
||
|
||
- **Admin → Bericht → „📷 Fotoqualität der Baustellen-App"**: `BERICHT_PHOTO_MAXSIDE`
|
||
(0 = Originalgröße, sonst 4000/3000/2000/1600 px) und `BERICHT_PHOTO_QUALITY`
|
||
(JPEG-Qualität, greift nur beim Verkleinern).
|
||
- **Vorgabe ist 0 = Originalgröße.** Ohne Eingriff lädt die App ab jetzt das unveränderte
|
||
Kamerabild hoch. Die PHP-Limits auf Prod tragen das mühelos (`upload_max_filesize` 300M).
|
||
- Neuer Endpoint **`api/config.php`** liefert die Werte an die PWA (Auth wie überall per
|
||
`awl_sso`-Cookie). Die App merkt sich die Antwort lokal, damit auch offline klar ist,
|
||
was gilt.
|
||
|
||
### Nebenbefund: den bisherigen Fotos fehlt das EXIF komplett
|
||
|
||
Ein Foto aus dem Bestand nachgemessen: `Quality: 85`, **kein** `DateTimeOriginal`, kein
|
||
EXIF-Block. Das Herunterrechnen lief über ein Canvas, und dabei geht sämtliche
|
||
EXIF-Information verloren — Aufnahmezeitpunkt, Ausrichtung, GPS. `bericht_file_taken_at()`
|
||
musste deshalb bisher immer auf das Dateidatum ausweichen. Mit der neuen Vorgabe (1:1, kein
|
||
Canvas) bleibt das EXIF der Kamera erhalten.
|
||
|
||
## 1.6.0 — 2026-08-28
|
||
|
||
### Dasselbe Foto kommt kein zweites Mal in den Auftragsordner
|
||
|
||
Am 28.08. lagen an Auftrag `(PROV105)` **34 Fotos, davon 11 exakte Wiederholungen** — eine
|
||
Serie war bei ausgeschaltetem Display nur halb durchgelaufen, der zweite Anlauf lud alles
|
||
noch einmal hoch. Der Upload ist bewusst *at-least-once* (KB #840: lieber ein Duplikat als
|
||
ein verlorenes Foto), aber er war eben auch duplikaterzeugend.
|
||
|
||
- **`bericht_find_identical_file()`** (lib/bericht.lib.php) vergleicht die hochgeladene Datei
|
||
mit dem Inhalt des Zielordners: erst die Dateigroesse, md5 nur bei einem Kandidaten.
|
||
- Eingebaut in **beide** Upload-Wege: `api/orders.php?action=upload_photo` (Baustelle-PWA,
|
||
JWT) und `mobile_upload.php` (Token-Link).
|
||
- Bei einem Treffer wird nichts abgelegt, die Antwort traegt `duplicate: true` — **und
|
||
trotzdem den `relpath` der vorhandenen Datei**. Das ist Pflicht: die PWA wertet eine
|
||
Antwort ohne `relpath` als „nicht bestaetigt" und haette das Foto sonst endlos
|
||
weiterversucht (lib/api.js).
|
||
|
||
Damit ist die Wiederholung idempotent statt duplikaterzeugend; die at-least-once-Regel bleibt
|
||
als Rueckfallebene bestehen.
|
||
|
||
## 1.5.1 — 2026-08-22
|
||
|
||
Die API-Seite zur Baustelle-PWA holt nach, was der Editor mit 1.5.0 bekommen hat.
|
||
|
||
### Thumbnails für die PWA
|
||
|
||
- **`api/photo.php` kann jetzt `size=thumb&w=<px>`** und rendert damit über
|
||
`bericht_attachment_thumb()` — dieselbe Funktion, die auch die Anhänge-Kacheln im Editor
|
||
füllt (GD, Cache unter `bericht/thumbs/`, EXIF-Ausrichtung).
|
||
- Bisher kannte der Endpoint nur `size=small|mini`, und das lieferte ausschließlich ein
|
||
Thumbnail, das **Dolibarr selbst** unter `thumbs/<name>_small.<ext>` abgelegt hatte. Fotos aus
|
||
der PWA kommen über `orders.php?action=upload_photo` herein, und dort läuft **kein
|
||
`vignette()`** — es gab also nie eines, und die Fotoliste lud für jede Kachel die
|
||
Originaldatei. Gemessen an einer Testdatei: **9,8 KB statt 235 KB je Kachel**.
|
||
- Antwort mit `ETag` aus der mtime und `Cache-Control: max-age=30 Tage`; ein wiederholter
|
||
Aufruf endet mit `304`. Ein ersetztes Original bekommt automatisch einen neuen ETag.
|
||
- Nicht-Bilder (PDF, Video) fallen unverändert auf das Original zurück.
|
||
|
||
### Aufnahmezeit in der Anhängeliste
|
||
|
||
- **`api/orders.php?action=photos` liefert `taken_at`** — die EXIF-Aufnahmezeit über
|
||
`bericht_file_taken_at()`, sonst das Dateidatum. Sortiert wird danach statt nach `filemtime`.
|
||
Bei Uploads aus der Galerie war die Upload-Reihenfolge bisher die falsche Reihenfolge.
|
||
|
||
### Bericht-Seiten: Titel und fertiges Seitenbild
|
||
|
||
- **`api/reports.php` gibt je Seite `title` und `composite_path` mit aus.**
|
||
- `title` konnte über `api/pages.php` gesetzt werden und wurde in der PWA auch gerendert, kam
|
||
aber nie zurück — der Titel wirkte, als würde er nicht gespeichert.
|
||
- `composite_path` ist das im Editor gebaute Seitenbild. Ohne dieses Feld zeigt ein Client nur
|
||
`source_path`, also das Rohbild ohne Anmerkungen — und bei einem Raster-Layout eines von bis
|
||
zu sechs Bildern. Bei `title_only` ist `source_path` leer, die PWA zeigte dort eine
|
||
Fehler-Kachel.
|
||
|
||
### Neu: Textnotizen zum Auftrag (`api/note.php`)
|
||
|
||
- Getippte Notiz zum Auftrag, aufgebaut wie die Sprachnotiz: die Notiz liegt als
|
||
`notiz_<betreff>_<datum>.txt` im Auftrags-Verzeichnis und ist damit im Dolibarr-Auftrag und
|
||
in der Anhänge-Spalte des Editors sichtbar.
|
||
- `GET` (Liste mit Betreff, Vorschau und Zeitstempel), `GET &file=` (eine Notiz),
|
||
`POST` (anlegen), `POST &file=` (ändern), `POST &file=&delete=1` (löschen).
|
||
- Dateikopf bis zur ersten Leerzeile trägt `Betreff:`, `Erfasst:` und `Geändert:` (jeweils mit
|
||
Login), darunter der freie Text. Bewusst als Klartext lesbar, auch wenn jemand die `.txt`
|
||
direkt im ECM öffnet.
|
||
- Der `file`-Parameter wird gegen `^notiz_[A-Za-z0-9_.\-]*\.txt$` geprüft — ohne das ließe sich
|
||
über `../` jede Datei unter `DOL_DATA_ROOT` überschreiben. Gegen Pfad-Ausbrüche getestet.
|
||
|
||
## 1.5.0 — 2026-08-21
|
||
|
||
### Anhänge-Spalte: Miniaturen statt Dateinamen
|
||
|
||
- Die linke Spalte im Editor ist jetzt ein **Kachelraster mit Vorschaubildern**. Bei Fotos mit
|
||
Namen wie `IMG_20260812_141233_HDR.jpg` war in der 260 px schmalen Spalte vorher nicht zu
|
||
erkennen, welches Bild gemeint ist.
|
||
- Neuer Endpoint **`ajax/attachment_thumb.php`**: erzeugt Miniaturen serverseitig mit GD,
|
||
legt sie unter `bericht/thumbs/` ab und liefert sie mit ETag aus. Die Originale (Handyfotos
|
||
mit mehreren MB) werden für die Spalte nicht mehr geladen.
|
||
EXIF-Ausrichtung wird berücksichtigt — mit eigenem Mini-Parser, weil das `exif`-Modul im
|
||
Prod-Container nicht geladen ist.
|
||
- **PDF-Anhänge** bekommen Seite 1 als Miniatur (PDF.js, erst beim Scrollen gerendert).
|
||
- **Klick auf eine Kachel öffnet die Großansicht** (`✕`/Esc schließt): Bilder mit Zoom, Pan und
|
||
Wischen, PDFs im PDF-Viewer des Browsers.
|
||
- Auswahl per Kachel-Checkbox, die **Reihenfolge ist sichtbar (① ② ③)** und bestimmt jetzt auch
|
||
die Platzverteilung im Raster-Layout (vorher die Reihenfolge im Dokument).
|
||
- Bereits verwendete Anhänge sind mit ✓ markiert, „alle"-Umschalter je Herkunft, Auswahlzähler,
|
||
Umschalter zwischen Kachel- und Listenansicht (wird gemerkt).
|
||
|
||
### Arbeitstisch zeigt die echte Seite
|
||
|
||
- Der Editor stellt jetzt **Blatt mit Kopfbereich, Seitenrändern und Fußbereich** dar; die
|
||
Arbeitsfläche ist exakt der Bereich, der gedruckt wird.
|
||
- Neue gemeinsame Geometrie-Quelle `bericht_page_geometry()` — Editor und PDF-Erzeugung
|
||
rechnen mit denselben Werten (Rand 10 mm, Kopf 30 mm, Fuß 16 mm, Notizzone 25 %).
|
||
- **Das PDF setzt die Arbeitsfläche 1:1 ein.** Vorher wurde das komplette Blatt noch einmal in
|
||
den Satzspiegel eingepasst, der Inhalt also ein zweites Mal verkleinert — daher der breite
|
||
Rand und der Unterschied zur Vorschau.
|
||
- Alle Layout-Zweige (Einzelbild, Raster, Vorher/Nachher, Notiz) nutzen dieselbe Geometrie.
|
||
Seiten ohne gespeichertes Composite liefen vorher über den Kopfbereich mit Logo und Titel.
|
||
- Umschalter „📐 Rand" blendet die Zonen aus.
|
||
- Ältere Composites (Blatt-Proportion) werden erkannt und proportional eingepasst statt verzerrt.
|
||
|
||
### Bild einer Seite austauschen
|
||
|
||
- Neu: **`ajax/replace_page_source.php`**. Über „🔄" auf der Seitenminiatur lässt sich das Bild
|
||
einer bestehenden Seite ersetzen — Reihenfolge, Notiz und Anmerkungen bleiben erhalten.
|
||
Bisher musste man die Seite löschen und neu anhängen, wodurch sie ans Ende rutschte.
|
||
- Bei Raster-Seiten ist der einzelne Platz austauschbar. Das dafür nötige `set_slot_image.php`
|
||
existierte bereits, hatte aber keine Bedienung.
|
||
- Finalisierte Berichte werden serverseitig abgelehnt.
|
||
|
||
### Arbeiten ohne ständiges Neuladen
|
||
|
||
- Hinzufügen, Löschen, Hochladen, Bildtausch und der QR-Upload luden bisher die **ganze Seite neu**.
|
||
Der Editor sprang dabei auf Seite 1 zurück und der Zoom war weg — bei 20 Fotos hintereinander
|
||
entsprechend zäh. Jetzt werden nur noch die betroffenen Listen aktualisiert.
|
||
- Neuer Endpoint **`ajax/fragments.php`** liefert Seiten- und Anhängeliste als HTML. Gerendert wird
|
||
über `bericht_print_page_list()` / `bericht_print_attachment_list()` — dieselben Funktionen, die
|
||
auch die Karte aufbauen, damit beide Darstellungen nicht auseinanderlaufen.
|
||
- Nach dem Finalisieren wird weiterhin neu geladen: der Bericht wechselt den Status.
|
||
|
||
### Automatisches Speichern
|
||
|
||
- Änderungen werden **4 Sekunden nach der letzten Aktion automatisch gespeichert**, außerdem beim
|
||
Seitenwechsel und beim Wegschalten des Browser-Tabs. Bisher gab es nur „💾 Entwurf speichern".
|
||
- In der Fußleiste steht der Stand („● nicht gespeichert" / „✓ gespeichert"), beim Verlassen der
|
||
Seite mit offenen Änderungen warnt der Browser.
|
||
|
||
### Sortieren und Filtern der Anhänge
|
||
|
||
- Sortierung nach **Aufnahmezeit** (auf/ab), Name oder Größe — bei Baustellenfotos ist die zeitliche
|
||
Reihenfolge meist genau die richtige. Filter: alle · nur Bilder · nur PDFs · noch nicht verwendet.
|
||
- Die Aufnahmezeit steht unter der Kachel. Ausgelesen wird sie mit einem **eigenen EXIF-Parser**,
|
||
weil das `exif`-Modul im Prod-Container nicht geladen ist; gegen das PHP-Modul geprüft, identische
|
||
Werte. Ohne EXIF gilt das Dateidatum.
|
||
|
||
### Bedienung: Tastenkürzel, Spaltenbreite, Ziehen und Ablegen
|
||
|
||
- **Tastenkürzel**: `V` Auswahl, `P` Zeichnen, `R` Rechteck, `K` Kreis, `A` Pfeil, `T` Text,
|
||
`Entf` löscht die Auswahl, `Strg+Z`/`Strg+Y` Rückgängig/Wiederholen, `Strg+S` speichern,
|
||
`↑`/`↓` blättert durch die Seiten. In Eingabefeldern und bei offenem Dialog greifen sie nicht;
|
||
das Hintergrundbild lässt sich mit `Entf` nicht versehentlich entfernen.
|
||
- **Anhänge-Spalte in der Breite ziehbar** (150–620 px, Doppelklick auf die Trennlinie setzt zurück)
|
||
und über „«" einklappbar — die Arbeitsfläche wird dabei neu gezeichnet.
|
||
- **Kachelgröße** in drei Stufen über „⤢".
|
||
- **Ziehen und Ablegen**: Kachel auf die Seitenliste legt neue Seiten an, Kachel auf die
|
||
Arbeitsfläche ersetzt das Bild der offenen Seite, Kachel auf einen Raster-Platz setzt genau
|
||
diesen. Dateien vom Rechner auf die Anhänge-Spalte werden hochgeladen.
|
||
|
||
### Seiten: mehrere auf einmal, verdoppeln
|
||
|
||
- Klick auf die **Seitennummer** markiert eine Seite, Umschalt erweitert bis dorthin. Über die
|
||
Sammelleiste lassen sich markierte Seiten **verdoppeln** oder **löschen**.
|
||
- Neuer Endpoint **`ajax/page_bulk.php`**. Kopien werden direkt hinter ihrem Original einsortiert,
|
||
nach dem Löschen wird die Reihenfolge lückenlos neu nummeriert. Anmerkungen, Notiz und — bei
|
||
Rastern — die Bilder in den Plätzen werden mitkopiert; das gespeicherte Seitenbild bewusst nicht,
|
||
sonst zeigten Original und Kopie auf dieselbe Datei.
|
||
|
||
### Raster-Plätze direkt auf der Seite
|
||
|
||
- Bei Raster-Layouts liegt über der Arbeitsfläche ein **Gitter mit einer Schaltfläche je Platz**
|
||
(bei Vorher/Nachher entsprechend beschriftet). Ein Klick setzt das links ausgewählte Bild, ein
|
||
abgelegtes Bild setzt genau diesen Platz. Bisher ließen sich Raster nur beim Anlegen befüllen —
|
||
der Endpoint dafür existierte, hatte aber keine Bedienung.
|
||
- Die Plätze reagieren nur im Auswahlmodus; sobald ein Zeichenwerkzeug aktiv ist, haben die
|
||
Werkzeuge Vorrang.
|
||
|
||
### Behobene Fehler
|
||
|
||
- `dol_dir_list()` wurde ohne `$mode = 1` aufgerufen — `size` und `date` blieben leer, in der
|
||
Anhängeliste stand „ Bytes" ohne Zahl.
|
||
- Der PDF.js-Worker-Pfad war ohne `/custom`-Präfix hartkodiert. PDF.js fiel auf den
|
||
„fake worker" zurück und rendert seitdem wieder im Worker statt auf dem Hauptthread.
|
||
- PDF-Anhänge wurden über `document.php` **ohne** `attachment=0` verlinkt und dadurch
|
||
heruntergeladen statt angezeigt.
|
||
- Die Größen-Auswahl einer Seite blieb leer: der DB-Wert `1` traf die Option `1.0` nicht.
|
||
- Der Datei-Upload verarbeitete nur die erste Datei einer Mehrfachauswahl.
|
||
- Eingabefelder im Editor nutzen jetzt `--inputbackgroundcolor`/`--inputbordercolor`. Die
|
||
Modul-Doku hielt die Variablen für im AwlDark nicht vorhanden — sie sind gesetzt (KB #512).
|
||
- **Schneller Seitenwechsel konnte Inhalte vertauschen**: zwei Durchläufe von `loadPage()` liefen
|
||
ineinander — der zweite speicherte die noch nicht umgeschaltete Seite ein weiteres Mal, und beide
|
||
zeichneten in denselben Canvas. Dabei konnte die Notiz der einen Seite bei der anderen landen.
|
||
Seitenwechsel laufen jetzt nacheinander; ein überholter Durchlauf bricht ab.
|
||
- Der Dialog beim Löschen eines Anhangs sagt jetzt, dass die Datei **endgültig aus den Dokumenten
|
||
des Belegs** verschwindet, und warnt, wenn sie im Bericht in Gebrauch ist.
|
||
|
||
## 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
|
||
|
||
### Fixes rund um die PWA-Auftragsanlage
|
||
|
||
- **`api/customers.php`**: Zahlart und Zahlungsbedingung im Kunden-Detail werden jetzt **übersetzt** — über die Dolibarr-Sprachkeys `PaymentTypeShort<code>` / `PaymentConditionShort<code>` (Sprachdatei `bills`) statt der rohen englischen `libelle`-Werte aus `c_paiement`/`c_payment_term`. Behebt die Anzeige „💳 Payment Condition · 🏦 Credit transfer" in der „Übernommen"-Zeile. Fallback auf `libelle`, wenn kein Sprachkey existiert (z. B. Custom-Einträge ohne `code`).
|
||
- **Baustelle-PWA** (Repo `baustelle-pwa`): „Neuer Auftrag"-Formular saß vertikal zu weit unten (der gemeinsame `.fs-body` erbte `justify-content:center`, was bei `flex-direction:column` vertikal zentriert) und wurde von der Bildschirmtastatur verdeckt → `justify-content:flex-start` im Modal + `scrollIntoView({block:'center'})` beim Feld-Fokus.
|
||
|
||
## 1.3.0 — 2026-07-18
|
||
|
||
### PWA Auftrag-Anlegen überarbeitet (Formular + Freigabe)
|
||
|
||
**Formular (Baustelle-PWA, `openNewOrderModal`)**
|
||
- Feld-Reihenfolge/Beschriftung angepasst: **„Ihr Zeichen"** (= `ref_client`) steht jetzt an **erster** Stelle und ist **Pflicht**; **„Auftragsbeschreibung"** (= Extrafield `options_auftragsbeschreibung`) an zweiter Stelle und optional. (Vorher genau umgekehrt: Titel Pflicht, Kunden-Referenz optional.)
|
||
- Neues Feld **„Geplanter Liefertermin"** (`datetime-local`, Datum + Uhrzeit in einem Feld) → Auftrag-Spalte `date_livraison`.
|
||
- Neue Checkbox **„Auftrag direkt freigeben"**.
|
||
|
||
**Backend (`api/orders.php?action=create`)**
|
||
- `ref_client` ist jetzt serverseitig **Pflicht** (Geschäftsregel — Dolibarr-Core verlangt nur den Kunden).
|
||
- Neuer Parameter `date_livraison` (Unix-TS) → `Commande->delivery_date`.
|
||
- Neuer Parameter `validate`: legt vor der Freigabe automatisch eine **Std-Lohn-Zeile** an und ruft dann `Commande::valid()`.
|
||
- Produkt: Kundenkarten-Default `options_stundenzettel_default_service`, sonst Fallback-Produkt über Ref `BERICHT_ORDER_DEFAULT_SERVICE_REF` (Default `ELEK-STD-M`, „Stundenlohn Meister" 45 €).
|
||
- Preis: kundenspezifischer Preis (`PRODUIT_CUSTOMER_PRICES`) hat Vorrang, sonst Produkt-Standardpreis. Menge 1.
|
||
- Response erweitert um `ref_client`, `date_livraison`, `validated`, `added_line`, `validate_warning`.
|
||
|
||
## 1.2.0 — 2026-05-27
|
||
|
||
### Phase 1.8 Lieferschein-Bestätigung in der PWA
|
||
|
||
**Neuer element_type='shipment'**
|
||
- Bericht-Modul unterstützt jetzt `element_type='shipment'` mit `fk_element = llx_expedition.rowid`
|
||
- Tab "Bericht" erscheint auf der Lieferung-Card (Konstante `BERICHT_TAB_ON_SHIPMENT`)
|
||
- `bericht_fetch_parent()` und `bericht_fetch_shipment_with_order()` laden Expedition + verknüpften Auftrag
|
||
|
||
**Signatur auf Lieferschein-PDF stempeln**
|
||
- Neue Tabelle `llx_bericht_signature_box`: Pro PDF-Template (merou/rouget/espadon/...) konfigurierbare Box-Geometrie (x/y/w/h in mm, Seite first/last, Label)
|
||
- Konstante `BERICHT_SIGNATURE_BOX_DEFAULT` als JSON-Default (`{"page":"last","x_mm":120,"y_mm":230,"w_mm":70,"h_mm":35,"label":"Unterschrift Kunde"}`)
|
||
- `bericht_stamp_signature_on_pdf()`: FPDI importiert Original-Lieferschein, TCPDF stempelt PNG + Name + Datum + GPS in die konfigurierte Box
|
||
|
||
**Visueller Admin-Editor (`admin/signature_box_editor.php`)**
|
||
- PDF.js rendert ein Beispiel-Lieferschein-PDF
|
||
- Fabric.js-Rechteck zum Drag&Resize der Signatur-Box auf dem Canvas
|
||
- Eingabefelder für X/Y/W/H/Label/Seite werden live synchronisiert
|
||
- "Speichern" persistiert via AJAX (`ajax/save_signature_box.php`) in `llx_bericht_signature_box` (UPSERT auf `template_name`)
|
||
- Reset-Button setzt zurück auf Default-Konstante
|
||
|
||
**Neue PWA-Route (Baustelle-App)**
|
||
- Order-Detail bekommt Button "🚚 Lieferungen"
|
||
- `#/orders/:id/shipments` zeigt Liste aller verknüpften Expeditionen mit Status- und Signed-Badge
|
||
- `#/shipments/:id` zeigt Lieferschein-PDF inline (PDF.js Canvas) + großen Button "Lieferung unterschreiben lassen"
|
||
|
||
**Vollbild-Querformat-Signatur (`openShipmentSignatureModal`)**
|
||
- `requestFullscreen()` + `screen.orientation.lock('landscape')` (Best-Effort)
|
||
- 2-Spalten-Layout: links Lieferschein-Info + Namens-Input + GPS-Toggle, rechts Vollbild-Canvas
|
||
- HiDPI-aware Canvas (`devicePixelRatio`), Pointer/Touch-Events mit quadratischer Glättung
|
||
- Beim Bestätigen: PNG → `POST /api/shipments.php?action=confirm` → Backend stempelt in PDF und legt es in `documents/expedition/<ref>/<ref>-signed.pdf`
|
||
|
||
**Auto-Workflow auf der Expedition**
|
||
- `signed_status=1` (via `CommonSignedObject::setSignedStatus`)
|
||
- Wenn Expedition noch Draft (Status 0): erst `valid()`, dann `setClosed()`
|
||
- Bericht-Record (`element_type='shipment'`) wird angelegt/aktualisiert mit `final_pdf_path` zum signierten PDF
|
||
- `<sig>.meta.json` neben der PNG mit voller Audit-Spur (signer, user, GPS, IP, Box, Template, signed_at)
|
||
|
||
**Neue API-Endpoints**
|
||
- `GET /api/shipments.php?order_id=<id>` — Liste der Lieferungen zu einem Auftrag
|
||
- `GET /api/shipments.php?id=<id>` — Detail einer Lieferung + Bericht-ID falls vorhanden
|
||
- `GET /api/shipments.php?id=<id>&action=pdf` — PDF-Stream (Original oder gestempelt)
|
||
- `POST /api/shipments.php?id=<id>&action=confirm` — Unterschrift einstempeln + Status-Workflow
|
||
|
||
## 1.1.0 — 2026-04-08
|
||
|
||
### Phase 1 Bericht-Modul Erweiterungen
|
||
|
||
**1.6 Verknüpfte Sicht Auftrag↔Rechnung**
|
||
- Bericht-Übersicht zeigt drei Sektionen: direkt zugeordnet, zusätzlich verknüpft, aus verknüpften Aufträgen
|
||
- "→ Übernehmen"-Button erstellt llx_element_element-Eintrag (n:m-Verknüpfung)
|
||
- "Lösen"-Button entfernt Verknüpfung
|
||
- Beim Finalisieren landet das PDF auch unter den verknüpften Elementen im ECM
|
||
|
||
**1.1 Live-PDF-Vorschau**
|
||
- 👁️ Vorschau-Button im Editor → Modal mit eingebettetem PDF
|
||
- Neuer Endpoint `ajax/preview_pdf.php` (kein ECM-Insert, kein Status-Wechsel)
|
||
- ESC oder Klick auf Backdrop schließt das Modal
|
||
|
||
**1.2 Anhänge löschen**
|
||
- 🗑️ Icon neben jedem Anhang in der linken Spalte
|
||
- Confirm-Dialog mit Auftrags-/Rechnungs-Referenz
|
||
- Path-Whitelist (nur facture/, commande/, propal/), Thumbs + ECM-Eintrag werden mitgelöscht
|
||
|
||
**1.3 Seitengröße A4/A3/A5/Letter + Hoch/Quer**
|
||
- Format und Orientation in der Bericht-Meta wählbar
|
||
- Auto-Save bei Änderung
|
||
- Bilder werden dynamisch auf die Seitengröße skaliert
|
||
|
||
**1.4 + 1.5 Mehrere Bilder pro Seite (DB-Schema)**
|
||
- Neue Tabelle `llx_bericht_page_image` für Multi-Image-Seiten
|
||
- Spalten `layout`, `image_scale`, `image_align` in `llx_bericht_page`
|
||
- Grid-Rendering im Editor + PDF folgt im nächsten Commit
|
||
|
||
**1.7 Tab „Berichte" auf Kundenkarte**
|
||
- Read-only Übersicht aller Berichte des Kunden
|
||
- Flache Tabelle sortiert nach Datum
|
||
- Springt zum Bericht oder zur Quelle (Auftrag/Rechnung/Angebot)
|
||
- Konstante `BERICHT_TAB_ON_THIRDPARTY` zum Aktivieren
|
||
|
||
### Sonstiges
|
||
- DB-Migrationen im `init()` für bestehende Installationen (ALTER TABLE mit Error-Suppress)
|
||
- `bericht_burn_annotations` und `bericht_render_cover_internal` in `lib/bericht.lib.php` zentralisiert (gemeinsam von generate_pdf + preview_pdf genutzt)
|
||
- Modal-CSS für Vorschau im Dolibarr Dark-Theme
|
||
|
||
## 1.0.0 — 2026-04-08
|
||
|
||
Initiales Release.
|
||
|
||
- Modul-Scaffold mit Reiter „Bericht" auf Rechnungen, Aufträgen und Angeboten
|
||
- CRUD für `Bericht` und `BerichtPage` (Tabellen `llx_bericht`, `llx_bericht_page`)
|
||
- Browser-Editor mit PDF.js + Fabric.js: Pfeile, Kreise, Rechtecke, Freihand, Text, Undo/Redo
|
||
- Anhänge-Browser zeigt eigene Anhänge + Anhänge verknüpfter Objekte
|
||
- Datei-Upload direkt in den Bericht
|
||
- Seiten-Verwaltung mit Drag&Drop (SortableJS), Löschen, Drehen
|
||
- Notizen pro Seite (werden im PDF gedruckt)
|
||
- Admin-Setup mit ODT-Template-Verwaltung (Upload, Löschen, Standard wählen)
|
||
- Platzhalter-System für ODT-Templates (`{auftragsnummer}`, `{kunde_name}`, …)
|
||
- PDF-Finalisierung mit TCPDF + FPDI, ODT→PDF Konvertierung des Deckblatts via LibreOffice
|
||
- Annotationen werden beim Export ins PDF eingebrannt
|
||
- Auftragsnummer wird automatisch aus dem vorhandenen Extrafield `options_auftragsnummer` geholt
|
||
- Beim Aktivieren werden fehlende Extrafields auf `llx_facture_extrafields` angelegt, vorhandene NICHT überschrieben
|
||
- Mehrere Berichte pro Dokument möglich
|
||
- Forgejo-Workflow für Deploy nach Dolibarr (Tag `[deploy]`)
|