<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
 * GPL v3+ — siehe COPYING
 */

/**
 *  \defgroup   bericht     Module Bericht
 *  \brief      Arbeitsberichte aus Anhängen erstellen, im Browser annotieren und an Rechnungen anhängen.
 *  \file       htdocs/bericht/core/modules/modBericht.class.php
 */
include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';

class modBericht extends DolibarrModules
{
    public function __construct($db)
    {
        global $conf, $langs;
        $this->db = $db;

        $this->numero = 500033; // Frei (500021 kollidiert mit BankImport, siehe llx_rights_def)
        $this->rights_class = 'bericht';
        $this->family = "other";
        $this->module_position = '90';
        $this->name = preg_replace('/^mod/i', '', get_class($this));
        $this->description = "Arbeitsberichte aus Rechnungs-Anhängen erstellen, im Browser annotieren und als PDF an die Rechnung anhängen.";
        $this->descriptionlong = "Fügt Rechnungen, Aufträgen und Angeboten einen Reiter 'Bericht' hinzu. Anhänge auswählen, im Browser mit Pfeilen/Kreisen/Rechtecken/Text annotieren, Seiten verwalten, Deckblatt aus ODT-Vorlage einfügen und als PDF unter Verknüpfte Dokumente speichern.";

        $this->editor_name = 'Alles Watt läuft';
        $this->editor_url = '';
        $this->version = '1.1.0';
        $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
        $this->picto = 'fa-file-pdf';

        $this->module_parts = array(
            'triggers' => 0,
            'login' => 0,
            'substitutions' => 0,
            'menus' => 0,
            'tpl' => 0,
            'barcode' => 0,
            'models' => 0,
            'printing' => 0,
            'theme' => 0,
            'css' => array('/bericht/css/bericht.css'),
            'js' => array(),
            'hooks' => array('data' => array('odtgeneration')),
            'moduleforexternal' => 0,
        );

        // Datenverzeichnisse
        $this->dirs = array(
            "/bericht/temp",
            "/bericht/templates",
            "/bericht/work",
        );

        // Konfigurationsseite im Admin-Bereich
        $this->config_page_url = array("setup.php@bericht");

        $this->hidden = false;
        $this->depends = array();
        $this->requiredby = array();
        $this->conflictwith = array();
        $this->langfiles = array("bericht@bericht");
        $this->phpmin = array(7, 4);
        $this->need_dolibarr_version = array(19, 0);
        $this->need_javascript_ajax = 1;

        // Konstanten beim Aktivieren anlegen
        $this->const = array(
            0 => array('BERICHT_DEFAULT_TEMPLATE',  'chaine', '',                'Standard ODT-Template für Deckblatt', 0, 'current', 0),
            1 => array('BERICHT_TAB_ON_INVOICE',    'chaine', '1',               'Reiter Bericht auf Rechnungen anzeigen', 0, 'current', 0),
            2 => array('BERICHT_TAB_ON_ORDER',      'chaine', '1',               'Reiter Bericht auf Aufträgen anzeigen', 0, 'current', 0),
            3 => array('BERICHT_TAB_ON_PROPAL',     'chaine', '1',               'Reiter Bericht auf Angeboten anzeigen', 0, 'current', 0),
            4 => array('BERICHT_BURN_ANNOTATIONS',  'chaine', '1',               'Annotationen beim Export ins PDF einbrennen', 0, 'current', 0),
            5 => array('BERICHT_LIBREOFFICE_BIN',   'chaine', '/usr/bin/libreoffice', 'Pfad zu LibreOffice für ODT→PDF Konvertierung', 0, 'current', 0),
            6 => array('BERICHT_TAB_ON_THIRDPARTY', 'chaine', '1',               'Reiter Berichte auf Kundenkarten (read-only Übersicht)', 0, 'current', 0),
            7 => array('BERICHT_TAB_ON_SHIPMENT',   'chaine', '1',               'Reiter Bericht auf Lieferungen anzeigen', 0, 'current', 0),
            8 => array('BERICHT_SIGNATURE_BOX_DEFAULT', 'chaine',
                       '{"page":"last","x_mm":120,"y_mm":230,"w_mm":70,"h_mm":35,"label":"Unterschrift Kunde"}',
                       'Standard-Geometrie der Unterschriftsbox auf Lieferschein-PDFs (JSON)', 0, 'current', 0),
            9 => array('BERICHT_SIGNATURE_IMAGE_RATIO', 'chaine', '0.35',
                       'Groessen-Faktor fuer Signatur im ODT (0.3 ergibt ca. 6×3 cm bei 800×400 Pixel)', 0, 'current', 0),
        );

        // Tabs werden über den Hook (actions_bericht.class.php → addMoreActionsButtons / completeTabsHead)
        // dynamisch hinzugefügt, weil wir die Sichtbarkeit pro Element-Typ über Konstanten steuern wollen.
        // Statisch geht aber auch — sicherer und einfacher:
        $this->tabs = array(
            'invoice:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=invoice',
            'order:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=order',
            'propal:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=propal',
            'thirdparty:+bericht:Berichte:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_thirdparty.php?socid=__ID__',
            'shipping:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=shipment',
        );

        $this->dictionaries = array();
        $this->boxes = array();
        // Kein Cronjob — Cleanup expired Upload-Tokens passiert on-demand
        // beim Anlegen eines neuen Tokens (siehe BerichtUploadToken::create()).
        $this->cronjobs = array();

        // Rechte — wie Stundenzettel: [4]=perms, [5]=subperms (leer)
        $this->rights = array();
        $r = 0;

        $this->rights[$r][0] = $this->numero + $r;
        $this->rights[$r][1] = 'Berichte lesen';
        $this->rights[$r][3] = 1; // Standard aktiviert
        $this->rights[$r][4] = 'read';
        $this->rights[$r][5] = '';
        $r++;

        $this->rights[$r][0] = $this->numero + $r;
        $this->rights[$r][1] = 'Berichte erstellen und bearbeiten';
        $this->rights[$r][3] = 1;
        $this->rights[$r][4] = 'write';
        $this->rights[$r][5] = '';
        $r++;

        $this->rights[$r][0] = $this->numero + $r;
        $this->rights[$r][1] = 'Berichte löschen';
        $this->rights[$r][3] = 1;
        $this->rights[$r][4] = 'delete';
        $this->rights[$r][5] = '';
        $r++;

        $this->rights[$r][0] = $this->numero + $r;
        $this->rights[$r][1] = 'Modul Bericht administrieren (Templates verwalten)';
        $this->rights[$r][3] = 0;
        $this->rights[$r][4] = 'admin';
        $this->rights[$r][5] = '';
        $r++;

        // Kein Menü — Berichte werden über Tabs auf Rechnungen/Aufträgen/Angeboten aufgerufen
        $this->menu = array();
    }

