feat(dokuwiki): Implement single-page DokuWiki integration
- Simplified architecture: ONE central documentation page per equipment
- Wiki ID generation from equipment name (e.g., 'sabako-laser')
- Namespace structure: werkstatt:ausruestung:doku:{name}
- View pages by area: werkstatt:ausruestung:{area}:{name}
- Smart page protection: central doku only created once, not overwritten
- View pages update on each sync (shows current Odoo metadata)
- Template detection: distinguishes real content from DokuWiki auto-templates
- JSONB multilingual name field handling
- Include Plugin integration for embedded content display
- Automatic sync option via write() override
- Configuration via System Parameters (url, user, password)
- Settings page in General Settings for easy credential management
This commit is contained in:
parent
5057985024
commit
e53c4028c9
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -159,3 +159,8 @@ cython_debug/
|
|||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# DokuWiki API Test Script (enthält Credentials)
|
||||
test_dokuwiki.py
|
||||
|
||||
# Python Virtual Environment
|
||||
venv/
|
||||
|
|
|
|||
3
open_workshop_dokuwiki/__init__.py
Normal file
3
open_workshop_dokuwiki/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
from .hooks import post_init_hook
|
||||
52
open_workshop_dokuwiki/__manifest__.py
Normal file
52
open_workshop_dokuwiki/__manifest__.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'Open Workshop - DokuWiki Integration',
|
||||
'version': '18.0.1.0.0',
|
||||
'category': 'Maintenance',
|
||||
'summary': 'Synchronisiert Equipment-Daten mit DokuWiki für Dokumentation',
|
||||
'description': """
|
||||
Open Workshop DokuWiki Integration
|
||||
===================================
|
||||
|
||||
Dieses Modul synchronisiert Equipment-Daten aus Odoo mit einem DokuWiki System.
|
||||
|
||||
Features:
|
||||
---------
|
||||
* Automatische Erstellung von Wiki-Seiten für Equipment
|
||||
* Multi-View Architektur (nach Bereich, nach Einsatzzweck)
|
||||
* Zentrale Dokumentation mit Unterseiten
|
||||
* Include-basierte Struktur für flexible Darstellung
|
||||
* Smart Button "Wiki öffnen" im Equipment-Formular
|
||||
* Automatische Synchronisation bei Equipment-Änderungen
|
||||
|
||||
Architektur:
|
||||
------------
|
||||
* Odoo generiert Hauptseiten (read-only für Users)
|
||||
* Zentrale Dokumentation unter werkstatt:ausruestung:_doku:{equipment_id}
|
||||
* Users editieren Unterseiten: _doku:{equipment_id}:bedienung, :wartung, :tipps
|
||||
* Hauptseiten inkludieren zentrale Dokumentation via DokuWiki Include Plugin
|
||||
|
||||
ACL:
|
||||
----
|
||||
* Phase 1: Nur @odoo Gruppe hat Zugriff
|
||||
* Phase 2: @werkstatt bekommt Lesezugriff auf Hauptseiten, Edit-Zugriff auf Doku-Seiten
|
||||
""",
|
||||
'author': 'Open Workshop',
|
||||
'website': 'https://hobbyhimmel.de',
|
||||
'license': 'LGPL-3',
|
||||
'depends': [
|
||||
'open_workshop_base',
|
||||
'maintenance',
|
||||
],
|
||||
'external_dependencies': {
|
||||
'python': ['dokuwiki'],
|
||||
},
|
||||
'data': [
|
||||
'data/ir_config_parameter.xml',
|
||||
'views/maintenance_equipment_views.xml',
|
||||
],
|
||||
'post_init_hook': 'post_init_hook',
|
||||
'installable': True,
|
||||
'application': False,
|
||||
'auto_install': False,
|
||||
}
|
||||
8
open_workshop_dokuwiki/data/ir_config_parameter.xml
Normal file
8
open_workshop_dokuwiki/data/ir_config_parameter.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!--
|
||||
DokuWiki System Parameters werden über post_init_hook initialisiert
|
||||
Dadurch werden sie bei Install und Update korrekt gehandhabt
|
||||
und User-Änderungen bleiben erhalten
|
||||
-->
|
||||
</odoo>
|
||||
8
open_workshop_dokuwiki/hooks.py
Normal file
8
open_workshop_dokuwiki/hooks.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
def post_init_hook(env):
|
||||
"""
|
||||
Hook der nach der Modul-Installation ausgeführt wird.
|
||||
Initialisiert die DokuWiki-Parameter falls sie nicht existieren.
|
||||
"""
|
||||
env['res.config.settings']._init_dokuwiki_parameters()
|
||||
4
open_workshop_dokuwiki/models/__init__.py
Normal file
4
open_workshop_dokuwiki/models/__init__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import dokuwiki_client
|
||||
from . import maintenance_equipment
|
||||
from . import res_config_settings
|
||||
177
open_workshop_dokuwiki/models/dokuwiki_client.py
Normal file
177
open_workshop_dokuwiki/models/dokuwiki_client.py
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
from dokuwiki import DokuWiki, DokuWikiError
|
||||
from odoo import api, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DokuWikiClient(models.AbstractModel):
|
||||
"""
|
||||
Wrapper für DokuWiki XML-RPC API Client.
|
||||
Managed die Verbindung zum DokuWiki und stellt Methoden für Seitenoperationen bereit.
|
||||
"""
|
||||
_name = 'dokuwiki.client'
|
||||
_description = 'DokuWiki API Client'
|
||||
|
||||
@api.model
|
||||
def _get_wiki_connection(self):
|
||||
"""
|
||||
Erstellt eine DokuWiki-Verbindung mit Credentials aus System-Parametern.
|
||||
|
||||
Returns:
|
||||
DokuWiki: Verbundenes DokuWiki-Client-Objekt
|
||||
|
||||
Raises:
|
||||
UserError: Wenn Konfiguration fehlt oder Verbindung fehlschlägt
|
||||
"""
|
||||
IrConfigParameter = self.env['ir.config_parameter'].sudo()
|
||||
|
||||
# Credentials aus System-Parametern holen
|
||||
wiki_url = IrConfigParameter.get_param('dokuwiki.url')
|
||||
wiki_user = IrConfigParameter.get_param('dokuwiki.user')
|
||||
wiki_password = IrConfigParameter.get_param('dokuwiki.password')
|
||||
|
||||
if not all([wiki_url, wiki_user, wiki_password]):
|
||||
raise UserError(
|
||||
"DokuWiki-Konfiguration unvollständig. "
|
||||
"Bitte unter Einstellungen → Technisch → Parameter → Systemparameter konfigurieren:\n"
|
||||
"- dokuwiki.url\n"
|
||||
"- dokuwiki.user\n"
|
||||
"- dokuwiki.password"
|
||||
)
|
||||
|
||||
try:
|
||||
wiki = DokuWiki(wiki_url, wiki_user, wiki_password)
|
||||
# Test-Verbindung
|
||||
version = wiki.version
|
||||
_logger.info(f"DokuWiki-Verbindung erfolgreich: {version}")
|
||||
return wiki
|
||||
except DokuWikiError as e:
|
||||
_logger.error(f"DokuWiki-Verbindung fehlgeschlagen: {e}")
|
||||
raise UserError(f"Verbindung zu DokuWiki fehlgeschlagen: {e}")
|
||||
|
||||
@api.model
|
||||
def create_page(self, page_id, content, summary="Erstellt von Odoo"):
|
||||
"""
|
||||
Erstellt oder aktualisiert eine DokuWiki-Seite.
|
||||
|
||||
Args:
|
||||
page_id (str): DokuWiki Page-ID (z.B. "werkstatt:ausruestung:holzwerkstatt:maschine1")
|
||||
content (str): Wiki-Markup-Inhalt der Seite
|
||||
summary (str): Änderungskommentar für die Wiki-History
|
||||
|
||||
Returns:
|
||||
bool: True bei Erfolg
|
||||
|
||||
Raises:
|
||||
UserError: Bei API-Fehlern
|
||||
"""
|
||||
wiki = self._get_wiki_connection()
|
||||
|
||||
try:
|
||||
wiki.pages.set(page_id, content, summary=summary)
|
||||
_logger.info(f"Wiki-Seite erstellt/aktualisiert: {page_id}")
|
||||
return True
|
||||
except DokuWikiError as e:
|
||||
_logger.error(f"Fehler beim Erstellen der Wiki-Seite {page_id}: {e}")
|
||||
raise UserError(f"Fehler beim Erstellen der Wiki-Seite: {e}")
|
||||
|
||||
@api.model
|
||||
def get_page(self, page_id):
|
||||
"""
|
||||
Liest den Inhalt einer DokuWiki-Seite.
|
||||
|
||||
Args:
|
||||
page_id (str): DokuWiki Page-ID
|
||||
|
||||
Returns:
|
||||
str: Wiki-Markup-Inhalt der Seite (leer wenn Seite nicht existiert)
|
||||
"""
|
||||
wiki = self._get_wiki_connection()
|
||||
|
||||
try:
|
||||
content = wiki.pages.get(page_id)
|
||||
return content or ""
|
||||
except DokuWikiError as e:
|
||||
_logger.warning(f"Fehler beim Lesen der Wiki-Seite {page_id}: {e}")
|
||||
return ""
|
||||
|
||||
@api.model
|
||||
def page_exists(self, page_id):
|
||||
"""
|
||||
Prüft ob eine DokuWiki-Seite existiert.
|
||||
|
||||
Args:
|
||||
page_id (str): DokuWiki Page-ID
|
||||
|
||||
Returns:
|
||||
bool: True wenn Seite existiert
|
||||
"""
|
||||
content = self.get_page(page_id)
|
||||
return bool(content.strip())
|
||||
|
||||
@api.model
|
||||
def delete_page(self, page_id, summary="Gelöscht von Odoo"):
|
||||
"""
|
||||
Löscht eine DokuWiki-Seite (setzt Inhalt auf leer).
|
||||
|
||||
Args:
|
||||
page_id (str): DokuWiki Page-ID
|
||||
summary (str): Änderungskommentar für die Wiki-History
|
||||
|
||||
Returns:
|
||||
bool: True bei Erfolg
|
||||
"""
|
||||
wiki = self._get_wiki_connection()
|
||||
|
||||
try:
|
||||
wiki.pages.set(page_id, "", summary=summary)
|
||||
_logger.info(f"Wiki-Seite gelöscht: {page_id}")
|
||||
return True
|
||||
except DokuWikiError as e:
|
||||
_logger.error(f"Fehler beim Löschen der Wiki-Seite {page_id}: {e}")
|
||||
raise UserError(f"Fehler beim Löschen der Wiki-Seite: {e}")
|
||||
|
||||
@api.model
|
||||
def list_pages(self, namespace):
|
||||
"""
|
||||
Listet alle Seiten in einem DokuWiki-Namespace auf.
|
||||
|
||||
Args:
|
||||
namespace (str): DokuWiki-Namespace (z.B. "werkstatt:ausruestung")
|
||||
|
||||
Returns:
|
||||
list: Liste von Dictionaries mit Page-Informationen
|
||||
"""
|
||||
wiki = self._get_wiki_connection()
|
||||
|
||||
try:
|
||||
pages = wiki.pages.list(namespace)
|
||||
return pages
|
||||
except DokuWikiError as e:
|
||||
_logger.error(f"Fehler beim Auflisten des Namespace {namespace}: {e}")
|
||||
return []
|
||||
|
||||
@api.model
|
||||
def get_wiki_url(self, page_id):
|
||||
"""
|
||||
Generiert die vollständige URL zu einer DokuWiki-Seite.
|
||||
|
||||
Args:
|
||||
page_id (str): DokuWiki Page-ID
|
||||
|
||||
Returns:
|
||||
str: Vollständige URL zur Wiki-Seite
|
||||
"""
|
||||
IrConfigParameter = self.env['ir.config_parameter'].sudo()
|
||||
wiki_url = IrConfigParameter.get_param('dokuwiki.url', '')
|
||||
|
||||
if not wiki_url:
|
||||
return ""
|
||||
|
||||
# Entferne trailing slash falls vorhanden
|
||||
wiki_url = wiki_url.rstrip('/')
|
||||
|
||||
return f"{wiki_url}/doku.php?id={page_id}"
|
||||
354
open_workshop_dokuwiki/models/maintenance_equipment.py
Normal file
354
open_workshop_dokuwiki/models/maintenance_equipment.py
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MaintenanceEquipment(models.Model):
|
||||
_inherit = 'maintenance.equipment'
|
||||
|
||||
# Wiki-Felder
|
||||
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")'
|
||||
)
|
||||
wiki_page_url = fields.Char(
|
||||
string='Wiki-Seiten URL',
|
||||
compute='_compute_wiki_page_url',
|
||||
help='URL zur Wiki-Seite im Browser'
|
||||
)
|
||||
wiki_synced = fields.Boolean(
|
||||
string='Wiki synchronisiert',
|
||||
default=False,
|
||||
help='Gibt an, ob die Wiki-Seite aktuell ist'
|
||||
)
|
||||
wiki_last_sync = fields.Datetime(
|
||||
string='Letzte Wiki-Synchronisation',
|
||||
readonly=True,
|
||||
help='Zeitpunkt der letzten erfolgreichen Wiki-Synchronisation'
|
||||
)
|
||||
wiki_auto_sync = fields.Boolean(
|
||||
string='Automatische Wiki-Synchronisation',
|
||||
default=True,
|
||||
help='Bei Änderungen automatisch zum Wiki synchronisieren'
|
||||
)
|
||||
|
||||
@api.depends('ows_area_id')
|
||||
def _compute_wiki_page_url(self):
|
||||
"""
|
||||
Berechnet die URL zur Haupt-Wiki-Seite (nach Bereich).
|
||||
"""
|
||||
dokuwiki_client = self.env['dokuwiki.client']
|
||||
|
||||
for record in self:
|
||||
wiki_doku_id = record._get_wiki_doku_id()
|
||||
if wiki_doku_id and record.ows_area_id:
|
||||
page_id = record._get_wiki_page_id_by_area()
|
||||
record.wiki_page_url = dokuwiki_client.get_wiki_url(page_id)
|
||||
else:
|
||||
record.wiki_page_url = False
|
||||
|
||||
def _get_wiki_doku_id(self):
|
||||
"""
|
||||
Generiert die Wiki-Dokumentations-ID aus dem Equipment-Namen.
|
||||
Format: normalisierter_name (z.B. "formatkreissaege", "tischkreissaege")
|
||||
|
||||
Returns:
|
||||
str: Wiki-Doku-ID oder False wenn keine ID vorhanden
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
# Verwende wiki_doku_id falls bereits gesetzt
|
||||
if self.wiki_doku_id:
|
||||
return self.wiki_doku_id
|
||||
|
||||
# Generiere aus Equipment-Namen
|
||||
if self.name:
|
||||
return self._normalize_wiki_name(self.name)
|
||||
|
||||
return False
|
||||
|
||||
def _get_wiki_page_id_by_area(self):
|
||||
"""
|
||||
Generiert die Wiki-Page-ID für die Bereichs-Ansicht.
|
||||
Format: werkstatt:ausruestung:{area_name}:{wiki_doku_id}
|
||||
|
||||
Returns:
|
||||
str: Page-ID
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
if not self.ows_area_id:
|
||||
return False
|
||||
|
||||
# Area-Name normalisieren (Umlaute, Leerzeichen, Sonderzeichen)
|
||||
area_name = self._normalize_wiki_name(self.ows_area_id.name)
|
||||
|
||||
wiki_doku_id = self._get_wiki_doku_id()
|
||||
return f"werkstatt:ausruestung:{area_name}:{wiki_doku_id}"
|
||||
|
||||
def _get_wiki_doku_page_id(self):
|
||||
"""
|
||||
Generiert die Wiki-Page-ID für die zentrale Dokumentation.
|
||||
Format: werkstatt:ausruestung:doku:{wiki_doku_id}
|
||||
|
||||
Returns:
|
||||
str: Page-ID der zentralen Doku
|
||||
"""
|
||||
self.ensure_one()
|
||||
wiki_doku_id = self._get_wiki_doku_id()
|
||||
return f"werkstatt:ausruestung:doku:{wiki_doku_id}"
|
||||
|
||||
def _normalize_wiki_name(self, name):
|
||||
"""
|
||||
Normalisiert einen Namen für DokuWiki-Page-IDs.
|
||||
- Umlaute ersetzen
|
||||
- Leerzeichen und Sonderzeichen durch Bindestriche ersetzen
|
||||
- Kleinbuchstaben
|
||||
|
||||
Args:
|
||||
name (str): Original-Name
|
||||
|
||||
Returns:
|
||||
str: Normalisierter Name
|
||||
"""
|
||||
if not name:
|
||||
return "unnamed"
|
||||
|
||||
# Umlaute ersetzen
|
||||
replacements = {
|
||||
'ä': 'ae', 'ö': 'oe', 'ü': 'ue',
|
||||
'Ä': 'ae', 'Ö': 'oe', 'Ü': 'ue',
|
||||
'ß': 'ss'
|
||||
}
|
||||
for old, new in replacements.items():
|
||||
name = name.replace(old, new)
|
||||
|
||||
# Nur alphanumerische Zeichen und Bindestriche
|
||||
name = re.sub(r'[^a-zA-Z0-9\-_]', '-', name)
|
||||
|
||||
# Mehrfache Bindestriche durch einen ersetzen
|
||||
name = re.sub(r'-+', '-', name)
|
||||
|
||||
# Führende/Trailing Bindestriche entfernen
|
||||
name = name.strip('-')
|
||||
|
||||
# Kleinbuchstaben
|
||||
name = name.lower()
|
||||
|
||||
return name or "unnamed"
|
||||
|
||||
def _generate_wiki_main_page_content(self, view_type='area'):
|
||||
"""
|
||||
Generiert den Wiki-Markup-Inhalt für eine Haupt-Ansichtsseite.
|
||||
|
||||
Args:
|
||||
view_type (str): 'area' oder 'purpose'
|
||||
|
||||
Returns:
|
||||
str: Wiki-Markup-Inhalt
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
# Zentrale Doku-Seite einbinden
|
||||
doku_page_id = self._get_wiki_doku_page_id()
|
||||
|
||||
# Header je nach View-Typ
|
||||
if view_type == 'area':
|
||||
view_name = self.ows_area_id.name if self.ows_area_id else "Unbekannt"
|
||||
view_label = "Bereich"
|
||||
else:
|
||||
# Später für Einsatzzweck
|
||||
view_name = "TODO: Einsatzzweck"
|
||||
view_label = "Einsatzzweck"
|
||||
|
||||
content = f"""====== {self.name} ======
|
||||
|
||||
**{view_label}:** {view_name}
|
||||
**Kategorie:** {self.category_id.name if self.category_id else 'Keine'}
|
||||
**Seriennummer:** {self.serial_no or 'Keine'}
|
||||
|
||||
===== Dokumentation =====
|
||||
{{{{page>{doku_page_id}&noheader}}}}
|
||||
|
||||
----
|
||||
[[{doku_page_id}|✏️ Zentrale Dokumentation bearbeiten]]
|
||||
|
||||
//Letzte Synchronisation: {datetime.now().strftime('%d.%m.%Y %H:%M')} von Odoo//
|
||||
"""
|
||||
return content
|
||||
|
||||
def _generate_wiki_doku_page_content(self):
|
||||
"""
|
||||
Generiert den initialen Wiki-Markup-Inhalt für die zentrale Dokumentationsseite.
|
||||
Einfacher Basis-Inhalt, den der Nutzer nach Belieben erweitern kann.
|
||||
|
||||
Returns:
|
||||
str: Wiki-Markup-Inhalt
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
content = f"""====== {self.name} - Dokumentation ======
|
||||
|
||||
**Bereich:** {self.ows_area_id.name if self.ows_area_id else 'Nicht zugeordnet'}
|
||||
**Kategorie:** {self.category_id.name if self.category_id else 'Keine'}
|
||||
**Seriennummer:** {self.serial_no or 'Keine'}
|
||||
|
||||
===== Beschreibung =====
|
||||
|
||||
Hier kann die Dokumentation für {self.name} geschrieben werden.
|
||||
|
||||
**Mögliche Inhalte:**
|
||||
* Bedienungsanleitung
|
||||
* Wartungshinweise
|
||||
* Sicherheitshinweise
|
||||
* Tipps & Tricks
|
||||
|
||||
//Hinweis: Diese Seite kann beliebig strukturiert werden. Unterseiten können bei Bedarf manuell angelegt werden.//
|
||||
|
||||
----
|
||||
//Erstellt: {datetime.now().strftime('%d.%m.%Y %H:%M')} von Odoo//
|
||||
"""
|
||||
return content
|
||||
|
||||
def sync_to_dokuwiki(self):
|
||||
"""
|
||||
Synchronisiert Equipment-Daten zum DokuWiki.
|
||||
Erstellt/aktualisiert:
|
||||
- wiki_doku_id beim ersten Sync (falls noch nicht gesetzt)
|
||||
- Zentrale Dokumentationsseite (_doku:) - nur wenn sie noch nicht existiert
|
||||
- Haupt-Ansichtsseite nach Bereich (wird immer aktualisiert)
|
||||
- TODO: Später auch nach Einsatzzweck
|
||||
|
||||
Returns:
|
||||
bool: True bei Erfolg
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
if not self.ows_area_id:
|
||||
raise UserError("Bereich muss gesetzt sein für Wiki-Synchronisation!")
|
||||
|
||||
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 generieren)
|
||||
if not self.wiki_doku_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}")
|
||||
|
||||
dokuwiki_client = self.env['dokuwiki.client']
|
||||
|
||||
try:
|
||||
# 1. Zentrale Dokumentationsseite erstellen (immer beim ersten Sync)
|
||||
doku_page_id = self._get_wiki_doku_page_id()
|
||||
|
||||
# Prüfen ob Seite mit echtem Inhalt existiert (nicht nur leere Template-Seite)
|
||||
page_has_content = False
|
||||
try:
|
||||
existing_content = dokuwiki_client.get_page(doku_page_id)
|
||||
# Prüfen ob es echten Inhalt hat (mehr als 100 Zeichen und nicht nur Template)
|
||||
if existing_content and len(existing_content) > 100 and 'catlist' not in existing_content.lower():
|
||||
page_has_content = True
|
||||
_logger.info(f"Zentrale Doku-Seite hat bereits Inhalt: {doku_page_id}")
|
||||
except Exception as e:
|
||||
_logger.debug(f"Seite existiert noch nicht: {e}")
|
||||
|
||||
if not page_has_content:
|
||||
doku_content = self._generate_wiki_doku_page_content()
|
||||
dokuwiki_client.create_page(
|
||||
doku_page_id,
|
||||
doku_content,
|
||||
f"Initial erstellt von Odoo: {self.name}"
|
||||
)
|
||||
_logger.info(f"Zentrale Doku-Seite für {self.name} erstellt: {doku_page_id}")
|
||||
else:
|
||||
_logger.info(f"Zentrale Doku-Seite für {self.name} existiert bereits: {doku_page_id}")
|
||||
|
||||
# 2. Haupt-Ansichtsseite nach Bereich erstellen/aktualisieren
|
||||
area_page_id = self._get_wiki_page_id_by_area()
|
||||
area_content = self._generate_wiki_main_page_content(view_type='area')
|
||||
dokuwiki_client.create_page(
|
||||
area_page_id,
|
||||
area_content,
|
||||
f"Synchronisiert von Odoo: {self.name}"
|
||||
)
|
||||
|
||||
# TODO: Später auch nach Einsatzzweck synchronisieren
|
||||
|
||||
# Sync-Status aktualisieren
|
||||
self.write({
|
||||
'wiki_synced': True,
|
||||
'wiki_last_sync': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
_logger.info(f"Equipment {self.name} erfolgreich zu DokuWiki synchronisiert")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
_logger.error(f"Fehler bei Wiki-Synchronisation für {self.name}: {e}")
|
||||
self.write({'wiki_synced': False})
|
||||
raise UserError(f"Wiki-Synchronisation fehlgeschlagen: {e}")
|
||||
|
||||
def action_sync_to_dokuwiki(self):
|
||||
"""
|
||||
Button-Action für manuelle Wiki-Synchronisation.
|
||||
"""
|
||||
for record in self:
|
||||
record.sync_to_dokuwiki()
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('Wiki-Synchronisation'),
|
||||
'message': _('Equipment wurde erfolgreich zum Wiki synchronisiert.'),
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
}
|
||||
}
|
||||
|
||||
def action_open_wiki(self):
|
||||
"""
|
||||
Button-Action zum Öffnen der Wiki-Seite im Browser.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
if not self.wiki_page_url:
|
||||
raise UserError("Wiki-URL nicht verfügbar. Bitte erst zum Wiki synchronisieren.")
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': self.wiki_page_url,
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def write(self, vals):
|
||||
"""
|
||||
Override write um automatische Synchronisation zu triggern.
|
||||
"""
|
||||
result = super().write(vals)
|
||||
|
||||
# Felder die eine Synchronisation auslösen
|
||||
sync_fields = {'name', 'serial_no', 'area_id', 'category_id'}
|
||||
|
||||
if sync_fields & set(vals.keys()):
|
||||
# Nur synchronisieren wenn auto_sync aktiviert und bereits synced
|
||||
for record in self:
|
||||
if record.wiki_auto_sync and record.wiki_synced:
|
||||
try:
|
||||
record.sync_to_dokuwiki()
|
||||
except Exception as e:
|
||||
_logger.warning(f"Automatische Wiki-Sync fehlgeschlagen: {e}")
|
||||
# Nicht abbrechen, nur loggen
|
||||
else:
|
||||
# Sync-Status zurücksetzen
|
||||
record.write({'wiki_synced': False})
|
||||
|
||||
return result
|
||||
30
open_workshop_dokuwiki/models/res_config_settings.py
Normal file
30
open_workshop_dokuwiki/models/res_config_settings.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
from odoo import api, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
@api.model
|
||||
def _init_dokuwiki_parameters(self):
|
||||
"""
|
||||
Initialisiert DokuWiki-Parameter beim Modul-Install falls sie nicht existieren.
|
||||
Wird automatisch beim Laden des Moduls aufgerufen.
|
||||
"""
|
||||
IrConfigParameter = self.env['ir.config_parameter'].sudo()
|
||||
|
||||
# Default-Parameter
|
||||
defaults = {
|
||||
'dokuwiki.url': 'https://wiki.hobbyhimmel.de',
|
||||
'dokuwiki.user': 'odoo.odoo',
|
||||
'dokuwiki.password': 'CHANGE_ME',
|
||||
}
|
||||
|
||||
# Nur fehlende Parameter anlegen
|
||||
for key, value in defaults.items():
|
||||
if not IrConfigParameter.get_param(key):
|
||||
IrConfigParameter.set_param(key, value)
|
||||
_logger.info(f"DokuWiki parameter '{key}' initialized with default value")
|
||||
74
open_workshop_dokuwiki/views/maintenance_equipment_views.xml
Normal file
74
open_workshop_dokuwiki/views/maintenance_equipment_views.xml
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Equipment Form View Extension -->
|
||||
<record id="maintenance_equipment_view_form_dokuwiki" model="ir.ui.view">
|
||||
<field name="name">maintenance.equipment.form.dokuwiki</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- Smart Button im Header -->
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_open_wiki"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-book"
|
||||
invisible="not wiki_page_url">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_text">Wiki</span>
|
||||
<span class="o_stat_text text-success" invisible="not wiki_synced">Synchronisiert</span>
|
||||
<span class="o_stat_text text-warning" invisible="wiki_synced">Nicht synchronisiert</span>
|
||||
</div>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!-- Wiki-Felder in neuem Tab -->
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Wiki" name="wiki">
|
||||
<group>
|
||||
<group string="Wiki-Synchronisation">
|
||||
<field name="wiki_doku_id" readonly="1"/>
|
||||
<field name="wiki_page_url" widget="url" readonly="1"/>
|
||||
<field name="wiki_synced" readonly="1"/>
|
||||
<field name="wiki_last_sync" readonly="1"/>
|
||||
<field name="wiki_auto_sync"/>
|
||||
</group>
|
||||
<group string="Aktionen">
|
||||
<button name="action_sync_to_dokuwiki"
|
||||
string="Zum Wiki synchronisieren"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
icon="fa-refresh"/>
|
||||
<button name="action_open_wiki"
|
||||
string="Wiki im Browser öffnen"
|
||||
type="object"
|
||||
class="btn-secondary"
|
||||
icon="fa-external-link"
|
||||
invisible="not wiki_page_url"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group string="Hilfe">
|
||||
<div class="alert alert-info" role="alert">
|
||||
<h4 class="alert-heading">DokuWiki-Integration</h4>
|
||||
<p>
|
||||
Dieses Equipment ist mit DokuWiki verbunden. Die Synchronisation erstellt:
|
||||
</p>
|
||||
<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>
|
||||
</ul>
|
||||
<hr/>
|
||||
<p class="mb-0">
|
||||
<strong>Automatische Synchronisation:</strong> Wenn aktiviert, werden Änderungen automatisch zum Wiki übertragen.
|
||||
</p>
|
||||
</div>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue
Block a user