From d469470b96ef205c2a933ede9f59e36b40e1538f Mon Sep 17 00:00:00 2001 From: "matthias.lotz" Date: Sat, 6 Jun 2026 14:16:06 +0200 Subject: [PATCH] initial POS Notice --- .../open_workshop_pos_partner_notice.md | 141 ++++++++++++++++++ open_workshop_pos/models/__init__.py | 1 + open_workshop_pos/models/res_partner.py | 12 ++ open_workshop_pos/static/src/css/pos.css | 11 ++ .../static/src/js/ows_pos_customer_sidebar.js | 15 +- .../src/xml/ows_pos_customer_sidebar.xml | 4 + 6 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 FEATURE_REQUEST/open_workshop_pos_partner_notice.md create mode 100644 open_workshop_pos/models/res_partner.py diff --git a/FEATURE_REQUEST/open_workshop_pos_partner_notice.md b/FEATURE_REQUEST/open_workshop_pos_partner_notice.md new file mode 100644 index 0000000..ce972eb --- /dev/null +++ b/FEATURE_REQUEST/open_workshop_pos_partner_notice.md @@ -0,0 +1,141 @@ +# Feature Request: POS Partner Interne Notizen + +## Ziel: +In der POS-Oberfläche des Moduls open_workshop_pos soll für die akuelle eingebuchten Kunden angezeigt werden, ob in res.partner interne Notizen vorhanden sind. Diese Notizen sollen durch anklicken eines Symbols im Kassiererbereich sichtbar und per Klick abrufbar sein. + +## Anforderung: + +1. Prüfe beim aktuell ausgewählten Partner, ob das Feld Interne Notizen in res.partner einen Inhalt hat. +2. Wenn das Feld nicht leer ist, zeige rechts neben dem Partnernamen ein Symbol an. +3. Klickt der Benutzer auf das Symbol, soll der Inhalt der internen Notiz in einem Popup angezeigt werden. +4. Wenn keine interne Notiz vorhanden ist, soll kein Symbol angezeigt werden. + +##Technische Vorgabe: +Die Anzeige und das Verhalten sollen in extra-addons/open_workshop/open_workshop_pos/static/src/js/ows_pos_customer_sidebar.js umgesetzt werden. + +## Akzeptanzkriterien: + + - Partner mit interner Notiz zeigen ein Symbol neben dem Namen. + - Partner ohne Notiz zeigen kein Symbol. + - Ein Klick auf das Symbol öffnet ein Popup mit dem Notiztext. + - Die bestehende POS-Oberfläche soll dabei nicht gestört werden. + +--- + +## Implementierungsplan + +### Analyse-Ergebnis + +Das Feld `comment` (Interne Notizen aus `res.partner`) wird von Odoo POS standardmäßig **nicht** an den Browser übertragen. Die Methode `_load_pos_data_fields` in `point_of_sale/models/res_partner.py` listet explizit die zu ladenden Felder auf – `comment` fehlt dort. + +Das bedeutet: Es sind Änderungen auf **zwei Ebenen** nötig – Backend (Python) und Frontend (JS + XML). + +--- + +### Schritt 1 – Backend: `comment`-Feld in POS-Datenübertragung aufnehmen + +**Datei:** `open_workshop_pos/models/res_partner.py` *(neu anlegen)* + +Das Modul muss `res.partner` erweitern und `_load_pos_data_fields` überschreiben, um das Feld `comment` in die Liste der an den POS-Client gesendeten Felder aufzunehmen. + +> **Warum nicht `pos_access.py` aus `open_workshop_base`?** +> Der Controller `pos_access.py` liefert Daten **on-demand per RPC-Aufruf** (async, pro Partnerwechsel). Das ist sinnvoll für volatile Daten wie Maschinenfreigaben. Das Feld `comment` ist dagegen ein statisches Partnerfeld – es reicht aus, es einmalig beim POS-Start zu laden. Der `_load_pos_data_fields`-Ansatz erfordert keinen extra Netzwerk-Request, keinen `useState` und keinen async-Code in der Sidebar-Komponente. + +```python +# -*- coding: utf-8 -*- +from odoo import models + +class ResPartner(models.Model): + _inherit = 'res.partner' + + def _load_pos_data_fields(self, config_id): + fields = super()._load_pos_data_fields(config_id) + if 'comment' not in fields: + fields.append('comment') + return fields +``` + +**Datei:** `open_workshop_pos/models/__init__.py` + +Den neuen Import hinzufügen: +```python +from . import res_partner +``` + +--- + +### Schritt 2 – Frontend JS: Logik und Popup in `ows_pos_customer_sidebar.js` + +**Datei:** `open_workshop_pos/static/src/js/ows_pos_customer_sidebar.js` + +Zwei neue Methoden in der Klasse `OwsPosCustomerSidebar` hinzufügen: + +1. `getPartnerComment(order)` – gibt den Wert des `comment`-Feldes des aktuellen Partners zurück oder `null`. +2. `showPartnerComment(order)` – öffnet einen Dialog mit dem Notizinhalt. Dafür kann der bereits vorhandene `this.dialog`-Service genutzt werden. + +```js +getPartnerComment(order) { + return order.get_partner()?.comment || null; +} + +showPartnerComment(order) { + const comment = this.getPartnerComment(order); + if (!comment) return; + this.dialog.add(/* AlertDialog oder ConfirmationDialog aus @web/core */, { + title: _t("Interne Notizen"), + body: comment, + }); +} +``` + +> Hinweis: Als Dialog-Komponente eignet sich `AlertDialog` aus `@web/core/confirmation_dialog/confirmation_dialog`, da dieser nur einen „OK"-Button benötigt. + +--- + +### Schritt 3 – Frontend XML: Symbol in Template einbauen + +**Datei:** `open_workshop_pos/static/src/xml/ows_pos_customer_sidebar.xml` + +Im bestehenden Template `open_workshop_pos.OwsPosCustomerSidebar` innerhalb der `.sidebar-line` ein Symbol (z. B. `ℹ️` oder ein Bootstrap-Icon) **konditional** anzeigen: + +```xml + + + 📋 + +``` + +Das `t-on-click.stop` verhindert, dass gleichzeitig der Click-Handler der übergeordneten `.order-entry` ausgelöst wird. + +--- + +### Schritt 4 – (Optional) CSS: Icon-Darstellung anpassen + +**Datei:** `open_workshop_pos/static/src/css/` *(vorhandene CSS-Datei oder neue)* + +```css +.partner-note-icon { + cursor: pointer; + font-size: 0.85em; + opacity: 0.7; +} +.partner-note-icon:hover { + opacity: 1; +} +``` + +--- + +### Zusammenfassung der betroffenen Dateien + +| Datei | Aktion | +|---|---| +| `models/res_partner.py` | Neu anlegen – `comment`-Feld in POS-Daten aufnehmen | +| `models/__init__.py` | `res_partner`-Import hinzufügen | +| `static/src/js/ows_pos_customer_sidebar.js` | Methoden `getPartnerComment` und `showPartnerComment` ergänzen | +| `static/src/xml/ows_pos_customer_sidebar.xml` | Symbol-Icon konditional in `.sidebar-line` einfügen | +| `static/src/css/` | (optional) Styling für Icon | + diff --git a/open_workshop_pos/models/__init__.py b/open_workshop_pos/models/__init__.py index 9e9e7ad..c078e7a 100644 --- a/open_workshop_pos/models/__init__.py +++ b/open_workshop_pos/models/__init__.py @@ -1,2 +1,3 @@ # -*- coding: utf-8 -*- from . import pos_order +from . import res_partner diff --git a/open_workshop_pos/models/res_partner.py b/open_workshop_pos/models/res_partner.py new file mode 100644 index 0000000..1fe286c --- /dev/null +++ b/open_workshop_pos/models/res_partner.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +from odoo import models + + +class ResPartner(models.Model): + _inherit = 'res.partner' + + def _load_pos_data_fields(self, config_id): + fields = super()._load_pos_data_fields(config_id) + if 'comment' not in fields: + fields.append('comment') + return fields diff --git a/open_workshop_pos/static/src/css/pos.css b/open_workshop_pos/static/src/css/pos.css index 603dd62..fbecbdc 100644 --- a/open_workshop_pos/static/src/css/pos.css +++ b/open_workshop_pos/static/src/css/pos.css @@ -56,6 +56,17 @@ text-overflow: ellipsis; } +.partner-note-icon { + flex-shrink: 0; + cursor: pointer; + font-size: 0.85em; + opacity: 0.7; + margin-left: 0.25em; +} +.partner-note-icon:hover { + opacity: 1; +} + .bg-200, .text-bg-200 { --background-color: rgb(122, 122, 122); diff --git a/open_workshop_pos/static/src/js/ows_pos_customer_sidebar.js b/open_workshop_pos/static/src/js/ows_pos_customer_sidebar.js index d852f60..27afd20 100644 --- a/open_workshop_pos/static/src/js/ows_pos_customer_sidebar.js +++ b/open_workshop_pos/static/src/js/ows_pos_customer_sidebar.js @@ -4,7 +4,7 @@ import { Component } from "@odoo/owl"; import { useService } from "@web/core/utils/hooks"; import { usePos } from "@point_of_sale/app/store/pos_hook"; import { _t } from "@web/core/l10n/translation"; -import { ask } from "@web/core/confirmation_dialog/confirmation_dialog"; +import { ask, AlertDialog } from "@web/core/confirmation_dialog/confirmation_dialog"; export class OwsPosCustomerSidebar extends Component { static template = "open_workshop_pos.OwsPosCustomerSidebar"; @@ -61,4 +61,17 @@ export class OwsPosCustomerSidebar extends Component { this.pos.set_order(order); this.env.bus.trigger('partner-changed'); } + + getPartnerComment(order) { + return order.get_partner()?.comment || null; + } + + showPartnerComment(order) { + const comment = this.getPartnerComment(order); + if (!comment) return; + this.dialog.add(AlertDialog, { + title: _t("Interne Notizen"), + body: comment, + }); + } } diff --git a/open_workshop_pos/static/src/xml/ows_pos_customer_sidebar.xml b/open_workshop_pos/static/src/xml/ows_pos_customer_sidebar.xml index 058d115..f9d2f04 100644 --- a/open_workshop_pos/static/src/xml/ows_pos_customer_sidebar.xml +++ b/open_workshop_pos/static/src/xml/ows_pos_customer_sidebar.xml @@ -18,6 +18,10 @@