feat(dokuwiki): Add equipment overview table with DataTables

- Add _generate_overview_table_row() to generate table row per equipment
- Add action_sync_overview_table() for fast overview page sync
- Add new sync mode 'Übersichtstabelle aktualisieren' in wizard
- Add config parameters for overview page and template IDs
- Add overview_url field to wizard result view
- Columns: Name (linked), Status, Security Category, Area, Location, Image
- Performance: Single page update without iterating all equipment
- Include DokuWiki template and setup documentation
- Requires DokuWiki DataTables plugin for sortable/filterable table
- Fix: Use status_id instead of equipment_status_id
This commit is contained in:
Matthias Lotz 2025-12-19 20:40:29 +01:00
parent 8ae586cca6
commit de317f46e6
6 changed files with 339 additions and 2 deletions

View File

@ -1,4 +1,142 @@
Verfügbare Platzhalter:
# Equipment Übersichtstabelle - Setup
## Voraussetzungen
Das **datatables Plugin** muss in DokuWiki installiert sein:
```bash
# Als DokuWiki Admin: Administration → Erweiterungsverwaltung
# Suche: "datatables"
# Installiere: "DataTables Plugin" von Matthias Schulte
```
## Setup-Schritte
### 1. Template-Seite in DokuWiki erstellen
Erstelle die Seite: `werkstatt:ausruestung:uebersicht_template`
Kopiere den Inhalt aus: `dokuwiki_uebersicht_template.txt`
**Wichtige Platzhalter:**
- `{{EQUIPMENT_TABLE_ROWS}}` → Wird durch Tabellenzeilen ersetzt
- `{{SYNC_DATETIME}}` → Wird durch Sync-Zeitstempel ersetzt
### 2. Odoo Konfiguration (optional)
Falls andere Seitennamen gewünscht:
```python
# In Odoo: Einstellungen → Technisch → Parameter → Systemparameter
dokuwiki.overview_page_id = werkstatt:ausruestung:uebersicht
dokuwiki.overview_template_id = werkstatt:ausruestung:uebersicht_template
```
### 3. Erste Synchronisation
1. In Odoo: **Wartung → Konfiguration → Wiki-Synchronisation**
2. Wähle: **"Übersichtstabelle aktualisieren"**
3. Klicke: **"Synchronisieren"**
Die Übersichtsseite wird erstellt unter: `werkstatt:ausruestung:uebersicht`
## Features
### DataTables Funktionen
- ✅ Sortieren nach allen Spalten (Klick auf Header)
- ✅ Filter/Suche über alle Felder
- ✅ Pagination bei vielen Einträgen
- ✅ Responsive Design
### Spalten
| Spalte | Inhalt | Quelle |
|--------|--------|--------|
| Name | Link zur Detail-Seite | `maintenance.equipment.name` |
| Status | In Betrieb, Wartung, etc. | `equipment_status_id` |
| Sicherheits-Kategorie | 🟢 Grün / 🟡 Gelb / 🔴 Rot | `ows_category` |
| Bereich | Holzwerkstatt, Metallwerkstatt, etc. | `ows_area_id` |
| Standort | Freier Text | `location` |
| Bild | Thumbnail 50px | `image_1920` |
## Performance
- ⚡ Schneller Sync: Keine DB-Iteration über 134 Einträge
- ⚡ Generiert nur eine Seite (statt 134 einzelne)
- ⚡ DokuWiki cached die Seite automatisch
## Troubleshooting
### "Template-Seite nicht gefunden"
→ Erstelle `werkstatt:ausruestung:uebersicht_template` in DokuWiki
### DataTables funktioniert nicht
→ Installiere DataTables Plugin in DokuWiki
### Bilder werden nicht angezeigt
→ Prüfe ob Equipment `image_1920` Feld gesetzt hat
→ Bilder müssen zuerst via "Alle Equipment" Sync hochgeladen werden
### Equipment fehlen in Tabelle
→ Nur Equipment mit gesetztem `ows_area_id` werden angezeigt
→ Prüfe Filter in `action_sync_overview_table()`
## Workflow
```
┌─────────────────┐
│ Odoo Equipment │
│ (134 Einträge) │
└────────┬────────┘
┌─────────────────────────┐
│ _generate_overview_ │
│ table_row() │ ← Pro Equipment eine Zeile
│ (maintenance_equipment) │
└────────┬────────────────┘
│ 134 Zeilen
┌─────────────────────────┐
│ Template laden │
│ werkstatt:ausruestung: │
│ uebersicht_template │
└────────┬────────────────┘
┌─────────────────────────┐
│ Placeholder ersetzen │
│ {{EQUIPMENT_TABLE_ROWS}}│
│ {{SYNC_DATETIME}} │
└────────┬────────────────┘
┌─────────────────────────┐
│ Seite speichern │
│ werkstatt:ausruestung: │
│ uebersicht │
└─────────────────────────┘
```
## Automatische Updates
Die Übersichtstabelle wird **NICHT** automatisch bei Equipment-Änderungen aktualisiert.
**Manueller Sync empfohlen:**
- Nach Massen-Importen
- Einmal täglich/wöchentlich
- Bei strukturellen Änderungen (neue Bereiche, etc.)
**Alternativ: Cronjob einrichten**
```python
# In Odoo: Einstellungen → Technisch → Automatisierung → Geplante Aktionen
Name: Wiki Übersichtstabelle Update
Modell: maintenance.equipment
Aktion: action_sync_overview_table()
Intervall: Täglich um 02:00 Uhr
```
# Verfügbare Platzhalter:
Basis-Felder (maintenance.equipment):

