diff --git a/__init__.py b/__init__.py index 6a137ce..0650744 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1 @@ from . import models -from . import controllers -from . import post_init_hook -# damit run_migration sichtbar ist: -run_migration = post_init_hook.run_migration \ No newline at end of file diff --git a/__manifest__.py b/__manifest__.py index ca9ccfa..45c7554 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -1,38 +1,19 @@ { 'name': 'POS Open Workshop', 'license': 'AGPL-3', - 'version': '13.0.1.0.0', + 'version': '16.0.1.0.0', 'summary': 'Erstellt Maschinenfreigaben basierend auf POS-Einweisungsprodukten', 'depends': ['base','product','sale','contacts','point_of_sale'], 'author': 'matthias.lotz', 'category': 'Point of Sale', 'data': [ + # 'data/data.xml', 'security/ir.model.access.csv', - 'views/machine_product_training_views.xml', - 'views/menu_views.xml', - 'views/machine_area_views.xml', - 'views/machine_views.xml', - 'views/res_partner_view.xml', - 'views/assets.xml', - 'data/data.xml', - ], - 'qweb': [ - 'static/src/xml/ows_briefing_details.xml', - 'static/src/xml/ows_briefing_details_edit.xml', - 'static/src/xml/ows_pos_order_selector.xml', - 'static/src/xml/ows_machine_sidebar.xml', - 'static/src/xml/ows_pos_machine_access_view.xml', - ], + ], + 'installable': True, - 'assets': { - 'point_of_sale.assets': [ - 'static/src/js/machine_access_sidebar.js', - 'static/src/css/pos.css', - ], - }, - 'post_init_hook': 'run_migration', 'description': """ Diese App erstellt Maschinenfreigaben basierend auf POS-Einweisungsprodukten. - Die App ist für den Einsatz in der Odoo-Version 13.0 konzipiert. + Die App ist für den Einsatz in der Odoo-Version 16.0 konzipiert. """, } diff --git a/controllers/__init__.py b/controllers/__init__.py deleted file mode 100644 index 4dc11d1..0000000 --- a/controllers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Datei: open_workshop/controllers/__init__.py - -from . import pos_access diff --git a/controllers/pos_access.py b/controllers/pos_access.py deleted file mode 100644 index b185398..0000000 --- a/controllers/pos_access.py +++ /dev/null @@ -1,11 +0,0 @@ -# Datei: controllers/pos_access.py - -from odoo import http -from odoo.http import request - -class OpenWorkshopPOSController(http.Controller): - - @http.route('/open_workshop/partner_access', type='json', auth='user') - def get_partner_machine_access(self, partner_id): - Machine = request.env['ows.machine'].sudo() - return Machine.get_access_list_grouped(partner_id) diff --git a/demo/demo_partners.csv b/demo/demo_partners.csv deleted file mode 100644 index 546340c..0000000 --- a/demo/demo_partners.csv +++ /dev/null @@ -1,51 +0,0 @@ -id,name,street,zip,city,phone,email,company_type,customer_rank,supplier_rank -res_partner_demo_1, AAAA Max Mustermann,Musterstraße 1,,,,,person,15,0 -res_partner_demo_2, Benjamin Winter,,,,,,person,1,0 -res_partner_demo_3, Martin Berthelon,Fabrikstr. 3,73728,Esslingen,,martin.berthelon@hotmail.fr,person,15,0 -res_partner_demo_4,Aaron Christ,Hohewartstraße 46,70469,Stuttgart,,christ.aaron@web.de,person,14,0 -res_partner_demo_5,Aaron Dörr,Riegeläckerstr. 60,71229,Leonberg,,aaron_doerr@web.de,person,33,0 -res_partner_demo_6,Aaron Gale,Chopinstr. 20,70195,Stuttgart,015172165290,aarongale1@live.com,person,4,0 -res_partner_demo_7,Aaron Zimmermann,Heinrichstr. 15,38106 ,Braunschweig,016091647469,,person,1,0 -res_partner_demo_8,Abalrahman Alsadi,Bachstr. 29,70563,Stuttgart,,abdulrahman.m.saadi@gmail.com,person,1,0 -res_partner_demo_9,Abdullah Zengin,Engelbertstr. 124,70499,Stuttgart,,,person,3,0 -res_partner_demo_10,Abdussamed Korkmaz,Bertha-von-Suttner-Straße 1,74366,Kirchheim Am Neckar,,korkmaz.abdussamed@gmail.com,person,1,0 -res_partner_demo_11,Achim Brendle,Oberwiesenstraße 45,70619,Stuttgart,7114797505,achim.brendle@web.de,person,2,0 -res_partner_demo_12,Achim Jatkowski,Hummelstr. 38,70569,Stuttgart,017621512316,achim.jatkowski@gmail.com,person,1,0 -res_partner_demo_13,Achim Jung,Kurt Tucholsky Str. 6,71254,Ditzingen,07156174013,acjung@web.de,person,1,0 -res_partner_demo_14,Achim Kelbel,Vivaldiweg 6,70195,Stuttgart,,a.kelbel@t-online.de,person,2,0 -res_partner_demo_15,Achim Kramer,Reinsburger 172,70197,Stuttgart,,achim@zibra.de,person,1,0 -res_partner_demo_16,Adalbert Zeisl,Bachstr. 20,71364,Winnenden,07195-2092884,betz1000@gmx.de,person,2,0 -res_partner_demo_17,Adalina Schäfer,Sancenbacherstr. 26,74538,Rosengarten,015778855550,lina_max_schaefer@gmx.de,person,1,0 -res_partner_demo_18,Adam Riegel,Marabustr. 35 / 84,70378,Stuttgart,0711 532082,,person,1,0 -res_partner_demo_19,Adam Swais,Obertürkheimerstr. 54,73733,Esslingen,,adamswais@web.de,person,1,0 -res_partner_demo_20,Adela Spulber,Obere Bismarck Str. 97,70197,Stuttgart,,,person,1,0 -res_partner_demo_21,Adem Uzun,Liesel-Bach-Str. 54,71034,Böblingen,015251690873,adem.uzun2@gmail.com,person,1,0 -res_partner_demo_22,Adnan Djekic,Vesoulerstr. 33,70839,Gerlingen,01724227468,adnandjekic@alice-dsl.net,person,1,0 -res_partner_demo_23,Adrian Berres,Bärgstadter Str. 90,63928,Gehenbühl,,a.berres@gmx.de,person,1,0 -res_partner_demo_24,Adrian Lanksweirt,Heidestraße 6,70469,Stuttgart,,adrian.lanksweirt@gmail.com,person,1,0 -res_partner_demo_25,Adrian Popov,Hallerstr. 42,90419,Nürnberg,+4915114305751,adrinuernberg@gmail.com,person,2,0 -res_partner_demo_26,Agnes Krettek,Seyfferstr. 62,70187,Stuttgart,,agneskrettek@gmail.com,person,1,0 -res_partner_demo_27,Ahmad Taijan,Rümelinstr 69,70191,Stuttgart,,,person,2,0 -res_partner_demo_28,Aileen Becker,Eichendorffstr. 4,73630,Remshalden,015780645637,aileen.becker@gmx.de,person,87,0 -res_partner_demo_29,Ailey Simpson,Eierstraße 44 A,70199,Stuttgart,,aileywsimpson@gmail.com,person,1,0 -res_partner_demo_30,Akira Mitsu,Fritz-Ulrich-Weg 5,70567,Stuttgart,,mitsuakira0914@gmail.com,person,5,0 -res_partner_demo_31,Aksel Özdemir,Rotebühlstraße 53,70178,Stuttgart,,aksel.oezdemir@gmx.de,person,2,0 -res_partner_demo_32,Albert Ebenbichler,Am Backhaus 9,73666,Boltmannsweiler,01726101655,info@albert-ebenbichler.com,person,1,0 -res_partner_demo_33,Albert Kaupp,Waldäckerstr. 10,70435,Stuttgart,0711 8263232,albert.kaupp@online.de,person,2,0 -res_partner_demo_34,Albrecht Barth,Klopstockstr. 39,70193,Stuttgart,,albrecht.barth@web.de,person,3,0 -res_partner_demo_35,Albrecht Schlayer,Im Netzbrunnen 17,70825,K-Münchingen,,aws1308@gmail.com,person,1,0 -res_partner_demo_36,Alec Dobler,Kräherwald 251,70193,Stuttgart,,,person,1,0 -res_partner_demo_37,Alejandro Cano Perez,Burgstallstraße 66,70199,Stuttgart,,cano.perez@gmx.de,person,2,0 -res_partner_demo_38,Alejandro Rodriguez,Im Hirschwinkel 1,76297,Stutensee,015771409317,ralexei95@yahoo.de,person,1,0 -res_partner_demo_39,Alejandro Zarza Aguado,Reinsburgstr. 152,70197,Stuttgart,017628401435,11alex96@gmail.com,person,1,0 -res_partner_demo_40,Aleksandar Vasić,Lothringer Str. 5,70435,Stuttgart,,aleksvasic@web.de,person,3,0 -res_partner_demo_41,Alen Minasyan,Kastanienallee 41/1,71638,Ludwigsburg,,bidilik@gmx.de,person,1,0 -res_partner_demo_42,Alex Olenberg,Theodor-Rottschildstr. 25,73760,Stuttgart,,,person,26,0 -res_partner_demo_43,Alex Schaut,Braunenbergweg 9,70806,Kornwestheim,07154 16530,aschaut@gmx.de,person,3,0 -res_partner_demo_44,Alexander Adloff,Charlottenstraße 2,74074,Heilbronn,,alexadloff@gmx.de,person,3,0 -res_partner_demo_45,Alexander Bauer,Im Himmel 20,70569,Stuttgart,071172237601,ab.312@icloud.com,person,1,0 -res_partner_demo_46,Alexander Blendl,Neckarstr. 8,70736,Fellbach,,blendl.alex@gmail.com,person,4,0 -res_partner_demo_47,Alexander Borshov,Schellingstraße 24,71277,Rutesheim,,aborshov@gmail.com,person,1,0 -res_partner_demo_48,Alexander Bosch,Osterwiesenstr. 37,70794,Filderstadt,,bosch-alexander@web.de,person,1,0 -res_partner_demo_49,Alexander Braig,Holzgrund Str. 25,70806,Kornwestheim,,a.braig84@gmx.de,person,17,0 -res_partner_demo_50,Alexander Carolus,Kornbergstr. 23,70176,Stuttgart,,alexander.carolus,person,1,0 diff --git a/demo/export.py b/demo/export.py deleted file mode 100644 index d36c615..0000000 --- a/demo/export.py +++ /dev/null @@ -1,2 +0,0 @@ -/opt/odoo/odoo/odoo-bin shell -d hobbyhimmel < /home/odoo/custom_addons/open_workshop/demo/export_partner.py - diff --git a/demo/export_partner.py b/demo/export_partner.py deleted file mode 100644 index 5d3424e..0000000 --- a/demo/export_partner.py +++ /dev/null @@ -1,38 +0,0 @@ -import csv -import random - -# Beispielsweise 50 Kunden mit Namen und E-Mail -partners = env['res.partner'].search( - [('customer_rank', '>', 0), ('is_company', '=', False)], - limit=50 -) - -with open('/home/odoo/custom_addons/open_workshop/demo/demo_partners.csv', 'w', newline='') as f: - writer = csv.writer(f) - writer.writerow([ - 'id', - 'name', - 'street', - 'zip', - 'city', - 'phone', - 'email', - 'company_type', - 'customer_rank', - 'supplier_rank' - ]) - - for idx, partner in enumerate(partners, start=1): - partner_id = f'res_partner_demo_{idx}' - writer.writerow([ - partner_id, - partner.name or '', - partner.street or '', - partner.zip or '', - partner.city or '', - partner.phone or '', - partner.email or '', - partner.company_type or 'person', - partner.customer_rank, - partner.supplier_rank, - ]) diff --git a/fix_missing_partners.py b/fix_missing_partners.py deleted file mode 100644 index 6c55728..0000000 --- a/fix_missing_partners.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -from odoo import SUPERUSER_ID -from odoo.api import Environment -import logging - -_logger = logging.getLogger(__name__) - -MISSING_PARTNERS = [ - 6534, 1594, 4700, 6557, 5392, 4960, 5226, 6535, 4666 -] - -def insert_missing_partners(cr, registry): - env = Environment(cr, SUPERUSER_ID, {}) - - for partner_id in MISSING_PARTNERS: - cr.execute(""" - INSERT INTO res_partner ( - id, name, customer_rank, create_uid, create_date, write_uid, write_date - ) - VALUES (%s, %s, 1, %s, now(), %s, now()) - ON CONFLICT (id) DO NOTHING; - """, (partner_id, f"Fehlender Partner {partner_id}", SUPERUSER_ID, SUPERUSER_ID)) - - cr.execute("SELECT setval('res_partner_id_seq', (SELECT MAX(id) FROM res_partner));") - - _logger.info(f"[OWS Repair] {len(MISSING_PARTNERS)} fehlende Partner hinzugefügt.") - cr.commit() - -# Automatischer Start in odoo-bin shell -if 'env' in globals(): - insert_missing_partners(env.cr, env.registry) \ No newline at end of file diff --git a/models/__init__.py b/models/__init__.py index 9f91cbd..6c9f9d9 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,5 +1,5 @@ from . import ows_models -from . import pos_order + diff --git a/models/pos_order.py b/models/pos_order.py deleted file mode 100644 index ddffff6..0000000 --- a/models/pos_order.py +++ /dev/null @@ -1,51 +0,0 @@ -from odoo import models, fields, api - -#import debugpy -import logging - -_logger = logging.getLogger(__name__) -_logger.info("✅ pos_order.py geladen") - -# debugpy.listen(("0.0.0.0", 5678)) -print("✅ debugpy wartet auf Verbindung (Port 5678) ...") -# Optional: Starte erst, wenn VS Code verbunden ist -#debugpy.wait_for_client() - -class PosOrder(models.Model): - _inherit = 'pos.order' - - def _process_order(self, order, draft, existing_order): - pos_order_id = super(PosOrder, self)._process_order(order, draft, existing_order) - pos_order = self.browse(pos_order_id) - - training_products = self.env['ows.machine.training'].search([]) - product_map = { - tp.training_id.product_tmpl_id.id: tp.machine_id.id - for tp in training_products - } - - partner = pos_order.partner_id - if not partner: - _logger.info("🟡 POS-Bestellung ohne Partner – keine Freigabe möglich") - return pos_order_id - - for line in pos_order.lines: - product_tmpl_id = line.product_id.product_tmpl_id.id - machine_id = product_map.get(product_tmpl_id) - - _logger.info("🔍 Prüfe Produkt %s → Maschine ID: %s", line.product_id.display_name, machine_id) - - if machine_id: - already_exists = self.env['ows.machine.access'].search([ - ('partner_id', '=', partner.id), - ('machine_id', '=', machine_id) - ]) - if not already_exists: - self.env['ows.machine.access'].create({ - 'partner_id': partner.id, - 'machine_id': machine_id, - 'granted_by_pos': True - }) - _logger.info("✅ Maschinenfreigabe erstellt: %s für %s", machine_id, partner.name) - - return pos_order_id diff --git a/scripts/fix_missing_pos_partner.py b/scripts/fix_missing_pos_partner.py deleted file mode 100644 index 7e95648..0000000 --- a/scripts/fix_missing_pos_partner.py +++ /dev/null @@ -1,41 +0,0 @@ -from odoo import SUPERUSER_ID - -def fix_missing_pos_order_partners(cr, registry): - """ - Findet POS-Bestellungen mit fehlendem Partner und fügt Dummy-Partner - direkt per SQL mit der passenden ID ein. - """ - cr.execute(""" - SELECT DISTINCT partner_id FROM pos_order - WHERE partner_id IS NOT NULL - AND partner_id NOT IN (SELECT id FROM res_partner) - """) - missing_ids = [row[0] for row in cr.fetchall()] - print(f"Superuser: {SUPERUSER_ID}") - if not missing_ids: - print("✅ Keine fehlenden Partner gefunden.") - return - - print(f"🚧 Fehlende Partner-IDs: {missing_ids}") - - # Direkter SQL-Insert für res_partner - for pid in missing_ids: - print(f"➕ Erzeuge Dummy-Partner mit ID {pid}") - cr.execute(""" - INSERT INTO res_partner (id, name, customer_rank, create_uid, create_date, write_uid, write_date) - VALUES (%s, %s, %s, %s, now(), %s, now()) - ON CONFLICT (id) DO NOTHING - """, (pid, f"Fehlender Partner {pid}", 1, SUPERUSER_ID, SUPERUSER_ID)) - - # Sequenz zurücksetzen, um ID-Kollision zu verhindern - cr.execute(""" - SELECT setval('res_partner_id_seq', (SELECT MAX(id) FROM res_partner)) - """) - print("✅ Alle fehlenden Partner ergänzt.") - - - -# Automatischer Start in odoo-bin shell -if 'env' in globals(): - fix_missing_pos_order_partners(env.cr, env.registry) - env.cr.commit() \ No newline at end of file diff --git a/scripts/import_machine_products.py b/scripts/import_machine_products.py deleted file mode 100644 index 9bd402f..0000000 --- a/scripts/import_machine_products.py +++ /dev/null @@ -1,79 +0,0 @@ -# import_machine_products.py -# odoo-bin shell -d deine_datenbank < import_machine_products.py -import logging -from odoo import api, SUPERUSER_ID - -_logger = logging.getLogger(__name__) - -# Mapping von product_id > machine_id -TRAINING_MAPPING = { - '16':'1', - '11':'2', - '10':'4', - '117':'5', - '14':'6', - '12':'7', - '15':'8', - '118':'10', - '118':'11', - '118':'12', - '18':'15', - '18':'16', - '13':'18', - '17':'19', -} - -# Mapping von product_id > machine_id -USAGE_MAPPING = { - '50':'1', - '49':'2', - '49':'3', - '49':'4', - '53':'5', - '52':'7', - '55':'8', - '59':'15', - '60':'15', - '59':'16', - '60':'16', - '57':'18', - '58':'19', -} - -def run_import(cr, registry): - env = api.Environment(cr, SUPERUSER_ID, {}) - - machine_model = env['ows.machine'] - product_model = env['product.product'] - training_model = env['ows.machine.training'] - usage_model = env['ows.machine.product'] - - created_training = 0 - created_usage = 0 - - for product_id, machine_id in TRAINING_MAPPING.items(): - machine = machine_model.search([('id', '=', machine_id)], limit=1) - product = product_model.search([('id', '=', product_id)], limit=1) - if machine and product: - training_model.create({ - 'machine_id': machine.id, - 'training_id': product.id, - }) - created_training += 1 - - for product_id, machine_id in USAGE_MAPPING.items(): - machine = machine_model.search([('id', '=', machine_id)], limit=1) - product = product_model.search([('id', '=', product_id)], limit=1) - if machine and product: - usage_model.create({ - 'machine_id': machine.id, - 'product_id': product.id, - }) - created_usage += 1 - - _logger.info(f"[OWS Import] ✅ Trainings-Zuordnungen erstellt: {created_training}, Nutzungs-Zuordnungen erstellt: {created_usage}") - env.cr.commit() - -# Automatischer Start in odoo-bin shell -if 'env' in globals(): - run_import(env.cr, env.registry) \ No newline at end of file diff --git a/scripts/install-odoo.sh b/scripts/install-odoo.sh deleted file mode 100755 index 8ec438c..0000000 --- a/scripts/install-odoo.sh +++ /dev/null @@ -1 +0,0 @@ -/opt/odoo/odoo/odoo-bin -d hobbyhimmel13_dev -i base,sale,pos_time_based_products,wk_coupons,pos_coupons,open_workshop --stop-after-init --load-language=de_DE \ No newline at end of file diff --git a/scripts/odoo-restore.sh b/scripts/odoo-restore.sh deleted file mode 100644 index 65a2b4d..0000000 --- a/scripts/odoo-restore.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -BACKUP_DIR=/root # Verzeichnis, in dem das Backup temporär gespeichert wird. -#MONITOR_URL='https://cronitor.link/p/c6debfe4e00f46fe9eb430ab9d2b2588/7PPIpd' # Cronitor-URL zur Überwachung des Skriptstatus. -ODOO_DATABASE=hobbyhimmel # Der Name der Odoo-Datenbank, die wiederhergestellt werden soll. -DEFAULT_URL="http://hobbybackend2.fritz.box:9013" # Standard-URL für die Odoo-Datenbank-Backup-API. -URL="${1:-$DEFAULT_URL}" # Falls ein Argument übergeben wird, wird es als URL genutzt, sonst bleibt die Standard-URL. -BACKUP_NAME=${ODOO_DATABASE}.latest.zip # Der Name der Backup-Datei, wobei das aktuelle Datum an den Namen angehängt wird. -remote_directory=/www/htdocs/${sftp_user}/odoo # Das Verzeichnis auf dem Remote-SFTP-Server, in dem die Backups gespeichert werden. - -# Function to report failure to Cronitor with step -# Diese Funktion meldet einen Fehler an Cronitor und beendet das Skript. -# Parameter: $1 - Der Schrittname, der beim Fehlschlag gemeldet wird. -report_failure() { - local step=$1 # Schrittname wird als erster Parameter übergeben. - echo "Error during $step" # Meldet den Fehler. - #curl "$MONITOR_URL?state=fail&message=$step" # Meldet den Fehlerstatus an Cronitor. - exit 1 # Beendet das Skript mit Exit-Code 1 (Fehler). -} - -echo "Restoring Odoo database from backup..." # Meldet den Beginn der Wiederherstellung der Odoo-Datenbank. -echo "Verbindungsdaten: ${sftp_password}, ssh-${sftp_user}, ${sftp_host}" - -cd /root # Wechselt in das Home-Verzeichnis des Benutzers. -# Holt die verschlüsselte Backup-Datei vom Remote-SFTP-Server in das lokale Verzeichnis. -sshpass -p "${sftp_password}" sftp -i ~/.ssh/id_rsa ssh-${sftp_user}@${sftp_host}:${remote_directory} < Funktioniert nicht, weil im Passwort ein ´ enthalten ist -#rm ${BACKUP_NAME} -#gpg --batch --yes --passphrase "{$gpg_password}" --output "${BACKUP_DIR}/${BACKUP_NAME}" --decrypt "${BACKUP_DIR}/${BACKUP_NAME}.gpg" - -echo "Admin password: ${ADMIN_PASSWORD}" # Meldet das Admin-Passwort. -echo "Database name: ${ODOO_DATABASE}" # Meldet den Namen der Odoo-Datenbank. -echo "Backup name: ${BACKUP_NAME}" # Meldet den Namen der Backup-Datei. -echo "URL: ${URL}" # Meldet die URL der Odoo-Datenbank-Backup-API. -echo "Backup directory: ${BACKUP_DIR}" # Meldet das Verzeichnis, in dem das Backup gespeichert wird. -echo "Delete database: ${ODOO_DATABASE}" # Meldet, dass die Datenbank gelöscht wird. -curl -X POST -s \ - -F "master_pwd=${ADMIN_PASSWORD}" \ - -F "name=${ODOO_DATABASE}" \ - ${URL}/web/database/drop || report_failure "Database deletion" - -echo "Restoring database..." # Meldet den Beginn der Wiederherstellung der Datenbank. -curl \ - -F "master_pwd=${ADMIN_PASSWORD}" \ - -F "name=${ODOO_DATABASE}" \ - -F "backup_file=@${BACKUP_DIR}/${BACKUP_NAME}" \ - -F "backup_format=zip" \ - -F "copy=true" \ - ${URL}/web/database/restore || report_failure "Database restoration" - -# If everything was successful, report completion -# Meldet den erfolgreichen Abschluss des Skripts an Cronitor. -#curl "$MONITOR_URL?state=complete" diff --git a/scripts/uninstall_rpc.py b/scripts/uninstall_rpc.py deleted file mode 100755 index 7dd53b4..0000000 --- a/scripts/uninstall_rpc.py +++ /dev/null @@ -1,59 +0,0 @@ -import sys -import os -import xmlrpc.client - -# ---------------------- -# KONFIGURATION AUS UMGEBUNG -# ---------------------- -url = os.getenv("ODOO_URL", "http://localhost:8069") -db = os.getenv("ODOO_DB", "hobbyhimmel") -username = os.getenv("ODOO_USERNAME") -password = os.getenv("ODOO_PASSWORD") - -# ---------------------- -# PRÜFUNG DER KONFIGURATION -# ---------------------- -if not all([url, db, username, password]): - print("❌ Fehler: ODOO_URL, ODOO_DB, ODOO_USERNAME und ODOO_PASSWORD müssen als Umgebungsvariablen gesetzt sein.") - sys.exit(1) - -# ---------------------- -# PARAMETER PRÜFEN -# ---------------------- -if len(sys.argv) != 2: - print("❌ Fehler: Modulname muss als Parameter übergeben werden.") - print("👉 Beispiel: python3 uninstall_rpc.py vvow_einweisungen") - sys.exit(1) - -module_name = sys.argv[1] - -# ---------------------- -# AUTHENTIFIZIERUNG -# ---------------------- -common = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/common") -uid = common.authenticate(db, username, password, {}) - -if not uid: - print("❌ Anmeldung fehlgeschlagen. Bitte Zugangsdaten prüfen.") - sys.exit(1) - -# ---------------------- -# MODUL SUCHEN & DEINSTALLIEREN -# ---------------------- -models = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/object") - -ids = models.execute_kw(db, uid, password, - 'ir.module.module', 'search', - [[['name', '=', module_name], ['state', '=', 'installed']]], - {'limit': 1} -) - -if ids: - print(f"📦 Deinstalliere Modul: {module_name}") - models.execute_kw(db, uid, password, - 'ir.module.module', 'button_immediate_uninstall', - [ids] - ) - print("✅ Deinstallation abgeschlossen.") -else: - print(f"ℹ️ Modul '{module_name}' ist nicht installiert oder nicht vorhanden.") diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv index 022703c..d011792 100644 --- a/security/ir.model.access.csv +++ b/security/ir.model.access.csv @@ -2,7 +2,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_ows_machine_access_user,ows.machine.access,model_ows_machine_access,base.group_user,1,1,1,1 access_ows_machine_user,ows.machine,model_ows_machine,base.group_user,1,1,1,1 access_ows_machine_product_user,ows.machine.product,model_ows_machine_product,base.group_user,1,1,1,1 -access_ows_machine_training_user,access_ows_machine_training_user,model_ows_machine_training,base.group_user,1,1,1,1 access_ows_machine_area,ows.machine.area,model_ows_machine_area,base.group_user,1,1,1,1 access_ows_user,ows.user,model_ows_user,base.group_user,1,1,1,1 -access_ows_machine_training,ows.machine.training,model_ows_machine_training,base.group_user,1,1,1,1 +access_ows_machine_training_user,ows.machine.training,model_ows_machine_training,base.group_user,1,1,1,1 + diff --git a/static/src/css/pos.css b/static/src/css/pos.css deleted file mode 100644 index 2d5340d..0000000 --- a/static/src/css/pos.css +++ /dev/null @@ -1,2622 +0,0 @@ -/* --- Fonts --- */ - -@font-face{ - font-family: 'Inconsolata'; - src: url(../fonts/Inconsolata.otf); -} - -/* --- Styling of OpenERP Elements --- */ -.ui-dialog, .modal-dialog { - background: white; - padding: 10px; - border-radius: 3px; - font-family: sans-serif; - box-shadow: 0px 10px 40px rgba(0,0,0,0.4); - position: absolute; - top: 30px; - height: 400px; - overflow: scroll; -} -.ui-dialog button, .modal-dialog button { - padding: 8px; - min-width: 48px; -} -.ui-dialog .ui-icon-closethick{ - float: right; -} -div.modal.in { - position: absolute; - background: white; - padding: 20px; - box-shadow: 0px 10px 20px black; - border-radius: 3px; - max-width: 600px; - max-height: 400px; - margin-top: -200px; - margin-left: -300px; - top: 50%; - left: 50%; -} - -/* --- Generic Restyling and Resets --- */ - -html { - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - font-family: sans-serif; -} - -table { - border-spacing: 0px; - border-collapse: collapse; -} -td { - padding: 0px; -} - -.oe_hidden{ - display: none !important; -} -.oe_invisible{ - visibility: hidden !important; -} -.clearfix:after { - content:" "; - display: block; - visibility: hidden; - line-height: 0; - height: 0; - clear: both; -} - - -.pos input::-webkit-outer-spin-button, -.pos input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} - -.pos button{ - box-shadow: none; - outline: none; - border: none; - font-family: 'Lato'; -} -.pos button:hover{ - background: default; -} -.pos textarea { - font-family: "Lato"; - font-size: 20px; - color: #444; - padding: 10px; - border-radius: 3px; - border: none; - box-shadow: 0px 0px 0px 1px rgb(220,220,220) inset; -} -.pos textarea:focus { - outline: none; - box-shadow: 0px 0px 0px 3px #6EC89B; -} - - -.pos .oe_hidden{ - display: none !important; -} - -.pos ul, .pos li { - margin: 0; - padding: 0; - list-style-type: none; -} - -.pos { - background: #d3d3d3 - direction: ltr; - padding: 0; - margin: 0; - background-color: #f0eeee; - font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial; - color: #555555; - font-size: 12px; - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - text-shadow: none; - overflow: hidden; -} - -/* ********* The black loading screen ********* */ - -.pos .loader{ - background-color: #222; - position:absolute; - left:0px; - top:0px; - width:100%; - height:100%; - z-index: 999; - text-align: center; - font-family: Lato; - color: #555555; -} - -.pos .loader-feedback{ - width: 400px; - height: 160px; - margin: -60px -200px; - position: absolute; - left: 50%; top: 50%; - text-align: center; -} -.pos .loader-feedback h1{ - font-weight: 300; -} -.pos .loader-feedback .progressbar{ - background: rgb(73,73,73); - height: 1px; -} -.pos .loader-feedback .progressbar > .progress{ - height: 100%; - background: white; - width: 0%; - box-shadow: 0px 0px 5px rgba(255,255,255,0.35); -} -.pos .loader-feedback .button{ - display: inline-block; - margin: 25px auto; - line-height: 42px; - padding: 0px 16px; - font-size: 20px; - font-weight: 300; - border: solid 1px; - border-radius: 5px; - cursor: pointer; -} -.pos .loader-feedback .button:active{ - color: #222; - background: #555555; -} -/* ********* Generic Layout Constructs ********* */ - -.pos .window{ - position: absolute; - top: 0px; - left: 0px; - width: 100%; - height: 100%; - display: table; - border: none; - overflow: hidden; -} -.pos .window .subwindow{ - display: table-row; - width: 100%; - height: 100%; -} -.pos .window .subwindow.collapsed{ - height: 0px; -} -.pos .window .subwindow-container .collapsed{ - height: 0px; -} -.pos .subwindow .subwindow-container{ - display: table-cell; - position: relative; -} -/* firefox seems to ignore the relative positionning of the subwindow-container - * putting this inside subwindow-container fixes it. - */ -.pos .subwindow .subwindow-container-fix{ - height: 100%; - position: relative; -} - -.pos .clientlist-screen .window, -.pos .clientlist-screen .full-content .subwindow{ - display: block; -} -.pos .clientlist-screen .full-content .subwindow-container{ - display: block; - height: 100%; -} -.pos .clientlist-screen .full-content .subwindow.collapsed, -.pos .clientlist-screen .full-content .subwindow-container.collapsed{ - height: auto; -} - -/* ---- Scrollers ----- */ - -.pos .scroller-container{ - position: absolute; - top: 0px; - left: 0px; - right: 0px; - bottom: 0px; -} -.pos .scroller{ - width: 100%; - height: 100%; - overflow: hidden; - overflow-y: auto; - -webkit-overflow-scrolling: touch; -} -.pos .scroller.horizontal{ - overflow-y: hidden; - overflow-x: auto; -} -.pos .scroller-content{ - -webkit-transform: translate3d(0,0,0); -} -.pos .scroller-container ::-webkit-scrollbar{ - width: 10px; - height: 10px; -} -.pos .scroller-container ::-webkit-scrollbar-track{ - background: rgb(224,224,224); - border-left: solid 1px rgb(200,200,200); - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; -} -.pos .scroller-container ::-webkit-scrollbar-thumb{ - background: rgb(168,168,168); - min-height: 30px; -} - -/* ********* Generic element styling ********* */ - -.pos a { - text-decoration: none; - color: #555555; -} -.pos button, .pos a.button { - display: inline-block; - cursor: pointer; - padding: 4px 10px; - font-size: 11px; - border: 1px solid #cacaca; - background: #e2e2e2; - border-radius: 3px; -} -.pos ul, .pos ol { - padding: 0; - margin: 0; -} -.pos li { - list-style-type: none; -} -.pos .pos-right-align { - text-align: right; -} -.pos .pos-center-align { - text-align: center; -} -.pos .pos-disc-font { - font-size: 12px; - font-style:italic; - color: #808080; -} - -/* ********* The black header bar ********* */ - - -.pos .pos-topheader { - position:absolute; - left:0; - top:0; - width: 100%; - height: 48px; - margin:0; - padding:0; - color: gray; - background: #393939; -} - -/* a) The left part of the top-bar */ - -.pos .pos-branding{ - position: absolute; - display: table-cell; - left:0; - top:0; - width:439px; - height:100%; - margin:0; - padding:0; - border-right: 1px solid #373737; - text-align:left; - line-height:100%; - vertical-align: middle; -} -.pos .pos-logo { - height: 35px; - margin-left: 10px; - margin-top: 5px; - vertical-align:middle; -} -.pos .pos-branding .username{ - float:right; - color:#DDD; - font-size:16px; - margin-right:32px; - line-height: 48px; - font-style:italic; - cursor: pointer; -} - -/* b) The right part of the top-bar */ - -.pos .pos-rightheader { - position: absolute; - right:0; - top:0; - height:100%; - display: -webkit-flex; - display: flex; - overflow : hidden; - overflow-x: auto; - -webkit-overflow-scrolling: touch; -} -.pos .pos-rightheader > * { - border-right: 1px solid #292929; -} - -.pos .new-order-button{ - text-align: center; - width : 100%; - height: 48px; - background : #d3d3d3; -/* overflow: auto; */ -} - -.pos .order-button{ - color: #f0f0f0; - display: inline-block; - box-sizing: border-box; - -moz-box-sizing: border-box; - padding-left: 6px; - margin: 2px; - background: #8b8b8b; - border-radius: 3px; - vertical-align: top; - line-height: 30px; - text-align: left; - box-shadow: 0px -5px 10px -6px rgb(82,82,82) inset; - cursor: pointer; - width : 98%; - min-width: 45px; -/* overflow: auto; */ -} - -.pos .order-button:first-child { - margin-left: 0px; -} - -.pos .orders .order-button { - display: flex; - justify-content: flex-start; /* falls nötig */ - flex-direction: row-reverse; - align-items: center; - gap: 0.5em; -} - - -.pos .order-button.selected{ - font-weight: 900; - background: #EEEEEE; - color: rgb(75,75,75); - height: 35px; - line-height: 35px; - border-bottom: solid 1px rgb(196, 196, 196); - border-right: solid 0px eeeeee; - box-shadow: none; - -webkit-flex-shrink: 0; - flex-shrink: 0; - width : 98%; -} - -.pos .order-button .order-sequence{ - font-size: 16px; - width: 99% - font-weight: 800; - vertical-align: middle; -} -.pos .order-button.selected .order-sequence{ - color: white; - background: black; - display: inline-block; - line-height: 24px; - min-width: 24px; - border-radius: 12px; - margin-right: 4px; - margin-left: -4px; -} - -.pos .order-button.square { - margin-left: 1px; - /* background: #5c5c5c; */ - /* color: rgb(160, 160, 160); */ - /* font-size: 18px; */ - text-align: center; - line-height: 36px; - width: 45%; - /* margin-top: 10px; */ - /* margin-bottom: 10px; */ - /* padding: 10px; */ -} -.pos .order-button:not(.square) > .fa { - font-size: 16px; - vertical-align: middle; - margin-right: 4px; -} -.pos .order-button .order-sequence{ - font-size: 16px; - font-weight: 800; -} - -.pos .order-selector { - width: 220px; - position: absolute; - height: 100%; - top: 48px; - - display: -webkit-flex; - display: flex; - -webkit-flex: 1; - flex: 1; - direction: rtl; -} - -.pos .orders { - width: 98%; - position: absolute; - vertical-align: top; - margin-left: 0px; - top: 48px; - /* make it wrap to multiple lines and get a scrollbar */ - overflow: auto; - scrollbar-color: gray gray; - box-sizing: border-box; - height: calc(100% - 2 * 48px); /* The pixels is the value of top */ - direction: rtl;; -} - -/* c) The session buttons */ - -.pos .pos-rightheader .header-button{ - float: right; - height: 48px; - padding-left: 16px; - padding-right: 16px; - border-right: 1px solid #292929; - border-left: 1px solid #292929; - color: #DDD; - line-height: 48px; - text-align: center; - cursor: pointer; - - -webkit-transition-property: background; - -webkit-transition-duration: 0.2s; - -webkit-transition-timing-function: ease-out; -} -.pos .pos-rightheader .header-button:last-child{ - border-left: 1px solid #3a3a3a; -} -.pos .pos-rightheader .header-button:active{ - background: rgba(0,0,0,0.2); - color:#EEE; -} -.pos .pos-rightheader .header-button.confirm { - background: #359766; - color: white; - font-weight: bold; -} - -/* c) The notifications indicator */ - -.pos .oe_status{ - float:right; - color: white; - padding: 14px; - line-height: 20px; - font-size: 30px; - vertical-align:middle; - font-style: italic; - font-weight: bold; - cursor:pointer; -} - -.pos .oe_status .username{ - margin-right: 200px; -} - -.pos .oe_status.oe_inactive{ - cursor: default; -} -.pos .oe_status .oe_icon{ - display:inline-block; - cursor:pointer; - width:20px; height:16px; - color: white; -} -.pos .oe_status .oe_red, -.pos .oe_icon.oe_red { - color: rgb(197, 52, 0); -} -.pos .oe_status .oe_green, -.pos .oe_icon.oe_green { - color: rgb(94, 185, 55); -} -.pos .oe_status .oe_orange, -.pos .oe_icon.oe_orange { - color: rgb(239, 153, 65); -} -.pos .oe_link_icon{ - cursor:pointer; -} -/* ********* Contains everything below the bar ********* */ -.pos .pos-content { - width: 80%; /* 200px is the value of the left property */ - left: 20%; - right: 0%; - - position: absolute; - top: 48px; - bottom: 0; - background: #F0EEEE; -} - -/* ********* The leftpane contains the order, numpad and paypad ********* */ - -.pos .leftpane { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - position:absolute; - left:0; - width:440px; - top:0px; - bottom:0; - border-right: solid 1px #CECBCB; - border-right: solid 3px #787878; - background: #e2e2e2; -} - -.pos .leftpane .pads { - border-top: solid 3px rgb(110, 200, 155); -} - -/* ********* The control buttons ********* */ - -.pos .control-buttons { - display: -webkit-flex; - display: flex; - -webkit-flex-flow: row wrap; - flex-flow: row wrap; - padding: 8px 16px 0px 11px; - margin-bottom: -6px; -} -.pos .control-button { - -webkit-flex-grow: 1; - flex-grow: 1; - background: #e2e2e2; - border: solid 1px #bfbfbf; - display: inline-block; - line-height: 38px; - min-width: 80px; - text-align: center; - border-radius: 3px; - padding: 0px 10px; - font-size: 18px; - margin-left: 6px; - margin-bottom: 6px; - cursor: pointer; - overflow: hidden; - transition: all linear 150ms; -} -.pos .control-button:hover { - background: #efefef; -} -.pos .control-button:active { - background: black; - color: white; - border-color: black; -} -.pos .control-button .fa{ - margin-right: 4px; -} -.pos .control-button .control-button-number { - color: rgb(226, 226, 226); - background: rgb(85, 85, 85); - display: inline-block; - height: 28px; - vertical-align: middle; - font-weight: bold; - line-height: 28px; - width: 28px; - border-radius: 50%; - text-align: center; - margin-left: -16px; - margin-right: 4px; -} - -.pos .control-button.highlight, -.pos .button.highlight { - background: #6EC89B !important; - border: solid 1px #64AF8A !important; - color: white !important; -} -.pos .control-button.altlight, -.pos .button.altlight { - background: #7F82AC !important; - border: solid 1px #756A99 !important; - color: white !important; -} -.pos .control-button.disabled, -.pos .control-button.disabled:active{ - background: #e2e2e2; - border: solid 1px #BEBEBE; - opacity: 0.5; - cursor: default; - color: inherit; -} - -/* ********* The actionpad (payment, set customer) ********* */ - -.pos .actionpad { - display: inline-block; - float: left; - padding: 0; - margin: 16px; - margin-top: 8px; - margin-right: 0; - text-align: center; - vertical-align: top; - width: 186px; - border: none; - border-radius: 0; - border-top: 1px solid; - border-left: 1px solid; - border-color: #bfbfbf; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; -} -.pos .actionpad .button { - position: relative; - display: block; - height: 54px; - width: 100%; - font-weight: bold; - vertical-align: middle; - color: #555555; - font-size: 14px; - border-radius: 0; - border: none; - border-right: 1px solid; - border-bottom: 1px solid; - border-color: #bfbfbf; - transition: all 150ms linear; -} -.pos .actionpad .button:hover { - background: #efefef; -} -.pos .actionpad .button:active { - background: black; - border-color: black; - color: white; -} -.pos .actionpad .button:first-child { - border-top-left-radius: 4px; -} -.pos .actionpad .button:last-child { - border-bottom-left-radius: 4px; -} -.pos .actionpad .button.pay { - height: 162px; -} -.pos .actionpad .button.pay .pay-circle { - display: block; - font-size: 32px; - line-height: 54px; - padding-top: 6px; - background: rgb(86, 86, 86); - color: white; - width: 60px; - margin: auto; - border-radius: 30px; - margin-bottom: 10px; -} -.pos .actionpad .button.pay .pay-circle .fa { - position: relative; - top: -1px; - left: 3px; -} - -.pos .actionpad .button.set-customer{ - padding-left: 40px; - padding-right: 40px; -} -.pos .actionpad .button.set-customer.decentered { - padding-left: 40px; - padding-right: 5px; -} -.pos .actionpad .button .fa-user { - position: absolute; - left: 13px; - top: 13px; - margin-right: 8px; - font-size: 18px; - background: rgba(255, 255, 255, 0.5); - line-height: 30px; - width: 30px; - border-radius: 100%; -} - -/* ********* The Numpad ********* */ - -.pos .numpad { - display: inline-block; - float: right; - text-align: center; - width: 216px; - margin: 16px; - margin-top: 8px; - margin-left: 0px; - border: none; - border-radius: 0; - border-top: 1px solid; - border-color: #bfbfbf; - border-top-right-radius: 4px; -} -.pos .numpad button { - float: left/*rtl:ignore*/; /* rtlcss forced to keep ltr */ - height: 54px; - width: 54px; - font-weight: bold; - vertical-align: middle; - color: #555555; - border-radius: 0; - border: none; - border-right: 1px solid; - border-bottom: 1px solid; - border-color: #bfbfbf; - transition: all 150ms linear; -} -.pos .numpad button:hover { - background: #efefef; -} -.pos .numpad button:active { - background: black; - color: white; - border-color: transparent; -} -.pos .numpad button:nth-child(4) { - border-top-right-radius: 4px; -} -.pos .numpad button:last-child { - border-bottom-right-radius: 4px; -} -.pos .input-button { - font-size: 24px; -} -.pos .mode-button { - font-size: 14px; -} -.pos .mode-button.selected-mode { - color: white; - background: #6EC89B; - border-color: transparent; -} -.pos .mode-button.selected-mode:hover { - background: #6EC89B; - color: white; - border-color: transparent; -} -.pos .numpad .disabled-mode, .pos .numpad .disabled-mode:hover { - background: #c7c7c7; - color: #a5a1a1; - cursor: not-allowed; -} - -/* ********* The right pane contains the screens and headers ********* */ - -.pos .rightpane { - position: absolute; - top: 0; - bottom:0; - left: 440px; - right: 0; - vertical-align: top; - -webkit-transform: translate3d(0,0,0); -} - -.pos .rightpane-header { - padding: 0; - height: 48px; - border-bottom: 1px solid #c7c7c7; - background: #d3d3d3; - text-align: center; -} - -/* ********* The product list ********* */ - -.pos .product-list { - padding: 10px; - text-align: left; - -webkit-transform: translate3d(0,0,0); -} - -.pos .product-list-scroller{ - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - width:100%; - height:100%; - overflow: hidden; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - -webkit-transform: translate3d(0,0,0); - -} -.pos .product-list-container { - position:absolute; - top:0px; - bottom:0px; - left:0px; - right:0px; -} - -/* a) the product list navigation bar */ - -.pos .breadcrumbs{ - display: inline-block; - text-align: left; - float:left; -} -.pos .breadcrumb{ - float: left; - display: inline-block; - line-height: 48px; - height: 48px; - min-width: 48px; -} -.pos .breadcrumb:last-child { - padding-right: 3px; - border-right: 1px solid #c5c5c5; -} -.pos .breadcrumb-button { - display: inline-block; - padding: 0 9px; - vertical-align: top; - color: #808080; - font-size: 14px; - cursor: pointer; -} -.pos .breadcrumb-button.breadcrumb-home { - line-height: 50px; - padding: 0; - width: 50px; - font-size: 25px; - text-align: center; -} - -.pos .breadcrumb-arrow{ - width: 28px; -} -.pos .breadcrumb-homeimg { - width: 27px; - margin: 12px 6px; -} - -/* b) the search box */ - -.pos .searchbox { - position: absolute; - right: 2px; -} -.pos .searchbox input { - width: 100px; - border: 1px solid #cecbcb; - padding: 10px 20px; - padding-left: 38px; - padding-right: 33px; - margin: 6px; - background-color: white; - border-radius: 20px; - font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial; - font-size: 13px; -} -.pos .searchbox input:focus { - outline: none; - box-shadow: 0px 0px 0px 2px rgb(153, 153, 255) inset; - color: rgb(153, 153, 255); -} - -.pos .search-clear { - position: absolute; - top: 9px; - width: 30px; - height: 30px; - display: flex; - align-items: center; - justify-content: center; -} - -.search-clear.left { - left: 11px; - color: #808080; -} - -.search-clear.right { - left: 145px; - color: #808080; - cursor: pointer; -} - -/* c) the categories list */ - -.pos .categories { - position: relative; - border-bottom: solid 3px rgb(110, 200, 155); -} -.pos .categories h4 { - display: inline-block; - margin: 9px 5px; -} -.pos .category-list-scroller{ - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - width:100%; - height:100%; - max-height:60vh; - overflow: hidden; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - -webkit-transform: translate3d(0,0,0); - -} -.pos .category-list { - text-align: left; - padding: 10px; - background: rgb(229, 229, 229); - border-bottom: 1px solid #cecece; -} -.pos .category-list.simple { - padding: 0px; - background: #cecece; - display: -webkit-flex; - display: flex; - -webkit-flex-flow: row wrap; - flex-flow: row wrap; - border-bottom: none; -} - - -/* d) the category button */ - -.pos .category-button { - position: relative; - vertical-align: top; - display: inline-block; - font-size: 11px; - margin: 8px !important; - width: 120px; - height:120px; - background:#fff; - border: 1px solid #d7d7d7; - border-radius: 3px; - border-bottom-width: 3px; - cursor: pointer; -} - -.pos .category-simple-button{ - position: relative; - display: inline-block; - font-size: 14px; - margin-right: 1px; - margin-bottom: 1px; - padding: 5px 12px; - line-height: 32px; - flex-grow: 1; - -webkit-flex-grow: 1; - cursor: pointer; - background: #e2e2e2; -} -.pos .category-simple-button:active{ - color: white; - background: black; - - -webkit-transition-property: background, border; - -webkit-transition-duration: 0.2s; - -webkit-transition-timing-function: ease-out; -} - - - -.pos .category-button .category-img { - position: relative; - width: 120px; - height: 100px; - text-align: center; - cursor: pointer; -} - -.pos .category-button .category-img img { - max-height: 100px; - max-width: 120px; - vertical-align: middle; -} - -.pos .category-button .category-name { - position: absolute; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - bottom: 0; - top: auto; - line-height: 14px; - width: 100%; - /* for some reason the -90deg orientation doesn't match the -webkit-linear-gradient. It should be 180deg here. - * webkit also insists on rendering *both* gradients instead of only the native one. So it doesn't looks right. ugh. - background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); */ - /*background:#FFF;*/ - padding: 3px; - padding-top: 15px; - color: #7C7BAD; -} - -/* e) the product */ - -.pos .product { - position:relative; - vertical-align: top; - display: inline-block; - line-height: 100px; - font-size: 11px; - margin: 8px !important; - width: 122px; - height:115px; - background:#fff; - border: 1px solid #e2e2e2; - border-radius: 3px; - border-bottom-width: 3px; - overflow: hidden; - cursor: pointer; -} - -.pos .product .product-img { - position: relative; - width: 120px; - height: 100px; - background: white; - text-align: center; -} - -.pos .product .product-img img { - max-height: 100px; - max-width: 120px; - vertical-align: middle; -} - -.pos .product .price-tag { - position: absolute; - top: 2px; - right: 2px; - vertical-align: top; - color: white; - line-height: 13px; - background: #7f82ac; - padding: 2px 5px; - border-radius: 2px; -} - -.pos .product .product-name { - position: absolute; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - bottom:0; - top:auto; - line-height: 14px; - width:100%; - overflow: hidden; - text-overflow: ellipsis; - background: -webkit-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); - background: -moz-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); - background: -ms-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); - /* troublesome in latest webkit - background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); - */ - /*background:#FFF;*/ - padding: 3px; - padding-top:15px; -} - - -/* ********* The Screens ********* */ - -.pos .screen { - position:absolute; - text-align: center; - top:0px; - bottom:0px; - width:100%; - overflow: auto; - -webkit-overflow-scrolling: touch; - background: #d3d3d3; -} -.pos .screen header h2 { - margin-top: 0px; - padding-top: 7px; -} -.pos .screen p{ - font-size: 18px; -} -.pos .dialog{ - width: 500px; - margin-left: auto; - margin-right: auto; - margin-top: 50px; - text-align: center; -} -.pos .dialog p{ - font-size: 25px; - margin-top: 10px; - color: #5a5a5a; -} - -/* a) Generic Screen Layout Constructs */ - -.screen .screen-content{ - /*margin: 0px auto;*/ - left: 0px; - max-width: 1200px; - text-align: left; - height: 100%; - overflow: hidden; - position: relative; - background: #eeeeee; -} - -@media screen and (min-width: 1024px) { - .screen .screen-content{ - border-left: dashed 1px rgb(215,215,215); - border-right: dashed 1px rgb(215,215,215); - } -} - -.screen .top-content{ - position: absolute; - left: 0px; top: 0px; right: 0px; - height: 64px; - border-bottom: dashed 1px rgb(215,215,215); - text-align: center; -} -.screen .top-content .button { - position: absolute; - top: 0px; - line-height: 32px; - padding: 3px 13px; - font-size: 20px; - background: rgb(230, 230, 230); - margin: 12px; - border-radius: 3px; - border: solid 1px rgb(209, 209, 209); - cursor: pointer; - transition: all 150ms linear; -} -.screen .top-content .button:hover { - background: #efefef; -} -.screen .top-content .button:active { - background: black; - border-color: black; - color: white; -} -.screen .top-content .button.highlight { - background: rgb(110,200,155); - color: white; - border: solid 1px rgb(110,200,155); -} -.screen .top-content .button.highlight:hover { - background: rgb(120,210,165); -} -.screen .top-content .button.back { - left: 0px; - margin-left: 16px; -} -.screen .top-content .button.next{ - right: 0px; - margin-right: 16px; -} -.screen .left-content{ - position: absolute; - left:0px; top: 64px; bottom: 0px; - right:50%; - overflow-x: hidden; - overflow-y: auto; - border-right: dashed 1px rgb(215,215,215); -} -.screen .left-content.pc40{ - right: 66%; -} -.screen .right-content{ - position: absolute; - right:0px; top: 64px; bottom: 0px; - left:50%; - overflow-x: hidden; - overflow-y: auto; -} -.screen .right-content.pc60{ - left:34%; -} -.screen .centered-content{ - position: absolute; - right:25%; top: 64px; bottom: 0px; - left:25%; - border-right: dashed 1px rgb(215,215,215); - border-left: dashed 1px rgb(215,215,215); - overflow-x: hidden; - overflow-y: auto; -} -.screen .full-content{ - position: absolute; - right: 0%; top: 65px; bottom: 0px; - left: 0%; -} - -/* a) Layout for the Product Screen */ - -.pos .screen .layout-table { - border:none; - width:100%; - height:100%; -} - -.pos .screen .header-row { - border:none; - width:100%; - height:0px; -} - -.pos .screen .header-cell{ - border:none; - width:100%; - height:0px; -} -.pos .screen .content-row { - width:100%; - height:100%; -} -.pos .screen .content-cell{ - width:100%; -} -.pos .screen .content-cell .content-container{ - height:100%; - position:relative; -} - - -/* b) The payment screen */ - -.pos .payment-numpad { - display: inline-block; - width: 50%; - box-sizing: border-box; - padding: 16px; - text-align: center; - float: left; -} -.pos .payment-numpad .numpad { - float: none; - border-radius: 4px; - border-top: 1px solid; - border-left: 1px solid; - border-color: #cacaca; - width: 296px; - overflow: hidden; - margin: 0; -} -.pos .payment-numpad .numpad button { - width: 74px; - height: 74px; -} -.pos .payment-numpad .numpad button:first-child { - border-top-left-radius: 4px; -} -.pos .payment-numpad .numpad button:nth-child(16) { - border-bottom-left-radius: 4px; -} - -.pos .paymentlines-container { - padding: 16px; - padding-top: 0; - border-bottom: dashed 1px gainsboro; - min-height: 154px; -} - -.pos .paymentlines { - width: 100%; - border-spacing: 0px 10px; - border-collapse: inherit; -} -.pos .paymentlines .controls { - width: 40px; -} -.pos .paymentlines .label > * { - font-size: 16px; - padding: 8px; -} -.pos .paymentlines tbody{ - background: white; - border-radius: 3px; -} -.pos .paymentline{ - font-size: 22px; -} -.pos .paymentline.selected { - font-size: 22px; - background: #6EC89B; - color: white; -} -.pos .paymentline.selected .edit { - background: white; - color: #6EC89B; - outline: 3px blue; - box-shadow: 0px 0px 0px 3px #6EC89B; - position: relative; - border-radius: 3px; -} -.pos .paymentline > *{ - padding: 8px 12px; -} -.pos .paymentline .col-due, -.pos .paymentline .col-tendered, -.pos .paymentline .col-change { - min-width: 90px; -} -.pos .paymentline.extra .col-due { - border-radius: 0 0 6px 6px; - border-top: solid 1px rgb(230, 230, 230); - font-weight: bold; -} -.pos .paymentline .col-change.highlight { - background: rgb(184, 152, 204); -} -.pos .paymentline .col-name { - font-size: 16px; -} -.pos .paymentline .delete-button{ - cursor: pointer; - text-align: center; -} -.pos .payment-buttons { - display: inline-block; - width: 50%; - box-sizing: border-box; - padding: 16px; - padding-left: 0; - float: right; -} -.payment-screen .payment-buttons .button { - background: #e2e2e2; - line-height: 73px; - font-size: 16px; - padding: 0px 8px; - border: solid 1px rgb(200,200,200); - border-top-width: 0; - cursor: pointer; - text-align: center; - position: relative; - transition: background-color, border-color, color 150ms linear; -} -.payment-screen .payment-buttons .button:hover { - background-color: #efefef; -} -.payment-screen .payment-buttons .button:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px; - border-top-width: 1px; -} -.payment-screen .payment-buttons .button:last-child { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} -.payment-screen .payment-buttons .button.highlight:not(:first-child) { - margin-top: -1px; - border-top: solid 1px; -} -.payment-screen .payment-buttons .button:active { - background: black; - border-color: black; - color: white; -} -.payment-screen .payment-buttons .button.highlight .fa { - border-color: rgba(0, 0, 0, 0.109804); - background: rgba(0, 0, 0, 0.0980392); -} -.payment-screen .payment-buttons .button .fa { - position: absolute; - left: 11px; - top: 50%; - width: 48px; - height: 48px; - line-height: 48px; - margin-top: -25px; - vertical-align: middle; - border-radius: 26px; - border: 1px solid rgba(0,0,0,0.2); - border-image-source: initial; - border-image-slice: initial; - border-image-width: initial; - border-image-outset: initial; - border-image-repeat: initial; - background: rgba(255,255,255,0.4); - font-size: 20px; - transition: all 150ms linear; -} -.payment-screen .paymentlines-empty .total { - text-align: center; - padding: 24px 0px 18px; - font-size: 64px; - color: #43996E; - text-shadow: 0px 2px white, 0px 2px 2px rgba(0, 0, 0, 0.27); -} -.payment-screen .paymentlines-empty .message { - text-align: center; -} - -.paymentlines .button { - cursor: pointer; - border: 1px solid #cacaca; -} -.paymentlines .electronic_payment { - background: #e2e2e2; - border-collapse: unset; - text-align: center; - font-size: 16px; -} - -/* c) The receipt screen */ - -.pos .receipt-screen .centered-content .button { - line-height: 40px; - padding: 3px 13px; - font-size: 20px; - text-align: center; - background: rgb(230, 230, 230); - margin: 16px; - margin-bottom: 0px; - border-radius: 3px; - border: solid 1px rgb(209, 209, 209); - cursor: pointer; -} - -.pos .pos-receipt-container { - font-size: 0.75em; - text-align: center; - direction: ltr; -} - -.pos .pos-receipt-container > div { - text-align: left; - width: 300px; - background-color: white; - margin: 20px; - padding: 15px; - font-size: 16px; - padding-bottom:30px; - display: inline-block; - border: solid 1px rgb(220,220,220); - border-radius: 3px; - overflow: hidden; -} - -@page { - margin: 0; -} - -@media print { - * { - color: black !important; - } - body { - margin: 0; - color: white !important; - /* avoid black background if backgrounds are printed */ - background: initial; - } - .o_notification_manager, - .oe_leftbar, - .oe_loading, - .pos .pos-topheader, - .pos .pos-leftpane, - .pos .keyboard_frame, - .pos .receipt-screen header, - .pos .receipt-screen .top-content, - .pos .receipt-screen .centered-content .button, - .pos .receipt-screen .centered-content .print_invoice { - display: none !important; - } - - .o_action_manager, - .pos, - .pos .pos-content, - .pos .rightpane, - .pos .screen, - .pos .window, - .pos .window .subwindow, - .pos .subwindow .subwindow-container{ - display: block; - position: static; - height: auto; - } - .pos{ - background: white !important; - } - .pos .rightpane { - left: 0px !important; - background-color: white; - } - .pos .receipt-screen { - text-align: left; - } - .pos .receipt-screen .centered-content{ - position: static; - border: none; - } - .pos .pos-receipt-container { - text-align: left; - } - .pos-actionbar { - display: none !important; - } - .debug-widget{ - display: none !important; - } - .pos *{ - text-shadow: none !important; - box-shadow: none !important; - background: transparent !important; - } - .pos .pos-receipt{ - margin: 0; - margin-left: auto !important; - margin-right: auto !important; - border: none !important; - font-size: 13px !important; - width: 266px !important; - } - .o_debug_manager { - display: none !important; - } - .o_chat_window { - display: none !important; - } - .order-selector { - display: none !important; - } - .blockUI { - display: none !important; - } -} - -/* d) The Scale screen */ - -.pos .scale-screen .product-price{ - font-size: 25px; - margin: 16px; - text-align: center; - display: inline-block; - width: 40%; -} -.pos .scale-screen .computed-price{ - font-size: 25px; - display: inline-block; - text-align: right; - margin: 16px; - margin-top: 0px; - padding: 16px; - background: white; - width: 40%; - border-radius: 3px; - font-family: Inconsolata; - font-weight: bold; - text-shadow: 0px 2px 0px rgb(210,210,210); - box-shadow: 0px 2px 0px rgb(225,225,225) inset; - float: right; -} -.pos .scale-screen .buy-product{ - text-align: center; - font-size: 32px; - background: rgb(110,200,155); - color: white; - border-radius: 3px; - padding: 16px; - margin: 16px; - cursor: pointer; -} - -.pos .scale-screen .weight{ - text-align: right; - margin: 16px; - background: white; - padding: 20px; - padding-right: 30px; - font-size: 56px; - border-radius: 3px; - font-family: Inconsolata; - text-shadow: 0px 2px 0px rgb(210, 210, 210); - box-shadow: 0px 2px 0px rgb(225,225,225) inset; -} - - -/* e) The Client List Screen */ - -.pos .clientlist-screen .client-list{ - font-size: 16px; - width: 100%; - line-height: 40px; -} -.pos .clientlist-screen .client-list th { - background: #f7f7f7; /* Hintergrundfarbe des Headers */ - position: sticky; - top: 0; - z-index: 10; /* Damit der Header über dem Inhalt bleibt */ -} -.pos .clientlist-screen .client-list th, -.pos .clientlist-screen .client-list td { - padding: 0px 8px; -} -.pos .clientlist-screen .client-list tr{ - transition: all 150ms linear; - background: rgb(230,230,230); -} -.pos .clientlist-screen .client-list thead > tr, -.pos .clientlist-screen .client-list tr:nth-child(even) { - background: rgb(247,247,247); -} -.pos .clientlist-screen .client-list tr.highlight{ - transition: all 150ms linear; - background: rgb(110,200,155) !important; - color: white; -} -.pos .clientlist-screen .client-list tr.lowlight{ - transition: all 150ms linear; - background: rgb(216, 238, 227); -} -.pos .clientlist-screen .client-list tr.lowlight:nth-child(even){ - transition: all 150ms linear; - background: rgb(227, 246, 237); -} - -.pos .clientlist-screen { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 0px; -} - - -.pos .clientlist-screen .client-picture{ - height: 64px; - width: 64px; - border-radius: 32px; - overflow: hidden; - text-align: center; - float: left; - margin-right: 16px; - background: white; - position: relative; -} -.pos .clientlist-screen .client-picture > img { - position: absolute; - top: -9999px; - bottom: -9999px; - right: -9999px; - left: -9999px; - max-height: 64px; - margin: auto; -} -.pos .clientlist-screen .client-picture > .fa { - line-height: 64px; - font-size: 32px; -} -.pos .clientlist-screen .client-picture .image-uploader { - position: absolute; - z-index: 1000; - top: 0; - left: 0; - right: 0; - bottom: 0; - opacity: 0; - cursor: pointer; -} -.pos .clientlist-screen .client-name { - font-size: 32px; - line-height: 64px; - margin-bottom:16px; -} -.pos .clientlist-screen .edit-buttons { - position: absolute; - right: 16px; - top: 10px; -} -.pos .clientlist-screen .edit-buttons .button{ - display: inline-block; - margin-left: 16px; - color: rgb(128,128,128); - cursor: pointer; - font-size: 36px; -} -.pos .clientlist-screen .client-details-box{ - position: relative; - font-size: 16px; -} -.pos .clientlist-screen .client-details-left{ - width: 50%; - float: left; -} -.pos .clientlist-screen .client-details-right{ - width: 50%; - float: right; -} -.pos .clientlist-screen .client-detail{ - line-height: 24px; -} -.pos .clientlist-screen .client-detail > .label{ - font-weight: bold; - display: inline-block; - width: 150px; - text-align: right; - margin-right: 8px; -} -.pos .clientlist-screen .client-detail > .briefinglabel{ - font-weight: bold; - display: inline-block; - - text-align: right; - margin-right: 8px; -} -.pos .clientlist-screen .client-details input, -.pos .clientlist-screen .client-details select -{ - padding: 4px; - border-radius: 3px; - border: solid 1px #cecbcb; - margin-bottom: 4px; - background: white; - font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial; - color: #555555; - width: 150px; - font-size: 14px; - box-sizing: border-box; -} -.pos .clientlist-screen .client-details input.client-name { - font-size: 24px; - line-height: 24px; - margin: 18px 6px; - width: 340px; -} -.pos .clientlist-screen .client-detail > .empty{ - opacity: 0.3; -} -.pos .clientlist-screen .searchbox{ - right: auto; - margin-left: -90px; - margin-top:8px; - left: 50%; -} -.pos .clientlist-screen .searchbox input{ - width: 120px; -} -.pos .clientlist-screen .button.new-customer { - left: 50%; - margin-left: 120px; -} - -.pos .clientlist-screen .button.new-registration { - right: 0%; - /*margin-left: 120px;*/ -} - - - -/* ********* The OrderWidget ********* */ - -.pos .order-container{ - position: absolute; - top: 0px; - width:100%; - height: 100%; - background: white; -} - -.pos .order-scroller{ - width:100%; - height:100%; - overflow: hidden; - overflow-y: auto; - -webkit-overflow-scrolling: touch; -} - -.pos .scrollable-y{ - overflow: hidden !important; - overflow-y: auto !important; - -webkit-overflow-scrolling: touch !important; -} - -.pos .order{ - background: white; - padding-bottom: 8px; - padding-top: 8px; - font-size: 16px; - text-align: left; - width: 99%; - max-width: 500px; - -webkit-transform: translate3d(0,0,0); -} - -.pos .order .order-empty { - text-align: center; - margin: 48px; - color: #DDD; -} -.pos .order .order-empty .fa { - font-size: 64px; -} -.pos .order .order-empty h1 { - font-size: 20px; -} - -.pos .order .summary{ - width:100%; - text-align:right; - font-weight: bold; - margin-top:20px; - margin-bottom:10px; -} -.pos .order .summary .line{ - float: right; - margin-right:15px; - margin-left: 15px; - padding-top:5px; - border-top: solid 2px; - border-color:#777; -} -.pos .order .summary .total { - font-size: 22px; -} -.pos .order .summary .line .subentry{ - font-size: 16px; - font-weight: normal; - text-align: center; -} -.pos .order .summary .line.empty{ - text-align: right; - border-color:#BBB; - color:#999; -} - -.pos .order .summary .fidpoints{ - position: absolute; - left: 20px; - padding: 10px; - color: #6EC89B; - background: rgba(110, 200, 155, 0.17); - border-radius: 3px; -} - -.submit-kitchen-button { - float: left; - background: rgb(61, 235, 82); - color: white; - padding: 12px 20px; - margin: 0px 15px; - border-radius: 3px; - cursor: pointer; -} - -/* ********* The OrderLineWidget ********* */ - -.pos .order .orderline{ - width:100%; - margin:0px; - padding-top:3px; - padding-bottom:10px; - padding-left:15px; - padding-right:15px; - cursor: pointer; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - -webkit-transition: background 250ms ease-in-out; - -moz-transition: background 250ms ease-in-out; - transition: background 250ms ease-in-out; -} -.pos .order .orderline:active{ - background: rgba(140,143,183,0.05); - -webkit-transition: background 50ms ease-in-out; - -moz-transition: background 50ms ease-in-out; - transition: background 50ms ease-in-out; -} -.pos .order .orderline.empty:active{ - background: transparent; - cursor: default; -} - -.pos .order .orderline.selected{ - background: rgba(140,143,183,0.2); - -webkit-transition: background 250ms ease-in-out; - -moz-transition: background 250ms ease-in-out; - transition: background 250ms ease-in-out; - cursor: default; -} -.pos .order .orderline .product-name{ - padding:0; - display:inline-block; - font-weight: bold; - width:80%; - overflow:hidden; - text-overflow: ellipsis; -} -.pos .order .orderline .price{ - padding:0; - font-weight: bold; - float:right; -} -.pos .order .orderline .info-list{ - color: #888; - margin-left:10px; -} -.pos .order .orderline .info-list em{ - color: #777; - font-weight: bold; - font-style:normal; -} - -/* ********* SplitBill ********* */ - -.splitbill-screen .order-info { - text-align: center; - margin-bottom:20px; - padding: 20px 0px; - font-size: 64px; - color: #43996E; - text-shadow: 0px 2px white, 0px 2px 2px rgba(0, 0, 0, 0.27); - border-bottom: dashed 1px rgb(215,215,215); -} -.pos .splitbill-screen .order { - background: white; - padding-bottom:15px; - padding-top:15px; - margin-left:16px; - margin-right:16px; - margin-top:16px; - margin-bottom:16px; - font-size:16px; - border-radius: 3px; - border: solid 1px rgb(220,220,220); - text-align: left; - max-width: 500px; - -webkit-transform: translate3d(0,0,0); -} -.splitbill-screen .order .orderline.selected{ - background: rgb(110,200,155); - color: white; - -webkit-transition: background 250ms ease-in-out; - -moz-transition: background 250ms ease-in-out; - transition: background 250ms ease-in-out; - cursor: default; -} -.splitbill-screen .order .orderline.partially.selected{ - background: rgb(136, 214, 176); -} -.splitbill-screen .order .orderline.selected .info-list { - color: white; -} -.splitbill-screen .order .orderline.selected .info-list em{ - color: white; - font-size: 24px; - vertical-align: top; -} -.paymentmethods { - margin: 16px; -} -.paymentmethods .button { - background: #e2e2e2; - line-height: 74px; - font-size: 16px; - border: solid 1px rgb(202, 202, 202); - border-top-width: 0px; - cursor: pointer; - text-align: center; -} -.paymentmethods .button:first-child { - border-top-width: 1px; - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.paymentmethods .button:last-child { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; -} -.paymentmethods .button:active { - background: black; - border-color: black; - color: white; -} -.paymentmethod .button.active { - background: #6EC89B; - color: white; - border-color: #6EC89B; -} - - - -/* ********* The ActionBarWidget ********* */ - -.pos .pos-actionbar{ - height: 105px; - background: #f5f5f5; /*#ebebeb;*/ - border-top: solid 1px #cecece; - z-index:900; -} - -.pos .pos-actionbar ul{ - list-style: none; -} - -.pos .pos-actionbar-button-list{ - height: 100%; - margin: 0px; - padding-left:3px; - padding-right:3px; - overflow:hidden; -} - -.pos .pos-actionbar .button{ - width: 90px; - height: 90px; - text-align:center; - margin:3px; - margin-top:6px; - float:left; - - font-size: 14px; - font-weight: bold; - - cursor: pointer; - - border: 1px solid #cacaca; - border-radius: 3px; - - background: #e2e2e2; -} -.pos .pos-actionbar .button .label{ - margin-top: 37px; -} -.pos .pos-actionbar .button .icon{ - margin-top: 10px; -} -.pos .pos-actionbar .button:active{ - color: white; - background: #7f82ac; - border: 1px solid #7f82ac; - - -webkit-transition-property: background, border; - -webkit-transition-duration: 0.2s; - -webkit-transition-timing-function: ease-out; -} - -.pos .pos-actionbar .button.disabled{ - opacity: 0.5; -} -.pos .pos-actionbar .button.disabled:active{ - border: 1px solid #cacaca; - color: #555; - cursor: default; - - background: #e2e2e2; -} - -.pos .pos-actionbar .button.rightalign{ - float:right; -} -/* ********* The Debug Widget ********* */ - -.pos .debug-widget{ - z-index:100000; - position: absolute; - right: 10px; - top: 10px; - width: 200px; - font-size: 10px; - - background: rgba(0,0,0,0.82); - color: white; - padding-bottom: 10px; - cursor: move; - -webkit-transform: translate3d(0,0,0); -} -.pos .debug-widget .toggle{ - position: absolute; - font-size: 16px; - cursor:pointer; - top:0px; - right:0px; - padding:10px; - padding-right:15px; -} -.pos .debug-widget .content{ - overflow: hidden; -} -.pos .debug-widget h1{ - background:black; - padding-top: 10px; - padding-left: 10px; - margin-top:0; - margin-bottom:0; -} -.pos .debug-widget .category{ - background: black; - padding-left: 10px; - margin: 0px; - font-weight: bold; - padding-top:3px; - padding-bottom:3px; -} -.pos .debug-widget .button{ - padding: 5px; - padding-left: 15px; - display: block; - cursor:pointer; -} -.pos .debug-widget .button:active{ - background: rgba(96,21,177,0.45); -} -.pos .debug-widget input{ - margin-left:10px; - margin-top:7px; - padding: 4px; - width: 180px; - border: none; - box-sizing: border-box; - -moz-box-sizing: border-box; - border-radius: 3px; -} -.pos .debug-widget .status{ - padding: 5px; - padding-left: 15px; - display: block; - cursor:default; -} -.pos .debug-widget .status.on{ - background-color: #6cd11d; -} -.pos .debug-widget .event{ - padding: 5px; - padding-left: 15px; - display: block; - cursor:default; - background-color: #1E1E1E; -} - -/* ********* The PopupWidgets ********* */ - -.pos .modal-dialog{ - position: absolute; - left: 0; - top: 0; - width: 100%; - height:100%; - background-color: rgba(0,0,0,0.5); - z-index:1000; -} -.pos .modal-dialog .popup{ - position: absolute; - top: 0; left: 0; right: 0; bottom: 0; - margin: auto; - width:500px; - height:400px; - text-align:center; - font-size:20px; - font-weight:bold; - background-color: #F0EEEE; - border-radius: 3px; - box-shadow: 0px 10px 20px rgba(0,0,0,0.4); - z-index:1200; - font-family: 'Lato'; - font-family: Lato; -} -.pos .modal-dialog .popup-confirm{ - height: 250px; -} -.pos .popup-confirm .body { - overflow: auto; - height: 120px; -} -.pos .popup .title { - background: rgba(255,255,255,0.5); - margin: 0; - padding: 20px; - border-radius: 3px 3px 0px 0px; - border-bottom: solid 1px rgba(60,60,60,0.1); -} -.pos .popup .body { - font-weight: normal; - font-size: 18px; - margin: 16px; - margin-top: 20px; -} -.pos .popup .body.traceback { - height: 238px; - overflow: auto; - font-size: 14px; - white-space: pre-wrap; - text-align: left; - font-family: 'Inconsolata'; - -webkit-user-select: text; - -moz-user-select: text; - user-select: text; -} -.pos .popup .footer{ - position:absolute; - bottom:0; - left:0; - width:100%; - height:60px; - border-top: solid 1px rgba(60,60,60,0.1); -} -.pos .popup .button{ - float:right; - width: 110px; - height: 40px; - line-height:40px; - text-align:center; - border-radius: 2px; - margin-top:10px; - margin-right:10px; - - font-size: 14px; - font-weight: bold; - - cursor: pointer; - - border: solid 1px rgba(60,60,60,0.1); - - background: rgba(0,0,0,0.05); -} -.pos .popup .button.icon { - width: 40px; - font-size: 20px; -} -.pos .popup .button:active{ - color: white; - background: black; - border: 1px solid black; - - -webkit-transition-property: background, border; - -webkit-transition-duration: 0.2s; - -webkit-transition-timing-function: ease-out; -} - - -.pos .popup .button.big-left{ - position:absolute; - top: 120px; - left:40px; - width: 180px; - height: 180px; - line-height:180px; -} - -.pos .popup .button.big-right{ - position:absolute; - top: 120px; - right:40px; - width: 180px; - height: 180px; - line-height:180px; -} -.pos .popup input, -.pos .popup-input { - text-align: left; - display: inline-block; - overflow: hidden; - background: white; - min-height: 44px; - font-family: "Lato"; - font-size: 20px; - color: #444; - padding: 10px; - border-radius: 3px; - border: none; - box-shadow: 0px 0px 0px 1px rgb(220,220,220) inset; - box-sizing: border-box; - width: 80%; -} -.pos .popup .packlot-lines{ - overflow: auto; - height: 250px; - margin: 10px; -} -.pos .popup .packlot-line-input { - margin: 3px; -} - -.pos .popup-number .popup-input { - text-align: center; -} -.pos .popup input:focus, -.pos .popup-input.active { - outline: none; - box-shadow: 0px 0px 0px 3px #6EC89B; -} -.pos .popup.popup-error { - background-color: #F3BBBB; - color: rgb(168, 89, 89); - box-shadow: 0px 10px 20px rgba(92,51,51,0.4); -} -.pos .popup.popup-error .title { - color: white; - background: rgba(255, 76, 76, 0.5); -} -.pos .popup.popup-selection .selection { - overflow-y: auto; - max-height: 273px; - font-size: 16px; - width: auto; - line-height: 50px; - margin-top: -1px; - border-top: solid 3px rgba(60,60,60,0.1); - -} -.pos .popup.popup-selection .selection-item { - width: auto; - background: rgb(230,230,230); - cursor: pointer; - text-align: left; - padding: 0px 16px; -} -.pos .popup.popup-selection .selection-item:nth-child(odd) { - background: rgb(247,247,247); -} -.pos .popup.popup-selection .selection-item.selected { - background: #6EC89B; -} -.pos .popup.popup-number { - width: 300px; - height: 450px; -} -.pos .footer.centered { - text-align: center; -} -.pos .footer.centered .button { - float: none; - display: inline-block; - margin-left: 3px; - margin-right: 3px; -} -.pos .popup-numpad { - direction: ltr/*rtl:ignore*/; /* rtlcss forced to keep ltr */ - margin: 12px auto; - text-align: center; - width: 254px; -} -.pos .popup-number .title, -.pos .popup-textinput .title -{ - margin-bottom: 20px; -} -.pos .popup-numpad .input-button, -.pos .popup-numpad .mode-button { - background: none; - height: 50px; - width: 50px; - padding: 0; - border-radius: 25px; - margin: 4px; - vertical-align: top; - color: #444; -} -.pos .popup-numpad .input-button:active, -.pos .popup-numpad .mode-button:active { - background: #444; - color: white; - border-color: #444; -} - -.pos .popup.popup-password { - width: 254px; -} -.pos .popup-password .mode-button.add, -.pos .popup-password .input-button.dot { - display: none; -} -.pos .popup-password .popup-numpad { - width: 190px; - text-align: left; -} -.pos .popup-password .popup-input { - width: 70%; - } - -.pos .popup .body ul, -.pos .popup ul.body { - text-align: left; - margin-left: 1em; -} -.pos .popup .body li { - text-indent: 1em; -} -.pos .popup .body li:before { - content: '—'; - position: relative; - font-size: 0.6em; - left: -1em; - bottom: 0.2em; -} - - -/* ********* The Webkit Scrollbar ********* */ - -.pos *::-webkit-scrollbar{ - width: 4px; - height: 4px; -} -.pos *::-webkit-scrollbar-track{ - background: rgb(224,224,224); - border-left: solid 1px rgb(200,200,200); -} -.pos *::-webkit-scrollbar-thumb{ - background: rgb(168,168,168); - background: #393939; - min-height: 30px; -} - -.pos.big-scrollbars *::-webkit-scrollbar{ - width: 40px; - height: 40px; -} -.pos.big-scrollbars *::-webkit-scrollbar-track{ - background: rgb(224,224,224); - border-left: none; -} -.pos.big-scrollbars *::-webkit-scrollbar-thumb{ - background: rgb(168,168,168); - min-height: 40px; - border-radius: 3px; -} -.pos.big-scrollbars *::-webkit-scrollbar-button{ - width: 40px; - height: 40px; - border-radius: 3px; - background: rgb(210,210,210); - background-size: cover; -} -.pos.big-scrollbars *::-webkit-scrollbar-button:decrement{ - background-image: url('../img/scroll-up.png'); -} -.pos.big-scrollbars *::-webkit-scrollbar-button:increment{ - background-image: url('../img/scroll-down.png'); -} - - -/* ********* Unsupported Browser Page ********* */ - -.pos .not-supported-browser{ - position: absolute; - z-index: 100000; - top: 0; bottom: 0; left: 0; right: 0; - background: #2C2C2C; -} -.pos .not-supported-browser .message{ - width:600px; - margin-top: 100px; - margin-left: auto; - margin-right: auto; - text-align: center; - color: #d3d3d3; - font-size: 14px; -} -.pos .not-supported-browser img{ - border-collapse: separate; -} - -/* Open Workshop specific styles */ -.pos { - display: flex; - flex-direction: row; - height: 100%; - width: 100%; - background: #d3d3d3 -} - -.pos .order-selector { - position: absolute; - top: 48px; - left: 0; - width: 10%; - height: calc(100% - 48px); - z-index: 10; -} - -/* Sidebar für Einweisungen*/ - -.pos .machine-access-sidebar { - position: absolute; - top: 48px; /* unter der Topbar */ - bottom: 0; - height: calc(100% - 48px); - left: 10%; /* Platz für Order-Selector */ - right: 0; - width: 10%; - background: #d3d3d3; - overflow-y: auto; - border-right: 3px solid #787878; - z-index: 20; -} - -.pos .machine-access-sidebar .access-content { - position: relative; - top: 0px; /* unter der Topbar */ - background : #eeeeee; -} - -.pos .machine-access-sidebar .client-details-label { - font-size: 18px; - line-height: 48px; -} - -.pos .machine-access-sidebar h5 { - margin-top: 1em; - margin-bottom: 0.5em; -} - -.pos .machine-access-sidebar ul { - padding-left: 1em; -} - -.pos .machine-access-sidebar li { - margin-bottom: 0.3em; -} - -.pos .machine-access-sidebar .subpoints { - margin-left: 0.5em; - list-style-type: none; /* oder none, wenn du keine Punkte willst */ -} - -.pos .machine-access-sidebar .client-details-vvow_sec_briefing_error{ - color: rgb(255, 0, 0); -} - -.pos .clientlist-screen .client-details{ - padding: 16px; - border-bottom: solid 5px rgb(110,200,155); -} -.pos .clientlist-screen .client-details-error{ - padding: 16px; - border-bottom: solid 5px rgb(110,200,155); - background: rgb(178, 34, 34); -} -/* .pos .clientlist-screen .client-details-vvow_briefing{ - color: rgb(128, 255, 0); -} */ -.pos .client-details-vvow_briefing_error{ - color: rgb(255, 0, 0); -} -.pos .clientlist-screen .client-details-vvow_sec_briefing_error{ - color: rgb(255, 0, 0); - font-size: xx-large; -} \ No newline at end of file diff --git a/static/src/js/machine_access_sidebar.js b/static/src/js/machine_access_sidebar.js deleted file mode 100644 index f94cb2b..0000000 --- a/static/src/js/machine_access_sidebar.js +++ /dev/null @@ -1,132 +0,0 @@ -/* This file is based on the original code from the OrderWidget in Odoo Point of Sale module (screen.js). - * It has been modified to create a sidebar that displays machine access information for the selected customer.*/ - -odoo.define('open_workshop.machine_access_sidebar', function (require) { - "use strict"; - - const DUMMY_PARTNER = { - id: 1, - name: "AAAA Max Mustermann", - security_briefing: false, - security_id: null, - create_date: null, - }; - - var rpc = require('web.rpc'); - var screens = require('point_of_sale.screens'); - var chrome = require('point_of_sale.chrome'); - var core = require('web.core'); - var QWeb = core.qweb; - - - - var MachineAccessSidebar = screens.ScreenWidget.extend({ - template: 'MachineAccessSidebar', - - init: function(parent, options) { - this._super(parent, options); - this.partner = null; - this.pos.bind('change:selectedOrder', this.bind_order_events, this); - }, - - show: function() { - this._super(); - this.render_access(); - }, - - update_machine_access: function(partner) { - console.log("🔁 Sidebar aktualisiert Maschinenfreigaben für Partner:", partner); - this.partner = partner; - this.render_access(); - }, - - render_access: function() { - var self = this; - var partner = this.partner || DUMMY_PARTNER; - - - - rpc.query({ - model: 'ows.machine', - method: 'get_access_list_grouped', - args: [partner.id], - }).then(function (result) { - partner.create_date = partner.create_date && partner.create_date.substring(0, 10); - var html = QWeb.render('PartnerMachineAccessList', { - areas: result || [], - partner: partner, - }); - self.$('.access-content').html(html); - }); - }, - - bind_order_events: function () { - var order = this.pos.get_order(); - if (!order) return; - - /*order.unbind('change:client', this); - order.bind('change:client', this, function () { - this.update_machine_access(order.get_client()); - });*/ - - this.update_machine_access(order.get_client()); - } - }); - - // Sidebar aktualisieren bei Klick im ClientListScreenWidget (Vorschau) - screens.ClientListScreenWidget.include({ - show: function () { - this._super(); - $('.order-selector').hide(); // ← wird hier versteckt - }, - hide: function () { - this._super(); - $('.order-selector').show(); // ← beim Verlassen wieder zeigen - }, - display_client_details: function (visibility, partner, clickpos) { - this._super(visibility, partner, clickpos); - - try { - if (partner && typeof partner === 'object' && 'id' in partner) { - var sidebar = this.pos.chrome.sidebar_widget; - if (sidebar) { - console.log("👤 ClientListScreen: Vorschau für", partner.name); - sidebar.update_machine_access(partner); - } - } - } catch (e) { - console.warn("⚠️ Fehler beim Update der Sidebar nach Kundenauswahl:", e); - } - } - }); - - chrome.Chrome.include({ - build_widgets: function () { - this._super(); - - var sidebar = new MachineAccessSidebar(this, {}); - this.sidebar_widget = sidebar; - sidebar.appendTo(this.$el); - - //this.pos.bind('change:selectedOrder', sidebar.bind_order_events, sidebar); - - if (this.pos.get_order()) { - sidebar.bind_order_events(); - } - } - }); -}); - - -odoo.define('open_workshop.models', function (require) { - "use strict"; - var models = require('point_of_sale.models'); - var field_utils = require('web.field_utils'); - models.load_fields('res.partner', 'create_date'); - models.load_fields('res.partner', 'birthday'); - models.load_fields('res.partner', 'security_briefing'); - models.load_fields('res.partner', 'security_id'); - models.load_fields('res.partner', 'rfid_card'); - - -}); \ No newline at end of file diff --git a/static/src/xml/ows_briefing_details.xml b/static/src/xml/ows_briefing_details.xml deleted file mode 100644 index 3f056b3..0000000 --- a/static/src/xml/ows_briefing_details.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - -
-
- Address - - - - - - - N/A - -
-
- Email - - - - - - - N/A - -
- -
- Geburtstag - - - - - - - N/A - -
-
- Phone - - - - - - - N/A - -
-
- Pricelist - - - - - - - N/A - -
-
- Haftungsausschluss prüfen! -
-
- -
- - - -
diff --git a/static/src/xml/ows_briefing_details_edit.xml b/static/src/xml/ows_briefing_details_edit.xml deleted file mode 100644 index 53c79a6..0000000 --- a/static/src/xml/ows_briefing_details_edit.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - -
-
- Street - -
-
- Postcode - -
-
- City - -
-
- Country - -
-
- Email - -
-
- Phone - -
-
- Geburtstag - -
-
- Pricelist - -
- -
- Haftungsauschschluß - -
-
-
- - -
diff --git a/static/src/xml/ows_machine_sidebar.xml b/static/src/xml/ows_machine_sidebar.xml deleted file mode 100644 index 9f45425..0000000 --- a/static/src/xml/ows_machine_sidebar.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - -
-
-
-
-
- -
-
-
    -
  • Einweisungen
  • -
