Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7fa003337 | |||
| adffd9f2ba | |||
| 392d88c030 | |||
| f4216d790c | |||
| eb17894a13 |
|
|
@ -1,5 +1,3 @@
|
|||
from . import models
|
||||
from . import controllers
|
||||
from . import post_init_hook
|
||||
# damit run_migration sichtbar ist:
|
||||
run_migration = post_init_hook.run_migration
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
'name': 'POS Open Workshop',
|
||||
'license': 'AGPL-3',
|
||||
'version': '13.0.1.0.0',
|
||||
'version': '17.0.1.0.0',
|
||||
'summary': 'Erstellt Maschinenfreigaben basierend auf POS-Einweisungsprodukten',
|
||||
'depends': ['base','product','sale','contacts','point_of_sale'],
|
||||
'depends': ['base','product','hr','sale','contacts','point_of_sale'],
|
||||
'author': 'matthias.lotz',
|
||||
'category': 'Point of Sale',
|
||||
'data': [
|
||||
|
|
@ -13,7 +13,6 @@
|
|||
'views/machine_area_views.xml',
|
||||
'views/machine_views.xml',
|
||||
'views/res_partner_view.xml',
|
||||
'views/assets.xml',
|
||||
'data/data.xml',
|
||||
],
|
||||
'qweb': [
|
||||
|
|
@ -26,13 +25,15 @@
|
|||
'installable': True,
|
||||
'assets': {
|
||||
'point_of_sale.assets': [
|
||||
'static/src/js/machine_access_sidebar.js',
|
||||
'static/src/css/pos.css',
|
||||
'open_workshop/static/src/js/product_screen_template_patch.js',
|
||||
'open_workshop/static/src/css/pos.css',
|
||||
'open_workshop/static/src/js/ows_pos_customer_sidebar.js',
|
||||
'open_workshop/static/src/xml/ows_pos_customer_sidebar.xml',
|
||||
'open_workshop/static/src/xml/ows_product_screen.xml',
|
||||
],
|
||||
},
|
||||
'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 17.0 konzipiert.
|
||||
""",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
/opt/odoo/odoo/odoo-bin shell -d hobbyhimmel < /home/odoo/custom_addons/open_workshop/demo/export_partner.py
|
||||
|
||||
|
|
@ -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,
|
||||
])
|
||||
|
|
@ -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)
|
||||
|
|
@ -8,6 +8,33 @@ import logging
|
|||
_logger = logging.getLogger(__name__)
|
||||
_logger.info("✅ ows_models.py geladen")
|
||||
|
||||
class HREmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
|
||||
@api.model
|
||||
def anonymize_for_testsystem(self):
|
||||
"""Benennt Admin-Angestellten um und archiviert alle anderen für das Testsystem."""
|
||||
admin_user = self.env['res.users'].search([('name', '=', 'Administrator')], limit=1)
|
||||
_logger.info(f"[OWS] Administrator-Benutzer gefunden: {admin_user.name} (ID: {admin_user.id})")
|
||||
admin_employee = self.search([('user_id', '=', admin_user.id)], limit=1)
|
||||
|
||||
if admin_employee:
|
||||
admin_employee.write({
|
||||
'name': 'TESTSYSTEM',
|
||||
'job_title': 'Testumgebung',
|
||||
'work_email': False,
|
||||
'work_phone': False,
|
||||
})
|
||||
_logger.info("[OWS] Admin-Angestellter wurde umbenannt.")
|
||||
else:
|
||||
_logger.warning("[OWS] Kein Angestellter für user_admin gefunden.")
|
||||
|
||||
# Alle anderen Angestellten archivieren
|
||||
other_employees = self.search([('id', '!=', admin_employee.id)])
|
||||
other_employees.write({'active': False})
|
||||
_logger.info("[OWS] %d Angestellte archiviert.", len(other_employees))
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
_logger.info("✅ ows ResPartner geladen")
|
||||
|
|
@ -141,32 +168,49 @@ class ResPartner(models.Model):
|
|||
def _compute_machine_access_html(self):
|
||||
areas = self.env['ows.machine.area'].search([], order="name")
|
||||
for partner in self:
|
||||
html = "<div style='display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem;'>"
|
||||
html = ""
|
||||
for area in areas:
|
||||
html += f"<div class='o_group' style='margin-bottom: 1em;'>"
|
||||
html += f"<table class='o_group o_inner_group'>"
|
||||
html += f"<thead><tr><th>{area.name}</th><th></th><th>Datum</th><th>Gültig bis</th></tr></thead><tbody>"
|
||||
html += f"""
|
||||
<div class="o_form_sheet">
|
||||
<h3 class="o_form_label">{area.name}</h3>
|
||||
<table class="table table-sm table-bordered o_form_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Maschine</th>
|
||||
<th>Status</th>
|
||||
<th>Datum</th>
|
||||
<th>Gültig bis</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
"""
|
||||
|
||||
machines = self.env['ows.machine'].search([('area_id', '=', area.id)], order="name")
|
||||
|
||||
for machine in machines:
|
||||
access = self.env['ows.machine.access'].search([
|
||||
('partner_id', '=', partner.id),
|
||||
('machine_id', '=', machine.id),
|
||||
], limit=1)
|
||||
icon = "<span class='fa fa-check text-success'></span>" if access else "<span class='fa fa-times text-danger'></span>"
|
||||
date_granted = access.date_granted.strftime('%Y-%m-%d') if access and access.date_granted else ""
|
||||
date_expiry = access.date_expiry.strftime('%Y-%m-%d') if access and access.date_expiry else ""
|
||||
icon = '<span class="text-success fa fa-check"/>' if access else '<span class="text-danger fa fa-times"/>'
|
||||
date_granted = access.date_granted.strftime('%Y-%m-%d') if access and access.date_granted else "-"
|
||||
date_expiry = access.date_expiry.strftime('%Y-%m-%d') if access and access.date_expiry else "-"
|
||||
|
||||
html += f"""
|
||||
<tr>
|
||||
<td class='o_td_label'><label>{machine.name}</label></td>
|
||||
<td class='o_td_field'>{icon}</td>
|
||||
<td class='o_td_field'>{date_granted}</td>
|
||||
<td class='o_td_field'>{date_expiry}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{machine.name}</td>
|
||||
<td>{icon}</td>
|
||||
<td>{date_granted}</td>
|
||||
<td>{date_expiry}</td>
|
||||
</tr>
|
||||
"""
|
||||
|
||||
html += "</tbody></table></div>"
|
||||
html += "</div>"
|
||||
|
||||
partner.machine_access_html = html
|
||||
|
||||
|
||||
|
||||
@api.model
|
||||
def migrate_existing_partners(self):
|
||||
"""
|
||||
|
|
@ -283,6 +327,31 @@ class ResPartner(models.Model):
|
|||
|
||||
_logger.info(f"[OWS Migration] ✅ Maschinenfreigaben erstellt: {count_created}")
|
||||
self.env.cr.commit()
|
||||
|
||||
@api.model
|
||||
def archive_partners_without_users(self):
|
||||
"""
|
||||
Archiviert alle Partner (res.partner), die keine Benutzer (res.users) sind.
|
||||
"""
|
||||
Partner = self.env['res.partner']
|
||||
User = self.env['res.users']
|
||||
|
||||
# IDs aller Partner, die ein Benutzerkonto haben
|
||||
user_partner_ids = User.search([]).mapped('partner_id').ids
|
||||
|
||||
# Alle Partner ohne Benutzerkonto
|
||||
partners_to_archive = Partner.search([
|
||||
('id', 'not in', user_partner_ids),
|
||||
('active', '=', True),
|
||||
])
|
||||
|
||||
count = len(partners_to_archive)
|
||||
partners_to_archive.write({'active': False})
|
||||
for p in partners_to_archive:
|
||||
_logger.debug(f"[OWS] Archiviert Partner: {p.name} (ID {p.id})")
|
||||
_logger.info(f"[OWS] Archiviert {count} Partner ohne Benutzerkonto.")
|
||||
self.env.cr.commit()
|
||||
|
||||
|
||||
class OwsUser(models.Model):
|
||||
_name = 'ows.user'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from odoo import models, fields, api
|
||||
from collections import defaultdict
|
||||
|
||||
#import debugpy
|
||||
import logging
|
||||
|
|
@ -19,10 +20,9 @@ class PosOrder(models.Model):
|
|||
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
|
||||
}
|
||||
product_map = defaultdict(list)
|
||||
for tp in training_products:
|
||||
product_map[tp.training_id.product_tmpl_id.id].append(tp.machine_id.id)
|
||||
|
||||
partner = pos_order.partner_id
|
||||
if not partner:
|
||||
|
|
@ -31,15 +31,13 @@ class PosOrder(models.Model):
|
|||
|
||||
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:
|
||||
machine_ids = product_map.get(product_tmpl_id, [])
|
||||
_logger.info("🔍 Prüfe Produkt %s → Maschinen IDs: %s", line.product_id.display_name, machine_ids)
|
||||
for machine_id in machine_ids:
|
||||
already_exists = self.env['ows.machine.access'].search([
|
||||
('partner_id', '=', partner.id),
|
||||
('machine_id', '=', machine_id)
|
||||
])
|
||||
], limit=1)
|
||||
if not already_exists:
|
||||
self.env['ows.machine.access'].create({
|
||||
'partner_id': partner.id,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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} <<EOF
|
||||
get ${BACKUP_NAME}.gpg
|
||||
get ${BACKUP_NAME}
|
||||
EOF
|
||||
# Prüft, ob der vorherige Befehl erfolgreich war, sonst bricht das Skript ab.
|
||||
if [ $? -ne 0 ]; then
|
||||
report_failure "SFTP transfer"
|
||||
fi
|
||||
cd /root
|
||||
|
||||
# Backup entschlüsseln -> 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"
|
||||
|
|
@ -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.")
|
||||
File diff suppressed because it is too large
Load Diff
44
static/src/js/ows_pos_customer_sidebar.js
Normal file
44
static/src/js/ows_pos_customer_sidebar.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// @odoo-module
|
||||
|
||||
import { Component } from "@odoo/owl";
|
||||
import { usePos } from "@point_of_sale/app/store/pos_hook";
|
||||
|
||||
export class OwsPosCustomerSidebar extends Component {
|
||||
static template = "open_workshop.OwsPosCustomerSidebar";
|
||||
|
||||
setup() {
|
||||
this.pos = usePos();
|
||||
}
|
||||
|
||||
addOrder() {
|
||||
this.pos.add_new_order();
|
||||
}
|
||||
|
||||
removeCurrentOrder() {
|
||||
const order = this.pos.get_order();
|
||||
if (order) {
|
||||
this.pos.removeOrder(order);
|
||||
}
|
||||
}
|
||||
|
||||
openTicketScreen() {
|
||||
this.pos.showScreen("TicketScreen");
|
||||
}
|
||||
|
||||
getFilteredOrderList() {
|
||||
return this.pos.get_order_list();
|
||||
}
|
||||
|
||||
getDate(order) {
|
||||
const date = new Date(order.creationDate || order.creation_date || Date.now());
|
||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
getPartner(order) {
|
||||
return order.get_partner()?.name || "Kein Kunde";
|
||||
}
|
||||
|
||||
selectOrder(order) {
|
||||
this.pos.set_order(order);
|
||||
}
|
||||
}
|
||||
16
static/src/js/product_screen_template_patch.js
Normal file
16
static/src/js/product_screen_template_patch.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// @odoo-module
|
||||
|
||||
import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { OwsPosCustomerSidebar } from "@open_workshop/js/ows_pos_customer_sidebar";
|
||||
|
||||
export class OwsProductScreen extends ProductScreen {
|
||||
static template = "open_workshop.ProductScreen";
|
||||
static components = {
|
||||
...ProductScreen.components,
|
||||
OwsPosCustomerSidebar,
|
||||
};
|
||||
}
|
||||
|
||||
registry.category("pos_screens").remove("ProductScreen");
|
||||
registry.category("pos_screens").add("ProductScreen", OwsProductScreen);
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="MachineAccessSidebar" owl="1">
|
||||
<t t-name="MachineAccessSidebar">
|
||||
<div class="machine-access-sidebar">
|
||||
<div class="access-content">
|
||||
</div>
|
||||
|
|
|
|||
23
static/src/xml/ows_pos_customer_sidebar.xml
Normal file
23
static/src/xml/ows_pos_customer_sidebar.xml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="open_workshop.OwsPosCustomerSidebar" owl="1">
|
||||
<div class="ows-sidebar p-2 bg-light border-end h-100">
|
||||
<div class="ows-sidebar-header mb-2 d-flex justify-content-between align-items-center">
|
||||
<button class="btn btn-secondary" t-on-click="openTicketScreen">Orders</button>
|
||||
<div>
|
||||
<button class="btn btn-sm btn-success me-1" t-on-click="addOrder">+</button>
|
||||
<button class="btn btn-sm btn-danger" t-on-click="removeCurrentOrder">–</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ows-customer-list overflow-auto">
|
||||
<t t-foreach="getFilteredOrderList()" t-as="order" t-key="order.uid">
|
||||
<div class="order-entry p-1 rounded mb-1 border"
|
||||
t-att-class="order === pos.get_order() ? 'bg-primary text-white' : 'bg-white'"
|
||||
t-on-click="() => selectOrder(order)">
|
||||
<div><t t-esc="getDate(order)"/> – <t t-esc="getPartner(order)"/></div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
45
static/src/xml/ows_product_screen.xml
Normal file
45
static/src/xml/ows_product_screen.xml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="open_workshop.ProductScreen" owl="1">
|
||||
<div class="product-screen d-flex h-100 bg-100" t-att-class="{ 'd-none': !props.isShown }">
|
||||
<div class="custompane d-flex flex-column border-end bg-200">
|
||||
<OwsPosCustomerSidebar />
|
||||
</div>
|
||||
|
||||
<div t-if="!ui.isSmall || pos.mobile_pane === 'left'"
|
||||
t-att-class="{'flex-grow-1': ui.isSmall}"
|
||||
class="leftpane d-flex flex-column border-end bg-200" >
|
||||
<OrderWidget lines="currentOrder.orderlines" t-slot-scope="scope"
|
||||
total="env.utils.formatCurrency(currentOrder.get_total_with_tax())"
|
||||
tax="!env.utils.floatIsZero(currentOrder.get_total_tax()) and env.utils.formatCurrency(currentOrder.get_total_tax()) or ''">
|
||||
<t t-set="line" t-value="scope.line" />
|
||||
<Orderline line="line.getDisplayData()"
|
||||
t-on-click="() => this.selectLine(line)"
|
||||
class="{ ...line.getDisplayClasses(), 'selected' : line.selected }"/>
|
||||
<t t-set-slot="details" />
|
||||
</OrderWidget>
|
||||
<div class="pads border-top">
|
||||
<div class="control-buttons d-flex flex-wrap border-bottom overflow-hidden bg-300" t-if="!ui.isSmall">
|
||||
<t t-foreach="controlButtons" t-as="cb" t-key="cb.name">
|
||||
<t t-component="cb.component" t-key="cb.name"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="subpads d-flex">
|
||||
<ActionpadWidget partner="partner" actionName="constructor.numpadActionName" actionType="'payment'" onClickMore.bind="displayAllControlPopup" />
|
||||
<Numpad buttons="getNumpadButtons()" onClick.bind="onNumpadClick" class="'w-100'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rightpane overflow-auto d-flex flex-grow-1 flex-column bg-300 w-60" t-if="!ui.isSmall || pos.mobile_pane === 'right'">
|
||||
<ProductsWidget />
|
||||
<t t-if="ui.isSmall">
|
||||
<div class="product-reminder d-flex justify-content-center align-items-center py-1 text-bg-warning bg-opacity-50 fw-bolder"
|
||||
t-if="currentOrder.get_selected_orderline() and currentOrder.hasJustAddedProduct" t-key="animationKey" >
|
||||
<span><t t-esc="selectedOrderlineQuantity"/> <t t-esc="selectedOrderlineDisplayName"/> <t t-esc="selectedOrderlineTotal"/></span>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
75
todo.md
75
todo.md
|
|
@ -1,3 +1,72 @@
|
|||
[ ] Help System
|
||||
[ ] Möglichkeit, Einweisungen manuell zu setzen?
|
||||
[ ]
|
||||
# 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 -> tests/test_access_rights.py
|
||||
|
||||
---
|
||||
|
||||
## 🎨 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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
<odoo>
|
||||
<data>
|
||||
<template id="assets" inherit_id="point_of_sale.assets">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/open_workshop/static/src/js/machine_access_sidebar.js"/>
|
||||
<template id="machine_access_template" name="Maschinenfreigaben Template" src="/open_workshop/static/src/xml/ows_machine_sidebar.xml"/>
|
||||
</xpath>
|
||||
<xpath expr="//link[@href='/point_of_sale/static/src/css/pos.css']" position="replace">
|
||||
<link rel="stylesheet" type="text/css" href="/open_workshop/static/src/css/pos.css"/>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
<!--<odoo>
|
||||
<template id="assets_open_workshop" inherit_id="point_of_sale._assets_pos">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/open_workshop/static/src/js/machine_access_sidebar.js"/>
|
||||
<link rel="stylesheet" type="text/css" href="/open_workshop/static/src/css/pos.css"/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>-->
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="machine_id"/>
|
||||
<field name="training_id" domain="[('categ_id.name', '=', 'Einweisungen')]"/>
|
||||
<field name="training_id" domain="[('categ_id.name', 'in', ['Einweisungen', 'Kurse'])]"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
<page string="Einweisungsprodukte">
|
||||
<field name="training_ids" context="{'default_machine_id': active_id}">
|
||||
<tree editable="bottom">
|
||||
<field name="training_id" domain="[('categ_id.name', '=', 'Einweisungen')]" />
|
||||
<field name="training_id" domain="[('categ_id.name', 'in', ['Einweisungen', 'Kurse'])]" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
|
|
|||
|
|
@ -1,34 +1,22 @@
|
|||
<!-- res_partner_view.xml -->
|
||||
<odoo>
|
||||
<!-- View-Erweiterung für res.partner: Tab mit HTML-Tabelle
|
||||
Der Inhalt wird in der Methode _compute_machine_access_html() generiert.
|
||||
Diese Methode wird in der Klasse res.partner definiert in der Datei models/ows_models.py.
|
||||
Die Methode wird aufgerufen, wenn das Partnerformular geöffnet wird.
|
||||
Die HTML-Tabelle wird in der Variable machine_access_html gespeichert.
|
||||
Die Variable wird in der View angezeigt.
|
||||
-->
|
||||
<record id="view_partner_form_inherit_open_workshop_html" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.ows.machine.access.html</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="inside">
|
||||
<page string="HOBBYHIMMEL Einweisungen">
|
||||
<field name="machine_access_html" readonly="1" widget="html"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
<!-- Zentrale View für alle drei Tabs in garantierter Reihenfolge -->
|
||||
<record id="view_partner_form_inherit_open_workshop_tabs" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.ows.tabs</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="priority" eval="10"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='sales_purchases']" position="before">
|
||||
<page name="ows_machine_access" string="Offene Werkstatt (Hobbyhimmel)">
|
||||
<!-- EINWEISUNG: Zwei Felder nebeneinander -->
|
||||
<group name="container_row_2" string="Sicherheitseinweisung" col="2">
|
||||
<field name="security_briefing"/>
|
||||
<field name="security_id"/>
|
||||
</group>
|
||||
|
||||
<!-- Teil 1: Maschinenfreigaben-Tabelle -->
|
||||
<record id="view_partner_form_inherit_open_workshop" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.ows.machine.access</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="inside">
|
||||
<page string="Einweisungen (Liste)">
|
||||
<field name="machine_access_ids">
|
||||
<!-- MASCHINENFREIGABEN: Volle Breite -->
|
||||
<group string="Maschinenfreigaben" col="2">
|
||||
<field name="machine_access_ids" colspan="2" context="{'default_partner_id': id}" nolabel="1">
|
||||
<tree>
|
||||
<field name="machine_id"/>
|
||||
<field name="date_granted"/>
|
||||
|
|
@ -36,96 +24,81 @@
|
|||
<field name="granted_by_pos"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
</group>
|
||||
|
||||
<!-- Teil 2: HOBBYHIMMEL Basis (ows_user_id Felder) -->
|
||||
<record id="view_partner_form_inherit_ows_user" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.ows.user</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- Geburtstag direkt unter USt-ID -->
|
||||
<xpath expr="//field[@name='vat']" position="after">
|
||||
<field name="birthday"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Eigene Seite "Basis" nach der Verkaufsseite -->
|
||||
<xpath expr="//page[@name='sales_purchases']" position="after">
|
||||
<page name="ows_basic" string="HOBBYHIMMEL Basis">
|
||||
<group name="container_row_2">
|
||||
<group string="Sicherheit">
|
||||
<field name="security_briefing"/>
|
||||
<field name="security_id"/>
|
||||
</group>
|
||||
<group string="Zugang">
|
||||
<field name="rfid_card"/>
|
||||
</group>
|
||||
<!-- ÜBERSICHT: Volle Breite -->
|
||||
<group string="Maschinenfreigaben Übersicht" >
|
||||
<field name="machine_access_html" colspan="2" readonly="1" widget="html" nolabel="1"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
<record id="contacts.action_contacts" model="ir.actions.act_window">
|
||||
<field name="view_mode">tree,kanban,form,activity</field>
|
||||
</record>
|
||||
<record id="contacts.action_contacts_view_kanban" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
</record>
|
||||
<record id="contacts.action_contacts_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
<!--tree default_order="create_date desc"/-->
|
||||
</record>
|
||||
<!-- Action to set default view to list view for Contacts
|
||||
<record id="contacts.action_contacts" model="ir.actions.act_window">
|
||||
<field name="name">Contacts</field>
|
||||
<field name="res_model">res.partner</field>
|
||||
<field name="view_mode">tree,kanban,form</field>
|
||||
<field name="view_id" ref="base.view_partner_tree"/>
|
||||
</record>
|
||||
-->
|
||||
<record id="ows_userList_inherit" model="ir.ui.view">
|
||||
<field name="name">res.partner.ows.tree</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='vat']" position="after">
|
||||
<field name="create_date" optional="show"/>
|
||||
<field name="security_briefing" optional="show"/>
|
||||
<field name="security_id" optional="show"/>
|
||||
<field name="rfid_card" optional="show"/>
|
||||
<field name="category_id" widget="many2many_tags"/>
|
||||
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='vat']" position="replace">
|
||||
<field name="vat" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='email']" position="replace">
|
||||
<field name="email" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='phone']" position="replace">
|
||||
<field name="phone" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='state_id']" position="replace">
|
||||
<field name="state_id" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='country_id']" position="replace">
|
||||
<field name="country_id" invisible="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_partner_form_inherit" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.inherit.default_person</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_type" position="attributes">
|
||||
<attribute name="default">person</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Geburtstag direkt nach der USt-ID -->
|
||||
<record id="view_partner_form_inherit_ows_birthday" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.ows.birthday</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="priority" eval="15"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='vat']" position="after">
|
||||
<field name="birthday"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- List View Anpassung -->
|
||||
<record id="ows_userList_inherit" model="ir.ui.view">
|
||||
<field name="name">res.partner.ows.tree</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='vat']" position="after">
|
||||
<field name="create_date" optional="show"/>
|
||||
<field name="security_briefing" optional="show"/>
|
||||
<field name="security_id" optional="show"/>
|
||||
<field name="rfid_card" optional="show"/>
|
||||
<field name="category_id" widget="many2many_tags"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='vat']" position="replace">
|
||||
<field name="vat" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='email']" position="replace">
|
||||
<field name="email" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='phone']" position="replace">
|
||||
<field name="phone" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='state_id']" position="replace">
|
||||
<field name="state_id" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='country_id']" position="replace">
|
||||
<field name="country_id" invisible="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Standardwerte setzen (company_type = person) -->
|
||||
<record id="view_partner_form_inherit" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.inherit.default_person</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_type" position="attributes">
|
||||
<attribute name="default">person</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Optional: Kontakte-Action, falls gebraucht -->
|
||||
<record id="contacts.action_contacts" model="ir.actions.act_window">
|
||||
<field name="view_mode">tree,kanban,form,activity</field>
|
||||
</record>
|
||||
<record id="contacts.action_contacts_view_kanban" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
</record>
|
||||
<record id="contacts.action_contacts_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user