Die API-Seite zur Baustelle-PWA holt nach, was der Editor mit 1.5.0 bekommen hat.
photo.php kann jetzt size=thumb&w=<px> und rendert ueber bericht_attachment_thumb()
(GD, Cache, EXIF-Rotation) statt die Originaldatei auszuliefern. size=small konnte nur
ein von Dolibarr vorgefertigtes thumbs/<name>_small.<ext> liefern - fuer Uploads ueber
orders.php?action=upload_photo gibt es das nicht, dort laeuft kein vignette(). Die PWA
lud dadurch fuer jede Kachel das komplette Foto: gemessen 9,8 KB statt 235 KB je Kachel.
Antwort mit ETag aus der mtime, Folgeaufrufe enden mit 304.
orders.php?action=photos liefert taken_at (EXIF-Aufnahmezeit ueber bericht_file_taken_at,
sonst Dateidatum) und sortiert danach statt nach filemtime.
reports.php gibt je Seite title und composite_path aus. title konnte ueber pages.php
gesetzt werden, kam aber nie zurueck. composite_path ist das im Editor gebaute
Seitenbild - ohne das zeigen Clients nur das Rohbild ohne Anmerkungen, bei
Raster-Layouts eines von bis zu sechs Bildern und bei title_only gar keins.
Neu: api/note.php - Textnotizen zum Auftrag, aufgebaut wie die Sprachnotiz. Die Notiz
liegt als notiz_<betreff>_<datum>.txt im Auftragsverzeichnis und ist damit auch im
Dolibarr-Auftrag und in der Anhaenge-Spalte des Editors sichtbar. Liste, Lesen, Anlegen,
Aendern, Loeschen. Der file-Parameter wird gegen ^notiz_[A-Za-z0-9_.-]*\.txt$ geprueft;
gegen Pfad-Ausbrueche getestet.
ROADMAP.md wiederhergestellt - sie war mit eb37a4b geloescht worden, weil alle Punkte
abgehakt waren. Sie bleibt ab jetzt liegen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
290 lines
19 KiB
Markdown
290 lines
19 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, user: {...} } + HttpOnly-Cookie awl_sso
|
||
```
|
||
|
||
Seit der SSO-Migration läuft die Anmeldung über das Modul **awlauth**: `auth.php` setzt das
|
||
HttpOnly-Cookie `awl_sso` (Single-Sign-on/-out über alle AWL-Apps), Folge-Requests
|
||
authentisieren sich same-origin über dieses Cookie. **Kein Bearer-Token und kein `?jwt=`
|
||
mehr** — auch `<img>`- und `<audio>`-Tags kommen ohne Query-Parameter aus.
|
||
Endpoints mit `awlauth_require` erwarten zusätzlich den Header `X-Requested-With:
|
||
XMLHttpRequest` (CSRF-Schutz); reine GET-Reads wie `photo.php` und `pdf.php` nutzen
|
||
`awlauth_verify` ohne diese Anforderung, damit sie auch per `window.location` gehen.
|
||
|
||
### 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
|
||
Je Datei: filename, size, mime, date (mtime), taken_at (EXIF-Aufnahmezeit, sonst
|
||
Dateidatum), relpath. Sortiert nach taken_at, neuste zuerst.
|
||
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>
|
||
Liefert Dateien aus DOL_DATA_ROOT (Whitelist: facture/, commande/, propal/, bericht/)
|
||
Auth über das awl_sso-Cookie (same-origin), auch für <img>-Tags.
|
||
|
||
?size=thumb&w=<px> Serverseitig erzeugtes Thumbnail (GD, gecacht unter
|
||
bericht/thumbs/, mit ETag aus der mtime → Folgeaufrufe 304).
|
||
w: 40–800, Default 320. Das ist der Weg für Kachel-Ansichten.
|
||
Ist die Datei kein Bild, kommt das Original.
|
||
?size=small|mini Altes Verhalten: nutzt ein von Dolibarr vorgefertigtes
|
||
thumbs/<name>_small.<ext>. Für Dateien, die über die API
|
||
hochgeladen wurden, existiert so eines NICHT (kein vignette()) —
|
||
dort kam bis 1.5.1 immer das Original zurück.
|
||
?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, title, rotation, layout }
|
||
POST /custom/bericht/api/pages.php?action=signature&bericht_id=<id>
|
||
Body: FormData mit file=<PNG-Blob>, signer_name, gps_lat, gps_lon
|
||
```
|
||
|
||
`reports.php?id=<id>` gibt je Seite `composite_path` und `title` mit aus. **Clients sollen
|
||
`composite_path` anzeigen, wenn es gesetzt ist** — das ist das im Editor gebaute Seitenbild
|
||
mit Anmerkungen. `source_path` ist nur die Quelldatei: bei Raster-Layouts eines von bis zu
|
||
sechs Bildern, bei `title_only` leer.
|
||
|
||
### Textnotizen zum Auftrag (PWA)
|
||
```
|
||
GET /custom/bericht/api/note.php?order_id=<id> Liste
|
||
GET /custom/bericht/api/note.php?order_id=<id>&file=<name> eine Notiz mit Text
|
||
POST /custom/bericht/api/note.php?order_id=<id> anlegen { subject, text }
|
||
POST /custom/bericht/api/note.php?order_id=<id>&file=<name> ändern { subject, text }
|
||
POST /custom/bericht/api/note.php?order_id=<id>&file=<name>&delete=1
|
||
```
|
||
|
||
Notizen liegen als `notiz_<betreff>_<datum>.txt` im Auftrags-Verzeichnis — dasselbe Muster
|
||
wie die Sprachnotiz (`voice.php`). Sie sind damit auch im Dolibarr-Auftrag und in der
|
||
Anhänge-Spalte des Editors zu sehen. Der Dateikopf (bis zur ersten Leerzeile) trägt
|
||
`Betreff:`, `Erfasst:` und `Geändert:`, darunter steht der freie Text. `file` wird gegen
|
||
`^notiz_[A-Za-z0-9_.\-]*\.txt$` geprüft — ohne das ließe sich über `../` jede Datei unter
|
||
`DOL_DATA_ROOT` überschreiben.
|
||
|
||
### 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 (Auth über awl_sso-Cookie, Modul awlauth)
|
||
│ ├── _inc.php Dolibarr-Init + awlauth_require + JSON-Helper
|
||
│ ├── 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 + Thumbnails (size=thumb)
|
||
│ ├── 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)
|
||
│ ├── note.php Textnotizen zum Auftrag (Liste/Lesen/Anlegen/Ändern)
|
||
│ └── 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+
|