fixed inverse unrelated fiels deletion, added tests
All checks were successful
odoo-restore-open_workshop-install / run-odoo-backup-in-docker (push) Successful in 4m40s

This commit is contained in:
gitea 2025-04-23 17:43:31 +00:00
parent ef46a18937
commit 5498b20ea5
3 changed files with 203 additions and 14 deletions

View File

@ -14,35 +14,36 @@ class ResPartner(models.Model):
ows_user_id = fields.One2many('ows.user', 'partner_id', string="OWS Benutzerdaten") ows_user_id = fields.One2many('ows.user', 'partner_id', string="OWS Benutzerdaten")
# ✳️ Zugriff auf Felder aus ows.user per compute + inverse (statt related) # Alte Felder (weiterhin sichtbar für externe Programme)
birthday = fields.Date( birthday = fields.Date(
string="Geburtstag", string="Geburtstag",
compute='_compute_ows_user_fields', compute='_compute_ows_user_fields',
inverse='_inverse_ows_user_fields', inverse='_inverse_birthday',
store=False store=False
) )
rfid_card = fields.Text( rfid_card = fields.Text(
string="RFID Card ID", string="RFID Card ID",
compute='_compute_ows_user_fields', compute='_compute_ows_user_fields',
inverse='_inverse_ows_user_fields', inverse='_inverse_rfid_card',
store=False store=False
) )
security_briefing = fields.Boolean( security_briefing = fields.Boolean(
string="Haftungsausschluss", string="Haftungsausschluss",
compute='_compute_ows_user_fields', compute='_compute_ows_user_fields',
inverse='_inverse_ows_user_fields', inverse='_inverse_security_briefing',
store=False store=False
) )
security_id = fields.Text( security_id = fields.Text(
string="Haftungsausschluss ID", string="Haftungsausschluss ID",
compute='_compute_ows_user_fields', compute='_compute_ows_user_fields',
inverse='_inverse_ows_user_fields', inverse='_inverse_security_id',
store=False store=False
) )
# Neue direkte vvow_* Felder
vvow_birthday = fields.Date(string="Geburtstag (vvow)")
vvow_rfid_card = fields.Text(string="RFID Card ID (vvow)")
vvow_security_briefing = fields.Boolean(string="Haftungsausschluss (vvow)")
vvow_security_id = fields.Text(string="Haftungsausschluss ID (vvow)")
@api.depends('ows_user_id') @api.depends('ows_user_id')
def _compute_ows_user_fields(self): def _compute_ows_user_fields(self):
@ -53,28 +54,76 @@ class ResPartner(models.Model):
partner.security_briefing = user.security_briefing if user else False partner.security_briefing = user.security_briefing if user else False
partner.security_id = user.security_id if user else False partner.security_id = user.security_id if user else False
def _inverse_ows_user_fields(self): def _inverse_birthday(self):
for partner in self: for partner in self:
user = partner.ows_user_id[0] if partner.ows_user_id else False user = partner.ows_user_id[0] if partner.ows_user_id else False
if user: if user:
user.birthday = partner.birthday user.birthday = partner.birthday
def _inverse_rfid_card(self):
for partner in self:
user = partner.ows_user_id[0] if partner.ows_user_id else False
if user:
user.rfid_card = partner.rfid_card user.rfid_card = partner.rfid_card
def _inverse_security_briefing(self):
for partner in self:
user = partner.ows_user_id[0] if partner.ows_user_id else False
if user:
user.security_briefing = partner.security_briefing user.security_briefing = partner.security_briefing
def _inverse_security_id(self):
for partner in self:
user = partner.ows_user_id[0] if partner.ows_user_id else False
if user:
user.security_id = partner.security_id user.security_id = partner.security_id
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
partners = super().create(vals_list) partners = super().create(vals_list)
for vals, partner in zip(vals_list, partners): for vals, partner in zip(vals_list, partners):
self.env['ows.user'].create({ self.env['ows.user'].create({
'partner_id': partner.id, 'partner_id': partner.id,
'birthday': vals.get('birthday'), 'birthday': vals.get('birthday') or vals.get('vvow_birthday'),
'rfid_card': vals.get('rfid_card'), 'rfid_card': vals.get('rfid_card') or vals.get('vvow_rfid_card'),
'security_briefing': vals.get('security_briefing'), 'security_briefing': vals.get('security_briefing') or vals.get('vvow_security_briefing'),
'security_id': vals.get('security_id'), 'security_id': vals.get('security_id') or vals.get('vvow_security_id'),
}) })
return partners return partners
def write(self, vals):
res = super().write(vals)
for partner in self:
user = partner.ows_user_id[0] if partner.ows_user_id else False
if not user:
continue
# Synchronisation alt -> user
if 'birthday' in vals:
user.birthday = vals['birthday']
if 'rfid_card' in vals:
user.rfid_card = vals['rfid_card']
if 'security_briefing' in vals:
user.security_briefing = vals['security_briefing']
if 'security_id' in vals:
user.security_id = vals['security_id']
# Synchronisation vvow_* -> user + alt
if 'vvow_birthday' in vals:
user.birthday = vals['vvow_birthday']
partner.birthday = vals['vvow_birthday']
if 'vvow_rfid_card' in vals:
user.rfid_card = vals['vvow_rfid_card']
partner.rfid_card = vals['vvow_rfid_card']
if 'vvow_security_briefing' in vals:
user.security_briefing = vals['vvow_security_briefing']
partner.security_briefing = vals['vvow_security_briefing']
if 'vvow_security_id' in vals:
user.security_id = vals['vvow_security_id']
partner.security_id = vals['vvow_security_id']
return res
machine_access_ids = fields.One2many( machine_access_ids = fields.One2many(
'ows.machine.access', 'ows.machine.access',
'partner_id', 'partner_id',
@ -87,6 +136,7 @@ class ResPartner(models.Model):
sanitize=False sanitize=False
) )
@api.depends('machine_access_ids') @api.depends('machine_access_ids')
def _compute_machine_access_html(self): def _compute_machine_access_html(self):
areas = self.env['ows.machine.area'].search([], order="name") areas = self.env['ows.machine.area'].search([], order="name")

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
from . import test_res_partner

