An Auftrag (PROV105) lagen 34 Fotos, davon 11 exakte Wiederholungen: eine Serie lief bei ausgeschaltetem Display nur halb durch, der zweite Anlauf lud alles noch einmal hoch. - bericht_find_identical_file() vergleicht die hochgeladene Datei gegen den Zielordner (Groesse als Vorfilter, md5 nur bei Kandidaten) - eingebaut in beide Upload-Wege: api/orders.php?action=upload_photo (PWA) und mobile_upload.php (Token-Link) - bei Treffer wird nichts gespeichert, die Antwort traegt duplicate:true UND den relpath der vorhandenen Datei — ohne relpath wertet die PWA den Upload als nicht bestaetigt und wiederholt ihn endlos (lib/api.js) Funktion isoliert geprueft: identischer Inhalt wird gefunden, neuer Inhalt und gleiche Groesse mit anderem Inhalt liefern null (kein Fehlalarm). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
21 KiB
Changelog
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) undmobile_upload.php(Token-Link). - Bei einem Treffer wird nichts abgelegt, die Antwort traegt
duplicate: true— und trotzdem denrelpathder vorhandenen Datei. Das ist Pflicht: die PWA wertet eine Antwort ohnerelpathals „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.phpkann jetztsize=thumb&w=<px>und rendert damit überbericht_attachment_thumb()— dieselbe Funktion, die auch die Anhänge-Kacheln im Editor füllt (GD, Cache unterbericht/thumbs/, EXIF-Ausrichtung).- Bisher kannte der Endpoint nur
size=small|mini, und das lieferte ausschließlich ein Thumbnail, das Dolibarr selbst unterthumbs/<name>_small.<ext>abgelegt hatte. Fotos aus der PWA kommen überorders.php?action=upload_photoherein, und dort läuft keinvignette()— 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
ETagaus der mtime undCache-Control: max-age=30 Tage; ein wiederholter Aufruf endet mit304. 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=photoslieferttaken_at— die EXIF-Aufnahmezeit überbericht_file_taken_at(), sonst das Dateidatum. Sortiert wird danach statt nachfilemtime. Bei Uploads aus der Galerie war die Upload-Reihenfolge bisher die falsche Reihenfolge.
Bericht-Seiten: Titel und fertiges Seitenbild
api/reports.phpgibt je Seitetitleundcomposite_pathmit aus.titlekonnte überapi/pages.phpgesetzt werden und wurde in der PWA auch gerendert, kam aber nie zurück — der Titel wirkte, als würde er nicht gespeichert.composite_pathist das im Editor gebaute Seitenbild. Ohne dieses Feld zeigt ein Client nursource_path, also das Rohbild ohne Anmerkungen — und bei einem Raster-Layout eines von bis zu sechs Bildern. Beititle_onlyistsource_pathleer, 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>.txtim 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:undGeändert:(jeweils mit Login), darunter der freie Text. Bewusst als Klartext lesbar, auch wenn jemand die.txtdirekt im ECM öffnet. - Der
file-Parameter wird gegen^notiz_[A-Za-z0-9_.\-]*\.txt$geprüft — ohne das ließe sich über../jede Datei unterDOL_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.jpgwar 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 unterbericht/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 dasexif-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.phpexistierte 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.phpliefert Seiten- und Anhängeliste als HTML. Gerendert wird überbericht_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:
VAuswahl,PZeichnen,RRechteck,KKreis,APfeil,TText,Entflöscht die Auswahl,Strg+Z/Strg+YRückgängig/Wiederholen,Strg+Sspeichern,↑/↓blättert durch die Seiten. In Eingabefeldern und bei offenem Dialog greifen sie nicht; das Hintergrundbild lässt sich mitEntfnicht 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 = 1aufgerufen —sizeunddateblieben 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.phpohneattachment=0verlinkt und dadurch heruntergeladen statt angezeigt. - Die Größen-Auswahl einer Seite blieb leer: der DB-Wert
1traf die Option1.0nicht. - 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: Mitvalidate=truewird der Auftrag jetzt ohne jede Position freigegeben. Bisher hängte das Backend vorher eine Std-Lohn-Zeile mit Menge 1 an (Kundenkarten-Defaultoptions_stundenzettel_default_service, sonst Fallback-Produkt).- Warum: Die Annahme,
Commande::valid()scheitere an einem leeren Auftrag, ist falsch — wedervalid()noch der Handlerconfirm_validateprüfen auf Zeilen, gesperrt ist nur die Button-Darstellung incommande/card.php(verifiziert gegen Dolibarr 22.0.2, KB #355/#989). Die Alibi-Zeile verfälschtetotal_ht, tauchte als offene Restmenge in der Lieferauflistung auf, stand im Kunden-PDF und ließ sich nach der Freigabe nicht mehr perdeleteLine()entfernen. Die Leistungen kommen aus dem Stundenzettel. - Das Antwortfeld
added_lineentfällt (wurde von der Baustelle-PWA nie ausgewertet). - Die Konstante
BERICHT_ORDER_DEFAULT_SERVICE_REFwird nicht mehr verwendet. - Gleiche Umstellung in der Stunden-App:
stundenzettel/ajax/pwa_api.php(Aktionvalidate_order) fügt ebenfalls keine Fallback-Position mehr ein, und legt mit der neuen Aktioncreate_orderselbst 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-SprachkeysPaymentTypeShort<code>/PaymentConditionShort<code>(Sprachdateibills) statt der rohen englischenlibelle-Werte ausc_paiement/c_payment_term. Behebt die Anzeige „💳 Payment Condition · 🏦 Credit transfer" in der „Übernommen"-Zeile. Fallback auflibelle, wenn kein Sprachkey existiert (z. B. Custom-Einträge ohnecode).- Baustelle-PWA (Repo
baustelle-pwa): „Neuer Auftrag"-Formular saß vertikal zu weit unten (der gemeinsame.fs-bodyerbtejustify-content:center, was beiflex-direction:columnvertikal zentriert) und wurde von der Bildschirmtastatur verdeckt →justify-content:flex-startim 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" (= Extrafieldoptions_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-Spaltedate_livraison. - Neue Checkbox „Auftrag direkt freigeben".
Backend (api/orders.php?action=create)
ref_clientist 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 dannCommande::valid().- Produkt: Kundenkarten-Default
options_stundenzettel_default_service, sonst Fallback-Produkt über RefBERICHT_ORDER_DEFAULT_SERVICE_REF(DefaultELEK-STD-M, „Stundenlohn Meister" 45 €). - Preis: kundenspezifischer Preis (
PRODUIT_CUSTOMER_PRICES) hat Vorrang, sonst Produkt-Standardpreis. Menge 1.
- Produkt: Kundenkarten-Default
- 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'mitfk_element = llx_expedition.rowid - Tab "Bericht" erscheint auf der Lieferung-Card (Konstante
BERICHT_TAB_ON_SHIPMENT) bericht_fetch_parent()undbericht_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_DEFAULTals 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) inllx_bericht_signature_box(UPSERT auftemplate_name) - Reset-Button setzt zurück auf Default-Konstante
Neue PWA-Route (Baustelle-App)
- Order-Detail bekommt Button "🚚 Lieferungen"
#/orders/:id/shipmentszeigt Liste aller verknüpften Expeditionen mit Status- und Signed-Badge#/shipments/:idzeigt 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 indocuments/expedition/<ref>/<ref>-signed.pdf
Auto-Workflow auf der Expedition
signed_status=1(viaCommonSignedObject::setSignedStatus)- Wenn Expedition noch Draft (Status 0): erst
valid(), dannsetClosed() - Bericht-Record (
element_type='shipment') wird angelegt/aktualisiert mitfinal_pdf_pathzum signierten PDF <sig>.meta.jsonneben 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 AuftragGET /api/shipments.php?id=<id>— Detail einer Lieferung + Bericht-ID falls vorhandenGET /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_imagefür Multi-Image-Seiten - Spalten
layout,image_scale,image_aligninllx_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_THIRDPARTYzum Aktivieren
Sonstiges
- DB-Migrationen im
init()für bestehende Installationen (ALTER TABLE mit Error-Suppress) bericht_burn_annotationsundbericht_render_cover_internalinlib/bericht.lib.phpzentralisiert (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
BerichtundBerichtPage(Tabellenllx_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_auftragsnummergeholt - Beim Aktivieren werden fehlende Extrafields auf
llx_facture_extrafieldsangelegt, vorhandene NICHT überschrieben - Mehrere Berichte pro Dokument möglich
- Forgejo-Workflow für Deploy nach Dolibarr (Tag
[deploy])