DokuWiki Integration: wiki_doku_id aus Name+Modell, zentraler Namespace konfigurierbar
- wiki_doku_id wird nun aus equipment.name und equipment.model kombiniert generiert - Systemparameter 'dokuwiki.central_documentation_namespace' für konfigurierbaren Namespace - Verbessertes Error-Handling in dokuwiki_client mit detaillierteren Fehlermeldungen - Docker-Netzwerk Unterstützung dokumentiert - Gelöschte veraltete WordPress-API Dateien
This commit is contained in:
parent
253d289633
commit
f79e126c8c
|
|
@ -1,300 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin Name: OpenWorkshop Odoo API
|
||||
* Plugin URI: https://hobbyhimmel.de/
|
||||
* Description: Bindet Daten aus Odoo (OpenWorkshop) per REST-API in WordPress ein. Stellt u.a. den Shortcode [openworkshop_machines] bereit.
|
||||
* Version: 0.1.0
|
||||
* Author: HobbyHimmel / Matthias Lotz
|
||||
* License: GPLv3
|
||||
* License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||||
* Text Domain: openworkshop-odoo-api
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class OpenWorkshop_Odoo_API_Plugin {
|
||||
|
||||
const OPTION_GROUP = 'openworkshop_odoo_api_options';
|
||||
const OPTION_NAME = 'openworkshop_odoo_api_settings';
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'admin_menu', array( $this, 'register_settings_page' ) );
|
||||
add_action( 'admin_init', array( $this, 'register_settings' ) );
|
||||
add_shortcode( 'openworkshop_machines', array( $this, 'shortcode_machines' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register settings page under Settings → OpenWorkshop Odoo API
|
||||
*/
|
||||
public function register_settings_page() {
|
||||
add_options_page(
|
||||
__( 'OpenWorkshop Odoo API', 'openworkshop-odoo-api' ),
|
||||
__( 'OpenWorkshop Odoo API', 'openworkshop-odoo-api' ),
|
||||
'manage_options',
|
||||
'openworkshop-odoo-api',
|
||||
array( $this, 'render_settings_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register settings (base URL + optional token)
|
||||
*/
|
||||
public function register_settings() {
|
||||
register_setting(
|
||||
self::OPTION_GROUP,
|
||||
self::OPTION_NAME,
|
||||
array(
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => array( $this, 'sanitize_settings' ),
|
||||
'default' => array(
|
||||
'base_url' => '',
|
||||
'api_token' => '',
|
||||
'machines_endpoint' => '/api/v1/machines',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_section(
|
||||
'openworkshop_odoo_api_main',
|
||||
__( 'Odoo API Einstellungen', 'openworkshop-odoo-api' ),
|
||||
'__return_false',
|
||||
'openworkshop-odoo-api'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'base_url',
|
||||
__( 'Odoo Basis-URL', 'openworkshop-odoo-api' ),
|
||||
array( $this, 'render_field_base_url' ),
|
||||
'openworkshop-odoo-api',
|
||||
'openworkshop_odoo_api_main'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'machines_endpoint',
|
||||
__( 'Endpoint für Maschinenliste', 'openworkshop-odoo-api' ),
|
||||
array( $this, 'render_field_machines_endpoint' ),
|
||||
'openworkshop-odoo-api',
|
||||
'openworkshop_odoo_api_main'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'api_token',
|
||||
__( 'API Token (optional)', 'openworkshop-odoo-api' ),
|
||||
array( $this, 'render_field_api_token' ),
|
||||
'openworkshop-odoo-api',
|
||||
'openworkshop_odoo_api_main'
|
||||
);
|
||||
}
|
||||
|
||||
public function sanitize_settings( $input ) {
|
||||
$output = array();
|
||||
|
||||
$output['base_url'] = isset( $input['base_url'] )
|
||||
? esc_url_raw( rtrim( $input['base_url'], '/' ) )
|
||||
: '';
|
||||
|
||||
$output['machines_endpoint'] = isset( $input['machines_endpoint'] )
|
||||
? sanitize_text_field( $input['machines_endpoint'] )
|
||||
: '/api/v1/machines';
|
||||
|
||||
$output['api_token'] = isset( $input['api_token'] )
|
||||
? sanitize_text_field( $input['api_token'] )
|
||||
: '';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function get_settings() {
|
||||
$settings = get_option( self::OPTION_NAME, array() );
|
||||
$defaults = array(
|
||||
'base_url' => '',
|
||||
'api_token' => '',
|
||||
'machines_endpoint' => '/api/v1/machines',
|
||||
);
|
||||
|
||||
return wp_parse_args( $settings, $defaults );
|
||||
}
|
||||
|
||||
public function render_settings_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = $this->get_settings();
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e( 'OpenWorkshop Odoo API Einstellungen', 'openworkshop-odoo-api' ); ?></h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php
|
||||
settings_fields( self::OPTION_GROUP );
|
||||
do_settings_sections( 'openworkshop-odoo-api' );
|
||||
submit_button();
|
||||
?>
|
||||
</form>
|
||||
|
||||
<h2><?php esc_html_e( 'Shortcodes', 'openworkshop-odoo-api' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Maschinenliste anzeigen:', 'openworkshop-odoo-api' ); ?></p>
|
||||
<code>[openworkshop_machines]</code>
|
||||
<p><?php esc_html_e( 'Optional können Attribute verwendet werden, um z. B. eine andere Anzahl von Maschinen anzuzeigen.', 'openworkshop-odoo-api' ); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_field_base_url() {
|
||||
$settings = $this->get_settings();
|
||||
?>
|
||||
<input type="text"
|
||||
name="<?php echo esc_attr( self::OPTION_NAME ); ?>[base_url]"
|
||||
value="<?php echo esc_attr( $settings['base_url'] ); ?>"
|
||||
class="regular-text"
|
||||
placeholder="https://odoo.example.org" />
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Basis-URL deiner Odoo-Instanz (ohne Slash am Ende). Die API-Route wird daran angehängt.', 'openworkshop-odoo-api' ); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_field_machines_endpoint() {
|
||||
$settings = $this->get_settings();
|
||||
?>
|
||||
<input type="text"
|
||||
name="<?php echo esc_attr( self::OPTION_NAME ); ?>[machines_endpoint]"
|
||||
value="<?php echo esc_attr( $settings['machines_endpoint'] ); ?>"
|
||||
class="regular-text"
|
||||
placeholder="/api/v1/machines" />
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Relativer Pfad zum Maschinen-Endpoint. Standard: /api/v1/machines', 'openworkshop-odoo-api' ); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_field_api_token() {
|
||||
$settings = $this->get_settings();
|
||||
?>
|
||||
<input type="text"
|
||||
name="<?php echo esc_attr( self::OPTION_NAME ); ?>[api_token]"
|
||||
value="<?php echo esc_attr( $settings['api_token'] ); ?>"
|
||||
class="regular-text" />
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Optionaler API-Token, der im Authorization-Header gesendet wird (Bearer <token>).', 'openworkshop-odoo-api' ); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode: [openworkshop_machines]
|
||||
* Attributes:
|
||||
* limit – Anzahl der Einträge (optional)
|
||||
*/
|
||||
public function shortcode_machines( $atts ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'limit' => 0,
|
||||
),
|
||||
$atts,
|
||||
'openworkshop_machines'
|
||||
);
|
||||
|
||||
$data = $this->fetch_machines();
|
||||
|
||||
if ( is_wp_error( $data ) ) {
|
||||
return '<p>' . esc_html__( 'Fehler beim Laden der Maschinendaten aus Odoo.', 'openworkshop-odoo-api' ) . '</p>';
|
||||
}
|
||||
|
||||
if ( ! is_array( $data ) || empty( $data ) ) {
|
||||
return '<p>' . esc_html__( 'Keine Maschinen gefunden.', 'openworkshop-odoo-api' ) . '</p>';
|
||||
}
|
||||
|
||||
$limit = intval( $atts['limit'] );
|
||||
if ( $limit > 0 ) {
|
||||
$data = array_slice( $data, 0, $limit );
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="openworkshop-machines">
|
||||
<table class="openworkshop-machines-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Name', 'openworkshop-odoo-api' ); ?></th>
|
||||
<th><?php esc_html_e( 'Bereich', 'openworkshop-odoo-api' ); ?></th>
|
||||
<th><?php esc_html_e( 'Status', 'openworkshop-odoo-api' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $data as $machine ) : ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php echo isset( $machine['name'] ) ? esc_html( $machine['name'] ) : ''; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo isset( $machine['area'] ) ? esc_html( $machine['area'] ) : ''; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo isset( $machine['status'] ) ? esc_html( $machine['status'] ) : ''; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the Odoo API and returns decoded JSON or WP_Error.
|
||||
*/
|
||||
protected function fetch_machines() {
|
||||
$settings = $this->get_settings();
|
||||
|
||||
if ( empty( $settings['base_url'] ) ) {
|
||||
return new WP_Error( 'openworkshop_no_base_url', __( 'Keine Odoo Basis-URL konfiguriert.', 'openworkshop-odoo-api' ) );
|
||||
}
|
||||
|
||||
$url = $settings['base_url'] . $settings['machines_endpoint'];
|
||||
|
||||
$args = array(
|
||||
'timeout' => 10,
|
||||
'headers' => array(
|
||||
'Accept' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
if ( ! empty( $settings['api_token'] ) ) {
|
||||
$args['headers']['Authorization'] = 'Bearer ' . $settings['api_token'];
|
||||
}
|
||||
|
||||
$response = wp_remote_get( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$code = wp_remote_retrieve_response_code( $response );
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( $code < 200 || $code >= 300 ) {
|
||||
return new WP_Error( 'openworkshop_bad_status', sprintf( 'HTTP %d', $code ) );
|
||||
}
|
||||
|
||||
$data = json_decode( $body, true );
|
||||
if ( json_last_error() !== JSON_ERROR_NONE ) {
|
||||
return new WP_Error( 'openworkshop_json_error', json_last_error_msg() );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
function openworkshop_odoo_api_bootstrap() {
|
||||
static $instance = null;
|
||||
if ( $instance === null ) {
|
||||
$instance = new OpenWorkshop_Odoo_API_Plugin();
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
openworkshop_odoo_api_bootstrap();
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
=== OpenWorkshop Odoo API ===
|
||||
Contributors: hobbyhimmel
|
||||
Tags: odoo, api, openworkshop, integration
|
||||
Requires at least: 5.8
|
||||
Tested up to: 6.6
|
||||
Stable tag: 0.1.0
|
||||
License: GPLv3
|
||||
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
Dieses Plugin bindet Maschinendaten aus einer Odoo/OpenWorkshop-Installation via REST-API in WordPress ein.
|
||||
|
||||
== Beschreibung ==
|
||||
|
||||
Das Plugin stellt u.a. den Shortcode [openworkshop_machines] bereit, der eine einfache Maschinenliste
|
||||
auf Basis eines JSON-Endpunkts in Odoo rendert.
|
||||
|
||||
In den Einstellungen kann die Basis-URL der Odoo-Instanz, der Endpoint (z.B. /api/v1/machines) sowie ein
|
||||
optionaler API-Token hinterlegt werden.
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. ZIP in WordPress unter Plugins → Installieren → Plugin hochladen hochladen.
|
||||
2. Aktivieren.
|
||||
3. Unter Einstellungen → OpenWorkshop Odoo API die Basis-URL und den Endpoint konfigurieren.
|
||||
4. Den Shortcode [openworkshop_machines] in einer Seite oder einem Beitrag einfügen.
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 0.1.0 =
|
||||
* Erste Version.
|
||||
|
|
@ -93,6 +93,13 @@ dokuwiki.overview_columns = Name|Hersteller|Modell|Seriennummer|Kosten|Garantie|
|
|||
dokuwiki.overview_column_data = {name}|{partner_id}|{model}|{serial_no}|{cost}|{warranty_date}|{location}|{ows_machine_id.category_icon}
|
||||
```
|
||||
|
||||
### Beispiel 4: Mit Tags
|
||||
|
||||
```python
|
||||
dokuwiki.overview_columns = Status|Name|Typ|Tags|Standort|Dokumentation
|
||||
dokuwiki.overview_column_data = {status_smiley}|{name}|{model}|{tags_list}|{location}|{wiki_doku_link}
|
||||
```
|
||||
|
||||
**Wichtig:** Anzahl der Pipes muss übereinstimmen!
|
||||
- 3 Pipes = 4 Spalten
|
||||
- Spalten und Daten müssen gleiche Anzahl haben
|
||||
|
|
@ -167,14 +174,45 @@ dokuwiki.overview_column_data = {name}|{partner_id}|{model}|{serial_no}|{cost}|{
|
|||
|
||||
## Automatische Updates
|
||||
|
||||
Die Übersichtstabelle wird **NICHT** automatisch bei Equipment-Änderungen aktualisiert.
|
||||
Die Übersichtstabelle kann optional automatisch bei Equipment-Änderungen aktualisiert werden.
|
||||
|
||||
**Manueller Sync empfohlen:**
|
||||
### Manueller Sync (empfohlen)
|
||||
|
||||
**Manueller Sync empfohlen für:**
|
||||
- Nach Massen-Importen
|
||||
- Einmal täglich/wöchentlich
|
||||
- Bei strukturellen Änderungen (neue Bereiche, etc.)
|
||||
|
||||
**Alternativ: Cronjob einrichten**
|
||||
**Vorteil:** Performanter, keine zusätzliche Last bei jeder Equipment-Änderung
|
||||
|
||||
### Automatischer Sync bei Equipment-Änderungen
|
||||
|
||||
**Was passiert beim Speichern eines Equipment?**
|
||||
|
||||
1. **Equipment-Detailseite wird immer aktualisiert** wenn:
|
||||
- Eines der überwachten Felder geändert wurde (siehe unten)
|
||||
- `wiki_auto_sync` für das Equipment aktiviert ist (Standard: `True`)
|
||||
- Equipment bereits synchronisiert wurde (`wiki_synced = True`)
|
||||
|
||||
2. **Übersichtstabelle wird zusätzlich aktualisiert** wenn:
|
||||
- Alle Bedingungen von (1) erfüllt sind UND
|
||||
- Systemparameter `dokuwiki.auto_update_overview_table = True` gesetzt ist
|
||||
|
||||
**Überwachte Felder (lösen Sync aus):**
|
||||
- `name`, `serial_no`, `ows_area_id`, `category_id`, `status_id`
|
||||
- `model`, `partner_id`, `location`, `note`, `image_1920`, `tag_ids`
|
||||
|
||||
**Aktivierung Übersichtstabellen-Sync:**
|
||||
```python
|
||||
# In Odoo: Einstellungen → Technisch → Parameter → Systemparameter
|
||||
dokuwiki.auto_update_overview_table = True
|
||||
```
|
||||
|
||||
**Achtung:**
|
||||
- Bei vielen gleichzeitigen Equipment-Änderungen kann dies Performance-Probleme verursachen!
|
||||
- Die komplette Übersichtstabelle wird bei jeder Änderung neu generiert (ca. 156 Zeilen)
|
||||
|
||||
### Cronjob (Alternative)
|
||||
```python
|
||||
# In Odoo: Einstellungen → Technisch → Automatisierung → Geplante Aktionen
|
||||
|
||||
|
|
@ -207,6 +245,12 @@ Alle Platzhalter aus dem Detail-Template sind verfügbar!
|
|||
- `{partner_id}` - Lieferant (Name)
|
||||
- `{partner_ref}` - Lieferanten-Referenz
|
||||
|
||||
## Tags (falls maintenance_equipment_tags installiert)
|
||||
|
||||
- `{tags}` - Komma-separierte Liste aller Tags (z.B. "Holz, CNC, Einweisung erforderlich")
|
||||
- `{tags_list}` - DokuWiki Bullet-Liste mit Zeilenumbrüchen (ideal für Tabellenzellen)
|
||||
- `{tags_count}` - Anzahl der zugewiesenen Tags
|
||||
|
||||
## Spezial-Felder
|
||||
|
||||
- `{view_type}` - "Bereich" oder "Einsatzzweck"
|
||||
|
|
@ -216,7 +260,7 @@ Alle Platzhalter aus dem Detail-Template sind verfügbar!
|
|||
- `{odoo_link}` - Fertiger Link zur Odoo Equipment-Seite
|
||||
- `{odoo_url}` - URL zur Odoo Equipment-Seite (ohne Link-Markup)
|
||||
- `{sync_datetime}` - Aktuelles Datum/Zeit
|
||||
- `{image}` - Equipment-Bild (300px Breite) - Format: `{{:media_id?300}}`
|
||||
- `{image}` - Equipment-Bild (100px Breite) - Format: `{{:media_id?100}}`
|
||||
- `{image_large}` - Equipment-Bild (Originalgröße) - Format: `{{:media_id}}`
|
||||
- `{image_id}` - Media-ID des Bildes (z.B. werkstatt:ausruestung:media:sabako-laser.jpg)
|
||||
|
||||
|
|
@ -236,7 +280,7 @@ Alle Platzhalter aus dem Detail-Template sind verfügbar!
|
|||
- **Pipe als Trenner**: Zwischen Spalten `|` verwenden
|
||||
- **Leere Werte**: Werden automatisch durch `-` ersetzt
|
||||
- **Links**: `{wiki_doku_link}` und `{odoo_link}` enthalten bereits DokuWiki Link-Syntax
|
||||
- **Bilder**: `{image}` ist bereits formatiert mit `{{:...?300}}`
|
||||
- **Bilder**: `{image}` ist bereits formatiert mit `{{:...?100}}`
|
||||
- **ows.machine**: Immer mit Präfix `ows_machine_id.` (z.B. `{ows_machine_id.location}`)
|
||||
|
||||
## Beispiel-Konfigurationen
|
||||
|
|
@ -258,3 +302,9 @@ Daten: {status_smiley}|{ows_machine_id.category_icon}|{partner_id}|{note}|{mod
|
|||
Spalten: Name|Status|Kategorie|Hersteller|Modell|S/N|Kosten|Garantie|Standort|Bereich|Bild|Doku
|
||||
Daten: {name}|{status_smiley}|{ows_machine_id.category_icon}|{partner_id}|{model}|{serial_no}|{cost}|{warranty_date}|{location}|{ows_area}|{image}|{wiki_doku_link}
|
||||
```
|
||||
|
||||
### Mit Tags
|
||||
```
|
||||
Spalten: Name|Status|Tags|Hersteller|Standort|Doku
|
||||
Daten: {name}|{status_smiley}|{tags_list}|{partner_id}|{location}|{wiki_doku_link}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ ACL:
|
|||
* Phase 1: Nur @odoo Gruppe hat Zugriff
|
||||
* Phase 2: @werkstatt bekommt Lesezugriff auf Hauptseiten, Edit-Zugriff auf Doku-Seiten
|
||||
""",
|
||||
'author': 'Open Workshop',
|
||||
'author': 'Hobbyhimmel',
|
||||
'website': 'https://hobbyhimmel.de',
|
||||
'license': 'LGPL-3',
|
||||
'depends': [
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
====== 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//
|
||||
|
|
@ -3,11 +3,11 @@
|
|||
<!-- DokuWiki Smiley-Werte für Status aus open_workshop_base -->
|
||||
|
||||
<record id="open_workshop_base.equipment_status_inbetrieb" model="maintenance.equipment.status">
|
||||
<field name="smiley">:-)</field>
|
||||
<field name="smiley">😊</field>
|
||||
</record>
|
||||
|
||||
<record id="open_workshop_base.equipment_status_defekt" model="maintenance.equipment.status">
|
||||
<field name="smiley">:-(</field>
|
||||
<field name="smiley">☹️</field>
|
||||
</record>
|
||||
|
||||
<record id="open_workshop_base.equipment_status_wartung" model="maintenance.equipment.status">
|
||||
|
|
|
|||
|
|
@ -42,15 +42,34 @@ class DokuWikiClient(models.AbstractModel):
|
|||
"- dokuwiki.password"
|
||||
)
|
||||
|
||||
# URL validieren/normalisieren
|
||||
if not wiki_url.startswith(('http://', 'https://')):
|
||||
raise UserError(f"DokuWiki URL muss mit http:// oder https:// beginnen: {wiki_url}")
|
||||
|
||||
try:
|
||||
_logger.info(f"Verbinde zu DokuWiki: {wiki_url} (User: {wiki_user})")
|
||||
wiki = DokuWiki(wiki_url, wiki_user, wiki_password)
|
||||
# Test-Verbindung
|
||||
version = wiki.version
|
||||
_logger.info(f"DokuWiki-Verbindung erfolgreich: {version}")
|
||||
_logger.info(f"DokuWiki-Verbindung erfolgreich: Version {version}")
|
||||
return wiki
|
||||
except DokuWikiError as e:
|
||||
_logger.error(f"DokuWiki-Verbindung fehlgeschlagen: {e}")
|
||||
raise UserError(f"Verbindung zu DokuWiki fehlgeschlagen: {e}")
|
||||
error_details = f"URL: {wiki_url}, User: {wiki_user}, Fehler: {e}"
|
||||
_logger.error(f"DokuWiki-Verbindung fehlgeschlagen: {error_details}")
|
||||
raise UserError(
|
||||
f"Verbindung zu DokuWiki fehlgeschlagen.\n\n"
|
||||
f"Details:\n"
|
||||
f"- URL: {wiki_url}\n"
|
||||
f"- User: {wiki_user}\n"
|
||||
f"- Fehler: {e}\n\n"
|
||||
f"Hinweise:\n"
|
||||
f"- Prüfen Sie ob die URL korrekt ist (sollte auf /lib/exe/xmlrpc.php zeigen)\n"
|
||||
f"- Stellen Sie sicher, dass XML-RPC in DokuWiki aktiviert ist\n"
|
||||
f"- Prüfen Sie die Benutzer-Zugangsdaten"
|
||||
)
|
||||
except Exception as e:
|
||||
_logger.error(f"Unerwarteter Fehler bei DokuWiki-Verbindung: {e}", exc_info=True)
|
||||
raise UserError(f"Unerwarteter Fehler: {e}")
|
||||
|
||||
@api.model
|
||||
def create_page(self, page_id, content, summary="Erstellt von Odoo"):
|
||||
|
|
@ -71,12 +90,24 @@ class DokuWikiClient(models.AbstractModel):
|
|||
wiki = self._get_wiki_connection()
|
||||
|
||||
try:
|
||||
_logger.info(f"Erstelle/Aktualisiere Wiki-Seite: {page_id} ({len(content)} Zeichen)")
|
||||
wiki.pages.set(page_id, content, summary=summary)
|
||||
_logger.info(f"Wiki-Seite erstellt/aktualisiert: {page_id}")
|
||||
_logger.info(f"Wiki-Seite erfolgreich 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}")
|
||||
_logger.error(f"DokuWiki API Fehler bei Seite {page_id}: {e}", exc_info=True)
|
||||
raise UserError(
|
||||
f"Fehler beim Erstellen der Wiki-Seite '{page_id}':\n\n"
|
||||
f"{e}\n\n"
|
||||
f"Mögliche Ursachen:\n"
|
||||
f"- XML-RPC nicht aktiviert in DokuWiki\n"
|
||||
f"- Keine Schreibrechte für den Namespace\n"
|
||||
f"- Ungültige Zeichen in der Page-ID\n"
|
||||
f"- DokuWiki gibt Fehler/Warnings aus (prüfen Sie die DokuWiki-Logs)"
|
||||
)
|
||||
except Exception as e:
|
||||
_logger.error(f"Unerwarteter Fehler beim Erstellen der Seite {page_id}: {e}", exc_info=True)
|
||||
raise UserError(f"Unerwarteter Fehler: {e}")
|
||||
|
||||
@api.model
|
||||
def get_page(self, page_id):
|
||||
|
|
|
|||
|
|
@ -9,6 +9,63 @@ _logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class MaintenanceEquipment(models.Model):
|
||||
"""
|
||||
Erweitert das Maintenance Equipment Modell um DokuWiki-Integration.
|
||||
Diese Klasse ermöglicht die Synchronisation von Werkstatt-Equipment-Daten mit einem
|
||||
DokuWiki-System. Jedes Equipment erhält eine zentrale Dokumentationsseite sowie
|
||||
verschiedene Ansichtsseiten (nach Bereich, später auch nach Einsatzzweck).
|
||||
Hauptfunktionen:
|
||||
- Automatische Generierung von Wiki-Seiten aus Equipment-Daten
|
||||
- Template-basierte Wiki-Seiten-Erstellung (verwendet c_template aus DokuWiki)
|
||||
- Bild-Upload und Einbindung in Wiki-Seiten
|
||||
- Zentrale Dokumentationsseite pro Equipment (manuell erweiterbar)
|
||||
- Bereichs-spezifische Übersichtsseiten (automatisch aktualisiert)
|
||||
- Automatische Übersichtstabelle aller Equipment (DataTable mit Sortierung/Filterung)
|
||||
- Automatische Synchronisation bei Feldänderungen (optional)
|
||||
Wiki-Seitenstruktur:
|
||||
- werkstatt:ausruestung:doku:{wiki_doku_id} - Zentrale Dokumentation
|
||||
- werkstatt:ausruestung:{area}:{wiki_doku_id} - Bereichsansicht
|
||||
- werkstatt:ausruestung:uebersicht - Equipment-Übersichtstabelle
|
||||
Neue Felder:
|
||||
- image_1920: Bild des Equipment (wird automatisch ins Wiki hochgeladen)
|
||||
- wiki_doku_id: Eindeutige ID für Wiki-Dokumentation (aus Equipment-Name generiert)
|
||||
- wiki_page_url: Berechnete URL zur Wiki-Seite
|
||||
- wiki_synced: Status der Synchronisation
|
||||
- wiki_last_sync: Zeitstempel der letzten Synchronisation
|
||||
- wiki_auto_sync: Schalter für automatische Synchronisation bei Änderungen
|
||||
Template-System:
|
||||
Die Wiki-Seiten werden aus einem Template (werkstatt:ausruestung:c_template)
|
||||
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
|
||||
- {image} - Bild-Einbindung (wird automatisch hochgeladen)
|
||||
- {tags} - Komma-separierte Tag-Liste
|
||||
- {sync_datetime} - Zeitstempel der Synchronisation
|
||||
Übersichtstabelle:
|
||||
Generiert eine zentrale Übersichtstabelle aller Equipment mit konfigurierbaren
|
||||
Spalten. Die Tabelle verwendet das DokuWiki DataTable-Plugin für interaktive
|
||||
Sortierung und Filterung. Konfiguration über Systemparameter:
|
||||
- dokuwiki.overview_page_id - Seiten-ID der Übersicht
|
||||
- dokuwiki.overview_title - Titel der Seite
|
||||
- dokuwiki.overview_columns - Spaltenüberschriften (pipe-separiert)
|
||||
- dokuwiki.overview_column_data - Spaltendaten mit Platzhaltern
|
||||
Verwendung:
|
||||
1. Equipment anlegen/bearbeiten in Odoo
|
||||
2. Bereich (ows_area_id) setzen (erforderlich für Wiki-Sync)
|
||||
3. Optional: Bild hochladen (wird automatisch ins Wiki übertragen)
|
||||
4. "Zum Wiki synchronisieren" klicken (oder automatisch bei Änderungen)
|
||||
5. Wiki-Seiten werden erstellt/aktualisiert
|
||||
6. "Wiki-Seite öffnen" für direkten Browser-Zugriff
|
||||
Notes:
|
||||
- Zentrale Dokumentationsseite wird nur beim ersten Sync erstellt
|
||||
- Bereichsansichten werden bei jedem Sync aktualisiert
|
||||
- Bilder werden als werkstatt:ausruestung:media:{wiki_doku_id}.jpg gespeichert
|
||||
- Wiki-Namen werden normalisiert (Umlaute, Sonderzeichen, Kleinschreibung)
|
||||
- Bei fehlendem Template wird Fallback-Inhalt verwendet
|
||||
- Übersichtstabelle kann manuell oder automatisch aktualisiert werden
|
||||
"""
|
||||
_inherit = 'maintenance.equipment'
|
||||
|
||||
# Bild-Feld
|
||||
|
|
@ -23,7 +80,7 @@ class MaintenanceEquipment(models.Model):
|
|||
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")'
|
||||
help='Eindeutige ID für die zentrale Wiki-Dokumentation (generiert aus Equipment-Namen, z.B. "formatkreissaege", und Modell "bosch-abc" -> "formatkreissaege-bosch-abc")'
|
||||
)
|
||||
wiki_page_url = fields.Char(
|
||||
string='Wiki-Seiten URL',
|
||||
|
|
@ -63,8 +120,8 @@ class MaintenanceEquipment(models.Model):
|
|||
|
||||
def _get_wiki_doku_id(self):
|
||||
"""
|
||||
Generiert die Wiki-Dokumentations-ID aus dem Equipment-Namen.
|
||||
Format: normalisierter_name (z.B. "formatkreissaege", "tischkreissaege")
|
||||
Generiert die Wiki-Dokumentations-ID aus dem Equipment-Namen und Modell.
|
||||
Format: normalisierter_name-normalisiertes_modell (z.B. "formatkreissaege-bosch-abc")
|
||||
|
||||
Returns:
|
||||
str: Wiki-Doku-ID oder False wenn keine ID vorhanden
|
||||
|
|
@ -75,9 +132,13 @@ class MaintenanceEquipment(models.Model):
|
|||
if self.wiki_doku_id:
|
||||
return self.wiki_doku_id
|
||||
|
||||
# Generiere aus Equipment-Namen
|
||||
# Generiere aus Equipment-Namen und Modell
|
||||
if self.name:
|
||||
return self._normalize_wiki_name(self.name)
|
||||
normalized_name = self._normalize_wiki_name(self.name)
|
||||
if self.model:
|
||||
normalized_model = self._normalize_wiki_name(self.model)
|
||||
return f"{normalized_name}-{normalized_model}"
|
||||
return normalized_name
|
||||
|
||||
return False
|
||||
|
||||
|
|
@ -103,14 +164,23 @@ class MaintenanceEquipment(models.Model):
|
|||
def _get_wiki_doku_page_id(self):
|
||||
"""
|
||||
Generiert die Wiki-Page-ID für die zentrale Dokumentation.
|
||||
Format: werkstatt:ausruestung:doku:{wiki_doku_id}
|
||||
Format: {central_namespace}:{wiki_doku_id}
|
||||
Der Namespace ist über Systemparameter 'dokuwiki.central_documentation_namespace' konfigurierbar.
|
||||
|
||||
Returns:
|
||||
str: Page-ID der zentralen Doku
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
# Namespace aus Systemparameter laden
|
||||
IrConfigParameter = self.env['ir.config_parameter'].sudo()
|
||||
central_namespace = IrConfigParameter.get_param(
|
||||
'dokuwiki.central_documentation_namespace',
|
||||
default='werkstatt:ausruestung:doku'
|
||||
)
|
||||
|
||||
wiki_doku_id = self._get_wiki_doku_id()
|
||||
return f"werkstatt:ausruestung:doku:{wiki_doku_id}"
|
||||
return f"{central_namespace}:{wiki_doku_id}"
|
||||
|
||||
def _normalize_wiki_name(self, name):
|
||||
"""
|
||||
|
|
@ -250,6 +320,19 @@ class MaintenanceEquipment(models.Model):
|
|||
'partner_ref': self.partner_ref or '',
|
||||
}
|
||||
|
||||
# Tags hinzufügen (falls vorhanden)
|
||||
if hasattr(self, 'tag_ids') and self.tag_ids:
|
||||
# Komma-separierte Liste für Template
|
||||
values['tags'] = ', '.join(self.tag_ids.mapped('name'))
|
||||
# DokuWiki Bullet-Liste für Tabellenzellen
|
||||
values['tags_list'] = ' * ' + '\\\\ * '.join(self.tag_ids.mapped('name')) if self.tag_ids else ''
|
||||
# Anzahl der Tags
|
||||
values['tags_count'] = str(len(self.tag_ids))
|
||||
else:
|
||||
values['tags'] = ''
|
||||
values['tags_list'] = ''
|
||||
values['tags_count'] = '0'
|
||||
|
||||
# ows.machine Felder hinzufügen (falls verknüpft)
|
||||
if self.ows_machine_id:
|
||||
machine = self.ows_machine_id
|
||||
|
|
@ -377,12 +460,12 @@ class MaintenanceEquipment(models.Model):
|
|||
str: Wiki-Markup-Inhalt
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.model:
|
||||
model_part = f" - Modell: {self.model}"
|
||||
else:
|
||||
model_part = ""
|
||||
|
||||
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'}
|
||||
content = f"""====== {self.name}{model_part} ======
|
||||
|
||||
===== Beschreibung =====
|
||||
|
||||
|
|
@ -421,9 +504,11 @@ Hier kann die Dokumentation für {self.name} geschrieben werden.
|
|||
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)
|
||||
# wiki_doku_id beim ersten Sync setzen (aus Equipment-Namen und Modell generieren)
|
||||
if not self.wiki_doku_id:
|
||||
generated_id = self._normalize_wiki_name(self.name)
|
||||
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}")
|
||||
|
||||
|
|
@ -521,7 +606,11 @@ Hier kann die Dokumentation für {self.name} geschrieben werden.
|
|||
result = super().write(vals)
|
||||
|
||||
# Felder die eine Synchronisation auslösen
|
||||
sync_fields = {'name', 'serial_no', 'area_id', 'category_id'}
|
||||
sync_fields = {'name', 'serial_no', 'ows_area_id', 'category_id', 'status_id',
|
||||
'model', 'partner_id', 'location', 'note', 'image_1920', 'tag_ids'}
|
||||
|
||||
# Flag ob Übersichtstabelle aktualisiert werden soll
|
||||
should_update_overview = False
|
||||
|
||||
if sync_fields & set(vals.keys()):
|
||||
# Nur synchronisieren wenn auto_sync aktiviert und bereits synced
|
||||
|
|
@ -529,6 +618,7 @@ Hier kann die Dokumentation für {self.name} geschrieben werden.
|
|||
if record.wiki_auto_sync and record.wiki_synced:
|
||||
try:
|
||||
record.sync_to_dokuwiki()
|
||||
should_update_overview = True
|
||||
except Exception as e:
|
||||
_logger.warning(f"Automatische Wiki-Sync fehlgeschlagen: {e}")
|
||||
# Nicht abbrechen, nur loggen
|
||||
|
|
@ -536,6 +626,21 @@ Hier kann die Dokumentation für {self.name} geschrieben werden.
|
|||
# Sync-Status zurücksetzen
|
||||
record.write({'wiki_synced': False})
|
||||
|
||||
# Optional: Übersichtstabelle aktualisieren
|
||||
if should_update_overview:
|
||||
IrConfigParameter = self.env['ir.config_parameter'].sudo()
|
||||
auto_update_overview = IrConfigParameter.get_param(
|
||||
'dokuwiki.auto_update_overview_table',
|
||||
default='False'
|
||||
)
|
||||
|
||||
if auto_update_overview.lower() == 'true':
|
||||
try:
|
||||
self.env['maintenance.equipment'].action_sync_overview_table()
|
||||
_logger.info("Übersichtstabelle automatisch aktualisiert")
|
||||
except Exception as e:
|
||||
_logger.warning(f"Automatische Übersichtstabellen-Sync fehlgeschlagen: {e}")
|
||||
|
||||
return result
|
||||
|
||||
# ==========================================
|
||||
|
|
|
|||
|
|
@ -3,6 +3,22 @@ from odoo import fields, models
|
|||
|
||||
|
||||
class MaintenanceEquipmentStatus(models.Model):
|
||||
"""
|
||||
Extension of the maintenance.equipment.status model to add DokuWiki smiley support.
|
||||
|
||||
This class extends the standard Odoo maintenance equipment status model to include
|
||||
a smiley field that can be used for DokuWiki integration. The smiley field allows
|
||||
administrators to associate DokuWiki emoticon syntax with each maintenance equipment
|
||||
status, enabling visual representation of equipment status in DokuWiki documentation.
|
||||
|
||||
The smiley field accepts DokuWiki emoticon syntax (e.g., ':-)', ':-(', ':-D', etc.)
|
||||
which can be used to display appropriate emoticons when exporting or displaying
|
||||
equipment status information in DokuWiki format.
|
||||
|
||||
This extension is particularly useful for workshops or maintenance departments that
|
||||
use DokuWiki as their documentation platform and want to have a visual representation
|
||||
of equipment status alongside textual information.
|
||||
"""
|
||||
_inherit = 'maintenance.equipment.status'
|
||||
|
||||
smiley = fields.Char(
|
||||
|
|
|
|||
|
|
@ -30,10 +30,12 @@ class ResConfigSettings(models.TransientModel):
|
|||
'dokuwiki.url': 'https://wiki.hobbyhimmel.de',
|
||||
'dokuwiki.user': 'odoo.odoo',
|
||||
'dokuwiki.password': 'CHANGE_ME',
|
||||
'dokuwiki.central_documentation_namespace': 'werkstatt:ausruestung:doku',
|
||||
'dokuwiki.overview_page_id': 'werkstatt:ausruestung:start',
|
||||
'dokuwiki.overview_title': 'Geräte & Maschinen - Übersicht',
|
||||
'dokuwiki.overview_columns': 'Name|Zustand|Sicherheit|Bereich|Standort|Bild',
|
||||
'dokuwiki.overview_column_data': '[[{wiki_page_id}|{name}]]|{status_smiley}|{ows_machine_id.category_icon}|{ows_area}|{location}|{image}',
|
||||
'dokuwiki.auto_update_overview_table': 'False', # Automatische Übersichtstabellen-Aktualisierung bei Equipment-Änderungen
|
||||
}
|
||||
|
||||
# Nur fehlende Parameter anlegen
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user