    /**
     *  Beim Aktivieren ausgeführt: SQL laden, Verzeichnisse anlegen,
     *  vorhandene Extrafields auf llx_facture_extrafields prüfen und ggf. anlegen.
     */
    public function init($options = '')
    {
        global $conf, $langs;

        // SQL-Tabellen anlegen
        $result = $this->_load_tables('/bericht/sql/');
        if ($result < 0) {
            return -1;
        }

        // Migrationen für bestehende Tabellen
        $migrations = array(
            // Phase 1.3: Seitenformat
            "ALTER TABLE ".$this->db->prefix()."bericht ADD COLUMN page_format VARCHAR(8) DEFAULT 'A4'",
            "ALTER TABLE ".$this->db->prefix()."bericht ADD COLUMN page_orientation VARCHAR(8) DEFAULT 'P'",
            // Phase 1.4: Layout für mehrere Bilder pro Seite
            "ALTER TABLE ".$this->db->prefix()."bericht_page ADD COLUMN layout VARCHAR(16) DEFAULT 'single'",
            // Phase 1.5: Bildgröße/-position
            "ALTER TABLE ".$this->db->prefix()."bericht_page ADD COLUMN image_scale FLOAT DEFAULT 1.0",
            "ALTER TABLE ".$this->db->prefix()."bericht_page ADD COLUMN image_align VARCHAR(16) DEFAULT 'fit'",
            // Phase 5.5: Bericht-Vorlagen
            "ALTER TABLE ".$this->db->prefix()."bericht ADD COLUMN is_template TINYINT(1) DEFAULT 0",
            "ALTER TABLE ".$this->db->prefix()."bericht ADD COLUMN template_label VARCHAR(255) DEFAULT NULL",
            // Phase C: Titel pro Seite (Zwischentitel)
            "ALTER TABLE ".$this->db->prefix()."bericht_page ADD COLUMN title VARCHAR(255) DEFAULT NULL",
            // Phase 5.3: Versionierung
            "ALTER TABLE ".$this->db->prefix()."bericht ADD COLUMN version INT DEFAULT 1",
            "ALTER TABLE ".$this->db->prefix()."bericht ADD COLUMN fk_bericht_parent INT DEFAULT NULL",
            // Phase 6: Composite-PNG (Client-WYSIWYG). Wenn gesetzt, wird die Seite
            // komplett aus diesem einen PNG gerendert statt aus source_path + fabric_json.
            // Der Editor rendert sein Fabric-Canvas bei jedem Save zu einem PNG und
            // lädt es hoch — damit ist PDF-Output identisch mit Editor-Anzeige.
            "ALTER TABLE ".$this->db->prefix()."bericht_page ADD COLUMN composite_path VARCHAR(512) DEFAULT NULL",
            // Foto-Upload entkoppeln: Token an Dolibarr-Objekt statt an Bericht binden
            "ALTER TABLE ".$this->db->prefix()."bericht_upload_token ADD COLUMN fk_element INTEGER NOT NULL DEFAULT 0",
            "ALTER TABLE ".$this->db->prefix()."bericht_upload_token ADD COLUMN element_type VARCHAR(32) NOT NULL DEFAULT 'order'",
            "UPDATE ".$this->db->prefix()."bericht_upload_token SET fk_element = fk_bericht, element_type = 'order' WHERE fk_element = 0 AND fk_bericht > 0",
            // Phase 1.8: Lieferschein-Bestaetigung (PWA) - Signatur-Box-Geometrie pro PDF-Template
            "CREATE TABLE IF NOT EXISTS ".$this->db->prefix()."bericht_signature_box ("
                ."rowid INT AUTO_INCREMENT PRIMARY KEY,"
                ."entity INT NOT NULL DEFAULT 1,"
                ."template_name VARCHAR(64) NOT NULL,"
                ."page VARCHAR(8) NOT NULL DEFAULT 'last',"
                ."x_mm DECIMAL(7,2) NOT NULL,"
                ."y_mm DECIMAL(7,2) NOT NULL,"
                ."w_mm DECIMAL(7,2) NOT NULL,"
                ."h_mm DECIMAL(7,2) NOT NULL,"
                ."label VARCHAR(128) DEFAULT 'Unterschrift Kunde',"
                ."fk_user_modif INT DEFAULT NULL,"
                ."tms TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,"
                ."UNIQUE KEY idx_bsb_template (entity, template_name)"
                .") ENGINE=innodb",
            // Phase 5.9: Materialliste pro Auftrag
            "CREATE TABLE IF NOT EXISTS ".$this->db->prefix()."bericht_material ("
                ."rowid INT AUTO_INCREMENT PRIMARY KEY,"
                ."element_type VARCHAR(32) NOT NULL,"
                ."fk_element INT NOT NULL,"
                ."label VARCHAR(255) NOT NULL,"
                ."qty FLOAT DEFAULT 1,"
                ."unit VARCHAR(16) DEFAULT 'Stk',"
                ."note TEXT DEFAULT NULL,"
                ."fk_user_creat INT NOT NULL,"
                ."datec DATETIME NOT NULL,"
                ."INDEX idx_bm_element (element_type, fk_element)"
                .") ENGINE=innodb",
        );
        foreach ($migrations as $sql) {
            // Errors ignorieren — Spalten existieren ggf. schon
            $this->db->query($sql, 1);
        }

        // Extrafields auf facture sicherstellen — vorhandene werden NICHT angefasst
        require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
        $extrafields = new ExtraFields($this->db);

        $fields = array(
            'auftragsnummer'  => array('label' => 'Auftragsnummer',     'type' => 'varchar', 'size' => 255,  'pos' => 100),
            'angebotsnummer'  => array('label' => 'Angebotsnummer',     'type' => 'varchar', 'size' => 255,  'pos' => 101),
            'rechnungsnummer' => array('label' => 'Rechnungsnummer',    'type' => 'varchar', 'size' => 255,  'pos' => 102),
            'beschreibung'    => array('label' => 'Auftragsbeschreibung', 'type' => 'text',  'size' => 2000, 'pos' => 103),
            'hinweis'         => array('label' => 'Hinweis',            'type' => 'varchar', 'size' => 255,  'pos' => 104),
        );

        foreach ($fields as $name => $def) {
            // Existiert das Feld bereits? → nicht überschreiben
            $check = $this->db->query("SELECT rowid FROM ".$this->db->prefix()."extrafields"
                ." WHERE name = '".$this->db->escape($name)."'"
                ." AND elementtype = 'facture'");
            if ($check && $this->db->num_rows($check) > 0) {
                continue;
            }
            $extrafields->addExtraField(
                $name,
                $def['label'],
                $def['type'],
                $def['pos'],
                $def['size'],
                'facture',
                0, 0, '', '', 1, '', 0, 0, '', '', 'bericht@bericht', '1'
            );
        }

        $sql = array();
        return $this->_init($sql, $options);
    }

    /**
     *  Beim Deaktivieren: Konstanten/Permissions entfernen, Daten und Extrafields BLEIBEN erhalten.
     */
    public function remove($options = '')
    {
        $sql = array();
        return $this->_remove($sql, $options);
    }
}
