feat(dokuwiki): Trennung von wiki_status_id und wiki_doku_id, verbesserte UI

- Neues Feld wiki_status_id: Eindeutige ID für Odoo-Status-Seite (name-seriennummer)
- Überarbeitung wiki_doku_id: Editierbar, für Benutzer-Dokumentation (Duplikate erlaubt)
- Funktion _get_wiki_doku_page_id → _get_wiki_status_page_id (bessere Benennung)
- Template-Platzhalter: wiki_doku_page/link → wiki_status_page/link
- Pre-Migration-Script für Upgrade ohne Fehler (18.0.2.1.0)

View-Verbesserungen:
- 3-spaltige Darstellung: Wiki Status Seite | Wiki Dokumentations Seite
- Separate Gruppe für Wiki URL
- Erweiterte Hilfe mit Unterscheidung Status-/Doku-Seite
- Include-Plugin-Beispiel für DokuWiki-Integration

Version: 18.0.2.0.0 → 18.0.2.1.0
This commit is contained in:
Matthias Lotz 2026-01-18 13:47:38 +01:00
parent b85ec97d9c
commit 0d27ca36b0
4 changed files with 171 additions and 44 deletions

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
{
'name': 'Open Workshop - DokuWiki Integration',
'version': '18.0.2.0.0',
'version': '18.0.2.1.0',
'category': 'Maintenance',
'summary': 'Synchronisiert Equipment-Daten mit DokuWiki für Dokumentation',
'description': """

View File

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
"""
Pre-Migration Script für open_workshop_dokuwiki 18.0.2.0.0
Fügt die neuen Felder wiki_status_id und wiki_doku_id zur Datenbank hinzu,
BEVOR die Views validiert werden.
Dieses Script wird automatisch vor dem Upgrade ausgeführt.
"""
import logging
_logger = logging.getLogger(__name__)
def migrate(cr, version):
"""
Fügt die neuen Wiki-ID-Felder zur maintenance_equipment Tabelle hinzu.
Args:
cr: Database cursor
version: Aktuelle Version vor dem Upgrade
"""
_logger.info("=== Pre-Migration: Füge wiki_status_id und wiki_doku_id Felder hinzu ===")
# Prüfe ob die Felder bereits existieren
cr.execute("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'maintenance_equipment'
AND column_name IN ('wiki_status_id', 'wiki_doku_id')
""")
existing_fields = [row[0] for row in cr.fetchall()]
# Füge wiki_status_id hinzu falls nicht vorhanden
if 'wiki_status_id' not in existing_fields:
_logger.info("Füge Spalte wiki_status_id hinzu...")
cr.execute("""
ALTER TABLE maintenance_equipment
ADD COLUMN wiki_status_id VARCHAR
""")
_logger.info("✓ wiki_status_id hinzugefügt")
else:
_logger.info("wiki_status_id existiert bereits")
# Füge wiki_doku_id hinzu falls nicht vorhanden
if 'wiki_doku_id' not in existing_fields:
_logger.info("Füge Spalte wiki_doku_id hinzu...")
cr.execute("""
ALTER TABLE maintenance_equipment
ADD COLUMN wiki_doku_id VARCHAR
""")
_logger.info("✓ wiki_doku_id hinzugefügt")
else:
_logger.info("wiki_doku_id existiert bereits")
_logger.info("=== Pre-Migration abgeschlossen ===")

View File