138
tests/test_res_partner.py Normal file
View File

@ -0,0 +1,138 @@
## 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
from odoo.tests.common import TransactionCase
from odoo.tests import tagged
import logging
_logger = logging.getLogger(__name__)
@tagged('post_install', 'open_workshop', 'vvow')
class TestResPartnerVvowFields(TransactionCase):
def setUp(self):
super().setUp()
self.partner_model = self.env['res.partner']
self.user_model = self.env['ows.user']
def test_create_with_vvow_fields_creates_user(self):
partner = self.partner_model.create({
'name': 'Max Test',
'vvow_birthday': '1990-01-01',
'vvow_rfid_card': 'ABC12345',
'vvow_security_briefing': True,
'vvow_security_id': 'HB-001',
})
user = partner.ows_user_id
self.assertEqual(len(user), 1)
self.assertEqual(user.birthday.isoformat(), '1990-01-01')
self.assertEqual(user.rfid_card, 'ABC12345')
self.assertTrue(user.security_briefing)
self.assertEqual(user.security_id, 'HB-001')
# Check that Fassade korrekt ausgerechnet ist
self.assertEqual(partner.birthday.isoformat(), '1990-01-01')
self.assertEqual(partner.rfid_card, 'ABC12345')
self.assertTrue(partner.security_briefing)
self.assertEqual(partner.security_id, 'HB-001')
def test_write_vvow_fields_updates_user_and_fassade(self):
partner = self.partner_model.create({'name': 'Update Tester'})
user = partner.ows_user_id
partner.write({
'vvow_birthday': '1985-12-31',
'vvow_rfid_card': 'NEW123',
'vvow_security_briefing': False,
'vvow_security_id': 'NEU-SEC',
})
self.assertEqual(user.birthday.isoformat(), '1985-12-31')
self.assertEqual(user.rfid_card, 'NEW123')
self.assertFalse(user.security_briefing)
self.assertEqual(user.security_id, 'NEU-SEC')
# Sicherstellen, dass die berechneten Felder auch aktualisiert wurden
self.assertEqual(partner.birthday.isoformat(), '1985-12-31')
self.assertEqual(partner.rfid_card, 'NEW123')
self.assertFalse(partner.security_briefing)
self.assertEqual(partner.security_id, 'NEU-SEC')
def test_change_fassade_field_updates_user(self):
partner = self.partner_model.create({
'name': 'Change Fassade',
'vvow_security_briefing': True,
})
user = partner.ows_user_id
# Ändere security_briefing (die Fassade)
partner.write({'security_briefing': False})
# Muss sich im ows.user widerspiegeln
self.assertFalse(user.security_briefing)
# vvow-Sync: vvow bleibt wie gehabt (wird nicht überschrieben)
self.assertTrue(partner.vvow_security_briefing)
def test_change_and_read_consistency(self):
partner = self.partner_model.create({
'name': 'Read-Change-Test',
'vvow_security_briefing': True,
})
user = partner.ows_user_id
# Ändere security_briefing über Fassade
partner.write({'security_briefing': False})
self.assertFalse(user.security_briefing)
self.assertFalse(partner.security_briefing)
# Lies vvow_* separat aus sollte weiterhin den ursprünglichen vvow-Wert zeigen
self.assertTrue(partner.vvow_security_briefing)
# Ändere vvow_* erneut jetzt sollte alles wieder gesetzt werden
partner.write({'vvow_security_briefing': True})
self.assertTrue(partner.security_briefing)
self.assertTrue(user.security_briefing)
def test_inverse_does_not_clear_unrelated_fields(self):
_logger.info("🔍 Starte Test für Feldsynchronisation")
# Schritt 1: Partner mit vvow_* Feldern erzeugen → soll automatisch ows.user erzeugen
partner = self.partner_model.create({
'name': 'Unabhängigkeits-Test',
'vvow_birthday': '1995-05-05',
'vvow_rfid_card': 'ABC999',
'vvow_security_briefing': True,
'vvow_security_id': 'SEC-XYZ',
})
_logger.debug("✅ Partner angelegt: %s", partner.name)
# Validierung: es wurde ein ows.user erzeugt
self.assertEqual(len(partner.ows_user_id), 1, "Kein ows.user erzeugt")
user = partner.ows_user_id
_logger.debug("👤 ows.user: %s", user.read(['birthday', 'security_id']))
# Sicherstellen, dass alle Felder korrekt gesetzt wurden
self.assertEqual(user.birthday.isoformat(), '1995-05-05')
self.assertEqual(user.rfid_card, 'ABC999')
self.assertTrue(user.security_briefing)
self.assertEqual(user.security_id, 'SEC-XYZ')
# Schritt 2: Nur ein Feld über die Fassade ändern (inverse wird getriggert)
partner.write({'security_briefing': False})
_logger.info("✏️ security_briefing auf False gesetzt")
# Schritt 3: DB-Cache leeren
user.flush()
user.invalidate_cache()
_logger.debug("📦 user nach write: %s", user.read(['birthday', 'security_id']))
# Schritt 4: Sicherstellen, dass die anderen Felder NICHT gelöscht wurden
self.assertEqual(user.birthday.isoformat(), '1995-05-05')
self.assertEqual(user.rfid_card, 'ABC999')
self.assertEqual(user.security_id, 'SEC-XYZ')
self.assertFalse(user.security_briefing)