bericht/CLAUDE.md
Eduard Wisch a7bf3929a4
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
feat: Phase 1.6 + 1.1 + 1.2 — verknüpfte Sicht, PDF-Vorschau, Anhänge löschen
Phase 1.6 Verknüpfte Sicht Auftrag↔Rechnung:
- Bericht::fetchLinkedForElement liest llx_element_element-Verknüpfungen
- linkToElement/unlinkFromElement n:m-API
- Bericht-Übersicht zeigt drei Sektionen: direkt zugeordnet,
  zusätzlich verknüpft, aus verknüpften Aufträgen (read-only)
- 'Übernehmen'-Button erstellt llx_element_element-Eintrag
- 'Lösen'-Button entfernt Verknüpfung
- generate_pdf legt das fertige PDF auch unter den verknüpften
  Elementen ab + ECM-Eintrag

Phase 1.1 Live-PDF-Vorschau:
- Neuer Endpoint ajax/preview_pdf.php — wie generate_pdf, aber:
  schreibt nicht in ECM, ändert nicht den Status, streamt direkt
- 👁️ Vorschau-Button im Editor öffnet Modal mit iframe (PDF.js
  Viewer des Browsers)
- bericht_burn_annotations und bericht_render_cover_internal in
  lib/bericht.lib.php verschoben (gemeinsam genutzt)
- ESC-Key + Backdrop-Click schließen das Modal

Phase 1.2 Anhänge löschen:
- Neuer Endpoint ajax/delete_attachment.php mit Path-Whitelist
  (nur facture/, commande/, propal/), löscht Datei + thumbs +
  llx_ecm_files-Eintrag
- 🗑️-Button in jeder Anhang-Zeile, Confirm-Dialog mit
  Quell-Auftrag/Rechnung im Text
- Inline-Remove ohne Page-Reload

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
2026-04-08 22:13:46 +02:00

6.7 KiB

Bericht-Modul — Projekt-Status & Architektur

Stand 2026-04-08

Dolibarr-Custom-Modul für Arbeitsberichte mit Browser-PDF-Editor.

Architektur (final)

Tab-Verteilung

  • Auftrag (commande) — primärer Erstellungsort, Berichte mit element_type='order', Auftragsnummer = commande->ref direkt
  • Rechnung (facture) — Berichte mit element_type='invoice', Auftragsnummer aus array_options['options_auftragsnummer']
  • Angebot (propal) — möglich, gleiche Logik
  • Kundenkarte (thirdparty) — read-only Übersicht (Phase 1.7), zeigt alle Berichte des Kunden über Joins, kein Anlegen, kein Speicher-Ort

Verknüpfung Auftrag → Rechnung

Berichte gehören 1:1 zu einem Parent (element_type + fk_element). Auf einer Rechnungs-Seite werden ZUSÄTZLICH die Berichte der verknüpften Aufträge angezeigt — über fetchObjectLinked() der Rechnung. Mit Button "→ Dieser Rechnung zuordnen" erzeugt man einen Eintrag in llx_element_element (Standard-Dolibarr-n:m-Verknüpfung), damit der Bericht beim Finalisieren auch im ECM der Rechnung landet.

DB-Tabellen

  • llx_bericht — Bericht (rowid, ref, titel, element_type, fk_element, auftragsnummer, template_odt, status, final_pdf_path, format, orientation, ...)
  • llx_bericht_page — Seite (rowid, fk_bericht, page_order, source_type, source_path, source_page, rotation, fabric_json, note, layout, image_scale, image_align, ...)
  • llx_bericht_upload_token — Phase 2: Mobile-Upload-Tokens (rowid, token, fk_bericht, expires_at, created_by)

Permissions

  • bericht/read (Standard für alle)
  • bericht/write (Standard für alle)
  • bericht/delete (Standard für alle)
  • bericht/admin (nur explizit)

WICHTIG: $this->rights[$r][4] = perms-Name ('read'), [5] = subperms (leer). NICHT Modul-Name in [4]!

Modul-Numero

500033 — kollidiert NICHT mit BankImport (500021). Permission-IDs sind 500033 + n.

CSS-Variablen (Dolibarr awl-dark Theme)

Verwendete: --colorbacktitle1, --colortext, --colorbackbody, --colorboxbordertitle1, --colortextlink, --colorbackhmenu1, --colortextbackhmenu, --colorbackvmenu1

NICHT vorhanden im awl-dark: --inputbackgroundcolor, --inputtextcolor — stattdessen Fallbacks nutzen.

JS-Libraries (lokal in js/lib/)

  • pdf.min.js (PDF.js 3.11)
  • pdf.worker.min.js
  • fabric.min.js (Fabric.js 5.3)
  • Sortable.min.js (SortableJS 1.15)

LocalStorage Settings

Key: bericht.editor.settings.v1 Speichert: color, stroke, fontFamily, fontSize, bold, italic, zoom

Forgejo

  • Repo: data/bericht (NICHT data-it/bericht — Token hat keine org-write rechte)
  • Workflow: [deploy]-Tag triggert rsync nach /mnt/appdata/firma/dolibarr-202509/modules/bericht
  • Lokaler Symlink: /var/www/dolibarr/custom/bericht/mnt/17 - Entwicklungen/30 - Scripts/php/Dolibarr - Module/Bericht/repo
  • Lokales Apache läuft als User data (NICHT http)