- -
-
    -
  • - - Werkstatt -
  • - -
  • - - - - - - - Haftungsausschluss -
  • - - - -
  • -
      ‼️Bitte Prüfen‼️
    -
  • -
    - - - -
      -
    • - Id: - - - - - N/A - -
    • -
    • - Erstellt: - - - - - N/A - -
    • -
    -
    - -
-
-
- - -
-
    - -
  • - - - - - - - -
  • -
    -
-
-
-
-
- -
diff --git a/static/src/xml/ows_pos_order_selector.xml b/static/src/xml/ows_pos_order_selector.xml deleted file mode 100644 index e4956b7..0000000 --- a/static/src/xml/ows_pos_order_selector.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - HOBBYHIMMEL - - - - - - - - - - - -
-
-
- - - -
-
- - - - - - -
- - - - - - - - - - - - - ? - - - - - - - - - - - - - - - ? - - - - - - -
-
- -
diff --git a/tests/__init__.py b/tests/__init__.py index d57d215..ea197db 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1,2 @@ from . import test_res_partner +from . import test_access_rights diff --git a/tests/test_access_rights.py b/tests/test_access_rights.py new file mode 100644 index 0000000..7f91d26 --- /dev/null +++ b/tests/test_access_rights.py @@ -0,0 +1,74 @@ +''' +/odoo_env/src/odoo/odoo-bin \ + -d hh16-test \ + --data-dir=/env/filestore/ \ + --addons-path=/odoo_env/src/odoo/addons,/odoo_env/src/odoo/odoo/addons,/odoo_env/src/openupgrade,/odoo_env/src/OCA/web,/odoo_env/src/OCA/server-tools,/odoo_env/src/vvow \ + --test-enable \ + --stop-after-init \ + --test-tags open_workshop \ + --log-level=debug \ + --http-port=9070 \ + --db_host=db \ + --db_user=odoo \ + --db_password=odoo +''' + +from odoo.tests.common import TransactionCase +from odoo.tests import tagged +import logging + +_logger = logging.getLogger(__name__) + +@tagged('post_install', 'open_workshop', 'access_rights') +class TestOpenWorkshopAccessRights(TransactionCase): + + def setUp(self): + super().setUp() + self.group_user = self.env.ref('base.group_user') + self.test_user = self.env['res.users'].create({ + 'name': 'Access Test User', + 'login': 'access_test_user', + 'groups_id': [(6, 0, [self.group_user.id])], + }) + self.models_to_test = [ + 'ows.machine', + 'ows.machine.access', + 'ows.machine.product', + 'ows.machine.training', + 'ows.machine.area', + 'ows.user', + ] + + def test_model_access_rights(self): + for model_name in self.models_to_test: + with self.subTest(model=model_name): + model = self.env[model_name].with_user(self.test_user) + records = model.search([], limit=1) + + # Test Lesezugriff + self.assertTrue(records.exists(), f"Kein Zugriff auf {model_name} oder leer") + + # Test Schreib-, Erstell- und Löschrechte nur wenn Eintrag existiert + if records: + # Schreibtest + write_fields = [f for f in records._fields if records._fields[f].type in ('char', 'text') and f != 'id'] + if write_fields: + field = write_fields[0] + test_value = 'Test Write' + try: + records.write({field: test_value}) + except Exception as e: + self.fail(f"❌ Schreibrechte auf {model_name}.{field} verweigert: {e}") + + # Erstellung + try: + new = records.copy() + self.assertTrue(new.exists(), f"❌ Kein Erstellrecht auf {model_name}") + except Exception as e: + self.fail(f"❌ Erstellung in {model_name} verweigert: {e}") + + # Löschung + try: + new.unlink() + except Exception as e: + self.fail(f"❌ Löschrechte auf {model_name} verweigert: {e}") diff --git a/tests/test_res_partner.py b/tests/test_res_partner.py index 6c88da7..967fe1e 100644 --- a/tests/test_res_partner.py +++ b/tests/test_res_partner.py @@ -1,8 +1,6 @@ ## Testausführung -# odoo-bin -d deine_testdatenbank --test-enable --init open_workshop -## oder: -# /opt/odoo/odoo/odoo-bin -d hobbyhimmel --test-enable --test-tags /test_res_partner.py --stop-after-init --http-port=8070 --log-level=debug -# /opt/odoo/odoo/odoo-bin -d hobbyhimmel --test-enable --stop-after-init --test-tags open_workshop --log-level=debug --update open_workshop --http-port=8070 +# /odoo_env/src/odoo/odoo-bin -d hh16 --test-enable --stop-after-init --test-tags open_workshop --log-level=debug --update open_workshop --stop-after-init --db_host=db --db_user=odoo --db_password=odoo + from odoo.tests.common import TransactionCase from odoo.tests import tagged diff --git a/todo.md b/todo.md index 0931f6e..b4aa4b5 100644 --- a/todo.md +++ b/todo.md @@ -1,3 +1,72 @@ -[ ] Help System -[ ] Möglichkeit, Einweisungen manuell zu setzen? -[ ] \ No newline at end of file +# TODO: Reaktivierung des Moduls "Open Workshop" in Odoo 16.0 + +## ✨ Ziel +Die schrittweise Wiederherstellung der Funktionalität des Moduls `open_workshop` in einer nach Odoo 16.0 migrierten Instanz, basierend auf einer zuvor deaktivierten Datenbank. + +--- + +## 🔄 1. Grundlagen sicherstellen +- [x] Sicherstellen, dass `ows_models.py` korrekt geladen wird +- [x] Alle Modelle müssen sich fehlerfrei installieren lassen +- [x] Tabellen wie `ows_user`, `ows_machine`, etc. sind vorhanden und konsistent +- [x] Relation `res.partner.ows_user_id` vorhanden + +--- + +## 🧹 2. Datenbasierte Komponenten reaktivieren +### 2.1 `data/demo_data.xml` +- [ ] Beispieldaten für `ows.machine.area` und `ows.machine` erstellen +- [ ] IDs müssen konfliktfrei mit bestehender Datenbank sein +- [ ] Module danach neu starten: `-u open_workshop` + +### 2.2 `security/ir.model.access.csv` +- [x] Zugriff für alle verwendeten Modelle definieren + - `ows.user`, `ows.machine`, `ows.machine.access` + - Optional: `res.partner` (nur read) +- [x] Installieren +- [ ] testen ob Zugriff möglich ist + +--- + +## 🎨 3. Backend Views stufenweise aktivieren +### 3.1 `views/menu_views.xml` +- [ ] Menüs einbinden, ohne Abhängigkeiten +- [ ] Test: Odoo starten & Menüs sichtbar? + +### 3.2 `views/machine_area_views.xml` +### 3.3 `views/machine_views.xml` +- [ ] Baumansicht (list) zuerst aktivieren +- [ ] Danach Form-View (form) hinzufügen + +### 3.4 `views/res_partner_view.xml` +- [ ] Tab "Maschinenfreigaben" aktivieren +- [ ] Nur Felder mit klarer Modellbindung einbinden + +--- + +## 💻 4. POS Assets & QWeb (optional) +### 4.1 `views/assets.xml` +- [ ] QWeb-Templates und POS JS nur aktivieren, wenn POS-Modul auch vorhanden ist +- [ ] Kompatibilität zu JS (ES5 / `odoo.define`) prüfen + +--- + +## 🔬 5. Tools & Debugging +- [ ] `odoo-bin shell -d hh16` für gezielte Tests nutzen +- [ ] Überprüfen ob Einträge in `ir.model.data` korrekt vorhanden sind +- [ ] Logdateien auf Foreign Key oder View-Probleme prüfen + +--- + +## 🔧 Optional +- [ ] `migrate_existing_partners()` über `res.partner` testen +- [ ] Migration der alten `vvow_*` Felder validieren + +--- + +## ⚙ Nächste Schritte +- [ ] Schritt 2 (Demo- und Security-Dateien) zuerst +- [ ] Schrittweise View-Dateien aktivieren +- [ ] Modul vollständig über Backend installierbar machen +- [ ] POS-Integration zuletzt wiederherstellen + diff --git a/views/assets.xml b/views/assets.xml deleted file mode 100644 index df9e202..0000000 --- a/views/assets.xml +++ /dev/null @@ -1,13 +0,0 @@ - - -