View File

@ -0,0 +1,24 @@
====== Geräte & Maschinen - Übersicht ======
Diese Seite wird automatisch von Odoo aktualisiert und bietet eine sortier- und filterbare Übersicht aller Geräte und Maschinen.
**Letztes Update:** {{SYNC_DATETIME}}
<datatable Equipment-Übersicht>
^ Name ^ Status ^ Sicherheits-Kategorie ^ Bereich ^ Standort ^ Bild ^
{{EQUIPMENT_TABLE_ROWS}}
</datatable>
----
**Hinweis:** Diese Tabelle ist interaktiv:
* Klicken Sie auf die Spaltenköpfe zum Sortieren
* Nutzen Sie das Suchfeld zum Filtern
* Klicken Sie auf den Namen für die Detail-Dokumentation
**Symbole:**
* 🟢 Grün = Keine Einweisung erforderlich
* 🟡 Gelb = Einweisung empfohlen
* 🔴 Rot = Einweisung zwingend erforderlich
//Automatisch generiert aus Odoo - Änderungen werden beim nächsten Sync überschrieben//

View File

@ -532,3 +532,134 @@ Hier kann die Dokumentation für {self.name} geschrieben werden.
record.write({'wiki_synced': False})
return result
# ==========================================
# Übersichtstabelle (DataTable)
# ==========================================
def _generate_overview_table_row(self):
"""
Generiert eine DokuWiki DataTable Zeile für dieses Equipment.
Format: | [[link|Name]] | Status | Kategorie | Bereich | Standort | {{image.jpg?50}} |
Returns:
str: Wiki-Markup für eine Tabellenzeile
"""
self.ensure_one()
# Name mit Link zur Detail-Seite
wiki_doku_id = self._get_wiki_doku_id()
doku_page_id = self._get_wiki_doku_page_id()
name_link = f"[[{doku_page_id}|{self.name}]]" if wiki_doku_id else self.name
# Status (maintenance_equipment_status)
status = self.status_id.name if self.status_id else "-"
# Sicherheitskategorie
category_map = {
'green': '🟢 Grün',
'yellow': '🟡 Gelb',
'red': '🔴 Rot',
}
ows_category = category_map.get(self.ows_category, '-')
# Bereich
area = self.ows_area_id.name if self.ows_area_id else "-"
# Standort
location = self.location if self.location else "-"
# Bild (als Thumbnail 50px)
if self.image_1920:
media_id = self._get_wiki_media_id()
image = f"{{{{:{media_id}?50}}}}"
else:
image = "-"
# Tabellenzeile
row = f"| {name_link} | {status} | {ows_category} | {area} | {location} | {image} |"
return row
@api.model
def action_sync_overview_table(self):
"""
Aktualisiert die Übersichtstabelle in DokuWiki mit allen Equipment-Einträgen.
Diese Methode:
1. Lädt das Template aus DokuWiki (mit {{EQUIPMENT_TABLE_ROWS}} Placeholder)
2. Generiert für jedes Equipment eine Tabellenzeile
3. Ersetzt den Placeholder mit den generierten Zeilen
4. Speichert die Übersichtsseite zurück zu DokuWiki
Returns:
dict: Ergebnis-Dictionary mit 'total', 'success', 'error_messages'
"""
IrConfigParameter = self.env['ir.config_parameter'].sudo()
dokuwiki_client = self.env['dokuwiki.client']
# Config Parameter
overview_page_id = IrConfigParameter.get_param('dokuwiki.overview_page_id', 'werkstatt:ausruestung:uebersicht')
overview_template_id = IrConfigParameter.get_param('dokuwiki.overview_template_id', 'werkstatt:ausruestung:uebersicht_template')
try:
# Template aus Wiki laden
template_content = dokuwiki_client.get_page(overview_template_id)
if not template_content:
raise UserError(f"Template-Seite '{overview_template_id}' nicht gefunden! Bitte erst im Wiki erstellen.")
# Alle Equipment mit ows_area_id laden (sortiert nach Bereich, dann Name)
equipment_records = self.search([
('ows_area_id', '!=', False)
], order='ows_area_id, name')
if not equipment_records:
raise UserError("Keine Equipment-Einträge mit Bereich gefunden!")
# Tabellenzeilen generieren
table_rows = []
for equipment in equipment_records:
try:
row = equipment._generate_overview_table_row()
table_rows.append(row)
except Exception as e:
_logger.warning(f"Fehler beim Generieren der Zeile für {equipment.name}: {e}")
continue
# Rows zusammenfügen
table_rows_markup = '\n'.join(table_rows)
# Placeholder ersetzen
overview_content = template_content.replace('{{EQUIPMENT_TABLE_ROWS}}', table_rows_markup)
# Sync-Zeitstempel hinzufügen
sync_datetime = datetime.now().strftime('%d.%m.%Y %H:%M:%S')
overview_content = overview_content.replace('{{SYNC_DATETIME}}', sync_datetime)
# Seite in DokuWiki speichern
dokuwiki_client.create_page(
overview_page_id,
overview_content,
f"Automatisches Update der Übersichtstabelle ({len(table_rows)} Equipment)"
)
_logger.info(f"✓ Übersichtstabelle aktualisiert: {len(table_rows)} Equipment in {overview_page_id}")
return {
'total': len(equipment_records),
'success': len(table_rows),
'error_messages': '',
'overview_url': dokuwiki_client.get_wiki_url(overview_page_id),
}
except Exception as e:
error_msg = f"Fehler beim Aktualisieren der Übersichtstabelle: {str(e)}"
_logger.error(error_msg)
return {
'total': 0,
'success': 0,
'error_messages': error_msg,
'overview_url': '',
}