Phase 1 — Bericht-Modul-Erweiterungen (in Arbeit)

Erledigt vor Phase 1

  • Modul-Scaffold (modBericht, SQL, Lang, Rechte korrekt nach Stundenzettel-Format)
  • Editor mit PDF.js + Fabric.js
  • Toolbar 2-zeilig, einheitliche Höhe 30px
  • Schriftart/Größe/Bold/Italic mit localStorage-Persistenz
  • Zoom (-/+/Reset), Seitenrotation, Pfeil mit Spitze (drag, drehbar)
  • Seiten-Thumbnails als echte Vorschau (PDF.js + Image), Hell/Dunkel-Toggle
  • ResizeObserver für Console-Open-Resize
  • ODT-Template-Verwaltung im Admin
  • Generate-PDF mit FPDI + Annotationen einbrennen
  • Mobile-Upload-Idee dokumentiert (Phase 2)

🔄 Phase 1 Features (in Arbeit)

  • 1.6 Verknüpfte Sicht Auftrag→Rechnung — Übersicht zeigt zwei Sektionen, Übernahme-Button erzeugt llx_element_element. (in Arbeit)
  • 1.1 Live-PDF-Vorschau — neuer Endpoint ajax/preview_pdf.php (wie generate_pdf, aber ohne ECM-Insert + status), JS-Modal mit PDF.js
  • 1.2 Anhänge löschen — neuer Endpoint ajax/delete_attachment.php, 🗑️-Icon neben Checkbox in Anhänge-Liste, Path-Whitelist, ECM-Cleanup
  • 1.3 Seitengröße A4/A3/Letter + Hoch/Quer — neue Spalten in llx_bericht (format, orientation), pro Seite überschreibbar in llx_bericht_page (format_override)
  • 1.4 Mehrere Bilder pro Seite — Layout-Picker (1/2/4/6 Grid), neue Spalte layout in llx_bericht_page, n:m-Bilder evtl. neue Tabelle
  • 1.5 Bildgröße pro Seite — Spalten image_scale, image_align, image_x, image_y in llx_bericht_page
  • 1.7 Kunden-Tab — Tab "Berichte" auf thirdparty, read-only, flache Tabelle sortiert nach Datum, Konstante BERICHT_TAB_ON_THIRDPARTY (default 0)

Phase 2 — Mobile-Vorbereitung + API-Layer (geplant)

  • 2.1 Mobile-Upload-Token Tabelle + Cleanup-Cron
  • 2.2 QR-Upload Lite Modal im Editor
  • 2.3 API-Layer unter bericht/api/ mit JWT-Auth
  • 2.4 REST-Endpoints: /auth/login, /orders, /orders/{id}, /orders/{id}/photos, /reports, /reports/{id}/pages

JWT-Secret aus $dolibarr_main_instance_unique_id, 7 Tage Lifetime, Multi-Device OK (stateless).

Auftragsfilter pro User: fk_user_author, fk_user_valid, fk_user_modif ODER llx_element_contact mit "intern verantwortlich".


Phase 3 — PWA MVP (geplant)

  • Repo: data-it/baustelle-pwa (separates SvelteKit-Projekt)
  • Hosting: awl.data-it-solution.de/baustelle/ (Apache-Alias)
  • Stack: SvelteKit + Workbox + idb-keyval
  • MVP: Login → Auftragsliste → Detail → Foto-Aufnahme → Offline-Queue → Sync

Phase 4 — PWA Voll (geplant)

  • Sprachnotizen (MediaRecorder)
  • Touch-Skizzen-Editor
  • Schnell-Bericht in PWA
  • Touch-Unterschrift
  • PIN-Schutz / WebAuthn
  • Push-Notifications
  • Web Share Target API

Phase 5 — Optional Später

Stamps, Vorher/Nachher, Versionierung, Mess-Werkzeug, Bericht-Vorlagen, Batch-Modus, Whisper-Transkription, Offline-Map


Wichtige Lessons Learned (für andere Dolibarr-Module)

  1. Numero muss kollisionsfrei sein — sonst werden Permissions stillschweigend verworfen
  2. Permission-Array-Format: [4]=perms (action), [5]=subperms (leer) — NICHT [4]=Modulname
  3. CSS-Variablen über Theme nutzen, nicht hardcoded Hex
  4. JS-Libs lokal in js/lib/ (Eddys Regel: kein CDN)
  5. Fabric.js wickelt Canvas in .canvas-container — den positionieren, nicht das innere Canvas
  6. PDF.js Buffer wird konsumiert — beim Re-Render arrayBuffer.slice(0) nutzen
  7. Lokales Dolibarr läuft als User data, mit Symlinks aus /var/www/dolibarr/custom/<modul> zu /mnt/17 - Entwicklungen/...
  8. Niemals direkt in /var/www/dolibarr oder /mnt/appdata editieren — alles über Git
  9. Niemals schreibend in dolibarr_test MySQL — nur lesend für Debugging
  10. Computed Extrafields mit $object->ref brauchen Null-Check, sonst PHP-Output beim eval → "headers already sent"