README: Anhaenge-Spalte, Arbeitstisch, Autosave, Tastenkuerzel, Bildtausch, Sammelaktionen und Drag & Drop beschrieben; Architektur-Baum vervollstaendigt (15 fehlende ajax-Endpoints, imageviewer, Root-Seiten, SQL-Dateien); GD als Voraussetzung ergaenzt; llx_bericht_upload_token ist nicht mehr "geplant". CLAUDE.md: Abschnitt zur Seitengeometrie als zentralem Begriff, LocalStorage-Keys, Phase 1 abgeschlossen. Korrigiert die falsche Notiz, --inputbackgroundcolor gebe es im awl-dark nicht — die Variable existiert (KB #512), deshalb waren die Eingabefelder im Editor anders gestylt als Dolibarrs eigene. Fix: dol_dir_list() zusaetzlich mit $nohook = 1 (KB #1060) — sonst laeuft der getDirList-Hook fremder Module mit, der global $object auswertet; bericht_collect_attachments() laeuft seit 1.5.0 auch im AJAX-Kontext (ajax/fragments.php), wo es das nicht gibt. ROADMAP.md entfernt: alle Punkte abgearbeitet, Inhalt steht im ChangeLog. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
251 lines
16 KiB
Markdown
251 lines
16 KiB
Markdown
# Bericht — Arbeitsberichte für Dolibarr
|
|
|
|
Erstellt aus den Anhängen einer Rechnung (oder eines Auftrags / Angebots) einen Arbeitsbericht als PDF.
|
|
Bilder und PDFs lassen sich im Browser annotieren (Pfeile, Kreise, Rechtecke, Text, Freihand) — der fertige Bericht wird unter *Verknüpfte Dokumente* der Rechnung abgelegt.
|
|
|
|
## Funktionen
|
|
|
|
- **Reiter „Bericht"** auf Rechnungen, Aufträgen, Angeboten und Lieferungen (jeweils per Konstante deaktivierbar)
|
|
- **Anhänge-Spalte als Kachelraster** mit Vorschaubildern — zeigt alle Dateien des aktuellen Dokuments **und** der direkt verknüpften Objekte (z. B. der Auftrag zur Rechnung). Bild-Miniaturen entstehen serverseitig (GD, gecacht), PDF-Anhänge zeigen Seite 1 (PDF.js). Klick öffnet die Großansicht — Bilder mit Zoom und Wischen, PDFs im PDF-Viewer des Browsers.
|
|
- **Sortieren und Filtern** der Anhänge nach Aufnahmezeit (EXIF), Name oder Größe · nur Bilder / nur PDFs / noch nicht verwendete. Spaltenbreite ziehbar, Spalte einklappbar, Kachelgröße in drei Stufen.
|
|
- **Auswahl per Kachel** — die Reihenfolge der Auswahl (① ② ③) bestimmt auch die Verteilung auf die Plätze im Raster-Layout. Bereits verwendete Dateien sind markiert.
|
|
- **Browser-Editor** mit PDF.js + Fabric.js: Pfeile, Kreise, Rechtecke, Freihand, Text, Farbe, Strichstärke, Undo/Redo — mit Tastenkürzeln (V/P/R/K/A/T, Entf, Strg+Z/Y/S, ↑/↓)
|
|
- **Arbeitstisch zeigt die echte Seite**: Kopfbereich (Logo/Titel), Seitenränder und Fußbereich sind sichtbar; die Arbeitsfläche entspricht genau dem Bereich, der gedruckt wird — das PDF übernimmt sie 1:1
|
|
- **Automatisches Speichern** kurz nach der letzten Änderung, beim Seitenwechsel und beim Wegschalten des Tabs; beim Verlassen mit offenen Änderungen warnt der Browser
|
|
- **Seiten-Verwaltung** per Drag&Drop (SortableJS): umordnen, löschen, drehen, neue Seiten hochladen. Mehrere Seiten markieren (Klick auf die Seitennummer, Umschalt für einen Bereich) und gesammelt löschen oder verdoppeln.
|
|
- **Bild einer Seite austauschen** ohne sie zu löschen — Reihenfolge, Notiz und Anmerkungen bleiben erhalten. Bei Raster-Layouts lässt sich jeder Platz einzeln tauschen, direkt auf der Seite anklickbar.
|
|
- **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.
|
|
- **Mobiler Upload per QR-Code** — Handy scannt, lädt Fotos direkt in den offenen Bericht (zeitlich begrenzte Token)
|
|
- **Notizen pro Seite** — werden im finalen PDF unten auf der Seite gedruckt
|
|
- **Deckblatt aus ODT-Vorlage** mit Platzhaltern (`{auftragsnummer}`, `{kunde_name}`, `{datum}`, …)
|
|
- **ODT-Templates** im Admin-Bereich verwaltbar (mehrere Vorlagen, Standard wählbar)
|
|
- **Auftragsnummer** wird automatisch aus dem Extrafield `options_auftragsnummer` der Rechnung gezogen
|
|
- **Mehrere Berichte pro Dokument** möglich
|
|
- Berichte als **Entwurf** speichern (jederzeit wieder editierbar) oder **finalisieren** (PDF erzeugen)
|
|
- **Lieferschein-Bestätigung mit Kunden-Unterschrift**: Vollbild-Querformat-Signatur in der PWA, Unterschrift wird via ODT-Hook (Platzhalter `{signature}`) ins Lieferschein-PDF gestempelt, Expedition wird automatisch validiert und geschlossen
|
|
- **PWA-API** für Mobile-Nutzung: Aufträge, Fotos, Sprachnotizen, Materiallisten, Lieferungen, Signaturen
|
|
- **PDF-Viewer in PWA** mit PDF.js Canvas-Rendering (Zoom, Seitennummerierung, Download)
|
|
|
|
## Voraussetzungen
|
|
|
|
- Dolibarr ≥ 19.0
|
|
- PHP ≥ 7.4
|
|
- TCPDF (in Dolibarr enthalten)
|
|
- **FPDI** (für PDF-Anhänge in den Bericht zu mergen) — empfohlen, optional
|
|
- **LibreOffice headless** (für ODT→PDF Konvertierung der Deckblätter)
|
|
- **GD** (PHP-Extension) für die Vorschaubilder der Anhänge und die Raster-Vorschau
|
|
- Optional: `pdfinfo` oder `imagick` für PDF-Seitenanzahl-Erkennung
|
|
|
|
> Imagick und die PHP-Extension `exif` sind im Produktions-Container **nicht** installiert.
|
|
> PDF-Vorschauen laufen deshalb über PDF.js im Browser, EXIF-Daten liest das Modul mit einem
|
|
> eigenen Parser (`bericht_jpeg_taken_at()` / `bericht_jpeg_orientation()`).
|
|
|
|
## Installation
|
|
|
|
1. Modul-Verzeichnis nach `dolibarr/htdocs/custom/bericht/` (oder per Symlink aus dem Module-Mount-Pfad) kopieren
|
|
2. In Dolibarr unter **Konfiguration → Module/Anwendungen** das Modul **Bericht** aktivieren
|
|
3. Beim Aktivieren werden die SQL-Tabellen `llx_bericht` und `llx_bericht_page` angelegt
|
|
4. Vorhandene Extrafields auf `llx_facture_extrafields` (`auftragsnummer`, `angebotsnummer`, …) werden erkannt und nicht überschrieben — fehlende werden angelegt
|
|
5. Im Admin-Bereich (`/bericht/admin/setup.php`) die ODT-Templates hochladen und Standard-Template setzen
|
|
|
|
## Verwendung
|
|
|
|
1. Eine Rechnung öffnen (`/compta/facture/card.php?id=…`)
|
|
2. Reiter **Bericht** auswählen
|
|
3. **+ Neuer Bericht** klicken — die Auftragsnummer wird automatisch übernommen
|
|
4. Im Editor links die gewünschten Anhänge auswählen (Kachel-Checkbox; die Reihenfolge der Auswahl zählt) → **Auswahl in Bericht übernehmen**. Alternativ eine Kachel direkt in die Seitenliste ziehen.
|
|
5. Im mittleren Editor mit den Werkzeugen Pfeile, Texte etc. zeichnen — der graue Bereich oben und unten zeigt, wo Logo, Titel und Seitenzahl gedruckt werden. Änderungen werden automatisch gespeichert.
|
|
6. Seiten rechts per Drag&Drop sortieren, einzelne Seiten löschen oder über die Seitennummer mehrere markieren und gesammelt löschen/verdoppeln. Ein falsches Bild lässt sich über **🔄** auf der Seitenminiatur austauschen.
|
|
7. **Bericht finalisieren** — PDF wird erzeugt, Deckblatt aus der ODT-Vorlage gerendert und unter den verknüpften Dokumenten der Rechnung abgelegt
|
|
|
|
## ODT-Template Platzhalter
|
|
|
|
| Platzhalter | Inhalt |
|
|
|---|---|
|
|
| `{auftragsnummer}` | Aus extrafield `options_auftragsnummer` der Rechnung |
|
|
| `{angebotsnummer}` | Aus extrafield `options_angebotsnummer` |
|
|
| `{rechnungsnummer}` | `ref` der Rechnung |
|
|
| `{kunde_name}` | Name des Kunden (Société) |
|
|
| `{kunde_adresse}` | Adresse des Kunden, mehrzeilig |
|
|
| `{datum}` | Heutiges Datum |
|
|
| `{beschreibung}` | extrafield `options_beschreibung` |
|
|
| `{hinweis}` | extrafield `options_hinweis` |
|
|
| `{bericht_titel}` | Titel des Berichts |
|
|
| `{ersteller}` | Login-Name des erstellenden Users |
|
|
| `{signature}` | Kunden-Unterschrift als Bild (nur Lieferschein-Workflow, ersetzt Text-Platzhalter durch eingebettetes PNG; Größe via `BERICHT_SIGNATURE_IMAGE_RATIO`) |
|
|
| `{signer_name}` | Name des unterschreibenden Kunden |
|
|
| `{signed_at}` | Zeitstempel der Unterschrift |
|
|
| `{gps}` | GPS-Koordinaten zum Zeitpunkt der Unterschrift (falls erlaubt) |
|
|
|
|
## PWA-Integration (Baustelle Mobile App)
|
|
|
|
Die **Baustelle-PWA** (`https://awl.data-it-solution.de/baustelle/`) nutzt die folgenden API-Endpoints des Bericht-Moduls:
|
|
|
|
### Authentifizierung
|
|
```
|
|
POST /custom/bericht/api/auth.php
|
|
Body: { login: string, password: string }
|
|
Response: { ok: true, token: JWT, user: {...} }
|
|
```
|
|
|
|
JWT-Token hat 7 Tage Gültigkeit und enthält: `sub` (user id), `login`, `name`, `perms` (read/write/delete/admin).
|
|
|
|
### Order-APIs
|
|
```
|
|
GET /custom/bericht/api/orders.php
|
|
GET /custom/bericht/api/orders.php?id=<id>
|
|
GET /custom/bericht/api/orders.php?id=<id>&action=photos
|
|
POST /custom/bericht/api/orders.php?action=create
|
|
Body: { socid, ref_client, title?, note_private?, date?, date_livraison?, validate? }
|
|
ref_client ("Ihr Zeichen") ist PFLICHT. validate=true gibt den Auftrag direkt frei —
|
|
OHNE Position (Commande::valid() verlangt keine, verifiziert gegen Dolibarr 22.0.2).
|
|
Die Leistungen kommen später aus dem Stundenzettel.
|
|
```
|
|
|
|
### Dateien
|
|
```
|
|
GET /custom/bericht/api/photo.php?relpath=<path>&jwt=<token>
|
|
Liefert Dateien aus DOL_DATA_ROOT (Whitelist: facture/, commande/, propal/, bericht/)
|
|
Optional: ?size=small|mini (Thumbnails), ?download=1 (Attachment-Header)
|
|
```
|
|
|
|
### PDF-Ansicht
|
|
```
|
|
GET /custom/bericht/api/pdf.php?id=<bericht_id>&jwt=<token>
|
|
Liefert finalisiertes Bericht-PDF als Blob
|
|
```
|
|
|
|
### Seiten-Verwaltung (PWA)
|
|
```
|
|
DELETE /custom/bericht/api/pages.php?id=<page_id>
|
|
POST /custom/bericht/api/pages.php?id=<page_id> Body: { note: string }
|
|
POST /custom/bericht/api/pages.php?action=signature&bericht_id=<id>
|
|
Body: FormData mit file=<PNG-Blob>, signer_name, gps_lat, gps_lon
|
|
```
|
|
|
|
### Lieferungen + Unterschrift (PWA)
|
|
```
|
|
GET /custom/bericht/api/shipments.php?order_id=<id>
|
|
Liste aller Expeditionen zum Auftrag (id, ref, date_delivery, status, signed_status, has_bericht)
|
|
|
|
GET /custom/bericht/api/shipments.php?id=<id>
|
|
Detail einer Lieferung inkl. bericht_id
|
|
|
|
GET /custom/bericht/api/shipments.php?id=<id>&action=pdf[&variant=auto|signed|unsigned]
|
|
Liefert Lieferschein-PDF (Default auto: signed wenn vorhanden, sonst Original)
|
|
|
|
POST /custom/bericht/api/shipments.php?id=<id>&action=confirm
|
|
FormData mit signature_png, signer_name, gps_lat, gps_lon, signed_at
|
|
Stempelt Unterschrift via ODT-Hook ({signature}-Platzhalter), legt <ref>-signed.pdf
|
|
in documents/expedition/<ref>/, setzt signed_status=1, validiert+schließt Expedition
|
|
wenn noch Draft. Response: { ok: true, pdf_url, bericht_id }
|
|
```
|
|
|
|
## Konfigurations-Konstanten
|
|
|
|
Per `admin/setup.php` oder `llx_const`:
|
|
|
|
| Konstante | Default | Zweck |
|
|
|---|---|---|
|
|
| `BERICHT_TAB_ON_INVOICE` | 1 | Reiter "Bericht" auf Rechnungen anzeigen |
|
|
| `BERICHT_TAB_ON_ORDER` | 1 | Reiter "Bericht" auf Aufträgen anzeigen |
|
|
| `BERICHT_TAB_ON_PROPAL` | 1 | Reiter "Bericht" auf Angeboten anzeigen |
|
|
| `BERICHT_TAB_ON_SHIPMENT` | 1 | Reiter "Bericht" auf Lieferungen anzeigen |
|
|
| `BERICHT_TAB_ON_THIRDPARTY` | 0 | Read-only Bericht-Tab auf Kundenkarte |
|
|
| `BERICHT_SIGNATURE_IMAGE_RATIO` | 0.35 | Größen-Faktor für `{signature}`-Platzhalter im ODT (höher = größer) |
|
|
| `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_LIBREOFFICE_BIN` | `soffice` | Pfad zur LibreOffice-Binary (für ODT→PDF) |
|
|
|
|
## Datenbank
|
|
|
|
| Tabelle | Zweck |
|
|
|---|---|
|
|
| `llx_bericht` | Bericht-Header (element_type ∈ {invoice, order, propal, shipment}, fk_element, status, …) |
|
|
| `llx_bericht_page` | Einzelne Seiten mit Fabric-JSON-Annotationen, Layout, Notiz |
|
|
| `llx_bericht_page_image` | Bilder der einzelnen Plätze bei Raster-Layouts (grid_2 … grid_6, before_after) |
|
|
| `llx_bericht_upload_token` | Zeitlich begrenzte Tokens für den QR-Mobile-Upload |
|
|
| `llx_bericht_signature_box` | Pro Lieferschein-Template gespeicherte Signatur-Box-Geometrie (mm) |
|
|
|
|
## Architektur
|
|
|
|
```
|
|
bericht/
|
|
├── core/modules/modBericht.class.php Modul-Descriptor, Tabs, Extrafields-Init, Konstanten
|
|
├── class/
|
|
│ ├── bericht.class.php Bericht + BerichtPage CRUD, Slot-Geometrie
|
|
│ ├── upload_token.class.php Tokens für den QR-Mobile-Upload
|
|
│ └── actions_bericht.class.php Hook: beforeODTSave setzt {signature} + Meta-Variablen
|
|
├── lib/bericht.lib.php Helper: Anhänge sammeln, Vorschaubilder, EXIF-Parser,
|
|
│ Seitengeometrie (bericht_page_geometry), PDF-Rendering,
|
|
│ Render-Funktionen für Seiten-/Anhängeliste,
|
|
│ Signature-Box, FPDI-Stempel-Fallback
|
|
├── bericht_card.php Editor-Seite (Tab-Inhalt)
|
|
├── admin/
|
|
│ ├── setup.php Admin: ODT-Templates, Konstanten, Signatur-Größe
|
|
│ ├── signature_box_editor.php Visueller PDF-Editor für Signatur-Box-Position
|
|
│ └── signature_box_preview.php Beispiel-PDF-Renderer für den Editor
|
|
├── bericht_batch.php Sammel-Erstellung von Berichten
|
|
├── bericht_thirdparty.php Read-only Übersicht auf der Kundenkarte
|
|
├── mobile_upload.php Upload-Seite für den QR-Code (Handy)
|
|
├── ajax/ Endpoints für den Editor (Token-geschützt)
|
|
│ ├── _inc.php Gemeinsamer Header (Rechte, JSON, Fatal-Handler)
|
|
│ ├── add_attachment.php Anhang als Seite hinzufügen
|
|
│ ├── attachment_thumb.php Vorschaubild eines Anhangs (GD, gecacht, ETag)
|
|
│ ├── create_grid_page.php Raster-Seite aus mehreren Bildern anlegen
|
|
│ ├── create_upload_token.php Token für den QR-Mobile-Upload
|
|
│ ├── delete_attachment.php Datei aus den Dokumenten des Belegs löschen
|
|
│ ├── delete_page.php Einzelne Seite löschen
|
|
│ ├── fragments.php Seiten-/Anhängeliste als HTML (Arbeiten ohne Reload)
|
|
│ ├── generate_pdf.php Finalisierung: TCPDF + FPDI + ODT-Deckblatt
|
|
│ ├── get_photo.php / list_photos.php Fotos für die PWA
|
|
│ ├── list_pages.php Seitenliste als JSON (Polling)
|
|
│ ├── page_bulk.php Mehrere Seiten löschen oder verdoppeln
|
|
│ ├── page_image.php Seitenbild/PDF ausliefern (Raster: Composite via GD)
|
|
│ ├── page_meta.php Annotationen + Notiz laden
|
|
│ ├── preview_pdf.php PDF-Vorschau ohne zu finalisieren
|
|
│ ├── process_document.php Import hochgeladener Dokumente
|
|
│ ├── reorder_pages.php Reihenfolge speichern
|
|
│ ├── replace_page_source.php Bild einer Seite / eines Rasterplatzes austauschen
|
|
│ ├── save_annotations.php Fabric-JSON + Composite-PNG speichern
|
|
│ ├── save_as_template.php Bericht als Vorlage sichern
|
|
│ ├── save_meta.php Titel, Format, Ausrichtung
|
|
│ ├── save_page_options.php Layout, Bildgröße, Position je Seite
|
|
│ ├── save_signature_box.php UPSERT der Signatur-Box pro Template
|
|
│ ├── set_slot_image.php Bild eines Rasterplatzes setzen
|
|
│ ├── upload_extra.php Direkter Upload
|
|
│ └── verify_signature.php Unterschrift prüfen
|
|
├── api/ REST-API (JWT-Auth)
|
|
│ ├── _inc.php JWT-Authentifizierung + Dolibarr-Init
|
|
│ ├── _jwt.php JWT encoding/decoding (mit ?jwt= Query-Fallback)
|
|
│ ├── auth.php Login-Endpoint
|
|
│ ├── orders.php Order-Liste, Detail, Fotos, Create
|
|
│ ├── shipments.php Lieferungen-Liste, PDF-Stream, Unterschrift-Confirm
|
|
│ ├── photo.php Datei-Serving mit Whitelist
|
|
│ ├── pdf.php Finalized Bericht-PDF
|
|
│ ├── pages.php Seiten-Verwaltung (Note, Rotation, Signature)
|
|
│ ├── reports.php Bericht-CRUD
|
|
│ ├── templates.php ODT-Templates
|
|
│ ├── materials.php Materiallisten
|
|
│ ├── voice.php Sprachnotizen (Upload + Transkription)
|
|
│ └── transcribe.php Whisper-Transkription
|
|
├── js/
|
|
│ ├── editor.js PDF.js + Fabric.js Integration, Anhänge-Spalte,
|
|
│ │ Seitengeometrie, Drag&Drop, Autosave, Tastenkürzel
|
|
│ ├── imageviewer.js Großansicht (Zoom, Wischen, PDF-Modus)
|
|
│ └── lib/ PDF.js, Fabric.js, SortableJS, QRCode (lokal)
|
|
├── css/
|
|
│ ├── bericht.css Editor-Layout, Kacheln, Blatt-Darstellung
|
|
│ └── imageviewer.css Großansicht
|
|
├── sql/
|
|
│ ├── llx_bericht.sql / .key.sql
|
|
│ ├── llx_bericht_page.sql / .key.sql
|
|
│ ├── llx_bericht_page_image.sql / .key.sql
|
|
│ ├── llx_bericht_upload_token.sql / .key.sql
|
|
│ └── llx_bericht_signature_box.sql / .key.sql
|
|
└── langs/{de_DE,en_US}/bericht.lang
|
|
```
|
|
|
|
## Lizenz
|
|
|
|
GPL v3+
|