View File

@ -21,6 +21,8 @@ class ResConfigSettings(models.TransientModel):
'dokuwiki.url': 'https://wiki.hobbyhimmel.de',
'dokuwiki.user': 'odoo.odoo',
'dokuwiki.password': 'CHANGE_ME',
'dokuwiki.overview_page_id': 'werkstatt:ausruestung:uebersicht',
'dokuwiki.overview_template_id': 'werkstatt:ausruestung:uebersicht_template',
}
# Nur fehlende Parameter anlegen

View File

@ -14,6 +14,7 @@ class EquipmentWikiSyncWizard(models.TransientModel):
('all', 'Alle Equipment'),
('area', 'Nach Bereich filtern'),
('unsynced', 'Nur nicht synchronisierte'),
('overview_table', 'Übersichtstabelle aktualisieren'),
], string='Synchronisations-Modus', default='all', required=True)
ows_area_id = fields.Many2one(
@ -33,6 +34,7 @@ class EquipmentWikiSyncWizard(models.TransientModel):
success_count = fields.Integer(string='Erfolgreich', readonly=True)
error_count = fields.Integer(string='Fehler', readonly=True)
error_messages = fields.Text(string='Fehlermeldungen', readonly=True)
overview_url = fields.Char(string='Übersichtsseite URL', readonly=True)
@api.onchange('sync_mode')
def _onchange_sync_mode(self):
@ -46,6 +48,10 @@ class EquipmentWikiSyncWizard(models.TransientModel):
"""
self.ensure_one()
# Übersichtstabelle-Modus: Schneller Update ohne Equipment-Iteration
if self.sync_mode == 'overview_table':
return self._sync_overview_table()
# Equipment-Liste basierend auf Modus ermitteln
domain = []
@ -121,3 +127,38 @@ class EquipmentWikiSyncWizard(models.TransientModel):
'target': 'new',
'context': {'show_result': True},
}
def _sync_overview_table(self):
"""
Aktualisiert die Übersichtstabelle in DokuWiki.
Ruft die Methode im maintenance.equipment Model auf.
Returns:
dict: Action zum Anzeigen des Ergebnisses
"""
self.ensure_one()
_logger.info("Starte Übersichtstabellen-Synchronisation")
# Equipment Model aufrufen
result = self.env['maintenance.equipment'].action_sync_overview_table()
# Statistik speichern
self.write({
'total_count': result.get('total', 0),
'success_count': result.get('success', 0),
'error_count': result.get('total', 0) - result.get('success', 0),
'error_messages': result.get('error_messages', 'Keine Fehler'),
'overview_url': result.get('overview_url', ''),
})
# Ergebnis-View anzeigen
return {
'type': 'ir.actions.act_window',
'name': 'Übersichtstabelle aktualisiert',
'res_model': 'equipment.wiki.sync.wizard',
'view_mode': 'form',
'res_id': self.id,
'target': 'new',
'context': {'show_result': True},
}

View File

@ -12,7 +12,7 @@
<field name="ows_area_id" invisible="sync_mode != 'area'" required="sync_mode == 'area'"/>
</group>
<group>
<field name="force_sync"/>
<field name="force_sync" invisible="sync_mode == 'overview_table'"/>
</group>
</group>
@ -24,6 +24,7 @@
<field name="error_count"/>
</group>
<group>
<field name="overview_url" widget="url" string="Übersichtsseite" invisible="not overview_url"/>
<field name="error_messages" widget="text" colspan="2" invisible="error_count == 0"/>
</group>
</group>