# -*- coding: utf-8 -*- # ows_models.py # Part of Odoo Open Workshop from odoo import models, fields, api import logging _logger = logging.getLogger(__name__) _logger.info("✅ ows_models.py geladen") class ResPartner(models.Model): _inherit = 'res.partner' _logger.info("✅ ows ResPartner geladen") ows_user_id = fields.Many2one( 'ows.user', string='OWS Benutzerdaten', compute='_compute_ows_user', inverse='_inverse_ows_user', store=True, ) # ✳️ Related-Felder zur Verwendung im Formular birthday = fields.Date(related='ows_user_id.birthday', readonly=False) rfid_card = fields.Text(related='ows_user_id.rfid_card', readonly=False) security_briefing = fields.Boolean(related='ows_user_id.security_briefing', readonly=False) security_id = fields.Text(related='ows_user_id.security_id', readonly=False) def _compute_ows_user(self): for partner in self: partner.ows_user_id = self.env['ows.user'].search( [('partner_id', '=', partner.id)], limit=1 ) @api.model_create_multi def create(self, vals_list): partners = super().create(vals_list) for partner in partners: self.env['ows.user'].create({'partner_id': partner.id}) return partners machine_access_ids = fields.One2many( 'ows.machine.access', 'partner_id', string='Maschinenfreigaben' ) machine_access_html = fields.Html( string="Maschinenfreigaben", compute="_compute_machine_access_html", sanitize=False ) @api.depends('machine_access_ids') def _compute_machine_access_html(self): """ Computes an HTML representation of the machine access permissions for each partner. The HTML is structured as a grid of machine areas, where each area contains a table listing the machines and whether the partner has access to them. - Iterates through all machine areas and their associated machines. - Checks if the partner has access to each machine. - Generates an HTML table with a checkmark or cross icon for each machine access status. - Assigns the generated HTML to the `machine_access_html` field of the partner. """ for partner in self: areas = self.env['ows.machine.area'].search([], order="name") html = """
""" for area in areas: html += f"
" html += f"" html += f"" 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 = "" if access else "" 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""" """ html += "
{area.name}DatumGültig bis
{icon} {date_granted} {date_expiry}
" html += "
" partner.machine_access_html = html @api.model def migrate_existing_partners(self): """ Erstellt für alle vorhandenen res.partner einen ows.user, wenn noch keiner existiert, und übernimmt alte vvow_* Felder. odoo-bin shell -d deine_datenbank env['res.partner'].migrate_existing_partners() """ migrated = 0 skipped = 0 partners = self.env['res.partner'].search([]) for partner in partners: if partner.ows_user_id: skipped += 1 continue # Werte lesen (werden evtl. durch _inherit hinzugefügt) vals = { 'partner_id': partner.id, 'birthday': getattr(partner, 'vvow_birthday', False), 'rfid_card': getattr(partner, 'vvow_rfid_card', False), 'security_briefing': getattr(partner, 'vvow_security_briefing', False), 'security_id': getattr(partner, 'vvow_security_id', False), } self.env['ows.user'].create(vals) migrated += 1 _logger = self.env['ir.logging'] _logger.info(f"[OWS Migration] ✅ Migriert: {migrated}, ❌ Übersprungen: {skipped}") return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': "Migration abgeschlossen", 'message': f"{migrated} Partner migriert, {skipped} übersprungen.", 'sticky': False, } } class OwsUser(models.Model): _name = 'ows.user' _description = 'OWS: Benutzerdaten' _table = 'ows_user' _logger.info("✅ ows_user geladen") partner_id = fields.Many2one( 'res.partner', required=True, ondelete='cascade', string='Kontakt' ) birthday = fields.Date('Geburtstag') rfid_card = fields.Text('RFID Card ID') security_briefing = fields.Boolean('Haftungsausschluss', default=False) security_id = fields.Text('Haftungsausschluss ID') _sql_constraints = [ ('partner_unique', 'unique(partner_id)', 'Jeder Partner darf nur einen OWS-Datensatz haben.') ] class OwsMachineArea(models.Model): _name = 'ows.machine.area' _table = "ows_machine_area" _description = 'OWS: Maschinenbereich' _order = 'name' name = fields.Char(required=True, translate=True) #color = fields.Integer(string="Farbe") color_hex = fields.Char(string="Farbe (Hex)", help="Hex-Farbcode wie #FF0000 für Rot") class OwsMachine(models.Model): _name = 'ows.machine' _table = 'ows_machine' _description = 'OWS: Maschine' name = fields.Char(required=True, translate=True) code = fields.Char(required=True, help="Eindeutiger Kurzcode, z.B. 'lasercutter'") description = fields.Text() active = fields.Boolean(default=True) area_id = fields.Many2one('ows.machine.area', string='Bereich') product_ids = fields.One2many('ows.machine.product', 'machine_id', string="Nutzungsprodukte") product_names = fields.Char(string="Nutzungsprodukte Liste", compute="_compute_product_using_names", store=False,) training_ids = fields.One2many('ows.machine.training', 'machine_id', string="Einweisungsprodukte") training_names = fields.Char(string="Einweisungsprodukte Liste", compute="_compute_product_training_names", store=False,) @api.depends('product_ids.product_id.name') def _compute_product_using_names(self): for machine in self: names = machine.product_ids.mapped('product_id.name') machine.product_names = ", ".join(names) @api.depends('training_ids.training_id.name') def _compute_product_training_names(self): for machine in self: names = machine.training_ids.mapped('training_id.name') machine.training_names = ", ".join(names) _sql_constraints = [ ('code_unique', 'unique(code)', 'Maschinencode muss eindeutig sein.') ] def name_get(self): return [(rec.id, f"{rec.name} ({rec.code})") for rec in self] @api.model def get_access_list_grouped(self, partner_id): areas = self.env['ows.machine.area'].search([], order="name") _logger.info("🔍 Maschinenbereiche: %s", areas.mapped('name')) _logger.info("🔍 Partner_id: %s", partner_id) res = [] for area in areas: machines = self.search([('area_id', '=', area.id)], order="name") machine_list = [] for machine in machines: has_access = bool(self.env['ows.machine.access'].search([ ('partner_id', '=', partner_id), ('machine_id', '=', machine.id), ], limit=1)) machine_list.append({ 'name': machine.name, 'has_access': has_access, }) res.append({ 'area': area.name, 'color_hex': area.color_hex or '#000000', 'machines': machine_list }) return res class OwsMachineAccess(models.Model): _name = 'ows.machine.access' _table = 'ows_machine_access' _description = 'OWS: Maschinenfreigabe' _order = 'partner_id, machine_id' partner_id = fields.Many2one('res.partner', required=True, ondelete='cascade') machine_id = fields.Many2one('ows.machine', required=True) date_granted = fields.Date(default=fields.Date.today) date_expiry = fields.Date(string="Ablaufdatum") granted_by_pos = fields.Boolean(default=True) _sql_constraints = [ ('partner_machine_unique', 'unique(partner_id, machine_id)', 'Der Kunde hat diese Freigabe bereits.') ] class OwsMachineProduct(models.Model): _name = 'ows.machine.product' _table = 'ows_machine_product' _description = 'OWS: Zurordnung Produkt der Nutzung zur die Maschine' product_id = fields.Many2one('product.product', required=True, domain=[('available_in_pos', '=', True)], ondelete='cascade') machine_id = fields.Many2one('ows.machine', required=True, ondelete='cascade') class OwsMachineTraining(models.Model): _name = 'ows.machine.training' _table = 'ows_machine_training' _description = 'OWS: Zurordnung Produkt der Einweisung zur die Maschine' training_id = fields.Many2one('product.product', required=True, domain=[('available_in_pos', '=', True)], ondelete='cascade') machine_id = fields.Many2one('ows.machine', required=True, ondelete='cascade')