@ -41,8 +41,8 @@ class MaintenanceEquipment(models.Model):
generiert, das folgende Platzhalter unterstützt:
- {feldname} - Direkte Equipment-Felder (z.B. {name}, {serial_no})
- {ows_machine_id.feldname} - Maschinenfelder (z.B. {ows_machine_id.power})
- {wiki_doku_page} - ID der zentralen Dokumentationsseite
- {wiki_doku_link} - DokuWiki-Link zur Dokumentationsseite
- {wiki_status_page} - ID der Odoo-Status-Seite
- {wiki_status_link} - DokuWiki-Link zur Odoo-Status-Seite
- {image} - Bild-Einbindung (wird automatisch hochgeladen)
- {tags} - Komma-separierte Tag-Liste
- {sync_datetime} - Zeitstempel der Synchronisation
@ -80,10 +80,15 @@ class MaintenanceEquipment(models.Model):
)
# Wiki-Felder
wiki_status_id = fields.Char(
string='Wiki Status-ID',
readonly=True,
help='Eindeutige ID für die Odoo-Status-Seite (automatisch generiert aus Name + Seriennummer, z.B. "formatkreissaege-eq001")'
)
wiki_doku_id = fields.Char(
string='Wiki Dokumentations-ID',
readonly=True,
help='Eindeutige ID für die zentrale Wiki-Dokumentation (generiert aus Equipment-Namen, z.B. "formatkreissaege", und Modell "bosch-abc" -> "formatkreissaege-bosch-abc")'
readonly=False,
help='ID für die Benutzer-Dokumentationsseite (editierbar, initial aus Equipment-Namen generiert, z.B. "formatkreissaege"). Mehrere Equipment können die gleiche ID nutzen.'
)
wiki_page_url = fields.Char(
string='Wiki-Seiten URL',
@ -121,12 +126,45 @@ class MaintenanceEquipment(models.Model):
else:
record.wiki_page_url = False
def _get_wiki_status_id(self):
"""
Generiert die Wiki-Status-ID aus Equipment-Namen und comp_serial_no.
Format: normalisierter_name-comp_serial_no (z.B. "formatkreissaege-eq001")
Diese ID ist eindeutig und wird für die Odoo-Status-Seite und Media-Dateien verwendet.
Die comp_serial_no wird automatisch generiert falls noch nicht vorhanden.
Returns:
str: Wiki-Status-ID oder False wenn kein Name vorhanden
"""
self.ensure_one()
# Verwende wiki_status_id falls bereits gesetzt
if self.wiki_status_id:
return self.wiki_status_id
# Name ist erforderlich
if not self.name:
return False
# comp_serial_no automatisch generieren falls nicht vorhanden
if not self.comp_serial_no:
self.generate_serial_no()
# Refresh nach generate_serial_no
self.refresh()
# wiki_status_id aus Name + comp_serial_no generieren
normalized_name = self._normalize_wiki_name(self.name)
normalized_serial = self._normalize_wiki_name(self.comp_serial_no)
return f"{normalized_name}-{normalized_serial}"
def _get_wiki_doku_id(self):
"""
Generiert die Wiki-Dokumentations-ID aus Equipment-Namen und comp_serial_no.
Format: normalisierter_name-comp_serial_no (z.B. "formatkreissaege-EQ001")
Generiert die Wiki-Dokumentations-ID aus Equipment-Namen (ohne Seriennummer).
Format: normalisierter_name (z.B. "formatkreissaege")
Die comp_serial_no wird automatisch generiert falls noch nicht vorhanden.
Diese ID ist editierbar und wird für die Benutzer-Dokumentationsseite verwendet.
Mehrere Equipment können die gleiche wiki_doku_id haben (z.B. alle Akkuschrauber).
Returns:
str: Wiki-Doku-ID oder False wenn kein Name vorhanden
@ -141,16 +179,9 @@ class MaintenanceEquipment(models.Model):
if not self.name:
return False
# comp_serial_no automatisch generieren falls nicht vorhanden
if not self.comp_serial_no:
self.generate_serial_no()
# Refresh nach generate_serial_no
self.refresh()
# wiki_doku_id aus Name + comp_serial_no generieren
# wiki_doku_id nur aus Name generieren (Duplikate sind erwünscht)
normalized_name = self._normalize_wiki_name(self.name)
normalized_serial = self._normalize_wiki_name(self.comp_serial_no)
return f"{normalized_name}-{normalized_serial}"
return normalized_name
def _get_wiki_page_id_by_area(self):
"""
@ -181,10 +212,10 @@ class MaintenanceEquipment(models.Model):
wiki_doku_id = self._get_wiki_doku_id()
return f"{equipment_namespace}:{area_name}:{wiki_doku_id}"
def _get_wiki_doku_page_id(self):
def _get_wiki_status_page_id(self):
"""
Generiert die Wiki-Page-ID für die Odoo-Status-Seite (nur lesbar für Benutzer).
Format: {equipment_namespace}:odoo-status:{wiki_doku_id}
Format: {equipment_namespace}:odoo-status:{wiki_status_id}
Diese Seite wird von Odoo generiert und kann mit dem include-Plugin eingebunden werden.
Returns:
@ -199,8 +230,8 @@ class MaintenanceEquipment(models.Model):
default='werkstatt:ausstattung:odoo-status'
)
wiki_doku_id = self._get_wiki_doku_id()
return f"{status_namespace}:{wiki_doku_id}"
wiki_status_id = self._get_wiki_status_id()
return f"{status_namespace}:{wiki_status_id}"
def _normalize_wiki_name(self, name):
"""
@ -250,8 +281,8 @@ class MaintenanceEquipment(models.Model):
Platzhalter-Format:
- {feldname} für maintenance.equipment Felder, z.B. {name}, {serial_no}
- {ows_machine_id.feldname} für ows.machine Felder, z.B. {ows_machine_id.power}
- {wiki_doku_page} für die zentrale Doku-Seite ID
- {wiki_doku_link} für Link zur zentralen Doku-Seite
- {wiki_status_page} für die Odoo-Status-Seite ID
- {wiki_status_link} für Link zur Odoo-Status-Seite
- {ows_area} für Bereichsname
- {category} für Kategoriename
- {sync_datetime} für aktuelles Datum/Zeit
@ -320,8 +351,8 @@ class MaintenanceEquipment(models.Model):
"""
self.ensure_one()
# Zentrale Doku-Seite
doku_page_id = self._get_wiki_doku_page_id()
# Odoo-Status-Seite
status_page_id = self._get_wiki_status_page_id()
# Odoo Base URL
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', 'http://localhost:8069')
@ -333,8 +364,8 @@ class MaintenanceEquipment(models.Model):
# Basis-Werte für maintenance.equipment
values = {
# Spezielle Werte
'wiki_doku_page': doku_page_id,
'wiki_doku_link': f"[[{doku_page_id}| Wiki Dokumentation]]",
'wiki_status_page': status_page_id,
'wiki_status_link': f"[[{status_page_id}|📊 Odoo Status]]",
'wiki_page_id': wiki_page_id, # Page-ID der Hauptseite (nach Bereich)
'wiki_page_url': self.wiki_page_url or '', # Externe URL zur Hauptseite
'odoo_link': f"[[{odoo_equipment_url}|🔗 In Odoo öffnen]]",
@ -398,7 +429,7 @@ class MaintenanceEquipment(models.Model):
# Bild-Upload und Referenz (falls vorhanden)
if self.image_1920:
wiki_doku_id = self._get_wiki_doku_id()
wiki_status_id = self._get_wiki_status_id()
# Media-ID mit gleicher Namespace-Struktur wie Pages (DokuWiki Best Practice)
IrConfigParameter = self.env['ir.config_parameter'].sudo()
equipment_namespace = IrConfigParameter.get_param(
@ -431,7 +462,7 @@ class MaintenanceEquipment(models.Model):
else:
ext = '.bin'
media_id = f"{equipment_namespace}:{area_name}:{wiki_doku_id}{ext}"
media_id = f"{equipment_namespace}:{area_name}:{wiki_status_id}{ext}"
dokuwiki_client = self.env['dokuwiki.client']
dokuwiki_client.upload_media(media_id, image_bytes, overwrite=True)
@ -555,19 +586,27 @@ class MaintenanceEquipment(models.Model):
if not self.name:
raise UserError("Equipment-Name muss gesetzt sein für Wiki-Synchronisation!")
# wiki_doku_id beim ersten Sync setzen (aus Equipment-Namen und Modell generieren)
# wiki_status_id beim ersten Sync setzen (aus Equipment-Namen und comp_serial_no generieren)
if not self.wiki_status_id:
generated_status_id = self._get_wiki_status_id()
if not generated_status_id:
raise UserError("wiki_status_id konnte nicht generiert werden!")
self.write({'wiki_status_id': generated_status_id})
_logger.info(f"Wiki-Status-ID für {self.name} gesetzt: {generated_status_id}")
# wiki_doku_id beim ersten Sync setzen (aus Equipment-Namen generieren, editierbar)
if not self.wiki_doku_id:
generated_id = self._get_wiki_doku_id()
if not generated_id:
generated_id = self._normalize_wiki_name(self.name)
self.write({'wiki_doku_id': generated_id})
_logger.info(f"Wiki-Doku-ID für {self.name} gesetzt: {generated_id}")
generated_doku_id = self._get_wiki_doku_id()
if not generated_doku_id:
generated_doku_id = self._normalize_wiki_name(self.name)
self.write({'wiki_doku_id': generated_doku_id})
_logger.info(f"Wiki-Doku-ID für {self.name} gesetzt: {generated_doku_id}")
dokuwiki_client = self.env['dokuwiki.client']
try:
# Odoo-Status-Seite erstellen/aktualisieren (immer beim Sync)
status_page_id = self._get_wiki_doku_page_id()
status_page_id = self._get_wiki_status_page_id()
status_content = self._generate_wiki_main_page_content(view_type='area')
dokuwiki_client.create_page(
@ -875,7 +914,8 @@ Diese Seite wird automatisch aktualisiert.
equipment_records.write({
'wiki_synced': False,
'wiki_last_sync': False,
'wiki_doku_id': False, # Auskommentiert: Nur aktivieren wenn IDs neu generiert werden sollen
'wiki_status_id': False, # Status-ID neu generieren
'wiki_doku_id': False, # Doku-ID neu generieren
})
_logger.info(f"Wiki-Sync-Status für {count} Equipment zurückgesetzt")

View File

@ -32,13 +32,27 @@
<xpath expr="//notebook" position="inside">
<page string="Wiki" name="wiki">
<group>
<group string="Wiki-Synchronisation">
<field name="wiki_doku_id" readonly="1"/>
<group string="Wiki Seiten Namen" colspan="2">
<group>
<field name="wiki_status_id" string="Wiki Status Seite" readonly="1"/>
</group>
<group>
<field name="wiki_doku_id" string="Wiki Dokumentations Seite"/>
</group>
</group>
</group>
<group>
<group string="Wiki URL">
<field name="wiki_page_url" widget="url" readonly="1"/>
</group>
<group string="Status">
<field name="wiki_synced" readonly="1"/>
<field name="wiki_last_sync" readonly="1"/>
<field name="wiki_auto_sync"/>
</group>
</group>
<group>
<group string="Aktionen">
<button name="action_sync_to_dokuwiki"
string="Zum Wiki synchronisieren"
@ -56,17 +70,34 @@
<group string="Hilfe">
<div class="alert alert-info" role="alert">
<h4 class="alert-heading">DokuWiki-Integration</h4>
<h4 class="alert-heading">📚 DokuWiki-Integration</h4>
<p>
Dieses Equipment ist mit DokuWiki verbunden. Die Synchronisation erstellt:
Dieses Equipment ist mit DokuWiki verbunden. Die Synchronisation erstellt <strong>zwei unterschiedliche Seiten</strong>:
</p>
<hr/>
<h5>📊 Wiki Status Seite (automatisch, nur lesbar)</h5>
<ul>
<li><strong>Zentrale Dokumentation:</strong> werkstatt:ausruestung:doku:<field name="wiki_doku_id" readonly="1" nolabel="1"/></li>
<li><strong>Bereichs-Ansicht:</strong> Nach Bereich gruppiert</li>
<li><strong>Zweck:</strong> Enthält aktuelle Odoo-Daten (Status, Standort, Hersteller etc.)</li>
<li><strong>Format:</strong> werkstatt:ausstattung:odoo-status:[name-seriennummer]</li>
<li><strong>Eindeutigkeit:</strong> Jedes Equipment hat eine eigene Status-Seite</li>
<li><strong>Update:</strong> Wird bei jeder Synchronisation automatisch aktualisiert</li>
</ul>
<h5>📖 Wiki Dokumentations Seite (manuell, editierbar)</h5>
<ul>
<li><strong>Zweck:</strong> Benutzer-Dokumentation, Anleitungen, Tipps</li>
<li><strong>Format:</strong> werkstatt:ausstattung:[bereich]:[doku-name]</li>
<li><strong>Besonderheit:</strong> Kann von mehreren Equipment geteilt werden (z.B. "akkuschrauber")</li>
<li><strong>Erstellung:</strong> Wird NICHT von Odoo erstellt - Benutzer erstellen diese manuell</li>
</ul>
<hr/>
<p class="mb-0">
<strong>Automatische Synchronisation:</strong> Wenn aktiviert, werden Änderungen automatisch zum Wiki übertragen.
<strong>💡 Tipp:</strong> Die Status-Seite kann mit dem include-Plugin in die Dokumentations-Seite eingebunden werden:<br/>
<code>{{page&gt;werkstatt:ausstattung:odoo-status:[name-seriennummer]}}</code>
</p>
<hr/>
<p class="mb-0">
<strong>⚙️ Automatische Synchronisation:</strong> Wenn aktiviert, werden Änderungen automatisch zur Status-Seite übertragen.
</p>
</div>
</group>