bericht/class/bericht.class.php
Eduard Wisch 923b50d65a
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
feat: Initiales Release Bericht-Modul v1.0.0 [deploy]
Dolibarr-Modul für Arbeitsberichte aus Rechnungs-Anhängen mit Browser-PDF-Editor.

- Reiter "Bericht" auf Rechnungen, Aufträgen und Angeboten
- Anhänge-Browser inkl. verknüpfter Objekte (Auftrag → Rechnung)
- PDF.js + Fabric.js Browser-Editor: Pfeile, Kreise, Rechtecke, Freihand, Text
- SortableJS Seiten-Verwaltung mit Drag&Drop
- ODT-Deckblatt mit Platzhaltern, Templates im Admin verwaltbar
- TCPDF + FPDI Finalisierung mit eingebrannten Annotationen
- ECM-Verknüpfung: PDF erscheint unter Verknüpfte Dokumente
- Auftragsnummer aus existierendem Extrafield options_auftragsnummer
- Mehrere Berichte pro Dokument
- Beim Aktivieren werden vorhandene Extrafields nicht überschrieben

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:18:59 +02:00

267 lines
9.7 KiB
PHP

<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
* GPL v3+
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
/**
* CRUD-Klasse für einen Bericht.
* Eine Bericht-Instanz gehört zu einem Parent-Objekt (invoice|order|propal)
* und enthält n Seiten (BerichtPage).
*/
class Bericht extends CommonObject
{
public $element = 'bericht';
public $table_element = 'bericht';
public $picto = 'fa-file-pdf';
public $id;
public $entity;
public $ref;
public $titel;
public $element_type; // invoice | order | propal
public $fk_element;
public $auftragsnummer;
public $template_odt;
public $status; // 0 = Entwurf, 1 = Final
public $final_pdf_path;
public $fk_user_creat;
public $fk_user_modif;
public $datec;
public $tms;
public $note;
const STATUS_DRAFT = 0;
const STATUS_FINAL = 1;
public function __construct(DoliDB $db)
{
$this->db = $db;
}
public function create(User $user, $notrigger = 0)
{
global $conf;
$this->entity = $conf->entity;
$this->datec = dol_now();
$this->status = self::STATUS_DRAFT;
$this->fk_user_creat = $user->id;
if (empty($this->ref)) {
$this->ref = 'BR'.dol_print_date($this->datec, '%y%m%d-%H%i%s');
}
$sql = "INSERT INTO ".$this->db->prefix()."bericht ("
."entity, ref, titel, element_type, fk_element, auftragsnummer, template_odt, status, fk_user_creat, datec, note"
.") VALUES ("
.((int) $this->entity).","
."'".$this->db->escape($this->ref)."',"
.($this->titel ? "'".$this->db->escape($this->titel)."'" : "NULL").","
."'".$this->db->escape($this->element_type)."',"
.((int) $this->fk_element).","
.($this->auftragsnummer ? "'".$this->db->escape($this->auftragsnummer)."'" : "NULL").","
.($this->template_odt ? "'".$this->db->escape($this->template_odt)."'" : "NULL").","
.((int) $this->status).","
.((int) $this->fk_user_creat).","
."'".$this->db->idate($this->datec)."',"
.($this->note ? "'".$this->db->escape($this->note)."'" : "NULL")
.")";
$this->db->begin();
$res = $this->db->query($sql);
if (!$res) {
$this->error = $this->db->lasterror();
$this->db->rollback();
return -1;
}
$this->id = $this->db->last_insert_id($this->db->prefix()."bericht");
$this->db->commit();
return $this->id;
}
public function fetch($id)
{
$sql = "SELECT rowid, entity, ref, titel, element_type, fk_element, auftragsnummer, template_odt,"
." status, final_pdf_path, fk_user_creat, fk_user_modif, datec, tms, note"
." FROM ".$this->db->prefix()."bericht WHERE rowid = ".((int) $id);
$res = $this->db->query($sql);
if (!$res) {
$this->error = $this->db->lasterror();
return -1;
}
if ($this->db->num_rows($res) == 0) {
return 0;
}
$obj = $this->db->fetch_object($res);
$this->id = $obj->rowid;
$this->entity = $obj->entity;
$this->ref = $obj->ref;
$this->titel = $obj->titel;
$this->element_type = $obj->element_type;
$this->fk_element = $obj->fk_element;
$this->auftragsnummer = $obj->auftragsnummer;
$this->template_odt = $obj->template_odt;
$this->status = (int) $obj->status;
$this->final_pdf_path = $obj->final_pdf_path;
$this->fk_user_creat = $obj->fk_user_creat;
$this->fk_user_modif = $obj->fk_user_modif;
$this->datec = $this->db->jdate($obj->datec);
$this->tms = $this->db->jdate($obj->tms);
$this->note = $obj->note;
return 1;
}
public function update(User $user, $notrigger = 0)
{
$sql = "UPDATE ".$this->db->prefix()."bericht SET "
."titel = ".($this->titel ? "'".$this->db->escape($this->titel)."'" : "NULL").","
."auftragsnummer = ".($this->auftragsnummer ? "'".$this->db->escape($this->auftragsnummer)."'" : "NULL").","
."template_odt = ".($this->template_odt ? "'".$this->db->escape($this->template_odt)."'" : "NULL").","
."status = ".((int) $this->status).","
."final_pdf_path = ".($this->final_pdf_path ? "'".$this->db->escape($this->final_pdf_path)."'" : "NULL").","
."note = ".($this->note ? "'".$this->db->escape($this->note)."'" : "NULL").","
."fk_user_modif = ".((int) $user->id)
." WHERE rowid = ".((int) $this->id);
$res = $this->db->query($sql);
if (!$res) {
$this->error = $this->db->lasterror();
return -1;
}
return 1;
}
public function delete(User $user, $notrigger = 0)
{
$this->db->begin();
// Seiten löschen (CASCADE räumt's bereits, aber explizit für robustes Verhalten)
$this->db->query("DELETE FROM ".$this->db->prefix()."bericht_page WHERE fk_bericht = ".((int) $this->id));
$res = $this->db->query("DELETE FROM ".$this->db->prefix()."bericht WHERE rowid = ".((int) $this->id));
if (!$res) {
$this->error = $this->db->lasterror();
$this->db->rollback();
return -1;
}
$this->db->commit();
return 1;
}
/**
* Liefert alle Berichte zu einem Parent-Objekt.
*
* @param string $element_type invoice | order | propal
* @param int $fk_element ID des Parent-Objekts
* @return Bericht[]
*/
public static function fetchAllForElement(DoliDB $db, $element_type, $fk_element)
{
$list = array();
$sql = "SELECT rowid FROM ".$db->prefix()."bericht"
." WHERE element_type = '".$db->escape($element_type)."'"
." AND fk_element = ".((int) $fk_element)
." ORDER BY datec DESC";
$res = $db->query($sql);
if (!$res) return $list;
while ($obj = $db->fetch_object($res)) {
$b = new self($db);
if ($b->fetch($obj->rowid) > 0) {
$list[] = $b;
}
}
return $list;
}
public function getLibStatut($mode = 0)
{
global $langs;
$langs->load("bericht@bericht");
if ($this->status == self::STATUS_FINAL) {
return '<span class="badge badge-status4">'.$langs->trans("BerichtStatusFinal").'</span>';
}
return '<span class="badge badge-status0">'.$langs->trans("BerichtStatusDraft").'</span>';
}
}
/**
* Eine Seite eines Berichts.
*/
class BerichtPage
{
public $db;
public $id;
public $fk_bericht;
public $page_order;
public $source_type;
public $source_path;
public $source_page;
public $rotation;
public $fabric_json;
public $note;
public function __construct(DoliDB $db)
{
$this->db = $db;
}
public function create()
{
$sql = "INSERT INTO ".$this->db->prefix()."bericht_page ("
."fk_bericht, page_order, source_type, source_path, source_page, rotation, fabric_json, note"
.") VALUES ("
.((int) $this->fk_bericht).","
.((int) $this->page_order).","
."'".$this->db->escape($this->source_type)."',"
."'".$this->db->escape($this->source_path)."',"
.($this->source_page !== null ? (int) $this->source_page : "NULL").","
.((int) ($this->rotation ?? 0)).","
.($this->fabric_json !== null ? "'".$this->db->escape($this->fabric_json)."'" : "NULL").","
.($this->note ? "'".$this->db->escape($this->note)."'" : "NULL")
.")";
$res = $this->db->query($sql);
if (!$res) return -1;
$this->id = $this->db->last_insert_id($this->db->prefix()."bericht_page");
return $this->id;
}
public function update()
{
$sql = "UPDATE ".$this->db->prefix()."bericht_page SET "
."page_order = ".((int) $this->page_order).","
."rotation = ".((int) ($this->rotation ?? 0)).","
."fabric_json = ".($this->fabric_json !== null ? "'".$this->db->escape($this->fabric_json)."'" : "NULL").","
."note = ".($this->note ? "'".$this->db->escape($this->note)."'" : "NULL")
." WHERE rowid = ".((int) $this->id);
return $this->db->query($sql) ? 1 : -1;
}
public function delete()
{
return $this->db->query("DELETE FROM ".$this->db->prefix()."bericht_page WHERE rowid = ".((int) $this->id)) ? 1 : -1;
}
public static function fetchAllForBericht(DoliDB $db, $fk_bericht)
{
$list = array();
$sql = "SELECT rowid, fk_bericht, page_order, source_type, source_path, source_page, rotation, fabric_json, note"
." FROM ".$db->prefix()."bericht_page"
." WHERE fk_bericht = ".((int) $fk_bericht)
." ORDER BY page_order ASC, rowid ASC";
$res = $db->query($sql);
if (!$res) return $list;
while ($obj = $db->fetch_object($res)) {
$p = new self($db);
$p->id = $obj->rowid;
$p->fk_bericht = $obj->fk_bericht;
$p->page_order = (int) $obj->page_order;
$p->source_type = $obj->source_type;
$p->source_path = $obj->source_path;
$p->source_page = $obj->source_page !== null ? (int) $obj->source_page : null;
$p->rotation = (int) $obj->rotation;
$p->fabric_json = $obj->fabric_json;
$p->note = $obj->note;
$list[] = $p;
}
return $list;
}
}